原文出处:Generative Networks 原作者:Microsoft · 许可证:MIT License 中文译本由诸葛AI学院整理,仅供学习参考,版权归原作者与微软所有。
课前小测
循环神经网络(Recurrent Neural Network,RNN)和它的门控单元变体,比如长短期记忆网络(LSTM)与门控循环单元(GRU),为语言建模提供了一套机制:它们能学习词的先后顺序,并对序列里的下一个词做出预测。有了这个能力,我们就可以用 RNN 来做生成式任务(generative task),比如普通的文本生成、机器翻译,甚至图像描述。
想一想:你在打字时受益于文本补全这类生成式任务多少次?去查一查你常用的应用,看看它们是不是用过 RNN。
生成式网络(generative network)这一讲就从这里出发。在上一单元讨论的 RNN 架构里,每个 RNN 单元把下一个隐状态(hidden state)作为输出。但我们还可以给每个循环单元再加一个输出,这样它就能输出一条序列,长度与原始序列相同。也可以采用另一种 RNN 单元:它在每一步都不接收输入,只从一个初始状态向量出发,产出一串输出。
这样就组合出下面几种不同的神经网络架构(原文此处有一张图,画的是四种常见的循环神经网络模式,配图来自 Andrej Karpathy 的博文《循环神经网络的不合理有效性》,作者主页在 karpathy.github.io):
- 一对一(one-to-one):传统神经网络,一个输入对应一个输出
- 一对多(one-to-many):生成式架构。接收一个输入值,生成一串输出值。比如要训练一个图像描述(image captioning)网络,给一张照片产出文字说明:照片作为输入,先经过 CNN 得到它的隐状态,再由一条循环链逐个词生成描述
- 多对一(many-to-one):对应上一单元介绍的 RNN 架构,例如文本分类
- 多对多(many-to-many),也叫序列到序列(sequence-to-sequence):对应机器翻译这类任务。前一条 RNN 把输入序列的全部信息收集进隐状态,后一条 RNN 链再把这个状态展开成输出序列
这一讲聚焦简单的生成式模型,用它来生成文本。为了简化,我们采用字符级分词。
下面这样一步一步训练 RNN 生成文本。每一步取一段长度为 nchars 的字符序列,让网络为每个输入字符生成下一个输出字符(原文此处有一张图,演示 RNN 逐字母生成单词 "HELLO" 的过程):
生成文本时(也就是推理阶段),我们从一段提示(prompt)出发,把它送过 RNN 单元产生中间状态,再从该状态开始往下生成。每次生成一个字符,把当前状态和刚生成的字符交给下一个 RNN 单元,如此循环,直到生成足够多的字符。(原文此处有一张图,画的是这个逐字推理流程,作者自绘。)
练习:生成式网络
在下面的笔记本里继续学习:
软文本生成与温度
每个 RNN 单元的输出是一份字符概率分布。如果我们每次都取概率最高的字符作为下一个字符,文本经常在同样的几段字符序列之间来回"循环",就像这个例子:
today of the second the company and a second the company ...
但看看下一个字符的概率分布,会发现排在最前面的几个概率差距可能不大:一个字符概率 0.2,另一个 0.19,等等。比如在序列 "play" 里找下一个字符,接一个空格可以,接 e 也行(组成单词 player)。
由此得出的结论是:总选概率更高的那个字符并不总是"公平"的,因为选第二高的字符同样可能生成有意义的文本。更明智的做法是从网络输出的概率分布中采样(sample)字符。还可以引入一个参数——温度(temperature):想要更多随机性时,用它把概率分布压平;想更紧贴高概率字符时,用它把分布变得更陡峭。
上面链接的笔记本里有这种软文本生成的实现,可以细看。
小结
文本生成本身就有用处,但更大的价值在于:RNN 可以从一个初始特征向量出发生成文本。机器翻译就是这么用的(序列到序列架构里,编码器(encoder)给出的状态向量被用来生成、也就是解码(decode)出译文);为图像生成文字描述也是同理,只是那种情况下特征向量来自 CNN 提取器。
挑战
去 Microsoft Learn 上找对应课程练手:
- 用 PyTorch / TensorFlow 做文本生成
课后小测
复习与自学
几篇延伸阅读:
- 文本生成的不同路线:马尔可夫链、LSTM 与 GPT-2,博文
- Keras 官方文档里的字符级文本生成示例
课后作业
我们已经看到如何逐字符生成文本。实验作业里,你将探索词级文本生成。