一、Example(案例)
前提:假设RNN已经训练好了。
输入文本,把文本分割成字符,用one-hot encoding来表示字符,每个字符表示为one-hot 向量,把one-hot向量一次输入RNN,RNN的状态向量h会积累看到的信息,RNN返回最后一个状态向量h,在RNN层上面是一个Softmax分类器,把h与参数矩阵W相乘得到一个向量,经过Softmax函数的变换,最终输入为一个向量,每个元素在(0,1)之间,元素全部相加为1。
Softmax的输出为一个概率分布:
Input text: “the cat sat on the ma”
Question: what is the next char?
RNN outputs a distribution over the chars.(Softmax的输出为一个概率分布)
Sample a char from it; we may get ‘t’.(假设我们得到字符t)
Take "the cat sat on the mat"as input.(把t接入到输入的文本末尾,然后把这句话作为输入,计算下一个字符的概率分布,从而生成下一个字符)
Maybe the next char is period “.” .(下一次可能抽到的是一个句号)
再下次可能抽到一个空格,不停重复下去,可能生成一段话,一篇文章,甚至是一本书
二、Train an RNN for Text Prediction
How do we train such an RNN?(怎么样训练一个RNN)
训练数据为文本,比如英文维基百科的所有文章
Cut text to segments (with overlap) 把文章划分为很多片段,这些片段可以有重叠
E.g: seg len_40 and stride=3. (设置片段的长度为40,红色的片段有40个字符;步长为3表示下一个片段会向右平移三个字符的长度)
红色片段作为输入的文本,输入神经网络,神经网络做出的预测是这个蓝色的字符a
蓝色的字符a作为标签
A segment is used as input text.(红色的片段用于神经网络的输入)
Its next char is used as label.(蓝色的字符会用作标签)
Training data: (segment , next _char ) pairs.(假如文章有3000个字符,文章会切成大约1000个pairs)
It is a multi-class classification problem.(它是一个多分类问题)
#class = #unique chars.(假如共有50个不同的字符,类别的数量是50,输入一个片段,输出50个概率值)
训练神经网络的目的:给定输入的片段,神经网络可以预测下一个字符。
If the RNN is trained on Shakespeare’s books, then the generated text is Shakespeare’s style.
三、Training a Text Generator(训练文本生成器)—模型训练
3.1 Prepare Training Data(准备训练数据)
print("Text length:",len(text)) # Text length: 600893 text[0:1000] # 文本的前1000个字符
3.2 Character to Vector(字符变为向量)
准备好文本,要处理文本,把一个字符变成一个向量,于是一个片段变成一个矩阵。
第一步,建立一个字典,把一个字符映射到一个正整数。用字典把字符变成正整数。
第二步,有了字典,做one-hot encoding。变成数值向量。
问题:前几次,得到one-hot向量之后,要进行word Embedding,用一个低维词向量来表示一个词,这次不需要Embedding层。
原因:前几次,把一句话分成多个单词,英语里面有10000个常用词,把vocabulary设置成10000,那么one-hot encoding得到的one-hot 向量都是10000维的,维度太高,所以要用word Embedding把高维的one-hot 向量变成低维词向量,而这里我们把一句话切割成很多字符,文本里面通常也就几十个或100个常用字符(比如字母,数字,标点等),所以字典里面的vocabulary顶多100个,做one-hot encoding得到的one-hot 向量顶多100维,维度足够低,因此不需要进一步做Embedding。
Vocabulary is V = 57 (including letter, blank, punctuation, etc.) (字典里共有V=57个不同的字符,包括26个小写字母,空格,标点符号等)
Segment length is l = 60. (A segment has 60 chars.) (设置每个片段的长度l=60,每个片段里面有60个字符)
于是每个长度为60的片段就变成了60×57的矩阵,每个字符用57维的one-hot向量表示
便签是这个片段的下一个字符,这个字符编码成了57维的one-hot向量
Number of segments is n = 200,278. (Number of training samples.)
3.3 Build a Neural Network(设计一个神经网络)
from keras import layers # 开始搭建网络 model = keras.models.Sequential() # 建立Sequential()模型 # LSTM层状态向量h的维度设为128,输入是60×57的矩阵,seg_len=60,vocabulary=57,每个片段编码成60×57的矩阵 # 这里面只能用单向LSTM,不能用双向LSTM,文本生成需要预测下一个字符,必须从前往后 model.add(layers.LSTM(128,input_shape=(seg_len,vocabulary))) # 上面加载一个全连接层,加一个激活函数softmax,输出是v=57的向量,向量的每个元素是字符的概率值 # 字典里面有57个不同的字符,输出的向量是57维的 model.add(layers.Dense(vocabulary,activation="softmax")) model.summary()
3.4 Train the Neural Network(训练神经网络)
编译模型 # 指定优化算法为 RMSprop,loss为损失函数, optimizer= keras.optimizers.RMSprop(lr=0.01) model.compile(loss="categorical_cossentropy",optimizer=optimizer) # 用训练数据来拟合模型,训练数据用x,y表示 model.fit(x,y,batch_size=128,epochs=1)
四、Text Generation(文本生成)
4.1 Predict the Next Char(预测下一个字符)
Question: Given the distribution, what will be the next char? (知道每个字符的概率值怎样生成下一个字符)
方法一:greedy selection.(哪个字符的概率大,选择哪个字符)
next_index = np.argmax(pred)
It is determipistic.(这种方法是确定性的,没有随机性)
Empirically not good.(从经验上讲不好。我们希望生成的文本尽量多元化)
方法二:sampling from the multinomial distrihution(多项式分布中随机抽取)
next_onehot = np.random.multinomial(1,pred,1) next_index = np.argmax(next_onehot)
Maybe too random.(这种抽样太随机,生成的文本会有很多拼写和语法错误)
方法三:adjusting the multinomial distribution.(调整概率)
pred = pred ** (1 / temperature) pred = pred / np.sum(pred) # 归一化,大的概率值变大,小的概率值变小
- Sample according to pred.
- Between greedy and multinomial (controlled temperature).
4.2 Text Generation: An Example
五、Summary(总结)
5.1 Train a Neural Network (训练神经网络)
Partition text to (segment, next_char) pairs. (把文本划分成片段)
One-hot encode the characters.(把字符编码成向量)
Character V x 1 vector. (每个字符用 V x 1的向量表示)
Segment LxV matrix. (每个片段用 LxV 的矩阵表示)
Build and train a neural network.
Lxv matrix ==> LSTM ==> Dense ==> vx1 vector.
5.2 Text Generation(文本生成)
Propose a seed segment.
Repeat the followings:
Feed the segment (with one-hot) to the neural network.
The neural network outputs probabilities.
next_char <——Sample from the probabilities.(根据概率值做抽样,得到下一个字符)
Append next char to the segment.(把新生成的字符接到片段的后面,作为神经网络新的输入,开始下一轮循环)