赞
踩
这里我假定你已经了解了One-Hot编码和n-gram的相关知识,现在让我们学习第一个语言模型。我也是一个小白,正在艰难的入门NLP和pytorch,由于网上pytorch的nlp教程较少且pytorch版本都比较靠前,所以想的是在那个基础上稍微修改一下,水平有限,只作为自己的一个学习总结,如果对你有帮助就最好。
Neural Network Language Model直接从语言模型出发,将模型最优化过程转化成求词向量表示的过程。
目
标
函
数
:
L
(
θ
)
=
∑
t
log
P
(
w
t
∣
w
t
−
n
+
1
,
.
.
.
w
t
−
1
)
目标函数:L(\theta) = \sum_t\log P(w_t|w_{t-n+1},...w_{t-1})
目标函数:L(θ)=t∑logP(wt∣wt−n+1,...wt−1)
使用了非对称的前向窗函数,窗长度为n-1
滑动窗口遍历整个语料库求和,计算量正比于语料库大小
概率P满足归一化条件,这样不同位置t处的概率才能相加,即: ∑ ω ∈ { v o c a b u l a r y } P ( w t ∣ w t − n + 1 , . . . w t − 1 ) = 1 \sum_{\omega\in\{vocabulary\}}P(w_t|w_{t-n+1},...w_{t-1}) = 1 ∑ω∈{vocabulary}P(wt∣wt−n+1,...wt−1)=1
目标:窗口大小为n,通过前n-1个词来推测第n的词是什么
输入:每个词的one-hot向量
投影层:就是矩阵C,设定我们想要的词编码的长度为D、字典长度为V,则矩阵C为
D
×
V
D\times V
D×V
之所以称为投影层是因为当我们的输入与C相乘时会得到这个词对应位置的词嵌入: D × V D \times V D×V * V × 1 V \times 1 V×1 = D × 1 D \times 1 D×1
hidden layer:将我们得到的每个词的词嵌入先做一次full connection全连接,然后激活函数采用tanh处理
softmax层:隐层出来之后,接一个SoftMax分类器,预测一下在V个词的词表中,出现每个单词出现概率有多大,即得到一个概率向量 V × 1 V\times 1 V×1
这里的代码仔细一点,对应着上面的图就可以看懂啦~~~
import torch import torch.nn as nn import torch.optim as optim dtype = torch.FloatTensor sentences = [ "i like dog", "i love coffee", "i hate milk"] word_list = " ".join(sentences).split() word_list = list(set(word_list)) word_dict = {w: i for i, w in enumerate(word_list)} number_dict = {i: w for i, w in enumerate(word_list)} n_class = len(word_dict) # 字典长度,number of Vocabulary # NNLM Parameter n_step = 2 # 窗口大小,n-1 in paper n_hidden = 2 # h in paper m = 2 # 最终词向量的长度,m in paper def make_batch(sentences): # 其实就是将句子对应成各自的向量,然后input_batch为前面的词,target_batch为要预测的词 input_batch = [] target_batch = [] for sen in sentences: word = sen.split() input = [word_dict[n] for n in word[:-1]] target = word_dict[word[-1]] input_batch.append(input) target_batch.append(target) return input_batch, target_batch # Model class NNLM(nn.Module): def __init__(self): super(NNLM, self).__init__() self.C = nn.Embedding(n_class, m) #投影矩阵 self.H = nn.Parameter(torch.randn(n_step * m, n_hidden).type(dtype)) # 隐藏层的weight self.W = nn.Parameter(torch.randn(n_step * m, n_class).type(dtype)) # softmax层作用于词嵌入的weight self.d = nn.Parameter(torch.randn(n_hidden).type(dtype)) # 隐藏层的bias self.U = nn.Parameter(torch.randn(n_hidden, n_class).type(dtype)) # softmax层作用于hidden层的weight self.b = nn.Parameter(torch.randn(n_class).type(dtype)) # softmax层的bias def forward(self, X): X = self.C(X) # 这里巧妙的采用embedding,取出第X行刚好就是该词我们想要的词嵌入 X = X.view(-1, n_step * m) # [数据个数即要训练样本数量, 窗口大小*词嵌入维度=每个训练样本的总的维度] tanh = torch.tanh(self.d + torch.mm(X, self.H)) # 全连接层 [batch_size, n_hidden] output = self.b + torch.mm(X, self.W) + torch.mm(tanh, self.U) # softmax层[batch_size, n_class] return output model = NNLM() criterion = nn.CrossEntropyLoss() optimizer = optim.Adam(model.parameters(), lr=0.001) input_batch, target_batch = make_batch(sentences) print(input_batch) print(target_batch) input_batch = torch.LongTensor(input_batch) # embedded只能接受LongTensor target_batch = torch.LongTensor(target_batch) # Training for epoch in range(5000): optimizer.zero_grad() output = model(input_batch) loss = criterion(output, target_batch) if (epoch + 1)%1000 == 0: print('Epoch:', '%04d' % (epoch + 1), 'cost =', '{:.6f}'.format(loss)) loss.backward() optimizer.step() # Predict predict = model(input_batch).data.max(1, keepdim=True)[1] # .data只取出tensor中的数据,对于其他信息都丢弃 # Test print([sen.split()[:2] for sen in sentences], '->', [number_dict[n.item()] for n in predict.squeeze()])
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。