首页
/ 基于NNLM的语言模型实现教程

基于NNLM的语言模型实现教程

2025-07-06 01:53:05作者:鲍丁臣Ursa

本教程将详细介绍如何使用PyTorch实现一个简单的神经网络语言模型(NNLM)。我们将从理论背景到代码实现,逐步解析这个经典的自然语言处理模型。

神经网络语言模型(NNLM)简介

神经网络语言模型(Neural Network Language Model, NNLM)是由Bengio等人在2003年提出的经典模型,它首次将神经网络应用于语言建模任务。与传统n-gram模型相比,NNLM具有以下优势:

  1. 能够自动学习词语的分布式表示(词向量)
  2. 可以捕捉更长的上下文依赖关系
  3. 解决了传统方法的维度灾难问题

实现细节解析

数据准备

我们使用三个简单的英文句子作为训练数据:

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)  # 词汇表大小

批处理生成

make_batch函数负责将原始句子转换为模型可处理的输入输出对:

def make_batch():
    input_batch = []
    target_batch = []

    for sen in sentences:
        word = sen.split() # 使用空格分词
        input = [word_dict[n] for n in word[:-1]] # 前n-1个词作为输入
        target = word_dict[word[-1]] # 最后一个词作为目标
        
        input_batch.append(input)
        target_batch.append(target)

    return input_batch, target_batch

模型架构

NNLM模型包含以下几个关键组件:

  1. 词嵌入层(Embedding Layer):将离散的词语索引映射为连续的向量表示
  2. 隐藏层(Hidden Layer):学习词语组合的非线性特征
  3. 输出层(Output Layer):预测下一个词的概率分布

具体实现如下:

class NNLM(nn.Module):
    def __init__(self):
        super(NNLM, self).__init__()
        self.C = nn.Embedding(n_class, m)  # 词嵌入层
        self.H = nn.Linear(n_step * m, n_hidden, bias=False)  # 隐藏层
        self.d = nn.Parameter(torch.ones(n_hidden))  # 隐藏层偏置
        self.U = nn.Linear(n_hidden, n_class, bias=False)  # 输出层权重1
        self.W = nn.Linear(n_step * m, n_class, bias=False)  # 输出层权重2
        self.b = nn.Parameter(torch.ones(n_class))  # 输出层偏置

    def forward(self, X):
        X = self.C(X)  # 获取词嵌入 [batch_size, n_step, m]
        X = X.view(-1, n_step * m)  # 展平 [batch_size, n_step * m]
        tanh = torch.tanh(self.d + self.H(X))  # 非线性变换
        output = self.b + self.W(X) + self.U(tanh)  # 最终输出
        return output

训练过程

训练过程采用标准的监督学习范式:

  1. 定义损失函数(交叉熵损失)
  2. 选择优化器(Adam)
  3. 迭代训练模型
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)

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 = model(input_batch).data.max(1, keepdim=True)[1]
print([sen.split()[:2] for sen in sentences], '->', [number_dict[n.item()] for n in predict.squeeze()])

输出结果将展示模型如何根据前两个词预测第三个词。

关键参数说明

  • n_step:上下文窗口大小,即使用前n-1个词预测第n个词
  • n_hidden:隐藏层维度
  • m:词嵌入维度
  • n_class:词汇表大小

总结

通过本教程,我们实现了一个简单的NNLM模型,它可以:

  1. 自动学习词语的分布式表示
  2. 基于上下文预测下一个词
  3. 展示神经网络在语言建模中的应用

虽然这个实现相对简单,但它包含了NNLM的核心思想。在实际应用中,可以通过增加模型复杂度、使用更大规模的训练数据来提升模型性能。