从0开始GAN-9-metric for NLG

related papers:

MoverScore

Motivation

评价指标对于模型的训练或选择至关重要,现阶段对于文本生成的模型(机器翻译,摘要生产,图像标题生成)大都采用的hard match的方式,比如 BLEU, ROUGE. 这些都是简单的基于共现词的统计,这种metric仅仅只考虑了表面的形式,无法覆盖同意却不同词的表达,所以他们并不太好(over correction),不具备评价文本相似性的能力。

MoverScore

It is particularly important for a metric to not only capture the amount of shared content between two texts, i.e., intersect(A,B), as is the case with many semantic textual similarity measures

根据语义相似度来计算距离。

计算 MoverScore 的一些符号:

  • sentence:$x=(x_1,x_2,…,x_m)$

  • $x^n$ 表示 x 中的 n-gram.

  • $f_{x^n}$ 表示x中每一个 n-gram 的权重。如果 n=(size of sentence), 那么 $f_{x^n}=1$

n-gram 之间的距离:

$$C_{ij}=d(x_i^n,y_j^n)$$

表示 x 中第 $i^{th}$ 个 n-gram 与 y 中第 $j^{th}$ 个 n-gram 的距离。

那么两个句子中所有 n-gram 的距离 Word Mover’s Distance (WMD):

$$WMD(x^n,y^n):=min_{F\in R^{|x^n|\times |y^n|}}<C,F>$$

$<>$ 表示加权求和。计算出两个 n-gram 序列的推土机距离与传统的推土机距离不太一样的地方是,这里每个 n-gram 还有权重。

那么如何计算两个 n-gram 的距离 $d(x_i^n,y_j^n)$ 呢, 作者采用的是 Euclidean distance:

$$d(x_i^n,y_j^n)=||E(x_i^n)-E(y^n_j)||_ {2}$$

$E$ 是n-gram 的向量表示,比如 $x_i^n=(x_i,..,x_{i+n-1})$ 是 x 中第 i 个 n-gram.

$$E{(x_i^n)}=\sum_{k=i}^{i+n-1}idf{(x_k)}\cdot E{(x_k)}$$

n-gram 的权重计算:

$$f_{x_i^n}=\dfrac{1}{Z}\sum_{k=i}^{i+n-1}idf{(x_k)}$$

Z 是归一化常数,也就是总和吧。

当 n>(size of sentence) 时,$WMD(x^n,y^n)$ 变成计算两个完整的句子的距离:

$$SMD(x^n,y^n)=||E(x_1^{l_x})-E(y_1^{l_y})||$$

其中 $l_x,l_y$ 表示两个sentence 的长度。

Contextualized Representations

如何得到一个 word/n-gram 的向量表示,基于预训练的模型来得到 contextualized 表示是一个开放性的问题,Elmo和BERT都是多层结构,不同的layer包含了不同的含义。作者这里提到了两种方法,并最终采用了前者:

  • the concatenation of power means

  • a routing mechanism for aggregation

power means:

$$h_i(p)=(\dfrac{z_{i,1}^p+…+z_{i,L}^p}{L})^{1/p}$$

L 表示预训练模型的层数,p=1是数值平均,p=0时是调和平均。

$$E(x_i)=h_i^{p_1}\oplus …. \oplus h_i^{p_k}$$

$\oplus$ 表示 concatenation. 作者设置 p=1,K=3. 也就是一个词的向量表示由三个向量表示 $h$ 拼接而成,而每个h又是不同层的数值平均。

result

对于这种提出新指标的问题,一直很疑惑怎么去 evaluation。好像只能通过人工去评价了对吧?

这是机器翻译的结果。

WMD-1/2+BERT+MNLI+PMeans:表示 1-gram 的word mover distences + 在NMLI语料上训练的BERT + PMeans 的融合方式。

根据 NMT system 得到 translations,然后与 references 计算对应的指标。然后根据指标与human evalation相似度进行对比,越接近人类评价的,这个指标就越好。

从0开始GAN-7-IRGAN

Motivation

IRGAN: A Minimax Game for Unifying Generative and Discriminative Information Retrieval Models

信息检索的方法主要分为两个流派,生成式检s索模型(generative retrieval model)和判别式检索模型(discriminative retrieval model)。

生成式检索模型 ($q \rightarrow d$):认为query和检索所需要的document之间有一个潜在的随机生成的过程。也就是给定一个 query,然后生成相应的 document.

判别式检索模型 ($q + d \rightarrow r$):把query和document作为联合feature,计算其相关性relevancy. 然后基于 relevancy 对 document 进行排序。其中关于 ranking a list of documents 有三种范式:pointwise, pairwise, listwise.

作者将上述两种模型与GAN相结合,利用GAN的对抗性的思想去提升两类模型。

判别式检索模型 $p_{\phi}(r|q,d)$ 作为判别器,maximize 来自真实 labeled 的数据。它提供信息来指导生成器的训练,这种信息不同于传统的 log-likelihood.

判别式检索模型 $p_{\theta}(d|q,r)$ 是生成器,生成generated sample来迷惑判别器,minimize 对应的目标函数。

Model Architecture

A Minimax Retrieval Framework

a set of queries ${q_1,…,q_N}$, a set of documents ${d_1,…,d_M}$. 其中 给定一个 query 都有对应的相关度较高的 document 也就是真实的数据 $true_{(q,d)}$,其数据量是远小于总的document数量 M 的.

The underlying true relevance distribution can be expressed

as conditional probability $p_{true} (d|q, r)$, which depicts the (user’s) relevance preference distribution over the candidate documents with respect to her submitted query.

这样真实的相关性 (q,d) 存在潜在的相关性条件分布 $p_{true}(d|q,r)$.

Generative retrieval model $p_{\theta}(d|q,r)$: 生成器的目的就是去尽可能的模拟真实的相关性分布 $p_{ture}(d|q,r)$, 从而尽可能生成相似度高的 document.

Discriminative retrieval model $f_{\phi}(q,d)$:是一个二分类分类器。

其中判别器具体的计算 $f_{\phi}(d,q)$ 与IR task有关。后续会详细介绍。

Overall Objective 目标函数:

最小化来自生成器 $p_{\theta}$ 的 sample 的概率,最大化来自true data $p_{true}$ 的 sample 的概率.

Optimising Discriminative Retrieval

优化判别器:

Optimising Generative Retrieval

这篇paper中生成器不是token by token的生成新的ducoment,而是从given documents中选择最相关的document.

对于生成器的优化,最小化目标函数(1):

上述公式从第一步到第二步有点小变化,简单推导下即可。

这里sample得到d的过程是离散的。怎么理解呢,可以类比文本的生成(尽管此表的分布是连续的,但是从中选一个token,然后作为判别器的输入,这个过程是不可导的)。同样,这里是从一系列documents中sample一个作为判别器的输入,这个过程是离散的,且不可导。所以作者采用了policy gradient的方法来解决这个问题。

公式(4)中对生成器的优化可以看作是 maximize $J^G(q_n)$. 使用policy gradient优化的推导如下:

这里的policy是 $p_{\theta}(d|q_n,r)$ 就是我们需要优化的生成式检索模型,对应的action是给定environment q的情况下sample得到 document. 判别器得到的log-prob就是reward.

为了减小REINFORCE方法中variance,作者采用了advantage-function,也就是减去baseline,其中baseline是均值:

整个IRGAN的训练过程的伪代码:

上图中的公式(22)就是公式(5). 整个过程理解起来还是蛮简单的。

还有个问题为解决的是,前面提到对于不同的 IR 任务,判别器 $f_{\phi}(q,d)$ 的方式是不一样的。

pairwise case

Furthermore, ifwe use graded relevance scales (indicating a varying degree of match between each document and the corresponding query) rather than binary relevance, the training data could also be represented naturally as ordered document pairs.

此外,如果我们使用分级相关性比例(指示每个文档与相应查询之间的不同匹配程度)而不是二元相关性,则训练数据也可以自然地表示为有序文档对.

也就是不仅仅根据query和document之间是否相似这样的二元文档对,而是利用有序文档对(这在IR中其实更为常见),作为判别器的输入,这样能获取更多的信息。

这个时候的labeled document是 $R_n={<d_i,d_j>|d_i > d_j}$, 其中 $d_i > d_j$ 意味着 $d_i$ 比 $d_j$ 的相关性更高。

使用pairwise discriminator对应的目标函数:

其中 $o = <d_u,d_v>, o’=<d_u’,d_v’>$. 在实际的操作中,选择一对document $<d_i,d_j>$. 然后选择相似度较低的 $d_j$ 与生成器得到的 $d_k$ 组成新的pairs $<d_k, d_j>$,作为判别器的输入。这样的目的就是认为 $d_k$ 的相似度高于 $d_j$ 的情况下,让 $d_k$ 尽可能的去与 $d_i$ 相似。

在前面介绍了生成器 $p_{\theta}(d|q,r)$ 实际上就是 softmax,看公式(2).

对于pairwise的形式,$d_j$ 也作为生成器的输入之一,对应的生成器是另一种 softmax:

其中 $g_{\theta}(q,d)$ is a task-specific real-valued function reflecting the chance of d being generated from q.

从0开始GAN-6-pretraining for NLG

cross-lingual word embedding

A survey of cross-lingual word embedding models, Ruder et al.2017

Word translation without parallel data. Conneau et al.2017

Massively multilingual sentence embeddings for zero-shot cross-lingual transfer and beyond. Artetxe et al.2018

contextual word embedding

ELMo

Word2vec

Glove

GPT

ULMFT: Universal language model fine-tuning for text classificatio

Cross-lingual language model pretraining

Polyglot contextual representations im- prove crosslingual transfer

pre-trained for NMT

Towards Making the Most of BERT in Neural Machine Translation

Unsupervised Pretraining for Sequence to Sequence Learning

When and Why are Pre-trained Word Embeddings Useful for Neural Machine Translation?

Cross-lingual Language Model Pretraining

XLM

paper: Cross-lingual Language Model Pretraining

作者提出了两种方法来学习 cross-lingual 语言模型。其中一种是仅基于 monolingual data, 另一种是基于平行语料。在 cross-lingal 相关的任务上都有很大的提升。比如 XNLI,unsupervised machine translation, 以及 supervised machine tranlsation.

现有的在NLP领域的发展主要是围绕英文进行的,一些start-of-the-art或者NLP任务的benchmarks都是以英文为基础的。其他的一些语言受限于语料的问题,发展相对缓慢。近期随着cross-lingual sentence representation的发展,消除English-centric bias,并且构建一个通用的cross-lingual encoder来讲任何语言的sentence编码到共享的embedding空间成为可能。

Shared sub-word vocabulary

使用 bpe,并且不同的language共享词表.

this greatly improves the alignment of embedding spaces across languages that share either the same alphabet or anchor tokens such as digits (Smith et al., 2017) or proper nouns.

共享词表能显著提升那些具有相同字母表或者anchor token(数字或专有名词)的语言之间的向量空间的对齐。

作者先从不同语言的monolingual data中筛选出部分data,然后学习bpe splits.

Sentences are sampled according to a multinomial distribution with probabilities ${q_i}_{i=1…N}$, where:

其中 $n_i$ 表示第 i 中语言中sentence的总数。 $\sum_{k=1}^nn_k$ 表示N种语言所有的sentence的总数。$p_i$ 则表示第 i 中语言sample的概率。设定 $\alpha=0.5$,这样能增加 low-resource 的比例,从而减轻 bias to high-resource language.

作者总共提出了三种 language model. 接下来一一介绍:

Causal Language Modeling (CLM)

$p(w_t|w_1,…,w_{t-1},\theta)$

也就是普通的 aotu-regressive 语言模型。

Character-Level Language Modeling with Deeper Self-Attention 这篇paper使用的self-attention, 我们知道self-attention 不像rnn那样具有hidden state的概率,这篇paper把上一个batch作为下一个batch的context,有点类似于 transformer-XL,但是这对于cross-lingual不太适合,所以这里的 CLM 与传统的language model完全一致。

Masked Language Modeling (MLM)

与 BERT 中MLM的区别:

Differences between our approach and the MLM of Devlin et al. (2018) include the use of text streams of an arbitrary number of sentences (truncated at 256 tokens) instead of pairs of sentences.

文本 stream 是任意数量的sentences,而不是pairs.(这里的pairs in BERT应该指的是 next sentence prediction.)

在筛选用来mask的词时,为了处理 rare word 和 frequent word(punctuation or stop words) 的不均衡问题:

tokens in a text stream are sampled according to a multinomial distribution, whose weights are proportional to the square root of their invert frequencies.

Translation Language Modeling (TLM)

在预测一个 masked english word 的同时,不仅可以attend english context,也可以 attend franch translation.

Cross-lingual Language Models

如何使用这三种语言模型,CLM 和 MLM 在单语上进行训练。 TLM 在平行语料上训练。TLM 在使用时是联合 MLM 一起训练的,迭代优化两个目标函数。

In this work, we consider cross-lingual language model pretraining with either CLM, MLM, or MLM used in combination with TLM. For the CLM and MLM objectives, we train the model with batches of 64 streams of continuous sentences composed of 256 tokens. At each iteration, a batch is composed of sentences coming from the same language, which is sampled from the distribution ${q_i}_{i=1…N}$ above, with α = 0.7. When TLM is used in combination with MLM, we alternate between these two objectives, and sample the language pairs with a similar approach.

CTNMT

paper: [Towards Making the Most of BERT in Neural Machine Translation

Jiacheng](https://arxiv.org/abs/1908.05672)

ByteDance 的一篇paper.

前人的研究中我们发现,BERT pretrian 对NMT几乎没有提升。作者认为其原因是,NMT 相对其他linguistic的任务,训练的steps会多很多,比如NMT一般是10万step,而 POS tagging只需要几百步。这使得在训练过程中,参数的更新太多导致 catastrophic forgetting problem. 也就是 BERT 训练得到的knowledge并不能给NMT代来提升。

于是乎,作者认为只是大家没有好好利用BERT而已,像我们这样搞, BERT还是能对NMT有提升的。然后提出了三种techniques:

Asymptotic Distillation

渐近蒸馏,主要是用来解决 catastrophic forgetting 这一问题的,和这篇paper “Overcoming Catastrophic Forgetting During Domain Adaptation of Neural Machine Translation“ 相似,也是采用的 Elastic Weight Consolidation(EWC) 的方法,对weight采用MSE的约束。

$$L_{kd}=-||\hat h^{lm}-h_l||^2_2$$

$$L=\alpha\cdot L_{nmt}+(1-\alpha)\cdot L_{kd}$$

其中 $L_{kd}$ 是正则化项,$\hat h^{lm}$ 是经过BERT编码之后的 sentence embedding. $h_l$ 则是NMT的encoded之后的 sentence embedding. 作者都使用的最后一层的表示。在后续实验中,作者也测试了不同层的表示进行约束。

Dynamic Switch

动态开关。

就是GRU中的gate机制。

$$g = \sigma(Wh^{lm} + Uh^{nmt} + b)$$

$$h=g\odot h^{lm}+(1-g)\odot h^{nmt}$$

Rate-scheduled learning

slanted triangular learning, 斜三角学习率。最开始提出是在 ULMFT: Universal language model fine-tuning for text classificatio 这篇论文中。

$$\theta_t=\theta_{t-1}-\eta\nabla_{\theta}L(\theta)$$

对 NMT 和 LM 对应的参数使用不同的学习率,但是都采用这种scheduled学习率.

Result

从0开始GAN-5-NAT Decoding

non-autoregressive decode 相关的paper:

paper1

Constant-Time Machine Translation with Conditional Masked Language Models

Motivation

把auto-regressive转换成non-autoregressive. 其做法是先确定一个target sentece的长度,然后可以看作是每一个time-step的分类任务了。这样decoder就是可并行的了。

architecture

模型架构采用transformer的架构。

原生的 Transformer:

  • source-language encoder: self-attention, 包括padding mask.

  • translation model decoder

    • self-attention, 包括padding mask和 look ahead mask,用以mask掉future information.

    • interaction attention with enc_out, 包括 padding mask.

这篇paper中的 conditional mask language model(CMLM) 与transormer的区别在于 decoder 部分的self-attention去掉了 look ahead mask. 所以可以类似于 BERT 那样基于上下文来预测被 mask 的词,decoder 是 bi-directional.

Decoding with Mask-Predict

decoder 的具体操作是一个迭代的过程。

| src | Der Abzug der franzsischen Kampftruppen wurde am 20. November abgeschlossen . |

| :—– | :—————————————————- |

|t=0|The withdrawal of French combat troops was completed on November 20th .|

|t=1|The departure of the French combat completed completed on 20 November .|

|t=2|The departure of the French combat completed completed on 20 November .|

表中加粗的部分是被 mask 的。可以看到随着迭代进行,mask的词越来越少。

如何选择mask的词:

  1. mask词的数量n: 基于一个递减的公式, $n=N\dfrac{T-t}{T}$. t 是迭代次数。

  2. mask哪些词呢:$Y^{(t)}_{mask}=argmin_i(p_i,n)$ $p_i$ 表示上一次prediction得到的每一个词的置信度,选择概率最低的 n 个词。

基于 encoder_src, $Y_{obs}$ 对 mask token 进行预测:

target sequence length

这中 non-Autoregressive 存在的一个大问题就是如何确定target sentence 的长度。在 auto-egressive 里面是根据 ${}$ 来确定句子长度的。

针对这个问题,作者采用了类似于 BERT 中 CLS 的做法。使用了 $LENGTH$ 来预测sentence的长度,也是一个分类任务,这个 LENGTH 对应的词表应该就是长度~

作者选取 top b length,类似于 beam search. 然后选择 candidated b sentence 中概率最大的.

$$\dfrac{1}{N}\sum logp_i^{(T)}$$

code reading

paper2

Non-Autoregressive Neural Machine Translation

Motivation:

现有的机器翻译模型在inference时,需要在生成前一个单词的基础上继续生成下一个单词,这种自回归的特性严重影响了推理的速度。

并且与训练阶段的不一致导致存在exposure bias。作者提出一个非自回归的方法,在infer阶段并行输出。

Exposure bias:

  • training 阶段上一个token是ground truth

  • infer 阶段上一个token是生成得到的,这样自回归生成整个句子存在误差累积

  • 两个阶段生成target的方式不一样,也就是 exposure bias.

Model Architecture:

  • 前一项表示基于监督学习来预测targets 句子的长度。在本文中作者使用了这个词 fertilities(生育能力) 来表示通过source句子通过encode之后所包含的知识.

  • 后一项依旧是极大似然估计,也就是 independent cross-entropy losses on each output distribution。 但不同的是,在inference阶段也是可以并行的。

这里有个疑问,在训练阶段会预测得到一个长度T,但是训练阶段时groud truth长度的,这个怎么解决?

这里在训练阶段显然需要长度与 ground truth 的target sentence长度一致,才能计算 word-wise corss entropy loss.

Decoder Stack

1.decoder input

首先关于 decoder 的初始输入,在已有的模型中,训练阶段 decoder 的输入是 time-shifted target outputs,推理阶段是前面时间步预测的输出。

对于NAT模型,需要提前确定 target output 的长度,作者提出了两种方法:

  • Copy source inputs uniformly

  • Copy source inputs using fertilities, 如上图中输入的每个时间步都有其对应的 fertility. 然后把source input按照其对应的次数copy到decoder的输入。

2.Non-causal self-attention

因为不是自回归,也就是下一个词的生成并不依赖于previous的tokens,所以可以去掉transformer中decoder部分的cause-mask,也就是可以结合上下文的词,而不仅仅只是上文。

3.position attention

We also include an additional positional attention module in each decoder layer, which is a multi-head attention module with the same general attention mechanism used in other parts of the Transformer network. 为了强调位置信息。

Modeling fertility to tackle the multimodality problem

$P_F(f_{t’}|x_{1:T’}; \theta)$ 表示 fertility 在 t’ 时间步的概率分布,其是通过encoder顶层的 mlp + softmax 得到的。

从0开始GAN-4-ScratchGAN

Training Language GANs from Scratch

发现一个问题,目前看到language gans的相关paper大部分是Google,DeepMind的paper. 感觉是个深不见底的坑,弱渣哭了。。。

Motivation

我们知道language GAN非常难训练,主要是因为gradient estimation, optimization instability, and mode collapse等原因,这导致很多NLPer选择先基于maximum likelihood对模型进行预训练,然后在用language GAN进行fine-tune.作者认为这种 fine-tune 给模型带来的benefit并不clear,甚至会带来不好的效果。

关于mode collapse,李宏毅老师讲过,在对话生成时,模型总是倾向于生成“我不知道”,”我知道了”这样通用的没有太多sense的回复,其实就是属于mode collapse. 类似于图像领域,既要生成鼻子,又要生成嘴巴,但是模型会倾向于生成一个居中的distribution来模拟这两个distribution。

关于gradient estimator,是因为对于离散的数据,其gradients的方差会很大。

[13-16]就是先使用ML预训练模型,然后在此基础上adversarial fine-tune.[17-18]则说明了 “that the best-performing GANs tend to stay close to the solution given by maximum-likelihood training”.

所以作者为了证明language GAN真的能work,就from scratch训练了一个language GAN, 对,没有预训练。作者认为从头训练好language GAN的核心技术是 large batch sizes, dense rewards and discriminator regularization.

本文的贡献:

  1. 从头训练一个language GAN能达到基于ML方法的unconditional text generation.

  2. 证明 large batch sizes, dense rewards and discriminator regularization 对于训练language GAN的重要性。

  3. 作者对文本生成模型的evaluation提出了一些性的拓展,能充分挖掘生成的language更多的特性。比如:

    • BLEU and Self-BLEU [19] capture basic local consistency.

    • The Frechet Distance metric [17] captures global consistency and semantic information.

    • Language and Reverse Language model scores [18] across various softmax temperatures to capture the diversity-quality trade-off.

    • Nearest neighbor analysis in embedding and data space provide evidence that our model is not trivially overfitting.

Generative Models of Text

生成模型的本质就是对unknown data distribution进行建模,也就是学习模型 p(x|y) 的参数。在传统的机器学习里面,我们认为模型 p(x|y) 的分布就是多维高斯正态分布,然后用EM算法去学习得到参数。在基于neural network的自然语言处理领域,对于 $x=[x_1,..,x_T]$, $p_{\theta}(x_t|x_1,…,x_{t-1})$ 也可以看作是学习这样一个distribution,只不过模型的参数不是高斯正态分布这么简单,而是基于network来模拟的。同样序列特性使得其非常适合使用自回归模型进行建模:

$$p_{\theta}=\prod_{t=1}^Tp_{\theta}(x_t|x_1,…,x_{t-1})$$

Maximum Likelihood

一旦模型建立好了,接下来就是训练模型。最常用的方法就是使用极大似然估计 maximum likelihood estimation(MLE).

$$\argmax_{\theta}\mathbb{E}{p^* (x)}logp{\theta}(x)$$

关于 maximum likelihood 是否是最优解,这篇paper有讨论[9]。

Generative Adversarial Networks

前面seqgan也说过自回归模型中 $p_{\theta}=\prod_{t=1}^Tp_{\theta}(x_t|x_1,…,x_{t-1})$的过程有个sample的操作,这是不可导的。针对这个问题,有三种解决方法:

  • 高方差,无偏估计的 reinforce[28]. 基于大数定律的条件下,去sample更多的example,来模拟 $p(y_t|s_t)$ 的分布,然后基于policy gradient去优化这个distribution,这使得速度很慢。

  • 低方差,有偏估计的 gumbel-softmax trick[29-30].

  • other continuous relaxations[11].

Learning Signals

对于generator的训练,作者采用了基于 REINFORCE 的方法:

其中同 MaliGAN[15] 一样,设置 $R(x)=\dfrac{p^* (x)}{p_{\theta}(x)}$, 这样等效于 MLE 估计。

基于MLE eatimator的梯度更新可以看作是reinforce的一个spacial case.区别在于language gans的reward是可以学习的,也就是discriminator是不断更新的。可学习的discriminator的效果已经被证明过了[34].

如果learned reward能够提供相比MLE loss更光滑的信号,那么discriminator就能提供更多有意义的signal,甚至training data没有cover的distribution.

同时,discriminator是可以ensemble的,使用更多的domain knowledge.这样能学习到更多的信息。

Training Language GANs from Scratch

作者通过实验验证,要训好一个language gans,所需要的是:

  • a recurrent discriminator used to provide dense rewards at each time step

  • large batches for variance reduction

  • discriminator regularization

dense rewards

判别器能够判别generated sentence和real sentence,但是对于不完整的句子,就没办法去判断。这就造成,如果generated sentence很容易就被判断为fake,那么在fix discriminator训练generator时,生成器无法获得有意义的信号,也就是梯度为0吧。

为了避免这种情况,作者采用了 MaskGAN[32] 的方法:

maskGAN

maskGAN是一种 actor-critic 方法,利用类似于完形填空的形式,只需要生成被挖去的词,就能对整个sentence进行判别,并计算reward,这样得到的reward相比sentence中的每一个词都是生成的,其variance会小很多。

具体做法是:

  1. 生成器是 seq2seq 的形式,输入sequence $x=(x_1,…,x_T)$. 通过 binary mask $m=(m_1,…,m_T)$ 得到 $m(x)$.

  2. 根据 m(x) 来生成得到完整的 generated examples $\hat x=(\hat x_1, \hat x_2,…,\hat x_T)$.

  1. 这里生成的时候参考上图,如果当前time-step被mask了,则需要用到上一个time-step生成的词,如果没有被mask,就直接使用当前词,类似于teacher-forcing.

  2. 判别器就是计算每一个词为真的概率,注意这里判别器的输入也有 m(x),其原因是让模型更好的识别生成的sentence中,哪一个是之前被mask了的。

$$D_{\phi}(\tilde x_t|\tilde x_{0:T}, m(x)) = P(\tilde x_t=x_t^{real}|\tilde x_{0:T}, m(x))$$

  1. reward 的计算:

$$r_t=logD_{\phi}(\tilde x_t|\tilde x_{0:T}, m(x))$$

Large Batch Sizes for Variance Reduction

reference:

[9] How (not) to train your generative model: Scheduled sampling, likelihood, adversary? arXiv

[12-16]

[17-18]

[32] Maskgan: Better text generation via filling in the ____

[34]

从0开始GAN-3-文本生成planning

写这篇博客源于在知乎上看到大佬Towser在 “BERT模型在NLP中目前取得如此好的效果,那下一步NLP该何去何从?” 这个问题下的回答,对于文本生成的总结觉得太赞了。所以基于大佬的回答,画了一个脑图(http://www.xmind.net/m/AcA3bE),接下来一两个月的时间也决定按照这个路线进行学习。

Reward Augmented Maximum Likelihood for Neural Structured Prediction

Motivation

Maximum likilihood based method

对于NMT或者其他的 conditional generation,最常用的seq2seq模型是基于maximum likilihood(ML)来最小化下面这个目标函数的:

$$L_{ML}=\sum_{(x,y^* )\in D}-logp_{\theta}(y^* |x)$$

但是这种方式存在几个问题:

  • Minimizing this objective increases the conditional probability of the target outputs, $logp_{\theta}p(y^* |x)$, while decreasing the conditional probability of alternative incorrect outputs. According to this objective, all negative outputs are equally wrong, and none is preferred over the others.

在最大化目标函数,意味着增加 ground truth output的概率 $logp_{\theta}p(y^* |x)$,减少其他错误输出的概率。这个过程中,对于错误的output,模型认为所有的negative output都是同等的,这其实是不太正确的。

  • Generating Sentences from a Continuous Space:However, by breaking the model structure down into a series of next-step predictions, the rnnlm does not expose an interpretable representation of global features like topic or of high-level syntactic properties.

将结构化输出的预测问题,分解成一系列word prediction(seq2seq在训练阶段,其目标函数的loss是将所有的word对应的cross entropy加起来,并没有将sentence作为一个整体来进行优化),所以使得模型很难学到global feature,类似于topic或者high-level的句法特性。

RL based method

$$L_{RL}(\theta;\tau,D)=\sum_{(x,y^* )\in D}{-\tau\mathbb{H}(p_{\theta}(y^* |x))-\sum_{y\in \mathbb{Y}}p_{\theta}(y|x)r(y,y^* )}\quad{(1)}$$

D 表示 training parallel data. $\mathbb{H}(p)$ 表示概率分布 $p_{\theta}$ 对应的交叉熵, $H(p(y))=\sum_{y\in \mathbb{Y}p(y)logp(y)}$. $\tau$ 表示 temperature parameter,是一个超参。这个公式的理解可以与上一篇blog中seqgan的公式对应起来:

$$J(\theta)=E[R_T|s_0,\theta]=\sum_{y_1\in V}G_{\theta}(y_1|s_0)\cdot Q_{D_{\phi}}^{G_{\theta}}(s_0,y_1)\quad{(2)}$$

(1)式中的第2项就是(2)式。那么(1)式中的第一项表示的是Maximum likilihood的交叉熵?

使用RL based的方法存在这样两个问题:

  • 使用随机梯度下降SGD来优化 $L_{RL}(\theta;\tau)$ 非常困难,因为reward对应的gradients的方差很大(large variance).

  • 没能有效利用到监督信息。

作者提出了一种新的方法,能结合ML和RL的优势。

RAMI

作者在output space定义了一个 exponentiated payoffdistribution, 表示ML和RL的central distribution:

其中 $Z(y^* ,\tau)=\sum_{y\in \mathbb{Y}}exp{r(y, y^* )/\tau}$. 简单点理解就是基于 $r(y,y^* )$ 计算得到的reward r,然后softmax得到的分布。

$$q(y|y^* ;\tau)=\dfrac{1}{Z(y^* ,\tau)}exp{r(y, y^* )/\tau}\quad(3)$$

显然,这个 $r(y,y^* )$ 的计算是基于 BLEU 来计算的。这样一来,既考虑到了不同的 y 之间的差异性,也将 BLEU 的计算转换成了 distribution.

然后作者推导了各种公式证明了从ML的角度来优化 $q(y|y^* ;\tau)$ 和 $p_{\theta}(y|x)$ 的KL散度等效于优化 $L_{RL}$.

所以 reward-augmented maximum likelihood (RAML) 的loss function可以写成:

Note that the temperature parameter, $\tau \ge 0$, serves as a hyper-parameter that controls the smoothness of the optimal distribution around correct targets by taking into account the reward function in the output space.

optimization

对于 $L_{RAMI}(\theta;\tau)$ 的优化很简单,就是直接通过 $q(y|y^* ;\tau)$ 来sampling出 unbiased samples y. 如果超参数 $\tau=0$,那么就只能sample出 $y^* $.

对公示(7)求导,可以得到:  

这里 $q(y|y^* ;\tau)$ 是通过 $y^* $ 来sample y,不包含需要训练的参数的。所以 RAMI 也就是优化log-likelihood,不过这里的 y 不是ground truth,而是基于 ground truth和评估指标metric来sample得到的y.

对比基于 RL 的优化,作者进行了吐槽:

  1. RL中sample得到的样本 y 是通过生成模型得到的,而且这个model还是不断进化的。这使得训练速度很慢,比如 seqgan 中的roll-out policy.

  2. reward 在高维output空间非常稀疏,这使得优化很困难。

  3. actor-critique methods.

Sampling from the exponentiated payoff distribution

在通过公式(9)进行优化之前,需要先通过 exponentiated payoff distribution $q(y|y^* ;\tau)$ 来sample得到 y. This sampling is the price that we have to pay to learn with rewards. 这个sample过程与RL相比是没有参数的,瞬间简单了很多啊。。

那么具体是怎么sample的呢,作者使用的基于edit distance的方法。

  • 给定的ground truth $y^* $ 长度是m

  • 基于edit distance $y^* $ sample出与 $y^* $ 距离在 e 范围内的sentences y, 其中 $e\in {0,…,2m}$.

知乎上有大佬对这篇paper做了一个简单的总结, NLP八卦每日谈 2.

RL: x –> 通过decoder sample一个句子y’ –> 和y计算metric –> 把metric作为reward,算policy gradient

RAML: y –> 通过和metric对应的一个distribution sample一个句子y* –> 把y* 作为GT进行ML训练

这样做的好处是RL的sample是根据decoder sample,而decoder有参数,所以需要policy gradient。而RAML,是根据y(target sentence)来sample句子。这样就没有参数的问题,也就不需要policy gradient了。

RAML看起来几乎完美,不存在任何优化问题。可天下没有免费的午餐。RAML的难点在于如何将Metric转化成对应的distribution。RAML只提供了将诸如edit distance等metric转化成dist的方法,但对于BLEU等却无能为力。

所以目前为止,RAML的主要贡献在于让我们理解RL language generation到底train了个啥。简单来说就是不学ground truth distribution,而学习一个跟metric相关的dense distribution。这么做的好处是y的distribution更大,相对来说更容易学习

关于结构化预测related work

(a) supervised learning approaches that ignore task reward and use supervision;

(b) reinforcement learning approaches that use only task reward and ignore supervision;

(c) hybrid approaches that attempt to exploit both supervision and task reward.

Generating Sentences from a Continuous Space Samuel

这是非常早期的一篇基于变分自编码做文本生成的论文,我们都知道VAE和GAN是非常类似的。所以在看 GAN text generation相关的paper之前先学习下如何用VAE做文本生成。

关于 VAE 有两篇非常不错的blog:

何为 VAE

Motivation

传统 RNNLM 在做text生成的时候,其结构是把一个序列breaking成一个个next word的prediction. 这使得模型并没有显示的获取文本的全局信息,也没有获取类似于topic和句法相关的高级特征。

于是乎,作者提出了一种基于vatiational encoder的方法,能有效获取global feature,并且能避免 MLM 带来的几乎不可能完成的计算。同时,作者认为基于传统的language model的验证方法并不能有效展示出global feature的存在,于是提出了一种新的 evaluation strategy.

For this task, we introduce a novel evaluation strategy using an adversarial classifier, sidestepping the issue of intractable likelihood computations by drawing inspiration from work on non-parametric two-sample tests and adversarial training.

从0开始GAN-2-sequence generation by GAN

paper list

为什么GAN不适合文本生成

前面学过了GAN很自然的就会想到将GAN引入到文本生成中来,比如对话可以看作是conditional GAN, 但实际上却并不如想象中那样简单,原因是GAN只适用于连续数据的生成,对离散数据效果不佳。

Role of RL in Text Generation by GAN(强化学习在生成对抗网络文本生成中扮演的角色) 这里面从两方面讲的很清楚:

  • sampling:从生成得到的softmax probability到one-hot向量,从而查询出对应index的词,这一步称为“sampling”,显然是不可微的。

  • 去掉sampling,将softmax probability和one-hot vector作为discriminator的输入,如果是discriminator是一个二分类器的话,判别器D很容易“作弊”,它根本不用去判断生成分布是否与真实分布更加接近,它只需要识别出给到的分布是不是除了一项是 1 ,其余都是 0 就可以了。因此,我们也可以想到用WGAN来解决这个问题。Improved Training of Wasserstein GANs也给出了文本生成的实验,效果当然是好了很多,不至于直接崩了。

但是WGAN为什么没那么好呢?将一个softmax probability强行拉倒一个one-hot vector真的可行吗?

Gumbel-softmax,模拟Sampling的softmax

RL in text generation

reinforcement learning

reinforcement learning 和监督学习、非监督学习一起构成机器学习的三大范式。

Reinforcement learning (RL) is an area of machine learning concerned with how software agents ought to take actions in an environment so as to maximize some notion of cumulative reward.

It differs from supervised learning in that labelled input/output pairs need not be presented, and sub-optimal actions need not be explicitly corrected. Instead the focus is finding a balance between exploration (of uncharted territory) and exploitation (of current knowledge)

RL所适用的环境是一个典型的马尔科夫决策过程(Markov decision process,MDP)。所以强化学习实际上也可以看作是一种动态规划的方法。不过与传统的dynamic programming方法不同的是,RL不会假设MDP的精确数学模型的知识。我的理解是,在很多DP问题中,状态转移矩阵是已知的,但是RL所处理的问题,从一个状态到另一个状态,不是根据已有的知识,而是取决于当前action带来的reward以及未来的reward,所以这也就涉及到了 exploration 和 exploitation 的平衡问题。

Markov decision process 包括:GANs-in-NLP/Reinforcement_learning_diagram.png

  • 环境以及agent状态的集合 S;

  • agent能采取的动作的集合 $A$

  • 状态之间转换的规则 $P_a(s,s’)=Pr(s_{t+1}=s’|s_t=s,a_t=a)$

  • 规定转换之后的即时奖励 $R_a(s,s’)$

  • 描述主体能够观察到什么的规则(这是啥玩意??)

policy

将从头到尾所有的动作连在一起就称为一个“策略”或“策略路径” $pi$ ,强化学习的目标就是找出能够获得最多奖励的最优策略.

$\pi: A\times S \rightarrow [0,1]$

$\pi(a,s)=Pr(a_t=a|s_t=s)$

state-value function

状态-值函数 $V_{\pi}(s)$ 定义在当前状态 s下,按照策略 $\pi$ 接下来能获得的 reward.也就是说,given state s,当前以及未来的reward期望.

$$V_{\pi}(s)=E[R]=E[\sum_{t=0}^{\infty}\gamma^tr_t|s_0=s]$$

其中 $\gamma^t$ 是折扣因子,因为还是当前利益最重要嘛,所以未来的reward要打个折。

$$R=\sum_{t=0}^{\infty}\gamma^tr_t$$

value function

value funcion 和 state-value function 的区别是后者给定了一个 state. 而value function是计算给定任意初始状态,得到的reward.

$$V^{\pi}=E[R|s,\pi]$$

所以最优的 policy 实际上就是 value function 的期望最大。$\rho^{\pi}=E[V^{\pi}(S)]$, 其中状态S是从一个分布 $\mu$ 随机采样得到的。

尽管 state-value 足够定义最优 policy,再定义一个 action-value 也是很有用的。 given state s, action a, policy $\pi$, action-value:

$$Q^{\pi}(s,a)=E[R|s,a,\pi]$$

个人理解,在强化学习的应用场景中,很多时候是由 action 来确定下一个 state 的。所以 action-value 这个function会更实用吧。比如 text generation,sample当前词就是 action,然后才有下一个时刻的 state.

Monte Carlo methods

Temporal difference methods

RL应用到对话场景下

Deep Reinforcement Learning for Dialogue Generation

对话生成任务本身非常符合强化学习的运行机理(让人类满意,拿奖励)。

输入句子是 h,模型返回的response是 x,其从人类得到的奖励是 $R(h,x)$. 基于RL的目标函数就是最大化对话的期望奖励。上图中 $p_{\theta}(x,h)$ 表示在 $\theta$ 参数下,一组对话 $(x,h)$ 出现的概率。$P(h)$ 表示出现句子 h 的概率。

最大化奖励期望:

$$公式(1)$$

  • 上式中 $h\sim P(h)$ 可以看作是均匀分布,所以 $E_{h\sim P(h)}\approx \dfrac{1}{N}$.

  • 其中 $E_{x\sim P_{\theta}(x|h)}$ 的计算无法考虑所有的对话,所以通过采样 $(h^1,x^1), (h^2,x^2), .., (h^N,x^N)$ 来计算。

然后问题来了,我们需要优化的参数 $\theta$ 不见了,这怎么对 $\theta$ 进行求导呢?可以采用强化学习中常用的 policy gradient 进行变形:

$$\dfrac{dlog(f(x))}{dx}=\dfrac{1}{f(x)}\dfrac{df(x)}{dx}$$

适当变形后,对 $\theta$ 进行求导:

$$公式(2)$$

这样一来,梯度优化的重心就转化到了生成对话的概率上来,也就是说,通过对参数 $\theta$ 进行更新,奖励会使模型趋于将优质对话的出现概率提高,而惩罚则会让模型趋于将劣质对话的出现概率降低。

自AlphaGo使得强化学习猛然进入大众视野以来,大部分对于强化学习的理论研究都将游戏作为主要实验平台,这一点不无道理,强化学习理论上的推导看似逻辑通顺,但其最大的弱点在于,基于人工评判的奖励 Reward 的获得,让实验人员守在电脑前对模型吐出来的结果不停地打分看来是不现实的,游戏系统恰恰能会给出正确客观的打分(输/赢 或 游戏Score)。基于RL的对话生成同样会面对这个问题,研究人员采用了类似AlphaGo的实现方式(AI棋手对弈)——同时运行两个机器人,让它们自己互相对话,同时,使用预训练(pre-trained)好的“打分器”给出每组对话的奖励得分 R(a^i, x^i) ,关于这个预训练的“打分器” R ,可以根据实际的应用和需求自己DIY。

SeqGAN

seqGAN对前面仅基于RL的对话生成进行了改进,也就是前面用pre-trained的打分器(或者是人类),用GAN中的判别器进行了代替。

这里问题在于生成得到的response x输入到判别器时,这个过程涉及到了sampling的操作,所以固定discriminator来更新generator时,梯度无法回流。

这就需要RL的出现了。

总结一下RL在这里面的作用:这里的discriminator得到的是reward。我们fix住判别器D来优化生成器 $\theta$ 的过程就变成了:生成器不再是原来的sample一个词,作为下一个time step的输入,因为这不可导。而是把当前time step作为一个state,然后采取action,这个action当然也是在词表中选一个词(用Monte Carlo Search). 以前是通过最大化似然概率(最小化交叉熵)来优化生成器,现在是寻找最优的 policy(最大化奖励期望)来优化生成器。而采用policy gradient可以将reward期望写成 $\theta$ 的连续函数,然后就可以根据最大化reward期望来优化 $\theta$,也就是梯度上升。

有了前面的基础再重新阅读seqGAN这篇paper.

motivation

传统的GAN在序列生成的能力有限主要是两个原因:

  1. 无法处理离散的数据(前面已经讲过了)

  2. 判别器D只能对完整的序列进行评价(原因是判别器就是基于完整的句子或dialogue进行训练的)。但是在序列生成的过程中,在生成部分序列的时候,对当前部分序列的评价也是很重要的。

传统的基于 RNN/attention 的序列生成模型也存在 exposure bias 的问题,也就是训练阶段和inference阶段不一致的问题。在训练阶段是teacher forcing,而在infer阶段,下一个词的预测仅仅依赖于当前的隐藏状态(attention-based会有attention vector). Bengio 的弟弟,另一个 Bengio 提出了 scheduled sampling 的方法,但这依然未能完全解决这个问题。

为此,作者提出基于RL的seqGAN。对序列生成的问题进行建模,把序列生成问题看作是马尔可夫决策过程(Data generation as sequential decision making),从而转换成基于RL的寻找最优policy的问题,有效的解决了上述三个问题。

Sequence Generative Adversarial Nets

这里先介绍一些数学符号:

我们的目的是训练得到一个生成模型 $G_{\theta}$,使其能生成得到这样的一个序列 $Y_{1:T}=(y_1,…,y_t,…,y_T)$. 其中 $y_t\sim V$. V是候选词表。用RL来描述序列生成的过程就是:

  1. 当前时间步 t 的状态 state s: $(y_1,…,y_{t-1})$

  2. action a 是选择下一个 token $y_t$.

  3. policy也就是生成模型 $G_{\theta}(y_t|Y_{1:t-1})$

  4. 状态的转移取决于 action a. 比如状态转移的概率 $\sigma_{s,s’}^a=1$,也就是在当前状态 $s=Y_{1:t-1}$ 情况下,下一个状态是 $s’$ 的概率为1,那么下一个状态是 $s’=Y_{1:t}$,对应的action也就是 $a=y_t$.

首先我们需要训练一个判别模型 $D_{\phi}(Y_{1:T})$, 通过判断输入来自 real or fake 进行训练。而生成器的训练需要借助于判别器D的输出,也就是 reward.

SeqGAN via Policy Gradient

如果不考虑中间每一个时间步的奖励,也就是只考虑整个sentence的reward, 那么基于生成模型(policy)$G_{\theta}(y_t|Y_{1:t-1})$ 的最大奖励期望的函数是:

$$J(\theta)=E[R_T|s_0,\theta]=\sum_{y\sim V}G_{\theta}(y|s_0)\cdot Q_{D_{\phi}}^{G_{\theta}}(s_0,y)$$

其中 $R_T$ 是对整个sentence的奖励, $G_{\theta}(y|s_0)$ 是 given $s_0$,生成 $y$ 的概率,$Q_{D_{\phi}}^{G_{\theta}}(s_0,y )$ 是 action-value 函数,也就是 given $s_0$ 和 policy $G_{\theta}$ 后采取的 action 是 $y$ 时对应的 reward. 在这篇论文里面,reward 就是判别器判断生成的sentence为real的概率。

$$Q_{D_{\phi}}^{G_{\theta}}(a=y_T,s=Y_{1:T-1})=D_{\phi}(Y_{1:T})$$

但是对于序列生成问题,不能仅仅考虑完整的句子的reward,还要考虑到每一个 time step. 但是在每一个time step也不能贪心的只考虑当前最大的reward,还要考虑到未来的情况. 作者提出基于 Monte Carlo search 的方法。

Monte Carlo methods can be used in an algorithm that mimics policy iteration. Policy iteration consists of two steps: policy evaluation and policy improvement. Monte Carlo is used in the policy evaluation step. In this step, given a stationary, deterministic policy ${\displaystyle \pi }$, the goal is to compute the function values ${\displaystyle Q^{\pi }(s,a)}$ (or a good approximation to them) for all state-action pairs ${\displaystyle (s,a)}$. Assuming (for simplicity) that the MDP is finite, that sufficient memory is available to accommodate the action-values and that the problem is episodic and after each episode a new one starts from some random initial state. Then, the estimate of the value of a given state-action pair ${\displaystyle (s,a)}$ can be computed by averaging the sampled returns that originated from ${\displaystyle (s,a)}$ over time. Given sufficient time, this procedure can thus construct a precise estimate ${\displaystyle Q}$ of the action-value function ${\displaystyle Q^{\pi }}$. This finishes the description of the policy evaluation step.

policy iteration分为两个步骤,policy evaluation和policy improvement.蒙特卡洛被用在policy evaluation step中,给定一个静态的,判别型的policy $\pi$,其目标是计算

具体来说,在当前状态 $s=Y_{1:t}$ 下,基于一个 roll-out policy $G_{\beta}$ 生成剩下的 T-t 个tokens,这个过程重复 N 次.

$${Y_{1:T}^1,…,Y_{1:T}^N}=MC^{G_{\beta}}(Y_{1:t;N})$$

式子左边是 N 个完整的sentence。 对于 roll-out policy $G_{\beta}$ 作者在这篇 paper 中采用的与生成模型一样的 $G_{\theta}$. 如果追求速度的话,可以选择更简单的策略。

这样基于 Monte Carlo method 就能计算每一个 time step 的能考虑到 future 的reward.

$$Q_{D_{\phi}}^{G_{\theta}}(s=Y_{1:t-1}, a=y_t)=

\begin{cases}

\dfrac{1}{N}\sum_{n=1}^ND_{\phi}(Y_{1:T}^n),Y_{1:T}^n \sim MC^{G_{\beta}}(Y_{1:t;N}), \quad \text{for t < T}\

D_{\phi}(Y_{1:t}),\quad\text{for t = T}

\end{cases}\quad (4)$$

公式还是比较好理解的。所以事实上判别器 $D_{\phi}$ 依旧是只能判断完整的sentence,但是在每一个 time step 可以借助于 roll-out policy 来得到完整的sentence,进而对当前 action 进行评分,计算得到 $a=y_t$ 的reward。

知道了如何计算reward,就可以利用最大化这个奖励期望来优化我们的生成器(policy $G_{\theta}$).对 $\theta$ 求导:

$$\nabla J(\theta)=\sum_{t=1}^T\mathbb{E}{Y{1:t-1}\sim G_{\theta}}[\sum_{y_t\sim V}\nabla_{\theta}G_{\theta}({y_t|Y_{1:t-1}})\cdot Q_{D_{\phi}}^{G_{\theta}}(Y_{1:t-1},y_t)]\quad\text{公式(3)}$$

公式(3)与前面李弘毅老师讲的公式(2)是一致的,只不过这里考虑的中间 reward.上式中 $E_{Y_{1:t-1}\sim G_{\theta}}[\cdot]$ 等同于前面提到的 $E_{x\sim P_{\theta}(x|h)}$ 都是通过sample 来计算的。同样 reward 的计算式 $Q_{D_{\phi}}^{G_{\theta}}(Y_{1:t-1},y_t)$ 也是不包含生成器的参数 $\theta$ 的。

上述公式中 $\sum_{y_t\sim V}\sim G_{\theta}(y_t|Y_{1:t-1})$

然后基于梯度上升来优化参数 $\theta$.

$$\theta \leftarrow \theta + \alpha_h\nabla J(\theta)\quad(8)$$

作者建议使用 Adam 或 RMSprop 优化算法。

除了生成器的优化,这里的判别器D是动态的。这样相比传统基于pre-train的判别器会更叼吧。优化判别器的目标函数是:

$$\min_{\phi}-\mathbb{E}{Y\sim p{data}}[logD_{\phi}(Y)]-\mathbb{E}{Y\sim G{\theta}}[log(1-D_{\phi}(Y))]\quad(5)$$

具体的算法步骤是:

And to reduce the vari- ability of the estimation, we use different sets of negative samples combined with positive ones, which is similar to bootstrapping (Quinlan 1996)

The Generative Model for Sequences

作者使用基于 LSTM 的生成器G。

$$h_t=g(h_{t-1},x_t)$$

$$p(y_t|x_1,…,x_t)=z(h_t)=softmax(c+Vh_t)$$

The Discriminative Model for Sequences

作者使用基于 CNN 的判别器,用来预测一个sentence为real的概率。

一些细节 + 一些延伸

到目前为止,基本理解了seqGAN的大部分细节,需要看看源码消化下。

接下来会有更多的细节和改进可先参考:Role of RL in Text Generation by GAN(强化学习在生成对抗网络文本生成中扮演的角色)

seagan 代码学习

TensorArray 和 基于lstm的MDP模拟文本生成

这也是seqgan的核心,用Monte Carlo search代替sampling来选择next token.在看具体代码之前先了解下 tensorarray.

TensorArray

Class wrapping dynamic-sized, per-time-step, write-once Tensor arrays

This class is meant to be used with dynamic iteration primitives such as while_loop and map_fn. It supports gradient back-propagation via special “flow” control flow dependencies.

一个封装了动态大小、per-time-step 写入一次的 tensor数组的类。在序列生成中,序列的长度通常是不定的,所以会需要使用动态tensorarray.

类初始化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

def __init__(self,

dtype,

size=None,

dynamic_size=None,

clear_after_read=None,

tensor_array_name=None,

handle=None,

flow=None,

infer_shape=True,

element_shape=None,

colocate_with_first_write_call=True,

name=None):

  • size: int32 scalar Tensor, 动态数组的大小

  • dynamic_size: Python bool, 是否可以增长,默认false

方法
  • stack
1
2
3
4
5
6
7

def stack(self, name=None):

"""Return the values in the TensorArray as a stacked `Tensor`.

"""

将动态数组 stack 起来,得到最终的 tensor.

  • concat
1
2
3
4
5
6
7

def concat(self, name=None):

"""Return the values in the TensorArray as a concatenated `Tensor`.

"""

将动态数组 concat 起来,得到最终的 tensor.

  • read
1
2
3
4
5
6
7
8
9

def read(self, index, name=None):

"""Read the value at location `index` in the TensorArray.

读过一次之后会清0. 不能读第二次。但可以再次写入之后。

"""

  • write
1
2
3
4
5
6
7
8
9
10
11

def write(self, index, value, name=None):

"""Write `value` into index `index` of the TensorArray.

"""

- index: int32 scalar with the index to write to.

- value: tf.Tensor

  • gather

  • unstack

  • split

  • scatter

tf.while_loop
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

def while_loop_v2(cond,

body,

loop_vars,

shape_invariants=None,

parallel_iterations=10,

back_prop=True,

swap_memory=False,

maximum_iterations=None,

name=None):

"""Repeat `body` while the condition `cond` is true.

"""

- cond: callable, return boolean scalar tensor. 参数个数必须和 loop_vars 一致。

- body: vallable. 循环执行体,参数个数必须和 loop_vars 一致.

- loop_vars: 循环变量,tuple, namedtuple or list of numpy array.

example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

matrix = tf.random.normal(shape=[5, 1], dtype=tf.float32)

sequence_length = 5

gen_o = tf.TensorArray(dtype=tf.float32, size=sequence_length,

dynamic_size=False, infer_shape=True)

init_state = (0, gen_o)

condition = lambda i, _: i < sequence_length

body = lambda i, gen_o : (i+1, gen_o.write(i, matrix[i] * 2))

n, gen_o = tf.while_loop(condition, body, init_state)

gen_o_stack = gen_o.stack()

gen_o_concat = gen_o.concat()用 LSTM 模拟马尔科夫决策过程



print(gen_o) # TensorArray object

print(gen_o_stack) # tf.Tensor(), [5,]

print(gen_o_concat) # tf.Tensor(), [5,1]

print(gen_o.read(3)) # -0.22972003, tf.Tensor 读过一次就被清0了

print(gen_o.write(3, tf.constant([0.22], dtype=tf.float32))) # TensorArray object

print(gen_o.concat()) # tf.Tensor([-2.568663 0.09471891 1.2042408 0.22 0.2832177 ], shape=(5,), dtype=float32)

print(gen_o.read(3)) # tf.Tensor([0.22], shape=(1,), dtype=float32)

print(gen_o.read(3)) # Could not read index 3 twice because it was cleared after a previous read

用 LSTM 模拟马尔科夫决策过程

  • current time t state: $(y_1,…,y_t)$. 但是马尔科夫决策过程的原理告诉我们一旦当前状态确定后,所有的历史信息都可以扔掉了。这个状态足够去预测 future. 所以在LSTM里面就是隐藏状态 $h_{t-1}$. 以及当前可观测信息 $x_t$.

  • action a: 选择 next token $y_t$.

  • policy: $G_{\theta}(y_t|Y_{1:t-1})$. 也就是生成next token的策略。下面代码的方法 $o_t \rightarrow log(softmax(o_t))$. 然后基于这个 log-prob 的分布进行 sample. 问题是这个过程不可导呀?

generator

这是生成器生成sample的过程,初始状态是 $h_0$.

g_recurrence 就是step-by-step的过程,next_token是通过tf.multinomial采样得到的,其采样的distribution是 log_prob [tf.log(tf.nn.softmax(o_t))]。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131

class Generator(tf.keras.Model):

...



self.h0 = tf.zeros([self.batch_size, self.hidden_dim])

self.h0 = tf.stack([self.h0, self.h0])



# define variables

self.g_embeddings = tf.Variable(self.init_matrix([self.vocab_size, self.emb_dim]))

self.g_params.append(self.g_embeddings)

self.g_recurrent_unit = self.create_recurrent_unit(self.g_params) # maps h_{t-1} to h_t for generator

self.g_output_unit = self.create_output_unit(self.g_params) # maps h_t to o_t (output token logits)



def _unsuper_generate(self):

""" unsupervised generate. using in rollout policy.

:return: 生成得到的 token index

"""

"""

:param input_x: [batch, seq_len]

:param rewards: [batch, seq_len]

:return:

"""

gen_o = tf.TensorArray(dtype=tf.float32, size=self.sequence_length,

dynamic_size=False, infer_shape=True)

gen_x = tf.TensorArray(dtype=tf.int32, size=self.sequence_length,

dynamic_size=False, infer_shape=True)



def _g_recurrence(i, x_t, h_tm1, gen_o, gen_x):

h_t = self.g_recurrent_unit(x_t, h_tm1) # hidden_memory_tuple

o_t = self.g_output_unit(h_t) # [batch, vocab] , logits not prob

log_prob = tf.log(tf.nn.softmax(o_t))

#tf.logging.info("unsupervised generated log_prob:{}".format(log_prob[0]))

next_token = tf.cast(tf.reshape(tf.multinomial(logits=log_prob, num_samples=1),

[self.batch_size]), tf.int32)

x_tp1 = tf.nn.embedding_lookup(self.g_embeddings, next_token) # [batch, emb_dim]

gen_o = gen_o.write(i, tf.reduce_sum(tf.multiply(tf.one_hot(next_token, self.vocab_size, 1.0, 0.0),

tf.nn.softmax(o_t)), 1)) # [batch_size] , prob

gen_x = gen_x.write(i, next_token) # indices, batch_size

return i + 1, x_tp1, h_t, gen_o, gen_x



_, _, _, def _super_generate(self, input_x):

""" supervised generate.



:param input_x:

:return: 生成得到的是 probability [batch * seq_len, vocab_size]

"""

with tf.device("/cpu:0"):

self.processed_x = tf.transpose(tf.nn.embedding_lookup(self.g_embeddings, input_x),

perm=[1, 0, 2]) # [seq_len, batch_size, emb_dim]

# supervised pretraining for generator

g_predictions = tf.TensorArray(

dtype=tf.float32, size=self.sequence_length,

dynamic_size=False, infer_shape=True)



ta_emb_x = tf.TensorArray(

dtype=tf.float32, size=self.sequence_length)

ta_emb_x = ta_emb_x.unstack(self.processed_x) self.gen_o, self.gen_x = tf.while_loop(

cond=lambda i, _1, _2, _3, _4: i < self.sequence_length,

body=_g_recurrence,

loop_vars=(tf.constant(0, dtype=tf.int32),

tf.nn.embedding_lookup(self.g_embeddings, self.start_token),

self.h0, gen_o, gen_x))



self.gen_x = self.gen_x.stack() # [seq_length, batch_size]

self.gen_x = tf.transpose(self.gen_x, perm=[1, 0]) # [batch_size, seq_length]

return self.gen_x

所以是通过monte carlo的形式生成fake sample,作为discriminator的输入吗?那这个过程也不可导呀。其实不是这样的。我们再看对抗学习中更新generator的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

def gen_reward_train_step(x_batch, rewards):

with tf.GradientTape() as tape:

g_loss = generator._get_generate_loss(x_batch, rewards)

g_gradients, _ = tf.clip_by_global_norm(

tape.gradient(g_loss, generator.trainable_variables), clip_norm=5.0)

g_optimizer.apply_gradients(zip(g_gradients, generator.trainable_variables))

return g_loss



tf.logging.info("------------------ 6. start Adversarial Training...--------------------------")

for total_batch in range(TOTAL_BATCH):

# fix discriminator, and train the generator for one step

for it in range(1):

samples = generator._unsuper_generate()

#tf.logging.info("unsuper generated samples:{}".format(samples[0]))

rewards = rollout.get_reward(samples, rollout_num=2, discriminator=discriminator) # 基于 monte carlo 采样16,计算并累计 reward.

#tf.logging.info("reward:{}".format(rewards[0]))

gen_reward_train_step(samples, rewards) # update generator.

# Update roll-out parameters

rollout.update_params() # update roll-out policy.

这儿采用的是 generator._get_generate_loss, 所以它对generator的参数都是可导的吗? 我们再看这个生成器中这个function的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111

class Generator(tf.keras.Model):

...



def _super_generate(self, input_x):

""" supervised generate.



:param input_x:

:return: 生成得到的是 probability [batch * seq_len, vocab_size]

"""

with tf.device("/cpu:0"):

self.processed_x = tf.transpose(tf.nn.embedding_lookup(self.g_embeddings, input_x),

perm=[1, 0, 2]) # [seq_len, batch_size, emb_dim]

# supervised pretraining for generator

g_predictions = tf.TensorArray(

dtype=tf.float32, size=self.sequence_length,

dynamic_size=False, infer_shape=True)



ta_emb_x = tf.TensorArray(

dtype=tf.float32, size=self.sequence_length)

ta_emb_x = ta_emb_x.unstack(self.processed_x)



def _pretrain_recurrence(i, x_t, h_tm1, g_predictions):

h_t = self.g_recurrent_unit(x_t, h_tm1)

o_t = self.g_output_unit(h_t)

g_predictions = g_predictions.write(i, tf.nn.softmax(o_t)) # [batch, vocab_size]

x_tp1 = ta_emb_x.read(i) # supervised learning, teaching forcing.

return i + 1, x_tp1, h_t, g_predictions



_, _, _, self.g_predictions = tf.while_loop(

cond=lambda i, _1, _2, _3: i < self.sequence_length,

body=_pretrain_recurrence,

loop_vars=(tf.constant(0, dtype=tf.int32),

tf.nn.embedding_lookup(self.g_embeddings, self.start_token),

self.h0, g_predictions))

self.g_predictions = tf.transpose(self.g_predictions.stack(),

perm=[1, 0, 2]) # [batch_size, seq_length, vocab_size]

self.g_predictions = tf.clip_by_value(

tf.reshape(self.g_predictions, [-1, self.vocab_size]), 1e-20, 1.0) # [batch_size*seq_length, vocab_size]

return self.g_predictions # [batch_size*seq_length, vocab_size]



def _get_generate_loss(self, input_x, rewards):

"""



:param input_x: [batch, seq_len]

:param rewards: [batch, seq_len]

:return:

"""

self.g_predictions = self._super_generate(input_x)

real_target = tf.one_hot(

tf.to_int32(tf.reshape(input_x, [-1])),

depth=self.vocab_size, on_value=1.0, off_value=0.0) # [batch_size * seq_length, vocab_size]

self.pretrain_loss = tf.nn.softmax_cross_entropy_with_logits(labels=real_target,

logits=self.g_predictions) # [batch * seq_length]

self.g_loss = tf.reduce_mean(self.pretrain_loss * tf.reshape(rewards, [-1])) # scalar

return self.g_loss

所以seqgan的作者是怎么做的呢,利用 generator._unsuper_generate先生成fake sample,然后再利用 generator._super_generate 得到 g_predictions, 将fake sample作为 real_targetg_predictions 做交叉熵求出 pretrain_loss,然后乘以每一个token对应的rewards得到最终的loss. 这个过程是可导的。

通常情况下Monte carlo方法在里面的作用其实就是 collect data. collecting data的过程用到了policy,然后基于reward对policy进行求导。

但是seqgan的作者在代码中呈现的是另一种trick. 先用generator生成fake样本,然后用rollout policy对该样本进行打分reward.这里并不是直接对reward求导,而是把fake样本作为target进行MLE训练,得到pretrain_loss,reward作为权重乘以pretrain_loss作为最终的损失函数。

roll-policy

这个过程比较容易理解,对于给定的 given_num,小于 given_num 的直接 copy,但是 $h_t$ 的计算依旧。大于 given_num 的token采用 generate._unsuper_generate.

疑问

看了代码总觉得代码写得与论文有出入。

基于policy gradient来更新policy(generator),按照公式应该是直接对rewards求导才对吧。基于Monte carlo采样的过程可以看作是sample不同的样本,是一种近似模拟 $o_t$ 分布的方法,是不要求可导的。

从0开始GAN-1-from-GAN-to-WGAN

From GAN to WGAN

Reference:

From GAN to WGAN

令人拍案叫绝的Wasserstein GAN

听李宏毅老师讲段子之 GAN

这是一篇 copy + translate + understand 的学习笔记. NLP 选手总是会听说 GAN 不适合自然语言处理这类任务,但学了才发现,emmmm,真香。。 不管是否适合,但真的好玩!

纵所周知,GAN非常难训练,在训练时总是会面临训练不稳定,以及难以收敛的情况。这里,作者尝试通过阐述GAN背后的数学原理,来解释为什么GAN不好训练,并且介绍了GAN的另一个版本来更好的解决这些训练难题。

Kullback–Leibler and Jensen–Shannon Divergence

在学习GAN之前,先回顾一下如何衡量两个概率分布相似度的标准。

KL (Kullback–Leibler) divergence

如何通俗的解释交叉熵与相对熵?

:

信息量可表示为 $log\dfrac{1}{p}$,其可理解为概率为p的随机事件所包含的信息量。比如“太阳明天早上在东边升起”,这个概率p=1,那么其所包含的信息就为0了,意思就是这不是句屁话嘛。。所以信息量与概率p成反比。至于为什么就是 $log\dfrac{1}{p}$ 这种形式,为啥不是 $1/p$,这需要去问香农了。。

而熵则是 信息量的期望,也可以理解为 随机性的度量。随机性越大,熵越大。

交叉熵

两个概率分布p和q,p为真实分布,q为非真实分布。按照真实分布来衡量识别一个样本或者是判断随机事件的准确性的度量,就是熵,也就是信息量的期望 $H(p)=\sum_ip(i) * log\dfrac{1}{p(i)}$,但是事实是,我们无法得知这个真实的分布,只能通过统计来预测这个分布,也就是用非真实分布q去衡量这个熵,$H(p,q)=\sum_ip(i) * log\dfrac{1}{q(i)}$, 注意这里的概率是真实分布 p(i). H(p,q)就是我们的“交叉熵”。

当用来预测的非真实分布q越接近真实分布,其随机性越小,准确率也就越高。

相对熵/KL散度

根据Gibbs’ inequality上述例子中的 $H(p,q) >= H(p)$ 恒成立。当且仅当q=p时,这个等号才成立。那么熵H(p,q)相比熵H(q)多出来的部分就是相对熵 $D(p||q)=H(p,q)-H(p)=\sum_ip(i)* log\dfrac{p(i)}{q(i)}$,也称为KL散度(Kullback–Leibler divergence,KLD).

从机器学习的角度去思考,我们预测得到的非真实分布就是q,当模型越好时,q与p越接近,也就是模型的准确度越高,随机性越小,所以交叉熵/相对熵也就越小。反过来,就可以通过交叉熵/相对熵来训练我们所需的模型了~

所以:

$$D_{KL}(p||q)=H(p,q)-H(p)=\sum_ip(i)* log\dfrac{p(i)}{q(i)}=\int_x{p(x)}log\dfrac{p(x)}{q(x)}dx$$

但是,这里有个问题,p和q并不是完全对称的。显然当p(x)为0,q(x)为非零值时,q(x)的影响就不存在了。反过来呢,q不可能为零。所以当两个概率完全相等时,用KL散度来衡量两个概率的相似度就会存在问题了。

Jensen–Shannon Divergence

JS散度的范围是[0,1],并且是完全对称的。

$$D_{JS}(p | q) = \frac{1}{2} D_{KL}(p | \frac{p + q}{2}) + \frac{1}{2} D_{KL}(q | \frac{p + q}{2})$$

p是均值为 0,方差为 1 的正态分布,q是均值为 1,方差为 1 的正态分布。两者的均值的分布是 m=(p+q)/2.可以看到 $D_{Kl}$ 是非对称的,而 $D_{JS}$ 是对称的。

[How (not) to Train your Generative Model: Scheduled Sampling, Likelihood, Adversary?

](https://arxiv.org/pdf/1511.05101.pdf)认为 GAN 能成功的很大一部分原因是用JS散度代替了传统的基于极大似然估计的KL散度。

Generative Adversarial Network (GAN)

GAN 包含两个模型:

  • Discrimator D: 判别器 D 用来估计来自 $p_r$ 或 $p_g$ 的样本是真实样本的概率

  • Generator G: 给定随机输入变量 z(随机 z 带来了多样性, $z\sim p_z$),输出得到合成的样本。G 的训练是通过捕捉真实样本的分布,从而生成尽可能真实的样本 ($G(z)=x\sim p_g$),换句话说,就是欺骗判别器 D 使得生成的样本获得较高的概率。

  • $p_z$ noise,可以是正态分布,也可以是均匀分布

  • $p_g$ 通过 sample 生成器生成的样本得到的分布

  • $p_r$ 通过 sanple 真实样本的 database 得到的分布

整个训练过程是迭代进行的:

  1. 固定生成器的参数,训练判别器

  2. 固定判别器参数,训练优化器

  3. iteration…

  4. 何时停止,以及如何判断何时停止,这也是 GAN 需要解决的问题。

Generator

实际上,可以把神经网络 G 看作是用来定义一个分布,$p_g$, 使得这个分布尽可能的接近真实样本的图像在高维空间中的分布 $p_r$.

所以对于生成器的目标函数是 $G^* =\argmax_{G}Div(P_g,p_r)$

但是问题在于,如何去评判两个 distributin 的接近程度呢,也就是 $Div(p_g,p_{data})$ 怎么计算?

Discriminator

GAN 牛逼的地方就是用另一个神经网络来判断这两个 distribution. 所以可以看作是一个二分类问题了。

当两个分布很接近的时候,判别器就很难去区分来自于 $p_g$ 和 $p_r$ 的样本。

所以对于判别器,其目标是尽可能的去区分出 $p_g$ 和 $p_r$,当计算出的 divergence 越大时,D 越好 $D^* =\argmax_{D}Div(D,G)$.

所以,G 和 D 两个模型在训练中是相互博弈的过程。G 尽可能的去欺骗 D,而 D 则尽可能的不被欺骗。这是一个有趣的zero-sum游戏。

loss function

从极大似然估计的角度来分析

根据极大似然估计,二分类判别器 D 的输入样本集 ${(x_1, y_1),(x_2,y_2),…,(x_N, y_N)}$ 的概率最大,而输入到判别器 D 的样本可能来自 real data, $x\sim p_r(x)$,也可能来自生成器 G, $x\sim p_g(x)$.

其中对应的 label:

$$ y= \begin{cases}

1, & \text {$x\sim p_r(x)$} \

0, & \text{$x\sim p_g(x)$}

\end{cases} $$

似然函数(样本集的概率最大):

$$L(\theta)=\prod_iD(y_i=1|x_i)^{y_i}(1-D(y_i=1|x_i))^{(1-y_i)}$$

对于 $x\sim p_r$, $y_i=1$,所以

$$logL=\sum_{x\sim p_r} logD(x)$$

对于 $x\sim p_g$, $y_i=0$, 可以得到:

$$logL=\sum_{x\sim p_g}log(1-D(x))$$

所以对于判别器D, 在生成器G固定参数时最优的判别器 D 就是最大化下面这个目标函数:

$$E_{x\sim p_r(x)}[logD(x)]+E_{x\sim p_g}[log(1-D(x)]\qquad\text{(1)}$$

事实上,我们发现,这个目标函数跟 logistic regression 是一样的。。。

从熵的角度来分析

我们通过最大化 $E_{x\sim p_r(x)}[logD(x)]$ 来保证判别器 D 在 real data $p_r$上的准确率。与此同时,G 生成得到的 fake 样本,G(z), $z\sim p_z(z)$,判别器D期望对于 fake 样本的概率 D(G(z)) 越接近于 0 越好,也就是最大化 $E_{z\sim p_z(z)}[log(1-D(G(z)))]$.

对于生成器,其目的就是让判别器D在 fake 样本上得到的概率更大,Goodfellow一开始提出来一个损失函数,后来又提出了一个改进的损失函数,分别是

$$E_{z\sim p_z}[log(1-D(G(z))]=E_{x\sim p_g}[log(1-D(x)]\qquad\text{(2)}$$ $$E_{z\sim p_z}[-logD(G(z)]=E_{x\sim p_g}[-logD(x)]\qquad\text{(3)}$$

这个直观上也很好理解~固定了判别器 G,然后让 $E_{x\sim p_g}[logD(x)]$ 尽可能大,也就是 $E_{x\sim p_g}[log(1-D(x)]$ 或者 $E_{x\sim p_g}[-logD(x)]$ 尽可能小。

然后把两者(1)和 (2)合并起来(它们有共同的第二项),D和G正在进行的就是一个 minimax game,而我们所需优化的loss function就是:

$$% <![CDATA[

\begin{aligned}

\min_G \max_D L(D, G)

& = \mathbb{E}{x \sim p{r}(x)} [\log D(x)] + \mathbb{E}_{z \sim p_z(z)} [\log(1 - D(G(z)))] \

& = \mathbb{E}{x \sim p{r}(x)} [\log D(x)] + \mathbb{E}_{x \sim p_g(x)} [\log(1 - D(x)] \quad (1.5)

\end{aligned} %]]>$$

对于生成器,需要最小化这个目标函数。对于判别器,需要最大化这个函数。

如何求关于判别器 D 的最优解

定义好了 loss function,接下来推导对于 D 的最优解. 上式可以写成积分函数:

$$L(G,D)=\int_x(p_r(x)log(D(x))+p_g(x)log(1-D(x)))dx\quad (4)$$

对于判别器 D,我们要求最大化上述目标函数。假设 D(x) 可以模拟任何函数(事实上 neural network 也是可以的),那么最大化上述函数等同于最大化积分内的函数。 也就是 given $\forall$ x ,求解其最优的判别器 D*.

$$p_r(x)log(D(x))+p_g(x)log(1-D(x))$$

为了简化计算,假设

$$\tilde x=D(x), A=p_r(x), B=p_g(x)$$

对积分内部求导(这里可以忽略积分,因为x是采样任何可能的值):

$$% <![CDATA[

\begin{aligned}

f(\tilde{x})

& = A log\tilde{x} + B log(1-\tilde{x}) \

\frac{d f(\tilde{x})}{d \tilde{x}}

& = A \frac{1}{ln10} \frac{1}{\tilde{x}} - B \frac{1}{ln10} \frac{1}{1 - \tilde{x}} \

& = \frac{1}{ln10} (\frac{A}{\tilde{x}} - \frac{B}{1-\tilde{x}}) \

& = \frac{1}{ln10} \frac{A - (A + B)\tilde{x}}{\tilde{x} (1 - \tilde{x})} \

\end{aligned} %]]>$$

然后,令 $\dfrac{df(\tilde x)}{d\tilde x}=0$,可以得到D(x)的最优解:

$D^* (x) = \tilde{x}^* = \frac{A}{A + B} = \frac{p_{r}(x)}{p_{r}(x) + p_g(x)} \in [0, 1]\qquad\text{(5)}$

这个结果从直观上很容易理解,就是看一个样本x来自真实分布和生成分布的可能性的相对比例。如果 $P_r(x) = 0$ 且 $P_g(x) \neq 0$,最优判别器就应该非常自信地给出概率0;如果 $P_r(x) = P_g(x)$,说明该样本是真是假的可能性刚好一半一半,此时最优判别器也应该给出概率0.5。

如何得到生成器 G 的最优解,也就是全局最优解

记住我们的目标是训练得到一个生成器,使得其生成的 $P_g$ 分布能尽可能的接近于 $P_r$. 所以当判别器最优时,最小化目标函数就能得到 G*,将 (4) 带入 (5) 式可以得到:

$$% <![CDATA[

\begin{aligned}

L(G, D^* )

&= \int_x \bigg( p_{r}(x) \log(D^* (x)) + p_g (x) \log(1 - D^* (x)) \bigg) dx \

&= \int_x (p_r(x)log\dfrac{p_r}{p_r+p_g} + p_g(x)log\dfrac{p_g}{p_r+p_g})dx \

&= \int_x(p_xlog\dfrac{\dfrac{1}{2}p_r}{\dfrac{1}{2}(p_r+p_g)} + p_glog\dfrac{\dfrac{1}{2}p_g}{\dfrac{1}{2}(p_r+p_g)})dx\quad\text{上下同时乘以$\dfrac{1}{2}$}\

&= -2log2 + \int_xp_r(x)log\dfrac{p_r(x)}{\dfrac{1}{2}(p_r(x)+p_g)}dx + \int_xp_g(x)log\dfrac{p_g(x)}{\dfrac{1}{2}(p_r(x)+p_g)}dx \quad\text{(6)}\

&= -2log2 + D_{KL}(p_r||\dfrac{p_r+p_g}{2}) + D_{KL}(p_g||\dfrac{p_r+p_g}{2})\quad\text{带入 KL 散度公式} \

&= -2log2 + D_{JS}(p_{r} | p_g)\quad\text{带入 JS 散度公式}

\end{aligned} %]]>$$

我们突然发现,诶,卧槽,厉害了。given D* 的条件下,当生成器 G 最优时,通过推导发现,最小化目标函数等同于最小化 $p_r$ 和 $p_g$ 的 JS 散度。所以啊,通过理论证明,让两个分布更接近的话,使用 JS 散度明显要比我们传统上使用的 KL 散度要合理呀~

所以如何判别两个分布的 Divergence, 通过推导告诉我们,JS 散度更好~

整个算法流程:

这个为什么 D 训练时是多次, 而 G 训练时只需要一次呢?

固定判别器为 $D^* $,通过梯度下降训练 $G_0 \rightarrow G_1$, 这里 $G_0$ 和 $G_1$ 不能差距太大. 因为如果 G 变化太大,那么对应的 JS divergence 变化可能就如上图所示,会突然变得很大,而不是我们所预想的减小了。

Problems in GANs

理论上,满足 JS 散度越小,两个分布越接近是可以的。但是要使得 JS 散度越来越小这个有点难度,因为图像是高维空间里面的低维 mainfold. 这也是接下来要讲的问题。

尽管 GAN 在图像生成上取得了很大的成功,但是其训练并不容易,过程很慢并且不稳定。令人拍案叫绝的Wasserstein GAN 将原始 GAN 的问题主要分成两部分。

  • 判别器的问题:D 越好,生成器梯度消失越严重。

  • 生成器的问题:最小化生成器loss函数,会等价于最小化一个不合理的距离衡量,导致两个问题,一是梯度不稳定,二是collapse mode即多样性不足。

判别器的问题:判别器越好,生成器梯度消失越严重

对于前面说到的 JS 散度上。我们会希望如果两个分布之间越接近它们的JS散度越小,我们通过优化JS散度就能将 $p_g$ “拉向” $p_r$,最终以假乱真。这个希望在两个分布有所重叠的时候是成立的,但是如果两个分布完全没有重叠的部分(要么是 $x\sim p_r$, 要么是 $x\sim p_g$),或者它们重叠的部分可忽略(等会儿解释什么叫可忽略),它们的JS散度是多少呢?

$p_1(x)=0且p_2(x)=0$

$p_1(x)\ne0且p_2(x)\ne0$

$p_1(x)=0且p_2(x)\ne 0$

$p_1(x)\ne 0且p_2(x)=0$

  • 第一种对计算JS散度无贡献

  • 第二种情况由于重叠部分可忽略,($p_r和 p_g$ 都是高维空间中的低维流形),所以贡献也为0.

  • 第三种情况,带入公式(6)倒数第三步的的后两项,JS 的散度计算可以得到其值为 log2.

  • 第四种情况同理。

换句话说,无论跟是远在天边,还是近在眼前,只要它们俩没有一点重叠或者重叠部分可忽略,JS散度就固定是常数,而这对于梯度下降方法意味着——梯度为0!此时对于最优判别器来说,生成器肯定是得不到一丁点梯度信息的;即使对于接近最优的判别器来说,生成器也有很大机会面临梯度消失的问题。

但是 $P_r$ 与 $P_g$ 不重叠或重叠部分可忽略的可能性有多大?不严谨的答案是:非常大。比较严谨的答案是:当 $P_r$ 与 $P_g$ 的支撑集(support)是高维空间中的低维流形(manifold)时,$P_r$ 与 $P_g$ 重叠部分测度(measure)为0的概率为1。

也就是接下来要说的: low dimensional support 和 gradient vanishing.

Low dimensional supports

有两个数学概念:

  • Manifold: A topological space that locally resembles Euclidean space near each point. Precisely, when this Euclidean space is of dimension n, the manifold is referred as n-manifold.

拓扑空间,在每个点附近局部类似于欧几里德空间。 确切地说,当该欧几里德空间具有n维时,该流形被称为n-流形。

  • Support: In mathematics, the support of a real-valued function f is the subset of the domain containing those elements which are not mapped to zero.

在数学中,实值函数f的支持是包含那些未映射到零的元素的域的子集

“Towards principled methods for training generative adversarial networks”. 这篇非常理论的论文讨论了对于 $p_r$ 和 $p_g$ 的support是处于低维的空间,并且这导致了GAN的训练中的不稳定性。

真实样本空间具有高度的人工特征,因为它的主题一旦确定,其包含的对象也就固定了。比如dog应该有two ears和a tail.一个Skyscraper应该有straight和tall的身体。这些限制使得图像不具备高维空间的形式。

同样的 $p_g$ 也是在低维流形空间。当给定初始的噪声输入变量为100维,生成器将其作为输入生成较大的图像 $64\times 64$,对于输出的分布 4096 pixels已经被100维随机的向量定义了,所以它也很难去填满整个高维空间。

“撑不满”就会导致真实分布与生成分布难以“碰到面”,这很容易在二维空间中理解:一方面,二维平面中随机取两条曲线,它们之间刚好存在重叠线段的概率为0;另一方面,虽然它们很大可能会存在交叉点,但是相比于两条曲线而言,交叉点比曲线低一个维度,长度(测度)为0,可忽略。三维空间中也是类似的,随机取两个曲面,它们之间最多就是比较有可能存在交叉线,但是交叉线比曲面低一个维度,面积(测度)是0,可忽略。从低维空间拓展到高维空间,就有了如下逻辑:因为一开始生成器随机初始化,所以几乎不可能与有什么关联,所以它们的支撑集之间的重叠部分要么不存在,要么就比和的最小维度还要低至少一个维度,故而测度为0。所谓“重叠部分测度为0”,就是上文所言“不重叠或者重叠部分可忽略”的意思。

因为 $p_r$ 和 $p_g$ 都是处于低维流形,他们很大可能性是不相交的。当他们具备不相交的特性时,我们就很容易找到一个完美的判别器来准确的100%区分fake样本和真实样本。

左侧图是两条线在三维空间。右侧是两个平面在三维空间。通过维度的对比来表明相交的可能性。

Vanishing gradient

当判别器非常完美的时候,$D(x)=1,\forall x\in p_r$, $D(x)=0, \forall x\in p_g$.

$$L(G,D)=\int_x(p_r(x)log(D(x))+p_g(x)log(1-D(x)))$$

带入这个公式可以发现,loss function L 会降为0,在迭代过程中,梯度也就无法更新。下图证明了,当判别器越好的时候,梯度消失越快。

WGAN前作Figure 2。先分别将DCGAN训练1,20,25个epoch,然后固定生成器不动,判别器重新随机初始化从头开始训练,对于第一种形式的生成器loss产生的梯度可以打印出其尺度的变化曲线,可以看到随着判别器的训练,生成器的梯度均迅速衰减。注意y轴是对数坐标轴。

生成器的问题:最小化生成器loss函数,会等价于最小化一个不合理的距离衡量

这样会导致两个问题:一是梯度不稳定,二是 mode collapse/dropping 即多样性不足。

前面说到 Goodfellow 给了两个 generator 的 loss function,也就是公式 (2)和(3).

Goodfellow 换成第二种 loss function 的理由如上图,因为在训练生成器 G 是,D(x) 肯定是很小的,所以观察上图可以看到 log(1-D(x)) 在 D(x) 偏小的区域梯度很小,所以导致训练很慢。

但是,换成第二种 loss 会导致 mode collapse. 接下来通过公式推导证明这俩问题。

通过公式(1.5)和公式(6)可以得到在 $D^* $ 的条件下:

$$ \mathbb{E}{x \sim p{r}(x)} [\log D^* (x)] + \mathbb{E}{x \sim p_g(x)} [\log(1 - D^* (x)]=-2log2 + D{JS}(p_{r} | p_g)\quad\text{(7)}$$

我们在算一个 KL 散度:

$$% <![CDATA[

\begin{aligned}

KL(p_g||p_r)

&=\mathbb{E}_{x\sim p_g}log(\dfrac{p_g(x)}{p_r(x)})\

&=\mathbb{E}_{x\sim p_g}[log\dfrac{p_g(x)/(p_g(x)+p_r(x))}{p_r(x)/p_g(x)+p_r(x)}]\

&=\mathbb{E}_{x\sim p_g}[log\dfrac{1-D^* (x)}{D^* (x)}]\

&=\mathbb{E}{x\sim p_g}log[1-D^* (x)]-\mathbb{E}{x\sim p_g}logD^* (x)\quad\text{(8)}

\end{aligned} %]]>$$

将公式(7)和 (8)带入到第二种 loss(3)中可以得到:

$$\begin{aligned}

\mathbb{E}_{x\sim p_g}logD^* (x)

&=KL(p_g||p_r)-\mathbb{E}_{x\sim p_g}log[1-D^* (x)]\

&=KL(p_g||p_r)-D_{JS}(p_{r} | p_g)+2log2-\mathbb{E}{x \sim p{r}(x)}\quad\text{(7)}

\end{aligned}$$

上式后两项与 G 无关,所以最小化 loss(3)等价于最小化:

$$KL(p_g||p_r)-D_{JS}(p_{r} | p_g)$$

这个等价最小化目标存在两个严重的问题。第一是它同时要最小化生成分布与真实分布的KL散度,却又要最大化两者的JS散度,一个要拉近,一个却要推远!这在直观上非常荒谬,在数值上则会导致梯度不稳定,这是后面那个JS散度项的毛病。

第二,即便是前面那个正常的KL散度项也有毛病。因为KL散度不是一个对称的衡量,KL(P_g || P_r)与KL(P_r || P_g)是有差别的。以前者为例:

当 $P_g(x)\rightarrow 0$ 而 $P_r(x)\rightarrow 1$ 时,$P_g(x) \log \frac{P_g(x)}{P_r(x)} \rightarrow 0$,对 $KL(P_g || P_r)$ 贡献趋近0

当 $P_g(x)\rightarrow 1$ 而 $P_r(x)\rightarrow 0$ 时,$P_g(x) \log \frac{P_g(x)}{P_r(x)} \rightarrow +\infty$,对 $KL(P_g || P_r)$ 贡献趋近正无穷

换言之,KL(P_g || P_r)对于上面两种错误的惩罚是不一样的,第一种错误对应的是“生成器没能生成真实的样本”,惩罚微小;第二种错误对应的是“生成器生成了不真实的样本” ,惩罚巨大。第一种错误对应的是缺乏多样性,第二种错误对应的是缺乏准确性。这一放一打之下,生成器宁可多生成一些重复但是很“安全”的样本,也不愿意去生成多样性的样本,因为那样一不小心就会产生第二种错误,得不偿失。这种现象就是大家常说的collapse mode。

第一部分小结:在原始GAN的(近似)最优判别器下,第一种生成器loss面临梯度消失问题,第二种生成器loss面临优化目标荒谬、梯度不稳定、对多样性与准确性惩罚不平衡导致mode collapse这几个问题。

这位老哥讲的太好了。。直接 copy 了。。

Mode collapse

mode collapse: 重复生成一张图片

mode dropping: G 在迭代时只能生成一类图片。

还有一个问题:Lack of a proper evaluation metric

GAN 没有一个好的目标函数来描述训练过程。没有好的验证指标,就好比在黑暗中work. 没有信号来提示该在什么时候停止,也没有好的指标来评价多种模型的好坏。

Improving GAN Training

Wasserstein GAN (WGAN)

Wasserstein Distance 是一种测量两个分布距离的方式。可以类比成 earth mover’s distance.

为了简单的理解,可以把两个分布看作是离散的。这里看作是两堆土,Wasserstein distance 就是计算如何移动最少量的土使得两个分布一致。

所以相比 JS 散度,从分类任务变成了回归任务。即使两个分布完全无交集,也是存在 divergence 更大或者更小的问题,所以也就不存在梯度为零的情况了。

但是问题来了,怎么计算 Wasserstein distance 呢?

step1: $p_1 \underrightarrow{2} p_2$, 使得 $p_1和Q_1$ match.

step2: $p_2 \underrightarrow{2} p_3$, 使得 $p_2和Q_2$ match.

step3: $Q_3 \underrightarrow{1} Q_4$, 使得 $p_3和Q_3$ match.

所以总的 W=5.

对于连续分布,Wasserstein distance:

$$W(p_r, p_g) = \inf_{\gamma \sim \Pi(p_r, p_g)} \mathbb{E}_{(x, y) \sim \gamma}[| x-y |]$$

$\Pi(p_r, p_g)$ 是所有可能的联合分布. 其中一种联合分布 $\gamma \sim \Pi(p_r, p_g)$ 表示一种 move plan, 就比如上图中的示例。

其中,对于任何一个联合分布 $\gamma$,其边缘分布分别是 $p_g(x)=\sum_x\gamma(x,y)$, $p_r(y)=\sum_y\gamma(x,y)$. 在此分布下的移动距离是 $||x-y||$. 那么当前联合分布下的 cost 是 $\gamma(x, y) \cdot | x-y |$. 其期望就是:

$$\sum_{x, y} \gamma(x, y) | x-y |= \mathbb{E}_{x, y \sim \gamma} | x-y |$$

而我们需要求的是所有可能的联合分布中的下界, 就定义为 Wasserstein distance.

Why Wasserstein is better than JS or KL divergence?

Wasserstein 距离的优势在于,即使两个分布没有交集,也能平滑的表示两个分布之间的散度。

$$

\forall (x, y) \in P, x = 0 \text{ and } y \sim U(0, 1)\

\forall (x, y) \in Q, x = \theta, 0 \leq \theta \leq 1 \text{ and } y \sim U(0, 1)\

$$

当 $\theta\ne 0$ 时,分别计算 KL,JS,WS 散度:

$$

% <![CDATA[

\begin{aligned}

D_{KL}(P | Q) &= \sum_{x=0, y \sim U(0, 1)} 1 \cdot \log\frac{1}{0} = +\infty \

D_{KL}(Q | P) &= \sum_{x=\theta, y \sim U(0, 1)} 1 \cdot \log\frac{1}{0} = +\infty \

D_{JS}(P, Q) &= \frac{1}{2}(\sum_{x=0, y \sim U(0, 1)} 1 \cdot \log\frac{1}{1/2} + \sum_{x=0, y \sim U(0, 1)} 1 \cdot \log\frac{1}{1/2}) = \log 2\

W(P, Q) &= |\theta|

\end{aligned} %]]>

$$

当 $\theta = 0$ 时,分别计算 KL,JS,WS 散度:

$$

% <![CDATA[

\begin{aligned}

D_{KL}(P | Q) &= D_{KL}(Q | P) = D_{JS}(P, Q) = 0\

W(P, Q) &= 0 = \lvert \theta \rvert

\end{aligned} %]]>

$$

当两个分布没有交集时,KL 散度的值是 inifity. JS 散度则存在不连续的问题,对于这个例子而言,当 $\theta=0$ 时,JS 散度不可微。只有 WS 距离是可微的,这对于梯度下降而言是非常友好的。

Use Wasserstein distance as GAN loss function

但是要穷尽两个联合分布的所有情况来计算 $\inf_{\gamma \sim \Pi(p_r, p_g)}$ 是不可能的。WGAN 的作者给出了一个聪明的转换,可以把公式 (8) 写成:

$$W(p_g,p_r)=\dfrac{1}{K}sup_{|f|_ L \le K}\mathbb{E}{x\sim p_r}[f(x)]-\mathbb{E}{x\sim p_g}[f(x)]\quad\text{(9)}$$

这里的意思就是用 f 函数来表示上面说到的任何可能的联合分布。所以 $\mathbb{E}{x\sim p_r}[f(x)]-\mathbb{E}{x\sim p_g}[f(x)]$ 等效于 $\mathbb{E}_{x, y \sim \gamma} | x-y |$.

然后我们又知道神经网络足够强大,所以用神经网络 D 来代替 f,来表示上面说到的任何可能的联合分布。但是 D 必须像前面提到的 Wasserstein distance 那样足够光滑。这样一来, Wasserstein distance 就转变成了我们想要的 loss function.

$$V(G,D)=\max_{D\sim \text{1-Lipschitz}}{\mathbb{E}{x\sim p_r}[D(x)]-\mathbb{E}{x\sim p_g}[D(x)]}\quad\text{(10)}$$

通过采样来计算 V(G,D),我们希望

这里用一个例子来说明为什么 D 要足够光滑:

我们看到要让 V(G,D) 在 real example 上增大,在 fake example 上减小, D 完全可以做到像上图中红色箭头那样。所以这样下来,D 无法收敛。

怎么保证一个神经网络足够光滑, $D\sim \text{1-Lipschitz}$,貌似听起来很难,毕竟涉及到那么多的参数。

Lipschitz continuity:

这里首先需要介绍一个概念——Lipschitz连续。它其实就是在一个连续函数 f 上面额外施加了一个限制,要求存在一个常数 $K\geq 0$ 使得定义域内的任意两个元素 $x_1$ 和 $x_2$ 都满足

$$|f(x_1) - f(x_2)| \leq K |x_1 - x_2|$$

此时称函数 f的Lipschitz常数为K。实际上就是 f 函数的导函数的值不能超过 K. Lipschitz 连续条件限制了一个连续函数的最大局部变动幅度。

在 WGAN 这篇论文中,作者采用了一种特别简单的方法,Weight Clipping. 对于任何参数,使其在 [-c,c] 范围内,就可以保证 K 不会特别大。。

到此,我们就能把 Wasserstein distance 应用到了 GAN 上,也就是 WGAN. 相比传统的 GAN,其区别在于:

  • 判别器 D 的任务不是分类,而是回归。所以去掉最后一层 sigmoid.

  • 生成器和判别器的 loss 不取 log,原因是 Wasserstein distance 就是这样呀~

  • 每次更新判别器的参数之后把它们的绝对值截断到不超过一个固定常数c

  • 不要用基于动量的优化算法(包括momentum和Adam),推荐RMSProp,SGD也行

总的流程就是:

  • $n_{\text{critic}}$ 表示判别器的训练迭代次数,生成器在一次完整的迭代中只训练一次。

  • 对于判别器的loss就是公式(10)

$$\mathbb{E}{x\sim p_g}[D(x)]-\mathbb{E}{x\sim p_r}[D(x)]\quad(11)$$

上图中与这个是相反的,所以上述流程中使用的是梯度上升。如果用公式(11)还是应该是梯度下降。

  • 生成器的loss是第二项

$$-\mathbb{E}_{x\sim p_g}[D(x)]\quad(12)$$

其中 $-\mathbb{E}{x\sim p_g}[D(x)]+\mathbb{E}{x\sim p_r}[D(x)]$ 可以指示训练进程,其数值越小,表示真实分布与生成分布的Wasserstein距离越小,GAN训练得越好。

improved WGAN

improved WGAN 主要是改进 weight clipping 这一略显粗糙的方式。取代它的是增加一个正则化项,来约束参数的变化。

$$|\nabla_xD(x)|\le 1$$

类似于 SVM loss:

$$-\lambda\mathbb{E}{x\sim p{penalty}}[max(0, |\nabla_xD(x)|- 1)]$$

其中 $x\sim p_{penalty}$ 这部分表示的是 $p_r和p_g$ 连线上的样本采样。

这里顺便把 $max(0, |\nabla_xD(x)|- 1)$ 改进成了 $(|\nabla_xD(x)|- 1)^2$ 以此来惩罚梯度太小的项。

“Simply penalizing overly large gradients also works in theory, but experimentally we found that this approach converged faster and to better optima.”

Spectrum Norm

Spectral Normalization → Keep gradient norm smaller than 1 everywhere [Miyato, et al., ICLR, 2018]

但其实前面说到的 $(|\nabla_xD(x)|- 1)^2$ 这一正则惩罚项依然是存在问题的。因为任意 sample $p_r 和 p_g$ 中的两点,然后拉进他们俩,实际上并不太合理,因为与 $p_g$ 最接近的 $p_r$ 中的一点并不就是采样到的这个.

论文笔记-GAN tutorial NIPS 2016

为什么要学习 GAN?

  • High-dimensional probability distributions, 从高维概率分布中训练和采样的生成模型具有很强的能力来表示高维概率分布。
  • Reinforcement learning. 和强化学习结合。
  • Missing data. 生成模型能有效的利用无标签数据,也就是半监督学习 semi-supervised learning。

生成模型如何工作的

Maximum likehood estimation

极大似然估计就是在给定数据集的情况下,通过合理的模型(比如语言模型)计算相应的似然(概率),使得这个概率最大的情况下,估计模型的参数。

$$\sum_i^mp_{\text{model}}(x^{(i)}; \theta)$$

m 是样本数量。

将上诉概率转换到 log 空间(log 函数是单调递增的),可以将乘积转换为相加,简化了计算。

同样的,也可以把上诉似然估计的极大化看做是最小化 KL 散度(或者交叉熵)。这样一来,相当于把无监督问题转换成了有监督问题。(不知理解的是否正确?)

相对熵

熵是信息量 $log{\dfrac{1}{p(i)}}$ (概率越大信息量越少)。

p 是真实分布, q 是非真实分布。

交叉熵是用 q 分布来估计 p 分布所需要消除的代价 cost:

$$H(p,q) = \sum_ip(i)log{\dfrac{1}{q(i)}}$$

用真实分布 p 估计真实分布所需要的 cost:

$$H(p) = \sum_ip(i)log{\dfrac{1}{p(i)}}$$

从这里也能看出,当概率 p 为 1 时,所需要的 cost 就为 0 了。

相对熵,又称 KL 散度(Kullback–Leibler divergence),就是指上诉两者所需要消耗的 cost 的差值:

$$D(p||q) = H(p,q)-H(p) = \sum_ip(i)log{\dfrac{p(i)}{q(i)}}$$

GAN 是如何工作的?

GAN 框架

  • 判别器 discriminator

  • 生成器 gererator

在左边场景,判别器学习如何分别样本是 real or fake. 所以左边的输入是 half real and half fake.

在右边的v场景,判别器和生成器都参与了。G 用来生成 G(z), D 用来判别 G(z) 是 real or fake.

结构化概率模型 Structured Probabilistic Modelsfor Deep Learning

containing latent variables z and observed variables x.

z 是需要学习的隐藏变量,x 是可观察到的变量。

判别器 D 的输入是 x,其需要学习的参数是 $\theta^{(D)}$. 生成器 G 的输入是 z, 其需要学习的参数是 $\theta^{(G)}$.

两个玩家都有各自的损失函数。 $J^{(D)}(\theta^{(D)}, \theta^{(G)})$, 但是 $J^{(D)}$ 并不影响参数 $\theta^{(G)}$. 同样的道理,反过来也是 $J^{(G)}(\theta^{(G)}, \theta^{(D)})$.

每个玩家的损失函数依赖于另一个玩家的参数,但是确不能控制它的参数。所以这是一种 Nash equilibrium 问题。找到这样一个局部最优解 $tuple(\theta^{(G)}, \theta^{(D)})$ 使得 $J^{(D)}$ 关于 $\theta^{(D)}$ 局部最小,$J^{(G)}$ 关于 $\theta^{(G)}$ 局部最小。

Generator

differentiable function G, 可微分函数 G. 实际上就是 神经网络。z 来自简单的先验分布,G(z) 通过模型 $p_{model}$ 生成样本 x. 实践中,对于 G 的输入不一定只在第一层 layer, 也可以在 第二层 等等。总之,生成器的设计很灵活。

Training process

两个 minibatch 的输入: x 来自 training dataset. z 来自先验隐藏变量构成的模型 $p_\text{model}$。通过优化算法 SGD/Adam 对两个损失 $J^{(D)} J^{(G)}$ 通过进行优化。梯度下降一般是同步的,也有人认为两者的迭代步数可以不一样。在这篇 tutorial 的时候,得到的共识是同步的。

cost function

目前大多数 GAN 的损失函数,$J(D)$ 都是一样的。区别在于 $J(G)$.

The discriminator’s cost, J (D)

这是个标准的用于二分类的交叉熵损失函数。只不过这里,正分类都来自于训练集,正分类的概率是 $\dfrac{1}{2}E_{x~d_{data}}$, 负分类来自于生成器,则其概率是 $\dfrac{1}{2}E_z$

通过训练判别器,我们可以得到这样一个比例:

$$\dfrac{p_{data}(x)}{p_{\text{model}}(x)}$$

GANs 通过监督学习来获得这个 ratio 的估计,这也是 GANs 不同于 变分自编码 和 波尔兹曼机 (variational autoencoders and Boltzmann machines) 的区别。

但是 GANs 通过监督学习来估计这个 ratio,会向监督学习一样遇到同样的问题:过拟合和欠拟合。但是通过足够的数据和完美的优化可以解决这个问题。

Minimax, zero-sum game

设计 cost function for generator.

前面我们知道,两个玩家 player 或者说 神经网络 G,D 实际上是一种博弈,D 希望能找出 G(z) 是 fake,而 G 希望能让 G(z) 尽可能像 real. 所以最简单的一种方式就是 all player’s cost is always zero.

$$J^{(G)} = -J^{(D)}$$

这样 $J^{(G)}, J^{(D)}$ 都可以用 value function 表示:

$$V(\theta^{(D)}, \theta^{(G)})=-J^{(D)}(\theta^{(D)}, \theta^{(G)})$$

那么整个 game 也就是一个 minmax 游戏:

outer loop 是关于 $\theta^{(G)}$ 的最小化,inner loop 是关于 $\theta^{(D)}$ 的最大化。

但是这种 function 在实际中并不能使用,因为其非凸性。

In practice, the players are represented with deep neural nets and updates are made in parameter space, so these results, which depend on convexity, do not apply

Heuristic, non-saturating game

Minimizing the cross-entropy between a target class and a classifier’s predicted distribution is highly effective because the cost never saturates when the classifier has the wrong output.

对一个分类器,最小化 目标类和预测概率的交叉熵 是一个非常有效的方法,因为当 分类器 存在误分类时,损失函数就永远不可能饱和。

所以,对于生成器的 cost 依旧使用交叉熵,但如果使用和 判别器一模一样的 cost(这里应该就是把正负分类反过来?):

$$J^{(G)}(\theta^{(D)}, \theta^{(G)})=-\dfrac{1}{2}E_zlogD(G(z))-\dfrac{1}{2}E_{x~p_{data}}log(1-D(x))$$

猜想应该是这样,文中没有给出。

不幸的是这样的在是实际中,也并不可行。当 判别器 拒绝一个高置信度(high confidence) 的样本时,生成器会出现梯度消失。

所以,改进之后就是:

$$J^{(G)}(\theta^{(D)}, \theta^{(G)})=-\dfrac{1}{2}E_zlogD(G(z))$$

In the minimax game, the generator minimizes the log-probability of the discriminator being correct. In this game, the generator maximizes the logprobability of the discriminator being mistaken.

在 Minmax,zero-game 中,生成器的目的是最小化 判别器 自认为自己判别对了的 log-probability, 而在 non-saturating game 中,生成器是最大化 判别器判别错误 的 log-probability.

Maximum likelihood game

前面提到极大似然估计是最小化模型与数据之间的 KL 散度。 GANs 使用极大似然估计则是对比不同的模型。

$$J^{(G)}=-\dfrac{1}{2}E_zexp(\sigma^{-1}(D(G(z))))$$

in practice, both stochastic gradient descent on the KL divergence and the GAN training procedure will have some variance around the true expected gradient due to the use of sampling (of x for maximum likelihood and z for GANs) to construct the estimated gradient.

在实践中,由于使用采样(x表示最大似然,z表示GAN)来构建估计的梯度,因此KL散度和GAN训练过程的随机梯度下降都会在真实预期梯度附近产生一些变化。

Is the choice of divergence a distinguishing feature of GANs?

Jensen-Shannon divergence, reverse KL

许多人认为 GANs 能够生成更加清晰、逼真的样本是因为他们最小化的是 Jensen-Shannon divergence. 而 VAEs 生成模糊的样本是因为他们最小化的是 KL divergence between the data and the model.

KL 散度并不是对称的。$D_{KL}(p_{data}||q_{model})$ 与 $D_{KL}(p_{model}||q_{data})$ 是不一样的。极大似然估计是前者,最小化 Jensen-Shannon divergence 则更像后者。

比较 $D_{KL}(p_{data}||q_{model})$ 与 $D_{KL}(p_{model}||q_{data})$ 区别。在模型能力不足以拟合数据的分布时,表现的尤为明显,如上图。给定的数据是两个高斯分布混合的分布。而模型是一个高斯模型。然后分别用极大似然 Maximum likehood 、reverse KL 散度作为 criterion,也就是 cost.

可以看到前者选择去平均两个模态,并希望在两个模态上都能得到较高的概率。而后者只选择其中一个模态,也有可能是另外一个模态,两个模态对于 reverse KL 都含有局部最优解。

所以,从这个视角来看, Maximum likehood 倾向于给 data 出现的位置更高的概率,而 reverse KL 则倾向于给没有出现 data 的位置较低的概率。所以 $D_{KL}(p_{model}||q_{data})$ 可以生成更棒的样本,因为模型不会生成不常见的样本,因为数据之间具有欺骗性的模态。

然而,也有一些新的研究表明,Jensen-Shannon divergence 并不是 GANs 能生成更清晰样本的原因。

f-GAN 证明,KL 散度也能生成清晰的sample,并且也只选择少量的modes, 说明 Jensen-Shannon divergence 并不是 GANs 不同于其他模型的特征。

GANs 通常选择少量的 mode 来生成样本,这个少量指的是小于模型的能力。 而 reverse KL 则是选择更可能多的 mode of the data distribution 在模型能力范围内。它通常不会选择更少的 mode. 这也解释了 mode collapse 并不是散度选择的原因。

Altogether, this suggests that GANs choose to generate a small number of modes due to a defect in the training procedure, rather than due to the divergence they aim to minimize.

所以,GANs 选择少量的 mode 是因为训练过程中的其他缺陷,而不是 散度 选择的问题。

Comparison of cost functions

生成对抗网络可以看做一种 reinforcement learning. 但是$j^{(G)}$ 并没有直接参考 training data,所有关于 training data 的信息都来自于 判别器 的学习。

所以和传统的强化学习是有区别的:

比较不同的 cost function:

$D(G(z))$ 表示 判别器 给 generate sample 为真的概率。

在左侧,Minimax 和 Maximum likehood 都趋向于饱和。也就是说,当一个样本很明显为 fake 时,cost 接近于 0.

似然估计还有个问题,cost 主要来源于 特别像真 的少部分样本,这也是不好的。需要用到 variance reduction techniques.

Maximum likelihood also suffers from the problem that nearly all of the gradient comes from the right end of the curve, meaning that a very small number of samples dominate the gradient computation for each minibatch. This suggests that variance reduction techniques could be an important research area for improving the performance of GANs, especially GANs based on maximum likelihood.

The DCGAN architecture

DCGAN 的结构。

GAN,NCE, MLE 的对比

相同点:

  • MiniMax GAN 和 NCE 的 cost function 相同

不同点:

  • 更新策略不一样,GAN 和 MLE 都是梯度下降,而 MLE copies the density model learned inside the discriminator and converts it into a sampler to be used as the generator. NCE never updates the generator; it is just a fixed source of noise.

Tips and Tricks

How to train a GAN: https://github.com/soumith/ganhacks

Research Frontiers

Non-convergence

mode collapse