NLP中的GAN(之一)

Posted 熊熊nlp白板报

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NLP中的GAN(之一)相关的知识,希望对你有一定的参考价值。

1. 感性地理解GAN

1.1 零和博弈

从博弈论的角度来讲, GAN是一种零和博弈: “彼之所得必为我之所失, 得失相加只能得零” (零和意思就是和是零).

零和博弈意思是双方博弈, 一方得益必然意味着另一方吃亏, 一方得益多少, 另一方就吃亏多少, 将胜负双方的“得”与“失”相加,总数为零。在零和博弈中, 双方是没有合作机会的。

尽管得失的总和是零,但是并不妨碍存在这样一个最优策略,也就是对参与双方来说都最“合理” 、最优的具体策略。怎样才是“合理” ?应用传统决定论中的“最小最大” 准则,即博弈的每一方都假设对方的所有功略的根本目的是使自己最大程度地失利,并据此最优化自己的对策。

1.2 生成式对抗

引申到GAN里面就是可以看成,GAN中有两个这样的博弈者,一个人是生成模型(Generator,用G表示),另一个是判别模型(Discriminator,用D表示)。一方面,G作为生成模型,其目的在于尽量生成以假乱真的数据,令D判别不出真假;另一方面,D作为判别模型,其目的在于最大程度判别一个数据的真假:是G生成的还是真实的数据。附上一张流传较广的GAN图示如下。


图1:GAN示意

2. 理性地理解GAN

明白了GAN就是在做这样一件G与D相互对抗的事情之后,我们就可以直接来理解GAN作为一个整体框架的一系列公式了,不过在抛公式之前,还是有必要强调一下D(x)与G(z)两个函数的定义:

  • NLP中的GAN(之一),判别器D的输入是一个样本x,D输出的是样本x真与假的测度,比如最简单的真与假的二值分类(binary classification)。值得一提的是,后续的内容中我们会看到除了二值分类这种判别方式之外的其他更优越的判别方式,比如ranking的判别,LM的判别,等等。 不过现在我们姑且将D(x)的输出就定义为0到1之间,越接近1越说明x是真实样本。

  • NLP中的GAN(之一),生成器G的输入是某一样本或噪声z,G输出(生成)一个新样本x’,其形式与真实样本x完全相同。

定义了D与G之后,我们正式进入到GAN作为一个大框架,为D和G规定的目标优化函数:
NLP中的GAN(之一) 其中花体的NLP中的GAN(之一)就是期望,期望的下标诸如NLP中的GAN(之一)的意思指的是x服从p的分布,并从p中采样得到,这二者合在一起可以直白地理解为采样,计算,求平均的过程。NLP中的GAN(之一)NLP中的GAN(之一)分别代表真实的分布以及G生成的分布,理解了符号之后,我们再来理解公式:

按学名来讲,这是一个bilevel optimization[1]问题,外层对应最小化,优化的是G;内层对应最大化,优化的是D,两层嵌套在了一起。正常过程都是从判别器训练起,因此我们也由内而外地看:

  • 优化D:
    NLP中的GAN(之一)在优化D时,我们希望D(x)=1,因为NLP中的GAN(之一)来自于真实数据,与此同时,我们还希望D(G(z))=0,因为G(z)是假的,因此等价于max( log(1-D(G(z))) ):log里面的1-D(G(z))同样make sense,因为D(G(z))取值范围是[0,1],代表的是一个置信概率,于是1-D(G(z))意为G(z)是假的概率。

  • 优化G:
    NLP中的GAN(之一)注意到这一步只剩下了minmax大公式中的第二项,因为第一项其实与G无关。与之前相反,此时我们希望的是NLP中的GAN(之一),将G优化到以假乱真的程度,即NLP中的GAN(之一),这里同样写成了NLP中的GAN(之一)的形式。这里有一点值得注意,原论文中也特意提到了,实际我们优化G的时候用的就是NLP中的GAN(之一), 而并非NLP中的GAN(之一)这种形式,原因在于刚开始学习的时候,G还很弱,因此D很轻易就能判别出G生成的样本,造成NLP中的GAN(之一)趋于0,而对于形如f(x)=log(1-x)的函数,其导数在x趋于0时近乎于0,也就是论文里提到的饱和现象:此时梯度更新会很难进行,因为梯度总是趋于0(附一个梯度示意图,注意x=0处的梯度)

NLP中的GAN(之一) NLP中的GAN(之一)

图2:函数与梯度示意图

基础概念大致就介绍到这里了,其他的许多GAN机制的理论推导,以及涉及到GAN成败的优化细节就不在这里赘述,读者可以自行阅读Ian Goodfellow的那篇GAN的开山鼻祖《Generative Adversarial Nets》[2]。大致概括就是:理论最优解存在,但是如何训练使模型收敛到最优解并不容易,这也是目前GAN相关研究的主要方面之一,可以说GAN的创立又为“深度炼金术”添加了浓墨重彩的一笔。。。

3. NLP中的GAN(之一) : SeqGAN

从上面的GAN过渡到这里的seqGAN[3]其实是比较有跳跃性的,因为seqGAN作为GAN在NLP领域当中的一个经典应用(也是NLP中的GAN早期应用的论文之一),来自于2017年的AAAI,与2014年的原始GAN已经时隔了三年。要知道三年对于AI领域已经算是超级长的间隔了。不可否认的是,随着GAN的不断实践,我们其实可以意识到这样一点,那就是GAN与强化学习(RL)存在着许多联系,特别是GAN的G与D的对抗机制,以及RL里面的actor-critic机制这两种机制之间的比较,都是一方面选择/生成一个action,另一方面评估这个action的价值并进行一些反馈 [4]。因此下面对seqGAN算法的介绍中会出现像reward、policy gradient等典型的RL里的字眼也就不足为奇了,这里只是稍微做个预告,下面正式进入论文的剖析。

3.1 引言

3.1.1 动机

做seqGAN的动机在哪里呢?这个动机其实是来源于一个序列生成模型的训练和推断之间的差异问题。不要看序列生成模型(比如recurrent NNs,RNN)现在应用的十分广泛,但其实它基于maximum likelihood的训练目标一直以来饱受诟病,而在N多诟病之中有这样一条:基于MLE loss的优化目标会造成训练(training)和推断(inference)之间的差异性,导致即使训练的loss收敛的很好,但是在inference阶段模型也不一定生成质量高的序列。这个问题是怎么出现的呢?RNN的训练过程有个名字叫做teacher forcing,意为每生成序列中的一个词的时候,我们实际上会给模型强迫输入上一时刻的target (ground-truth),这种做法有着很强的指导性(就像有个teacher教导一样),然而等到了推断阶段,尽管我们要模型做的同样是生成一个序列,但此时不再存在ground-truth,每一步模型的输入只能是上一时刻模型自己的输出。seqGAN的作者将这个问题称为exposure bias,感觉还是很有概括性的,笔者这样理解:在训练阶段暴露了太多ground-truth,从而导致了bias的出现。

一个比较普遍的解决办法叫做scheduled sampling[5],看下面这张图很容易理解:一方面我们不希望抛弃teacher forcing带来的快速收敛的指导性作用,一方面我们希望训练阶段与推断阶段不会产生这么大的模式差异。于是在训练阶段,我们采取“抛硬币”的概率形式,以一定概率决定是输入上一刻的ground-truth还是模型自己上一时刻的输出(这就是sampling一词的由来),并且输入ground-truth的概率会逐渐递减(scheduled一词的由来),直到减到0完全和推断的情景一样。这种做法颇有些“授之以鱼,不如授之以渔”的意味在里面:从一开始完全teacher forcing,渐渐地直到模型能够自我推断而不再需要老师,可以说是一个更好的教育方式,不过这种做法其实也存在争议,这里就不赘述了(详情参考seqGAN里的引用);另一种解决办法,在于改变loss的形式,使用一个更全局的loss来指导序列生成,而不再是一句话一个MLE loss,作者举了例子是翻译任务里的BLEU,不过这样也有问题,这种loss一般都是可遇而不可求的,是task-specific的,许多task(比如对话生成),其实目前根本就没有好使的一个loss指标。有鉴于此,作者希望从GAN的角度来address这个issue,目的就是提升序列生成的效果,特别是推断阶段,通过GAN的判别器来提升这个序列生成器的质量。

NLP中的GAN(之一)

图3:Scheduled sampling示意

顺便一说,对于熟悉tensorflow的同学而言,在序列生成的框架中,上面说到的训练阶段的teacher forcing, scheduled sampling以及推断阶段,都是以helper API的形式出现的:

tf.contrib.seq2seq.TrainingHelper  # Teacher forcing
tf.contrib.seq2seq.ScheduledEmbeddingTrainingHelper  # Scheduled sampling
tf.contrib.seq2seq.GreedyEmbeddingHelper  # Inference

3.1.2 难点与挑战

事实上把GAN应用在离散序列生成模型并不容易,作者主要列出了两点挑战:

  • 连续与离散
    原始的GAN本是为了生成实数的(real-valued)、连续的(continuous)数据而设计的,也因此在一开始就应用在了图像领域,并且在其中取得了极大成就。然而GAN并不适合直接用在离散的语言上面。回想一下GAN的判别器D用来提升生成器G的方式:通过D对G生成数据会进行判别,而这个判别会作为反馈通过梯度下降的方式对G的参数进行更新,从而会轻微地影响到G的生成数据,使得更新过后的下一次生成数据更像真实数据。但是作为离散的语言序列而言,所谓对生成数据的“轻微的影响”就不很make sense了,因为图片像素你可以增加0.0001的扰动,改变了灰度也好,rgb值也罢,总是解释的通的;而对于一句话的一个token来讲,增加0.0001的扰动却解释不通,如果强行解释那大概是这样的画风:扰动使得原token变成了一个词典之外的某个未知的token,并且该token与原token的词向量在某一维度差了0.0001。。。

  • 未完成序列的评估
    一般而言,判别器判别的是一个完整的样本,但是由于序列模型离散地生成序列这个特点,一个样本序列有可能还没生成完,使得我们不好说该序列当前(partially generated sequence)的好坏以及将来生成的完整序列(entire sequence)的好坏的关系,这一点是需要在模型训练过程中进行考量与平衡的。

于是相应的,seqGAN的贡献也正是提出了方法解决这两个难点,就不再赘述了。

3.2 模型

3.2.1 问题描述

一般而言,介绍一个模型总会从问题描述(problem formulation)开始讲起:

  • G模型的第一种描述:一般描述
    生成器NLP中的GAN(之一),其中NLP中的GAN(之一)表示其参数,NLP中的GAN(之一)的目的在于生成一个T长度的序列NLP中的GAN(之一),其中NLP中的GAN(之一)NLP中的GAN(之一)是词典,即生成的所有y(一个y我们不妨称之为token)都属于这个事先固定好的词典NLP中的GAN(之一)


  • G模型的第二种描述:RL描述
    t时刻的状态(state):之前已经生成的序列NLP中的GAN(之一)
    t时刻的动作(action):选择当前要生成的token,即NLP中的GAN(之一)
    策略模型(policy model):NLP中的GAN(之一),输出在当前t时刻的state下做出action的概率。

之所以提出第二种描述,是因为序列生成任务实际上也可以看做一个序列化的决策问题,每一时刻需要做出选择那个词的action,妥妥地可以套用强化学习那一套方法,也是为了方便后续方法诸如reward、policy gradient的提出。

  • D模型的描述
    判别器NLP中的GAN(之一),其中NLP中的GAN(之一)表示其参数,NLP中的GAN(之一)的目的在于判别上述NLP中的GAN(之一)的好坏,NLP中的GAN(之一)即是判断真实数据的置信概率。

于是乎,在进入到细节之前,我们先从整体把握一下seqGAN的框架(如图4):判别器D会同时接触正样本(real data)与负样本(Generated data),从而学习判断真假;生成器G则通过从D得到的对完整生成序列的期望奖励(Expected end reward)更新自己的参数,当序列未生成完时,则采用Monte Carlo方法将未完成序列补全(图中的波浪线部分),之后再去交给D得到反馈的奖励。首先这样概括性地把握一下seqGAN的框架就好了,接下来我们进入模型的细节。

NLP中的GAN(之一)

图4:SeqGAN示意

3.2.2 模型细节

我们可以直接写出对于G而言,基于强化学习的目标函数,即需要最大化的期望最终奖励(Expected End Reward):NLP中的GAN(之一)这是从论文里摘抄的原公式,其实不难解读:

  • 首先,NLP中的GAN(之一)是针对1次序列生成过程的期望,即如果要写成生成N次样本的loss函数的话,将会是NLP中的GAN(之一)的形式;

  • 其次,关于一些符号:NLP中的GAN(之一)表示生成T长度序列的End reward,NLP中的GAN(之一)为序列生成(RNN)的初始状态,NLP中的GAN(之一)是G的参数,y是从词典NLP中的GAN(之一)中选出的词,NLP中的GAN(之一)则是强化学习中比较重要的action value function(一般称作Q函数),该函数的作用就是提供(评估)当前action(生成当前词)带来的reward,结合GAN的主题,reward显然会由Q函数的下标——判别器D来提供的;Q函数的上标——生成器G,则代表着选择action的policy,正如G模型的RL描述那样。

于是接下来,便是对Q函数的具体定义:NLP中的GAN(之一)上文说过,大写的Y(非花体)表示的是序列,而上式其实意思也很直接,就是用判别器来衡量Q,也就是对当前action(生成当前y)的reward的评估,这也正是对判别器D原本的定义:判别一个生成的完整序列的好坏。但是呢,细心的小伙伴不难发现当前Q函数这样设计的一个缺点,也正是我们之前铺垫过的第二点挑战,在于我们无法衡量未完成序列的reward——换言之,我们无法衡量生成NLP中的GAN(之一)、生成NLP中的GAN(之一)……、生成NLP中的GAN(之一)步骤的reward,而是只能限制在衡量末尾处生成NLP中的GAN(之一)的reward。

  • 为什么?
    从这一处继续研究下去之前,我们不妨再想一想:这到底为啥是个问题呢?只衡量结尾处有什么坏处?作者给出了辨析:这确实是个问题。原因在于我们其实是在意长期奖励的(long-term reward),而不能只看当下的reward,放在序列生成的任务里就是:我们不能只看之前生成的Y序列的好坏,我们还需要考虑当前生成这个词对将来的影响。举个例子就是:假设目前生成的序列是:你 今天 _,下划线是当前要生成的词,那么当前生成“吃”的话,这个序列可能就很容易最终变成 “你 今天 吃 了 吗”,但是如果当前生成“会”的话,那么或许接下来的生成就会更困难一些,比如最终序列可能变成了“你 今天 会 准时 下班 吗”。由此可见,当前生成什么样的词对未来序列会很有影响,假设我们希望生成更困难的序列的话,那么显然当前时刻生成“会”的奖励理应比生成“吃”的奖励更高一点才好,但是明显这一点在我们现在这个NLP中的GAN(之一)的设定中是体现不出来的(因此是很难学到的)。

引申:爱思考的小伙伴也许会更进一步发现,我这个例子其实是有些不太恰当的(咱是故意的):目前我们对判别器D的设定就是真假二分类,因此实际上我举例子的两句话在D眼中其实并没有区别,他们都应该被判别为真话(比较贴近人说的话);要想真的将这两句话区分开来,使得判别器对其中一个句子给出更高的reward,则需要更高级的判别方式(如判别器是个语言模型LM,是个ranking模型等等)。回到正题,尽管例子并不恰当,但是意思是一样的:当前生成的词会对未来序列的补完造成影响,从而使得判别器D做出不同的判断,因此理应将这一点考虑进去。

- 怎么办?
我们就是想要评估生成
NLP中的GAN(之一)、生成NLP中的GAN(之一)......、生成NLP中的GAN(之一)所有步骤的reward,但问题是这些步骤对应的序列Y并不完整,而判别器是不能判别不完整序列的。因此,论文的解决方法也正是针对于此:将未完成序列补全,补全之后送给D就可以了!于是作者提出了听起来高大上的Monte-Carlo search with rollout policyNLP中的GAN(之一)。公式表达如下:

NLP中的GAN(之一)

待笔者一一道来,你会发现这其实真的很简单。。首先从字面上理解一下这个名字:附带rollout policy的蒙特卡罗搜索:首先是rollout,如果你熟悉RNN的话,你一定记得一些教程里将一个箭头指向自己的循环神经元“roll out”成了按时间展开的RNN序列结构,这个roll out就可以理解为展开,而在我们这个情景下,完全就可以理解为补全:把当前的序列NLP中的GAN(之一)补全为NLP中的GAN(之一)。而蒙特卡罗(MC)其实非常容易理解,简单来讲就是个采样之后取平均的思路(下图左边就是通过采样M个点计算单位圆面积,重复计算采样过程N次,最终取个平均面积,从而估算圆周率的蒙特卡罗方法),注意到上面公式等号左边的那些个上标(从1到N),那就是我们采的样,针对1个序列NLP中的GAN(之一),我们会根据rollout policy NLP中的GAN(之一)将其补全N次(按照概率生成N个序列),于是就出现了上面公式左边那N个序列的集合。至于这个rollout policy NLP中的GAN(之一),其实论文里直接选择了其参数与生成器NLP中的GAN(之一)一样(当然你也可以选择和生成器G不同的参数,虽说笔者也不知道还可以怎么选)。来个简单的示意图:

NLP中的GAN(之一)

NLP中的GAN(之一)

图5:Monte Carlo求圆周率(上)MC rollout示意(下)

注:又有细心的同学可能会发现笔者在右图中又故意让补全的句子拥有同样的长度了,这是有原因的,原因在于该论文中的任务就是限定在生成序列长度一致上(长度都是T),后面还会细说。如果是真实的自然语言的话当然不会非要补全成长度一样的序列,而应当是补全直到生成了结束符(比如“EOS”)。
那么最后再碎碎念一遍:对于补全的完整序列,其中前面NLP中的GAN(之一)的部分就是NLP中的GAN(之一),序列后面的部分则是通过NLP中的GAN(之一)以及t时刻状态采样出来的补全的内容。

理清了这个过程之后,下面的表达式就很自然了:

NLP中的GAN(之一)

当序列不完整时(t<T),采用MC rollout方法,对不完整的序列补全得到D提供的reward,该补全过程会重复N次,最终的reward则是这N次的平均(MC的采样取平均思路);当序列完整时,则无需MC,直接一次得到最终reward即可。

下面放上优化用到的一些公式,可以大致浏览一下,不过笔者比较推荐的方式还是去直接去理解实验源码最实在:

https://github.com/LantaoYu/SeqGAN


  • 对D的优化:

NLP中的GAN(之一)

  • 对G的优化:

NLP中的GAN(之一)

NLP中的GAN(之一)

NLP中的GAN(之一)

其中上面的第二个等式是对期望reward的求导,可以由policy gradient得到。policy gradient描述的就是一个等式:对reward的期望求导=reward乘以log(policy)的导数这个乘积的期望。而我们这里的policy正是G,reward正是Q。第三个等式则是对数学期望的近似表示。

3.2.2 SeqGAN算法总结

这里直接复制来论文的algorithm对算法流程做个总结,对于D和G轮流交替迭代更新这个过程,一般我们会让D训练的更充分一些,原因也比较容易理解,那就是希望D能提供更合理的reward用于G的更新,也就是算法中的d-step一般会设的大一些;此外,训练D时特意保证了正负样本的均衡。


NLP中的GAN(之一)

不难注意到任何GAN都可以看做是一个框架,是一种增强的手段,它应用的对象是某个模型(基于神经网络的模型)。因此在使用GAN之前,总要有预训练这样的一个过程,往往都是按照正常的训练方式进行训练(这里就是最大似然MLE的方式),之后GAN才会介入,来通过生成与判别的对抗方式进一步提升模型的性能。

3.2.2 G与D的模型选择

了解了套用在G与D上的seqGAN框架,接下来G和D模型的选择就相对随意了,论文中G选择了LSTM(基本的序列生成模型),D选择了CNN+highway(普遍的文本分类模型),在模型的描述上就不多做赘述了,更详细的可以去看原论文。

3.3 实验

接下来进入实验阶段,论文在这里引入了一个所谓的oracle序列生成模型(也是个LSTM),oracle本身可以翻译为神谕,预示,言外之意就是这个生成模型生成的序列都是真的(由oracle产生的数据就是real data,应被判别器D判别为真),简单理解为这就是一个训练完美的LSTM。之所以这样做有两点原因:第一点在于我们可以直接用oracle生成的序列作为训练数据,不需要去额外找训练数据(因此G的最终目标就是去模仿这个oracle);其二在于我们用oracle直接对G进行测评。关于测评,在自然语言生成这上面,其实最准确的方法就是人工测评,这里使用oracle模型自动测评就省略了人工测评的复杂成本。具体来讲,对于由G生成的序列,我们会使用oracle评估它的negative log likelihood,类似应用比较普遍的困惑度(perplexity),数值越低,意味着生成的序列在oracle的角度看句子概率越大(注意到log外部求和等价于log内部连乘,而G每一步输出生成当前词的概率),因此也就越好。于是,实验时令G生成10万个序列,我们最终汇报的是这10万个序列的NLL oracle的平均值。

NLP中的GAN(之一)

论文挑选了几个baseline作为对比,分别是:随机生成(random),基于MLE训练(MLE),使用scheduled sampling技巧(SS),根据BLEU分数的强化学习(PG-BLEU),结果如下,seqGAN的效果和它们比起来就是一个字:好。如果我们回想引言部分里提到的两种针对MLE训练缺点现有的两种解决手段的话,它们正是这里对比的scheduled sampling以及PG-BLEU,而实验证明使用GAN是更优的办法,比像PG-BLEU人为事先定义好一个全局的score(BLEU)去优化要更好。

NLP中的GAN(之一)

图6:SeqGAN实验(一)

实验进行到这里还没用完,还有一些有趣的discussion:首先就是有关于一些参数与seqGAN收敛的关系,g-steps与d-steps不用说,k是训练的epoch,在这里的epoch特指在开始训练D之前要反复训练G多少次,如下图:

图7:SeqGAN的收敛

可以看到如果G训练的太多,D训练的不足,那么D就会给出误导性的reward,使得G训练的不稳定,甚至变差。至于每一轮训练多少个epoch也是有一定影响。在这里,论文再一次强调了训练好判别器D对于GAN框架稳定性、高效性的重要作用。


在最后,作者同样在real world中进行了实验,比如作诗(中文五言绝句16,394首),政治演讲(奥巴马演讲11,092段),音乐生成(诺丁汉695首民俗tunes,88个音调(对应钢琴88个键位)),在此仅使用了MLE作为baseline进行比较。使用BLEU-2衡量绝句的质量,因为研究表明大部分中文古典诗词由长度为1或2的n-grams组成;类似的,使用BLEU-3和BLEU-4去衡量政治演讲;音乐生成额外使用均方差(MSE)来衡量音调高低的差别。效果可以看到都是不错。


图8:SeqGAN的实验(二)

4. 填坑预告

那么这次算是对GAN在NLP中的应用开了一个头,接下来为了衔接自然,在将来的NLP中的GAN(之二)中,笔者会一一道来本文中提及的所谓更高级的判别方式,一些关键词如adversarial ranking以及diversity promoting GAN可以先有个印象;除此之外,GAN在NLP领域的应用已经开始不断的浮现了,大概这个坑是永远也填不完的吧,不过填一点是一点嘛~

参考文献

[1] Pfau D , Vinyals O . Connecting Generative Adversarial Networks and Actor-Critic Methods[J]. 2016.
[2] Goodfellow I J , Pouget-Abadie J , Mirza M , et al. Generative Adversarial Nets[C]. International Conference on Neural Information Processing Systems. MIT Press, 2014.
[3] Yu L, Zhang W, Wang J, et al. SeqGAN: Sequence Generative Adversarial Nets with Policy Gradient[J]. 2016.
[4] Pfau D , Vinyals O . Connecting Generative Adversarial Networks and Actor-Critic Methods[J]. 2016.
[5]  Bengio S , Vinyals O , Jaitly N , et al. Scheduled Sampling for Sequence Prediction with Recurrent Neural Networks[J]. 2015.


以上是关于NLP中的GAN(之一)的主要内容,如果未能解决你的问题,请参考以下文章

基于NLP和GAN的小说影视化

学习笔记GAN003:GANDCGANCGANInfoGAN

机器学习PAI实战—— 玩转人工智能之利用GAN自动生成二次元头像

视频直接变漫画!GAN又有了新玩法|Demo+代码+论文

我的作业文档中的 NLP 示例崩溃了

片段中的 super.onCreateView