pytorch入门NLP教程(一)——NNLM

NNLM

这里我假定你已经了解了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(θ)=tlogP(wtwtn+1,...wt1)

  • 使用了非对称的前向窗函数,窗长度为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(wtwtn+1,...wt1)=1

pytorch入门NLP教程(一)——NNLM_第1张图片
目标:窗口大小为n,通过前n-1个词来推测第n的词是什么

输入:每个词的one-hot向量

投影层:就是矩阵C,设定我们想要的词编码的长度为D、字典长度为V,则矩阵C为 D × V D\times V D×V
pytorch入门NLP教程(一)——NNLM_第2张图片

之所以称为投影层是因为当我们的输入与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()])

你可能感兴趣的:(深度学习,NLP)