您的当前位置:首页正文

李宏毅DLHLP.21.Text Style Transfer

2024-11-08 来源:个人技术集锦

介绍

本门课程是2020年李宏毅老师新课:Deep Learning for Human Language Processing(深度学习与人类语言处理)


公式输入请参考:
这里的style不单指文章的文风。
之前有讲过和的Style Transfer。

也就是想要完成如下模型:

Cycle GAN

这个结构讲过很多了,一看就懂。模型Generator吃负面句子,生成一个正面的句子,这个结果要骗过Discriminator,Discriminator看过很多groud truth的正面句子,会对Generator生成结果进行判断。这里为了使得Generator不能作弊(每次都生成同一个正面句子就能作弊骗过Discriminator),加一个AE效果的Reconstruction,要把Generator生成的句子再变回换来的句子

Generator

Generator吃输入文本的第一个token的feature(粉色方块)和前一个token(采样结果),然后模型(RNN、LSTM等)会输出当前time step预测出来的token distribution(黄色带AB的方块),在distribution中进行sample,得到当前time step的结果(这个结果接入下一个时间步的输入【黄色带B或A的方块】),最后模型经过若干时间步得到预测的一串token sequence(红框中),把这个sequence输入Discriminator,Discriminator就会吐出一个scalar(分数),这个分数表示现在输出的句子是不是有某种风格。

Gumbel-softmax

估计这个方法已经有点过时(或者有点复杂),老师没有详细讲,可以看。里面最主要就是一个Re-parameterization Trick,通过用这个trick使得采样这个事情从反向传播的路径中消失了,变到了另外一边。

Continuous Input for Discriminator

第二个方法的思路是跳过采样这个步骤,直接将下图中的黄色方块(带AB的分布)作为Discriminator的输入。
Use the distribution as the input of discriminator. Avoid the sampling process. We can do backpropagation now.

Reinforcement Learning

这个是通用的解法,只要有不可微分的情况,用这个没错。具体做法如下图,将采样过程看成是Action,Discriminator看做是Environment,最后的scalar看成是reward。Generator看成是Agent,它的目标是使得最后的reward越高越好。

这里和普通的RL不一样的地方在于Environment,普通的RL的Environment是不变的,例如:游戏中的各种关卡,敌人出没时机等,玩围棋的规则是不变的。这里的Environment则是不断变化的(Discriminator是一个NN,参数是变化的),因此模型不好训练。

老师给出了几个相关的tip。这些tip从ScratchGAN这个文章来,衡量标准FED是越小越好(https://kuaibao.qq.com/s/20190528AZNML000?refer=spider)

tip1:Reward for Every Generation Step

普通的RL在训练过程中Discriminator是对整段文字直接给出最终的reward,并没有跟Generator说明是整段文字中哪一个部分造成了比较低的reward。跟下棋一样,下一盘棋才知道赢或者输,而不能对某一步棋的好坏进行评判,当然这样对于整体的信息把握有好处(天龙八部的虚竹下棋)

因此Discriminator可以把Generator的每个时间步的结果都进行判别一下,可以看到,当生成is的时候得分变低,而You没有问题。

有三种方法:
1.Monte Carlo (MC) Search:和AlphaGo很像,sample更多的以You开头的句子,丢到Discriminator。中,将得分结果平均后就得到You这个子序列的得分(下棋也是如此,先横炮还是先走卒,那个胜率高)
2.Discriminator For Partially Decoded Sequences:直接训练一个特别的Discriminator,它可以直接吃子序列给得分。
3.Step-wise evaluation:训练一个特别的Discriminator,在按token读取sequence的时候,按时间步给出相应token的分数。

实作结果


除此之外,还有另外一些风格的转换,例如:男转女,年青转老年,放松转烦躁等。

Star GAN

Cycle GAN可以用在两种风格的转换上,但是如果是要多个风格进行转换就要用到Star GAN,这个之前在将图像和的风格转换上都有讲过,这里就不展开了,总之Star GAN也可以用在Text Style Transfer上。

Feature Disentangle

之前在将VC的时候有讲过:

借鉴这个思想把Feature Disentangle用在Text Style Transfer中:

上图模型目标就是训练一个content encoder只抽取content的特征,同时训练一个style encoder只抽取style的特征。然后要换style,只需要把style这部分的特征换掉就可以了。这种方法17年左右用得多,但其效果不如Cycle GAN,因为要做句子的embedding,把句子压到一个latent space是比较困难的(因为文字本身是discrete的,压缩到continuous空间上回留下很多空洞)。解决这个问题就是句子不映射到连续的空间中,直接还是用离散的东西来表达,这个东西还是词语。例如:

将句子中的【delicious】盖掉,可以加入风格表征,Decoder可以生成对应的单词。具体做法参考相关文献,不展开。(盖掉词汇这个事情不可微分,因此模型是用RL来训练的,有一个小trick,作者用了一个分类器来做初始化,用其来判断哪些词汇与style相关。)

Unsupervised Abstractive Summarization

Text Style Transfer不光可以把正面情绪的句子转化为负面情绪的句子,如果我们把完整的文章作为一种风格,简短的摘要作为另外一种风格,那么我们就可以利用Text Style Transfer的方法做无监督的摘要生成。
好处就是有大量无标签数据可以作为训练数据,如下图所示,模型不需要文章与摘要一一对应。

具体做法和Cycle GAN做法一样,Generator把文章转成摘要,并想要骗过Discriminator;然后需要一个Discriminator来判别输入的是不是摘要;最后还需要一个Reconstructor来吧Generator生成的摘要重新变回原来的文章。

下面表是效果对比:

ROUGE这个评价指标是越大越好,比对的是模型生成结果与人工写的摘要结果相同词的个数,这里只考虑相同词的个数,不考虑语句的意思。1代表unigram,2代表bigram,L代表LCS
第一行是有监督模型的结果,效果最好;
第二行是取文章前几句话作为摘要的结果,相当于基于规则的模型;
第三行是用同一个语料库( English Gigaword)的文章和摘要做训练得到的结果;
第四行是用不同语料库(CNN/Diary Mail)的文章和摘要训练得到的结果。

Unsupervised Translation

Unsupervised Translation的思想是将不同语言当作不同的风格,来实现无监督的翻译。

Mapping of Word Embedding

直接做句子的翻译估计比较难,刚开始的研究是从词的翻译而来,有各个语言的词的embedding:

然后把它们都对应起来:

具体例子:

假设我们分别训练了中文的embedding和英文的embedding,明显两组embedding是不在一起的,但是可以通过一个线性变换W,使得二者重合。如何找这个线性变换系数W有很多研究:

1.监督方式:可以找人来做单词标注,也可以利用一些特殊单词,例如阿拉伯数字在各种语言表示都一样。
2.GAN:把线性变换看作Generator,然后再训练一个Discriminator来判别经过Generator之后的embedding和右边的接近程度。
下面来看具体的无监督训练的过程:

具体过程

先训练两个VAE,得到四个编码器: E N A EN_A ENA D E A DE_A DEA E N B EN_B ENB D E B DE_B DEB,为了防止Decoder变成一个只会复制粘贴的模型,这里会加入一些噪声(替换词,改词序)。

然后我们希望A经过 E N A EN_A ENA后经过 D E B DE_B DEB得到句子A在语言B中的翻译结果。但是这样直接 E N A EN_A ENA D E B DE_B DEB有问题,因为 D E B DE_B DEB不认识 E N A EN_A ENA是什么东西,只认识 E N B EN_B ENB的输出。这里有几个方法解决这个问题:
法一:就是 E N A EN_A ENA E N B EN_B ENB后面加一个Discriminator,用来区别encoder的输出是属于A的还是B的。使 E N A EN_A ENA E N B EN_B ENB尽可能用同样的格式去编码。这样 D E B DE_B DEB不仅可以看懂 E N B EN_B ENB的结果,也可以看懂 E N A EN_A ENA的结果。

法二:按下图的箭头方向,把 E N A EN_A ENA的输出丢到 D E B DE_B DEB,然后把 D E B DE_B DEB的输出丢到 E N B EN_B ENB,最后把 E N B EN_B ENB的输出丢到 D E A DE_A DEA,目标是 E N A EN_A ENA的输入和 D E A DE_A DEA的输出越接近越好。

但是这样模型并不能具备翻译的能力,例如下图中,如果把“再见”对应成“How are you”也是符合目标的。

改进方法是将 E N A EN_A ENA D E B DE_B DEB替换为另外的模型(可以是比较简单的模型,例如上面提到的Mapping of Word Embedding 模型,可以进行逐字翻译),这样做可以在训练前期引导模型生成正确的句子训练 E N B EN_B ENB D E A DE_A DEA,等这两个模块收敛后,再固定住 E N B EN_B ENB D E A DE_A DEA,来训练 E N A EN_A ENA D E B DE_B DEB,如此交替训练。

结果:

可以看到当时在数据量比较小的情况下用该方法效果比较好。

Unsupervised ASR


思路和前面一样,也是用GAN,语音识别系统(作为Generator)先吃一段语音信号,得到Phoneme的序列,Discriminator要分辨这段序列是否是人类写的句子

这里对Generator进行分析。

Generator v1

刚开始用的不是Seq2Seq的方式来生成Phoneme序列。这里由于声音信号没有具体的标注,因此,只能把声音信号中的发音波形相近的归为一类,并赋予编号(没有标注不知道对应什么Phoneme),这个方法叫Acoustic Token Discovery:

有了这些编号,那么一段声音信号就变成了一串数字序列:
我们可以把这个看做一种语言,然后按照翻译的套路来做即可。也可以简单的将这些ID数字通过查表的方式对应到具体的Phoneme:

然后再按翻译的套路来做。
整个Generator如下图所示:

但是这个Generator的无监督模型效果不好(错误率76%),但是这个方向是可以做。

Generator v2

语音信号经过DNN,得到对应Phoneme,这里由于有重复的输出,因此需要用Phoneme boundaries obtained by Gate Activation Signals (GAS)对语音信号进行分组,语音信号分组后产生的Phoneme也对应了分组,然后从这些分组中分别进行sample,得到最后的Phoneme序列。

最后老师介绍了为什么这里用的是DNN不是RNN,因为RNN模型是吃当前时间步的输入以及前一个时间步的输入产生输出,这个模型的特点是你随便给一个输入它都可以给出一个比较合理的输出,这个输出特别像是人类写的句子,因此用RNN效果不好。最后结果错误率从76降低到48

Refining Boundaries

按下图进行迭代训练,不断优化语音识别和Phoneme Boundaries。

最后结果又有提升

Semi-supervised Speech Recognition


当然如果语音数据有部分标注,那么可以做半监督学习,ASR除了做原来模型中的任务之外,如果当前的语音信号有对应的人工标注结果,那么ASR的目标是使得模型识别结果与人工标注结果越接近越好。

Top