中国工厂网站,东莞乐从网站建设,网站设计步骤的教学设计,网络管理培训课程RNNLM
基于RNN的语言模型称为RNNLM(Language Model)。 Embedding 层#xff1a;将单词ID转化为单词的分布式表示#xff08;单词向量#xff09;。
RNN层#xff1a;向下一层(上方)输出隐藏状态#xff0c;同时也向下一时刻的RNN层(右边)输出隐藏状态。
对于“you say …RNNLM
基于RNN的语言模型称为RNNLM(Language Model)。 Embedding 层将单词ID转化为单词的分布式表示单词向量。
RNN层向下一层(上方)输出隐藏状态同时也向下一时刻的RNN层(右边)输出隐藏状态。
对于“you say goodbye and i say hello.”如果模型学习顺利。
输入的数据是单词ID列表输入单词ID为0的youSoftmax层输出的概率分布P0中say的概率最高。这说明预测出了you后面出现的单词为say。
输入单词ID为1的saySoftmax层输出的概率分布P1中goodbye和hello的概率最高。RNN层记忆了you say这一上下文。RNN将you say这一过去的信息保存成隐藏状态向量。
RNNLM可以记忆目前为止输入的单词并以此为基础预测接下来会出现的单词。 如果整体处理时序数据神经网络就如下图所示。整体处理含有T个时序数据的层称为Time xx层。 Time Affine 层使用T个Affine层分别处理各个时刻的数据。代码使用矩阵运算实现整体处理。
class TimeAffine:def __init__(self, W, b):#接收权重参数和偏置参数self.params [W, b]#参数设置为列表类型的成员变量paramsself.grads [np.zeros_like(W), np.zeros_like(b)]self.x Nonedef forward(self, x):#x包含T个时序数据N, T, D x.shape#批大小是 N输入向量的维数是 Dx形状为(N,T,D)W, b self.paramsrx x.reshape(N*T, -1)out np.dot(rx, W) b#使用矩阵运算实现整体处理self.x xreturn out.reshape(N, T, -1)def backward(self, dout):x self.xN, T, D x.shapeW, b self.paramsdout dout.reshape(N*T, -1)rx x.reshape(N*T, -1)db np.sum(dout, axis0)dW np.dot(rx.T, dout)dx np.dot(dout, W.T)dx dx.reshape(*x.shape)self.grads[0][...] dWself.grads[1][...] dbreturn dxTime Softmax with Loss 层
x表示从下方的层传来的得分(正规化为概率之前的值)t表示正确解标签T个Softmax with Loss层各自算出损失相加并求平均得到的值作为最终的损失。 class TimeSoftmaxWithLoss:def __init__(self):self.params, self.grads [], []self.cache Noneself.ignore_label -1def forward(self, xs, ts):N, T, V xs.shapeif ts.ndim 3: # 在监督标签为one-hot向量的情况下ts ts.argmax(axis2)mask (ts ! self.ignore_label)# 按批次大小和时序大小进行整理reshapexs xs.reshape(N * T, V)ts ts.reshape(N * T)mask mask.reshape(N * T)ys softmax(xs)ls np.log(ys[np.arange(N * T), ts])ls * mask # 与ignore_label相应的数据将损失设为0loss -np.sum(ls)loss / mask.sum()self.cache (ts, ys, mask, (N, T, V))return lossdef backward(self, dout1):ts, ys, mask, (N, T, V) self.cachedx ysdx[np.arange(N * T), ts] - 1dx * doutdx / mask.sum()dx * mask[:, np.newaxis] # 与ignore_label相应的数据将梯度设为0dx dx.reshape((N, T, V))return dxRNNLM学习与评价
将RNNLM使用的网络实现为SimpleRnnlm类结构如下。 class SimpleRnnlm:def __init__(self, vocab_size, wordvec_size, hidden_size):V, D, H vocab_size, wordvec_size, hidden_sizern np.random.randn# 初始化权重对各个层使用的参数权重和偏置进行初始化embed_W (rn(V, D) / 100).astype(f)rnn_Wx (rn(D, H) / np.sqrt(D)).astype(f)rnn_Wh (rn(H, H) / np.sqrt(H)).astype(f)rnn_b np.zeros(H).astype(f)affine_W (rn(H, V) / np.sqrt(H)).astype(f)affine_b np.zeros(V).astype(f)使用 Truncated BPTT 进行学习将 Time RNN 层的 stateful设置为 TrueTime RNN 层就可以继承上一时刻的隐藏状态RNN 层和 Affine 层使用了Xavier 初始值# 生成层Time RNN 层就可以继承上一时刻的隐藏状态self.layers [TimeEmbedding(embed_W),TimeRNN(rnn_Wx, rnn_Wh, rnn_b, statefulTrue),TimeAffine(affine_W, affine_b)]self.loss_layer TimeSoftmaxWithLoss()self.rnn_layer self.layers[1]# 将所有的权重和梯度整理到列表中self.params, self.grads [], []for layer in self.layers:self.params layer.paramsself.grads layer.gradsdef forward(self, xs, ts):for layer in self.layers:xs layer.forward(xs)loss self.loss_layer.forward(xs, ts)return lossdef backward(self, dout1):dout self.loss_layer.backward(dout)for layer in reversed(self.layers):dout layer.backward(dout)return doutdef reset_state(self):self.rnn_layer.reset_state()
常使用困惑度perplexity评价语言模型。
困惑度是概率的倒数(数据量为1时)因为预测出的正确单词的概率越大越好所以困惑度越小越好。
困惑度可以解释为分叉度表示下一个可以选择的选项的数量(下一个可能出现单词的候选个数)。
输入数据为多个的情况困惑度计算
L是神经网络的损失数据量为N个tn是one-hot向量形式正确解标签tnk表示第n个数据的第k个值ynk是概率分布(神经网络Softmax的输出)。 RNNLM的学习和评价的代码如下。
# 设定超参数
batch_size 10
wordvec_size 100
hidden_size 100
time_size 5 # Truncated BPTT的时间跨度大小
lr 0.1
max_epoch 100# 读入训练数据缩小了数据集
corpus, word_to_id, id_to_word ptb.load_data(train)
corpus_size 1000
corpus corpus[:corpus_size]
vocab_size int(max(corpus) 1)xs corpus[:-1] # 输入
ts corpus[1:] # 输出监督标签
data_size len(xs)
print(corpus size: %d, vocabulary size: %d % (corpus_size, vocab_size))# 学习用的参数
max_iters data_size // (batch_size * time_size)
time_idx 0
total_loss 0
loss_count 0
ppl_list []# 生成模型
model SimpleRnnlm(vocab_size, wordvec_size, hidden_size)
optimizer SGD(lr)
使用 Truncated BPTT 进行学习因此数据需要按顺序输入.
mini-batch 的各批次要平移读入数据的开始位置。# 计算读入mini-batch的各笔样本数据的开始位置
jump (corpus_size - 1) // batch_size
offsets [i * jump for i in range(batch_size)]#offsets 的各个元素中存放了读入数据的开始位置for epoch in range(max_epoch):for iter in range(max_iters):# 获取mini-batch,按顺序读入数据batch_x np.empty((batch_size, time_size), dtypei)batch_t np.empty((batch_size, time_size), dtypei)for t in range(time_size):#for i, offset in enumerate(offsets):#各批次增加偏移量batch_x[i, t] xs[(offset time_idx) % data_size]#将time_idx 处的数据从语料库中取出,将当前位置除以语料库大小后的余数作为索引使用batch_t[i, t] ts[(offset time_idx) % data_size]#取余数为的是读入语料库的位置超过语料库大小时回到语料库的开头time_idx 1# 计算梯度更新参数loss model.forward(batch_x, batch_t)model.backward()optimizer.update(model.params, model.grads)total_loss lossloss_count 1# 各个epoch的困惑度评价ppl np.exp(total_loss / loss_count)#计算每个 epoch 的平均损失然后计算困惑度print(| epoch %d | perplexity %.2f% (epoch1, ppl))ppl_list.append(float(ppl))total_loss, loss_count 0, 0# 绘制图形
x np.arange(len(ppl_list))
plt.plot(x, ppl_list, labeltrain)
plt.xlabel(epochs)
plt.ylabel(perplexity)
plt.show()
结果如下。困惑度逐渐减小。
| epoch 78 | perplexity 16.30
| epoch 79 | perplexity 15.07
| epoch 80 | perplexity 14.23
| epoch 81 | perplexity 13.74
| epoch 82 | perplexity 13.12
| epoch 83 | perplexity 12.36
| epoch 84 | perplexity 11.58
| epoch 85 | perplexity 11.16
| epoch 86 | perplexity 10.23
| epoch 87 | perplexity 10.12
| epoch 88 | perplexity 9.08
| epoch 89 | perplexity 8.71
| epoch 90 | perplexity 8.29
| epoch 91 | perplexity 8.24
| epoch 92 | perplexity 7.79
| epoch 93 | perplexity 7.41
| epoch 94 | perplexity 6.99
| epoch 95 | perplexity 7.17
| epoch 96 | perplexity 6.36
| epoch 97 | perplexity 5.98
| epoch 98 | perplexity 5.78
| epoch 99 | perplexity 5.55
| epoch 100 | perplexity 5.48Process finished with exit code 0