赞
踩
神经网络语言模型(Neural Network Language Model, NNLM)是利用神经网络计算词向量的方法,根据(w{t-n+1}...w{t-1})来预测(w{t})是什么词,即用前(n-1)个单词来预测第(n)个单词。
- import torch
- import torch.nn as nn
- import torch.optim as optim
- from torch.utils.data import DataLoader, TensorDataset
- from tqdm import tqdm
- import numpy as np
- import re
-
- sentences = ["我爱你", "喜羊羊", "灰太狼"] # sentences = ['我爱你', '喜羊羊', '灰太狼']
-
- # 将输入的句子进行中文分字处理。它首先使用正则表达式找到句子中的中文字符,并将句子按照中文字符进行分割。然后,去除分割后的结果中的空白字符,最后返回分割后的中文字符列表。
- def seg_char(sent):
- pattern = re.compile(r'([\u4e00-\u9fa5])')
- chars = pattern.split(sent)
- chars = [w for w in chars if len(w.strip()) > 0]
- return chars
-
- # 对给定的句子列表进行中文分字处理,得到一个包含所有句子中汉字的二维数组。
- chars = np.array([seg_char(i) for i in sentences]) # chars = [['我' '爱' '你'], ['喜' '羊' '羊'], ['灰' '太' '狼']]
-
- # 将二维数组展平为一个一维数组。
- chars = chars.reshape(1, -1) # chars = [['我' '爱' '你' '喜' '羊' '羊' '灰' '太' '狼']]
-
- # 通过去除数组中的空白字符和重复项,得到汉字的列表。
- word_list = np.squeeze(chars) # word_list = ['我' '爱' '你' '喜' '羊' '羊' '灰' '太' '狼']
- word_list = list(set(word_list)) # word_list = ['灰', '太', '狼', '喜', '羊', '爱', '你', '我']
-
- # 建立汉字与索引的映射关系,生成词典。 i=0—>灰;i=1—>太;i=2—>狼...i=7—>我
- word_dict = {w: i for i, w in enumerate(word_list)} # word_dict = {'灰': 0, '太': 1, '狼': 2, '喜': 3, '羊': 4, '爱': 5, '你': 6, '我': 7}
-
- # 创建索引与汉字的反向映射关系,生成反向词典。
- number_dict = {i: w for i, w in enumerate(word_list)} # number_dict = {0: '灰', 1: '太', 2: '狼', 3: '喜', 4: '羊', 5: '爱', 6: '你', 7: '我'}
-
- # 确定词汇表的大小。
- n_class = len(word_dict) # 词汇表的大小 n_class = 8
-
- # NNLM 参数
- n_step = 2 # 步数
-
- # 将句子列表转换为神经网络模型训练所需的输入批次和目标批次。输入输出 one-hot 编码
- def make_batch(sentences): # sentences = ['我爱你', '喜羊羊', '灰太狼']
- input_batch = []
- target_batch = []
-
- # 遍历句子列表,对每个句子进行中文分字处理,得到汉字列表。
- for sen in sentences: # sen = '灰太狼'
-
- # 对于每个句子,将汉字列表中的前n-1个字符作为输入,最后一个字符作为目标。
- word = seg_char(sen) # word = ['灰', '太', '狼']
- input = [word_dict[n] for n in word[:-1]] # 使用词典将汉字转换为对应的索引。input = [0, 1]
- target = word_dict[word[-1]] # target = 2
-
- # 对输入和目标进行 one-hot 编码,生成输入批次和目标批次。
- # [tensor([[0., 0., 0., 0., 0., 0., 0., 1.], [0., 0., 0., 0., 0., 1., 0., 0.]]),
- # tensor([[0., 0., 0., 1., 0., 0., 0., 0.], [0., 0., 0., 0., 1., 0., 0., 0.]]),
- # tensor([[1., 0., 0., 0., 0., 0., 0., 0.], [0., 1., 0., 0., 0., 0., 0., 0.]])]
- input_batch.append(torch.eye(n_class)[input])
-
- # [tensor([0., 0., 0., 0., 0., 0., 1., 0.]), tensor([0., 0., 0., 0., 1., 0., 0., 0.]), tensor([0., 0., 1., 0., 0., 0., 0., 0.])]
- target_batch.append(torch.eye(n_class)[target])
-
- return input_batch, target_batch
-
- # 将所有输入批次和目标批次合并为一个张量,并整理成模型需要的形状。
- input_batch, target_batch = make_batch(sentences)
-
- # tensor:(3, 16)
- # tensor([[0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 1., 0., 0.],
- # [0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0.],
- # [1., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0.]])
- input_batch = torch.cat(input_batch).view(-1, n_step * n_class)
-
- # tensor:(3, 8)
- # tensor([[0., 0., 0., 0., 0., 0., 1., 0.],
- # [0., 0., 0., 0., 1., 0., 0., 0.],
- # [0., 0., 1., 0., 0., 0., 0., 0.]])
- target_batch = torch.cat(target_batch).view(-1, n_class)
-
- # 定义模型
- class NNLM(nn.Module):
-
- # 初始化函数: 定义了模型的各个层和激活函数
- def __init__(self):
- super(NNLM, self).__init__()
- self.linear1 = nn.Linear(n_step * n_class, 2) # 全连接层, 输入大小为 n_step * n_class,输出大小为 2
- self.tanh = nn.Tanh() # tanh 激活函数
- self.linear2 = nn.Linear(2, n_class) # 另一个全连接层,输入大小为 2,输出大小为 n_class
- self.softmax = nn.Softmax(dim=1) # softmax 激活函数,用于输出层
-
- # 前向传播函数: 定义了数据流的传递方式
- def forward(self, x):
- x = self.linear1(x) # 输入 x 经过第一个全连接层 self.linear1 得到中间表示
- x = self.tanh(x) # 中间表示经过 tanh 激活函数
- x = self.linear2(x) # 经过第二个全连接层 self.linear2 得到输出
- x = self.softmax(x) # 输出经过 softmax 激活函数,得到最终的预测结果
- return x
-
- # 准备训练数据
- train_dataset = TensorDataset(input_batch, target_batch)
- train_loader = DataLoader(train_dataset, batch_size=1)
-
- # NNLM(
- # (linear1): Linear(in_features=16, out_features=2, bias=True)
- # (tanh): Tanh()
- # (linear2): Linear(in_features=2, out_features=8, bias=True)
- # (softmax): Softmax(dim=1)
- # )
- model = NNLM()
-
- # 定义损失函数和优化器
- # 损失函数使用交叉熵损失函数 nn.CrossEntropyLoss(),用于计算模型预测结果与真实标签之间的差异
- criterion = nn.CrossEntropyLoss() # criterion = CrossEntropyLoss()
-
- # 优化器使用 Adam 优化器 optim.Adam,用于更新模型的参数以最小化损失函数
- # Adam (
- # Parameter Group 0
- # amsgrad: False
- # betas: (0.9, 0.999)
- # capturable: False
- # differentiable: False
- # eps: 1e-08
- # foreach: None
- # fused: None
- # lr: 0.001
- # maximize: False
- # weight_decay: 0
- # )
- optimizer = optim.Adam(model.parameters())
-
- # 训练模型: 使用了一个循环来迭代执行多个 epoch(训练轮数)
- epochs = 5000
- for epoch in tqdm(range(epochs), desc='训练进度'): # epoch = 0,..., epoch = 4
- total_loss = 0.0
- correct = 0
- total_samples = 0
-
- for inputs, targets in train_loader:
- optimizer.zero_grad() # 首先,使用优化器的 zero_grad() 方法将模型参数的梯度归零,以准备计算新一轮的梯度。
-
- # 然后,通过模型前向传播计算得到模型的输出 outputs。
- # epoch = 0时:
- # outputs = tensor([[0.1091, 0.0567, 0.0587, 0.0967, 0.1380, 0.1759, 0.1786, 0.1863],
- # [0.1626, 0.0645, 0.0532, 0.1406, 0.0927, 0.1947, 0.1429, 0.1487],
- # [0.1081, 0.0481, 0.0837, 0.1257, 0.1359, 0.1466, 0.1929, 0.1590]],
- # grad_fn=<SoftmaxBackward0>)
-
- # epoch = 4时:
- # outputs = tensor([[0.1272, 0.1309, 0.1559, 0.0674, 0.1287, 0.0707, 0.1293, 0.1898],
- # [0.1423, 0.1347, 0.1282, 0.0570, 0.1251, 0.0887, 0.1523, 0.1716],
- # [0.1320, 0.1184, 0.1521, 0.0699, 0.1312, 0.0632, 0.1283, 0.2050]],
- # rad_fn=<SoftmaxBackward0>)
- outputs = model(input_batch)
-
- # 接着,计算模型的预测结果与真实标签之间的交叉熵损失,即模型在当前轮次的损失值 loss。
- # epoch = 0时:
- # loss = tensor(2.0923, grad_fn=<NllLossBackward0>)
-
- # epoch = 4时:
- # loss = tensor(2.0697, grad_fn=<NllLossBackward0>)
- loss = criterion(outputs, torch.max(target_batch, 1)[1])
-
- # 使用损失函数的 backward() 方法计算损失关于模型参数的梯度。
- loss.backward()
-
- # 最后,使用优化器的 step() 方法更新模型的参数,以最小化损失函数。
- optimizer.step()
-
- total_loss += loss.item() * inputs.size(0)
- _, predicted = torch.max(outputs, 1)
- correct += (predicted == torch.max(targets, 1)[1]).sum().item()
- total_samples += inputs.size(0)
-
- accuracy = correct / total_samples
- avg_loss = total_loss / total_samples
-
- # 每隔 100 个 epoch 打印一次当前轮次的损失值。
- if (epoch+1) % 1000 == 0:
- print(f'Epoch {epoch + 1}/{epochs}')
- print(f'Loss: {avg_loss:.4f} - Accuracy: {accuracy:.4f}\n')
- # print('Epoch [{}/{}], Loss: {:.4f}'.format(epoch+1, epochs, loss.item()))
-
- # 预测测试
- predict = model(input_batch) # 使用训练好的模型对测试数据进行预测; 将测试数据输入模型,得到模型的预测结果
- _, predict = torch.max(predict, 1) # 通过 torch.max() 函数找到每个预测结果中概率最大的类别索引
-
- # 将预测结果转换为汉字,并打印出原始输入数据和模型预测得到的结果。
- print('输入的是:', [seg_char(sen)[:2] for sen in sentences])
- print('预测得到:', [number_dict[n.item()] for n in predict])
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。