【NNLM】:A Neural Probabilistic Language Model
该模型通过词的分布式表示,解决了维数灾难的问题。这种方法允许每一个训练语句给模型提供关于语义相邻句子的指数级别的信息。
该模型同时学习:
- 每个词的分布式表示
- 词序列的概率函数
语言模型与维数灾难
利用上述联合概率计算词语序列,会带来维数灾难的问题(参数过多,导致过拟合)
假设要建模一个有
- 模型
其中:
- 训练语料里面有些
元组没有出现过,其对应的条件概率就是 ,导致计算一整句话的概率为 。尤其在 取值较大时,这种数据稀疏导致的计算为 的现象变得特别严重; - 基于统计的语言模型无法把
取得很大,参数量随着 的增大而增大; - 该模型不考虑单词之间的相似性。
模型
输入:长度为
输出:下一个词为词表中各个词的条件概率
网络结构:主体是一个三层的前馈神经网络,包括输入层,隐藏层和输出层。(本质上也是一个
第一部分:
将一个单词映射到
第二部分:从
第三部分:从隐藏层到输出层的映射(通过矩阵
第四部分:从
得到
最后经过
代码实现
import torch
import torch.nn as nn
import torch.optim as optim
class NNLM(nn.Module):
def __init__(self, num_word, m, n_step, n_hidden):
super(NNLM, self).__init__()
self.num_word = num_word
self.m = m
self.n_step = n_step
self.n_hidden = n_hidden
self.C = nn.Embedding(num_embeddings=num_word, embedding_dim=m)
self.H = nn.Parameter(torch.randn(n_step * m, n_hidden).type(torch.FloatTensor))
self.d = nn.Parameter(torch.randn(n_hidden).type(torch.FloatTensor))
self.U = nn.Parameter(torch.randn(n_hidden, num_word).type(torch.FloatTensor))
self.W = nn.Parameter(torch.randn(n_step * m, num_word).type(torch.FloatTensor))
self.b = nn.Parameter(torch.randn(num_word).type(torch.FloatTensor))
def forward(self, input):
x = self.C(input)
x = x.view(-1, self.n_step * self.m)
hidden_out = torch.tanh(torch.mm(x, self.H) + self.d)
out = self.b + torch.mm(x, self.W) + torch.mm(hidden_out, self.U)
return out
def make_batch(sentences):
input_batch = []
target_batch = []
for sentence in sentences:
word = sentence.split()
input = [word_dict[w] for w in word[:-1]]
target = word_dict[word[-1]]
input_batch.append(input)
target_batch.append(target)
return input_batch, target_batch
if __name__ == '__main__':
# 句子
sentences = ["i like dog", "i love coffee", "i hate milk"]
# 预处理
word_list = " ".join(sentences).split(" ") # 获取所有的单词
print("未去重词表:", word_list)
word_list = list(set(word_list)) # 去重
print("去重词表:", word_list)
word_dict = {w: i for i, w in enumerate(word_list)} # 单词->索引
print("单词索引:", word_dict)
number_dict = {i: w for i, w in enumerate(word_list)} # 索引->单词
print("索引单词:", number_dict)
num_words = len(word_dict) # 单词总数
print("单词总数:", num_words)
input_batch, target_batch = make_batch(sentences)
input_batch = torch.LongTensor(input_batch)
target_batch = torch.LongTensor(target_batch)
print("input_batch:", input_batch)
print("target_batch:", target_batch)
# 训练
model = NNLM(num_words, 2, 2, 2)
criterion = nn.CrossEntropyLoss() # 使用cross entropy作为loss function
optimizer = optim.Adam(model.parameters(), lr=0.001) # 使用Adam作为optimizer
for epoch in range(2000):
# 梯度清零
optimizer.zero_grad()
# 计算predication
output = model(input_batch)
# 计算loss
loss = criterion(output, target_batch)
if (epoch + 1) % 100 == 0:
print("Epoch:{}".format(epoch + 1), "Loss:{:.3f}".format(loss))
# 反向传播
loss.backward()
# 更新权重参数
optimizer.step()
# 验证
pred = model(input_batch).data.max(1, keepdim=True)[1] # 找出概率最大的下标
print("Predict:", pred)
print([sentence.split()[:2] for sentence in sentences], "---->", [number_dict[n.item()] for n in pred.squeeze()])
文章参考文献
本作品采用 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议 (CC BY-NC-ND 4.0) 进行许可。