文本生成任务

主要讨论

  • 文本生成的方法:inference

  • 增加文本生成的多样性:variational auto encoder

  • 可以控制的文本生成、文本风格迁移

  • Generative Adversarial Networks

  • Data to text

log loss:

  • [s1, s2, …, s_n] –> softmax(s) = exp(s_i) / sum_i exp(s_i)

  • p_i log q_i

关于文本生成

之前的课程中,我们主要讨论了Natural Language Understanding,也就是给你一段文字,如何从各个方面去理解它。常见的NLU任务有:文本分类,情感分类,命名实体识别(Named Entity Recognition, NER),Relation Extraction等等。也就是说,从文字中提取出我们想要了解的关键信息。

这节课我们来讨论文本生成的一些方法。

对于文本生成,我们关心哪些问题?

  • 与文本理解相反,我们有一些想要表达的信息,这些信息可能来自于对话的历史,可能来自于结构化的数据 (structured data, data-to-text generation)。现在我们要考虑的是如何把这些我们想要表达的信息转换成自然语言的方式。这一任务在构建聊天机器人中显得尤为重要。目前看来,基于模板 (template) 的方法仍然是最保险的,但是在研究领域中,人们越来越关注基于神经网络的文本生成方法

  • 基于上文的文本补全任务,故事生成,生成式聊天机器人

  • 人们一直希望计算机可以完成一些人类才可以完成的创造性任务,例如作画。AI作画实际上已经不是什么新闻了,Portrait of Edmond de Belamy,一幅AI创作的画像,拍卖出了43.2万美金的高价。

  • 那么AI能不能写文章讲故事呢?关于文本生成的研究相对来说没有特别客观的评价指标,所以很多时候人们会按照自己的主观评价来判断模型的好坏。例如给定故事的上文,AI系统能不能很好地补全这个故事呢?

  • 文本补全这个任务本质上就是训练一个语言模型,当然也有人尝试使用Seq2Seq的方法做文本生成。目前看来最强的模型是基于GPT-2预训练的语言模型。很多研究者使用GPT-2来进行文本生成相关的实验。由于训练GPT-2这样规模的语言模型需要大量的算力和数据资源,所以大部分的研究都关注在如何使用模型,也就是inference的步骤,而不在于模型的训练环节。

Greedy Decoding

autoregressive: 基于之前生成的文字来生成后续的文字?

P(y_i | y_1, … y_{i-1})

parallel generation

大部分基于神经网络的文本生成模型采用的是一种条件语言模型的方法,也就是说,我们有一些先决条件,例如 auto encoder 中的隐向量,然后我们基于这个隐向量来生成句子。

大部分语言模型的基本假设是从左往右的条件概率模型,也就是说,给定了单词1至n-1,我们希望生成第n个单词。假设我们现在采用一个基于LSTM的语言模型,在当前第i个位置上,我们预测下一个生成单词的概率分布为 p = (p_1, p_2, … p_|V|),那么在当前位置上我们应该生成什么单词呢?

argmax_i p_i = 2

一个最简单的方法是使用Greedy Decoding,也就是说,我们直接采用 argmax_i (p_i) 即可。当然,同学们很容易联想到,这种decoding的方法是有问题的,因为每次都选择最大概率的单词并不能保证我们生成出来的句子的总体概率分布是最大的。事实上,大部分时候这样生成的句子其实是不好的。然而我们没有办法遍历所有可能的句子:首先句子的长度是不确定的;即使我们假定自己知道句子的长度 l,如果在每个位置上考虑每个可能的单词,我们需要考虑 |V|^l 种可能的情况,在计算资源上也是不现实的。

一种妥协的方法是采用 Beam Searchhttps://shimo.im/docs/rHwdq8wd8txyXjP6)。也就是说,在decoding的每个步骤,我们都保留着 top K 个可能的候选单词,然后到了下一个步骤的时候,我们对这 K 个单词都做下一步 decoding,分别选出 top K,然后对这 K^2 个候选句子再挑选出 top K 个句子。以此类推一直到 decoding 结束为止。当然 Beam Search 本质上也是一个 greedy decoding 的方法,所以我们无法保证自己一定可以得到最好的 decoding 结果。

p(x_1, x_2, …, x_n) = log (p(x_1) * p(x_2 | x_1) … p(x_n | x_1, …, x_{n-1})) / n

Greedy Decoding的问题

  • 容易出现很无聊的回答:I don’t know.

  • 容易重复自己:I don’t know. I don’t know. I don’t know. I don’t know. I don’t know. I don’t know.

  • Beam search K = 200

Sampling

argmax 不一定是最好的

vocab(y_i) = [0.9, 0.05, 0.01, 0.01, 0.01, …., 0.01] softmax(logits/temperature)

sample(vocab(y_i))

sample很多个句子,然后用另一个模型来打分,找出最佳generated text

sampling over the full vocabulary:我们可以在生成文本的时候引入一些随机性。例如现在语言模型告诉我们下一个单词在整个单词表上的概率分布是 p = (p_1, p_2, … p_|V|),那么我们就可以按照这个概率分布进行随机采样,然后决定下一个单词生成什么。采样相对于greedy方法的好处是,我们生成的文字开始有了一些随机性,不会总是生成很机械的回复了。

1 - 0.98^n

Sampling的问题

  • 生成的话容易不连贯,上下文比较矛盾。

  • 容易生成奇怪的话,出现罕见词

top-k sampling 可以缓解生成罕见单词的问题。比如说,我们可以每次只在概率最高的50个单词中按照概率分布做采样。

我只保留top-k个probability的单词,然后在这些单词中根据概率做sampling

Neucleus Sampling

The Curious Case of Neural Text Degeneration

https://arxiv.org/pdf/1904.09751.pdf

img

这篇文章在前些日子引起了不小的关注。文章提出了一种做sampling的方法,叫做 Neucleus Sampling。

Neucleus Sampling的基本思想是,我们不做beam search,而是做top p sampling。

设置一个threshold,p=0.95

top-k sampling 和 neucleus sampling 的代码:https://gist.github.com/thomwolf/1a5a29f6962089e871b94cbd09daf317

Variational Auto Encoder (VAE)

Auto Encoder 自编码器

NLP中的一个重要问题是获得一种语言的表示,无论是单词的表示还是句子的表示。为了获得句子的表示,一种直观的思路是训练一个auto encoder,也就是说一个encoder用来编码一个句子,把一个句子转换成一个vector;另一个decoder用来解码一个句子,也就是说把一个vector解码成一个句子。auto encoder 事实上是一种数据压缩的方法。

Encoder(text) –> vector

Decoder(vector) –> text

Encoder:得到很好的文本表示,这个文本表示你可用用于任何其他的任务。

Decoder: conditional language model

generalize能力不一定好。过拟合。

预期:希望类似的句子,能够变成比较相近的vector。不类似的句子,能够距离比较远。

Decoder(0,200,-23, 122) –> text?

我爱[MASK]然语[MASK]处理 –> vector –> 我爱自然语言处理

在 auto encoder 的基础上又衍生出了各种类型的 auto encoder,例如 denoising auto encoder (https://www.cs.toronto.edu/~larocheh/publications/icml-2008-denoising-autoencoders.pdf)。denoising auto encoder 的基本思想是要加强 auto encoder 的 robustness。也就是说,我们希望把输入句子的一部分给“污染” (corrupt) 了,但是我们希望在经过编码和解码的过程之后,我们能够得到原来的正确的句子。事实上 BERT 的 masking 就是一种“污染”的手段。

Encoder(corrupt(text)) –> vector

Decoder(vector) –> text

随机产生一个vector –> decoder –> 生成一个句子

mapping

N(0, 1) –> 各种各样的文字

从一个分布去生成一些东西

为了训练出可以用来sample文字的模型,人们发明了variational auto encoder (VAE)。VAE与普通auto encoder的不同之处在于,我们添加了一个constraint,希望encoder编码的每个句子都能够局限在某些特定的位置。例如,我们可以要求每个句子的encoding在空间上满足一个多维标准高斯分布。

vector ~ N(0, 1)

什么是VAE?

网上有很多VAE的论文,博客,建议感兴趣的同学可以选择性阅读。我们这节课不会讨论太多的数学公式,而是从比较high level的层面介绍一下VAE模型以及它所解决的一些问题。

简单来说,VAE本质上是一种生成模型,我们希望能够通过隐向量z生成数据样本x。在文本生成的问题中,这个x往往表示的是一些文本/句子等内容。

img

下面是 Kingma 在 VAE 论文中定义的优化目标。

文本–> 向量表示 –> 文本

auto encoder: sentence –> vector –> sentence

Loss = -log P_{sentence}(dec(enc(sentence)))

img

z -> z’ -> decoder(z) –> 一个句子

crossentropyloss(decoder(encoder(x)), x)

我们对z没有任何的约束条件

q: encoder

p: decoder

KL divergence: 计算两个概率分布的差值

z: 把句子变成一个概率分布

z: (\mu, \sigma) –> 正态分布的参数

用z做采样

KL Divergence的定义

img

sampling

N(0,1): sampling: 0.1, 0.05, 0.2, -0.1, -100

我们可以发现,VAE模型本质上就是要最大化样本的生成概率,并且最小化样本encode之后的参数表示与某种分布(正态分布)的KL散度。之所以我们会限制数据被编码后的向量服从某个局部的正态分布,是因为我们不希望这些数据被编码之后杂乱地散布在一个空间上,而是希望信息能够得到一定程度上的压缩。之所以让他们服从一个分布而不是一些固定的值,是因为我们希望模型中能够有一些随机性,好让模型的解码器能够生成各种各样的句子。

有了这个VAE模型的架构之后,人们就可以在各种任务上玩出各种不同的花样了。

例如对于图像来说,这里的imgimg可能是CNN模型,对于自然语言来说,它们可能是一些RNN/LSTM之类的模型。

下面我们来看一些VAE在NLP领域的具体模型。

Generating Sentences from a Continuous Space

https://arxiv.org/pdf/1511.06349.pdf

img

img

从上图可以看到,这篇论文的思路非常简单,就是把一个句子用RNN编码起来,编码之后得到的隐向量输出两个信息\mu和\simga,分别表示一个正太分布的平均值和标准差。然后这个分布应该尽可能地接近标准正态分布,在KL散度的表示下。并且如果我们用这个分布去采样得到新的向量表示,那么decoder应该要尽可能好地复原我们原来的这个句子。

具体的实验细节我们就不展开了,但是我们看一些论文中展示的生成的句子。

img

下面看看VAE当中编码的空间是否具有某种连续性。

img

代码阅读:

  • https://github.com/timbmg/Sentence-VAE/blob/master/model.py

  • 练习:这份代码已经一年多没有更新了,感兴趣的同学可以把它更新到最新版本的PyTorch上,作为写代码练习,并且在自己的数据集上做一些实验,看看能否得到与论文中类似的效果(sentence interpolation)。

GAN: generative adversarial networks

  • generator: G(z) –> x 一张逼真的汽车照片

  • discriminator: D(x) –> 这个到底是不是一张汽车的照片 二分类

Discriminator的目标

D(G(z)) –> False

D(true photo) –> True

Generator 的目标 D(G(z)) –> True

可控制的文本生成

Toward Controlled Generation of Text

https://arxiv.org/pdf/1703.00955.pdf

  • Controlled Text Generation: 控制生成文本的一些特征

  • Learning disentangled latent representations: 对于文本不同的特征有不同的向量表示

模型

img

To model and control the attributes of interest in an interpretable way, we augment the unstructured variables z with a set of structured variables c each of which targets a salient and independent semantic feature of sentences.

这篇文章试图解决这样一个问题,能不能把一句话编码成几个向量(z和c)。z和c分别包含了一些不同的关于句子的信息。

img

模型包含几个部分,一个generator可以基于若干个向量(z和c)生成句子,几个encoder可以从句子生成z和c的分布,几个discriminator用来判断模型编码出的向量(c)是否符合example的正确分类。这个模型的好处是,我们在某种程度上分离了句子的信息。例如如果向量c用来表示的是句子的情感正负,那么模型就具备了生成正面情感的句子和负面情感句子的能力。

img

参考代码

https://github.com/wiseodd/controlled-text-generation

更多阅读

VAE论文:Auto-Encoding Variational Bayes https://arxiv.org/pdf/1312.6114.pdf

An Introduction to Variational Autoencoders https://arxiv.org/pdf/1906.02691.pdf

Stype Transfer

文本 –> 内容z,风格c

z, 换一个风格c’ –> 同样内容,不同风格的文本

文本生成的应用:文本风格迁移

Style Transfer from Non-Parallel Text by Cross-Alignment

论文:https://papers.nips.cc/paper/7259-style-transfer-from-non-parallel-text-by-cross-alignment.pdf

代码:https://github.com/shentianxiao/language-style-transfer/blob/master/code/style_transfer.py

style transfer 其实也是controlled text generation的一种,只是它control的是文本的风格。文本风格有很多种,例如情感的正负面,文章是随意的还是严肃的。

img

img

一个很好的repo,总结了文本风格迁移领域的paper

https://github.com/fuzhenxin/Style-Transfer-in-Text

Generative Adversarial Networks (GAN) 在NLP上的应用

最早Ian Goodfellow的关于GAN的文章,其基本做法就是一个generator和一个discriminator(辅助角色),然后让两个模型互相竞争对抗,在对抗的过程中逐渐提升各自的模型能力。而其中的generator就是我们希望能够最终optimize并且被拿来使用的模型。

早期GAN主要成功应用都在于图像领域。其关键原因在于,图像的每个像素都是三个连续的RGB数值。discriminator如果给图像计算一个概率分数,当我们在优化generator希望提高这个分数的时候,我们可以使用Back Propagation算法计算梯度,然后做梯度上升/下降来完成我们想要优化的目标。

discriminator: 二分类问题 图片–>分类

D(G(z)) –> cross entropyloss –> backprop 到generator

文本–>

LSTM –> P_vocab() –> argmax 文字 –> discriminator

LSTM –> P_vocab() –> discriminator

而文本生成是一个不同的问题,其特殊之处在于我们在做文本生成的时候有一步argmax的操作,也就是说当我们做inference生成文字的时候,在输出层使用了argmax或者sampling的操作。当我们把argmax或者sampling得到的文字传给discriminator打分的时候,我们无法用这个分数做back propagation对生成器做优化操作。

真正的sample –> one hot vector ([1, 0, 0, 0, 0, 0])

预测一个输出单词的时候:([0.8, 0.1, 0, 0.05, 0, 0.05]) –> gumbel_softmax –> discriminator判断一下

为了解决这个问题,人们大致走了两条路线,一条是将普通的argmax转变成可导的Gumbel-softmax,然后我们就可以同时优化generator和discriminator了。

预测一个输出单词的时候:([0.8, 0.1, 0, 0.05, 0, 0.05]) –> gumbel_softmax –> discriminator判断一下

https://arxiv.org/pdf/1611.04051.pdf

https://www.zhihu.com/question/62631725

另外一种方法是使用Reinforcement Learning中的Policy Gradient来估算模型的gradient,并做优化。

根据当前的policy来sample steps。

NLP: policy就是我们的语言模型,也就是说根据当前的hidden state, 决定我下一步要生成什么单词。

P_vocab –> argmax

P_vocab –> sampling

backpropagation –> 没有办法更新模型

文本翻译 – 优化BLEU?

训练? cross entropy loss

policy gradient直接优化BLEU

可以不可以找个方法估算gradient。

Policy: 当前执行的策略,在文本生成模型中,这个Policy一般就是指我们的decoder(LSTM)

Policy Gradient: 根据当前的policy执行任务,然后得到reward,并估算每个参数的gradient, SGD

这里就涉及到一些Reinforcement Learning当中的基本知识。我们可以认为一个语言模型,例如LSTM,是在做一连串连续的决策。每一个decoding的步骤,每个hidden state对应一个状态state,每个输出对应一个observation。如果我们每次输出一个文字的时候使用sampling的方法,Reinforcement Learning有一套成熟的算法可以帮助我们估算模型的梯度,这种算法叫做policy gradient。如果采用这种方法,我们也可以对模型进行优化。

https://arxiv.org/pdf/1609.05473.pdf

这一套policy gradient的做法在很多文本生成(例如翻译,image captioning)的优化问题上也经常见到。

翻译:优化BLEU

Improved Image Captioning via Policy Gradient optimization of SPIDEr

http://openaccess.thecvf.com/content_ICCV_2017/papers/Liu_Improved_Image_Captioning_ICCV_2017_paper.pdf

还有一些方法是,我们不做最终的文本采样,我们直接使用模型输出的在单词表上的输出分布,或者是使用LSTM中的一些hidden vector来传给discriminator,并直接优化语言模型。

我个人的看法是GAN在文本生成上的作用大小还不明确,一部分原因在于我们没有一种很好的机制去评估文本生成的好坏。我们看到很多论文其实对模型的好坏没有明确的评价,很多时候是随机产生几个句子,然后由作者来评价一下生成句子的好坏。

Data-to-text

img

  • Content selection: 选择什么数据需要进入到我们的文本之中

  • Sentence planning: 决定句子的结构

  • Surface realization: 把句子结构转化成具体的字符串

img

问题定义

  • 输入: A table of records。每个record包含四个features: type, entity, value, home or away

  • 输出: 一段文字描述

相关资料

https://github.com/Morde-kaiser/LearningNotes/blob/master/GAN-Overview-Chinese.pdf

William Wang关于GAN in NLP的slides: http://sameersingh.org/files/ppts/naacl19-advnlp-part1-william-slides.pdf

这篇博文也讲的很好

https://zhuanlan.zhihu.com/p/29168803

参考该知乎专栏文章 https://zhuanlan.zhihu.com/p/36880287

文章目录
  1. 1. 关于文本生成
    1. 1.1. Greedy Decoding
    2. 1.2. Sampling
    3. 1.3. Neucleus Sampling
      1. 1.3.1. The Curious Case of Neural Text Degeneration
  2. 2. Variational Auto Encoder (VAE)
    1. 2.1. Auto Encoder 自编码器
    2. 2.2. 什么是VAE?
      1. 2.2.1. Generating Sentences from a Continuous Space
    3. 2.3. 可控制的文本生成
      1. 2.3.1. Toward Controlled Generation of Text
  3. 3. 文本生成的应用:文本风格迁移
    1. 3.0.1. Style Transfer from Non-Parallel Text by Cross-Alignment
  • 4. Generative Adversarial Networks (GAN) 在NLP上的应用
  • 5. Data-to-text
    1. 5.1. 相关资料
  • |