【王树森】RNN模型与NLP应用(6/9):Text Generation(个人向笔记)
前言
本节课是对RNN的应用,我们可以训练一个RNN来自动生成文本,生成的文本就和人写的一样。如果用莎士比亚的文学来训练RNN,就能训练出能生成莎士比亚风格的RNN
RNN for Text Prediction
1. 生成原理
对输入的text在字符级别进行One-Hot编码,在经过RNN处理后会输出一个状态向量
h
h
h ,
h
h
h 与一个参数矩阵
W
W
W 相乘然后丢进 Softmax 里面,输出一系列词在下一个出现的概率,它们全加起来等于 1 。
从上图可以得知:对于文本"the cat sat on the ma",它下一个字符为 “t” 的概率最大,固我们添加 “t” 到句子的末尾,然后将修改后的句子作为输入继续预测。这样不停重复下去,我们就能实现对一段文本的生成。
2. 如何训练RNN?(思路)
- 指定 seg_len 长度的字段,如下图的红色字体所示,而这段红色字体要预测的字符就是蓝色的那个
- 指定 stride 大小的移动步数,我们会将红色字体往右移动三个字符,然后将它的下一个字符作为要预测的蓝色字符。
- 假设我们有长度为3000个字符的文本的话,我们就能得到1000条这种 (segment, next_char) 训练数据,其中segment为输入文本,next_char为标签。
- 这是一个多分类问题,例如在这里我们有50个类别
- 我们用什么训练数据训练,就会生成什么类型风格的文本
3. Training a Text Generator(具体实现)
- Prepare training data
我们用以下文本进行训练:其中已经把所有字符转为小写字符,文本长度为600893
设置segment长度为60,stride为3把给定的文本作为训练数据。重复移动segment直到所有文本耗尽。文本长度为60w+,每次移动3个字符,所以大概会得到20+个片段。
- Character to Vector
与前几节课不同,我们这里对字符进行One-Hot编码而不是Embedding,这是因为字符数量总共最多也就100个,vocabulary很小,维度已经很低,不需要再映射成低维的向量了。而前几节课的情况不同,vocabulary有几万的水平,这种情况就需要Embedding了。
我们把文本转化成矩阵,其中矩阵的行数为文本的包含字符数量,而列数则为vocabulary的大小
而本次训练的vocabulary大小是
v
=
57
v=57
v=57,而文本长度
l
=
60
l=60
l=60,所以我们的segment就是一个
60
×
57
60×57
60×57 的矩阵,而 next_char 是一个
57
×
1
57×1
57×1 的向量。我们总共有
n
=
200278
n=200278
n=200278 个这样的矩阵和向量
-
Build a Neural Network.
注意这里只能用单向LSTM,因为文本预测本身就是一个单向的问题。- 我们这里用Sequential来搭建模型
- 用上面提到的参数搭建一个LSTM
- 然后用一个线性分类器,激活函数为Softmax
- 用summary查看网络信息
开始训练,由于是分类问题,损失函数用交叉熵。
Predict the Next Char
model为训练好的模型,我们输入segment长度的文本,然后模型的输出是一个57维的向量,每一个元素是一个字符的概率值
那么我们有了概率分布,应该如何选择下一个文本呢?
Option1: greedy selection
- 直接取概率最大的下一个字符
- 使用python的argmax来确定概率最大的字符的index:
next_index = np,argmax(pred)
- 这种方法是确定性的,给定一个初始文本,后续的文本都是确定的
Option2:sampling from the multinomial distribution
- 很多时候我们会希望模型更多样化一点,如果只是每次选最大,那么可生成的文本其实不多
- 我们采用多项式分布来进行抽取
next_onehot = np.random.multinomial distribution(1, pred, 1)
这种随机抽取的规则为:若下一个字符可能出现的概率为0.3,那么它就有0.3的概率被抽到next_index = np.argmax(next_onehot)
- 但是这种方法有点过于随机了,可能会导致很多拼写错误
Option3: adjusting the multinomial distribution
- 第三种方法兼顾了上面两者,既不失准确率,也有一定的随机性
pred = pred ** (1 / temperature)
pred = pred / np.sum(pred)
- 这种操作会使得概率大的变大,小的概率变小,当概率很大时,这种处理就会使得最大的概率很接近1
- 例:当temperature=0.5时,会发生如下的变化:
- 当减小temperature=0.2时,变化如下:可以看到变化更极端了
Text Generation: An Example
Generate Text Using the Trained LSTM
下面是训练了1个epoch的结果,可以发现生成的都是不好的文本
下面是训练了5个epoch的结果,此时大多数都是正常的单词
下面是训练了20个epoch的结果,此时基本已经收敛了,效果比之前好很多。不过依旧存在错词,此时可以考虑更换更大的模型
Summary
博主偷懒就直接截图了XD