当前位置:   article > 正文

Python实现神经网络语言模型(代码详解)_神经网络模型python代码

神经网络模型python代码

目录 

一、原理图

二、代码

三、结果


引言

神经网络语言模型(Neural Network Language Model, NNLM)是利用神经网络计算词向量的方法,根据(w{t-n+1}...w{t-1})来预测(w{t})是什么词,即用前(n-1)个单词来预测第(n)个单词。


一、原理图


二、代码

参考TensorDataset和DataLoader解释

  1. import torch
  2. import torch.nn as nn
  3. import torch.optim as optim
  4. from torch.utils.data import DataLoader, TensorDataset
  5. from tqdm import tqdm
  6. import numpy as np
  7. import re
  8. sentences = ["我爱你", "喜羊羊", "灰太狼"] # sentences = ['我爱你', '喜羊羊', '灰太狼']
  9. # 将输入的句子进行中文分字处理。它首先使用正则表达式找到句子中的中文字符,并将句子按照中文字符进行分割。然后,去除分割后的结果中的空白字符,最后返回分割后的中文字符列表。
  10. def seg_char(sent):
  11. pattern = re.compile(r'([\u4e00-\u9fa5])')
  12. chars = pattern.split(sent)
  13. chars = [w for w in chars if len(w.strip()) > 0]
  14. return chars
  15. # 对给定的句子列表进行中文分字处理,得到一个包含所有句子中汉字的二维数组。
  16. chars = np.array([seg_char(i) for i in sentences]) # chars = [['我' '爱' '你'], ['喜' '羊' '羊'], ['灰' '太' '狼']]
  17. # 将二维数组展平为一个一维数组。
  18. chars = chars.reshape(1, -1) # chars = [['我' '爱' '你' '喜' '羊' '羊' '灰' '太' '狼']]
  19. # 通过去除数组中的空白字符和重复项,得到汉字的列表。
  20. word_list = np.squeeze(chars) # word_list = ['我' '爱' '你' '喜' '羊' '羊' '灰' '太' '狼']
  21. word_list = list(set(word_list)) # word_list = ['灰', '太', '狼', '喜', '羊', '爱', '你', '我']
  22. # 建立汉字与索引的映射关系,生成词典。 i=0—>灰;i=1—>太;i=2—>狼...i=7—>我
  23. word_dict = {w: i for i, w in enumerate(word_list)} # word_dict = {'灰': 0, '太': 1, '狼': 2, '喜': 3, '羊': 4, '爱': 5, '你': 6, '我': 7}
  24. # 创建索引与汉字的反向映射关系,生成反向词典。
  25. number_dict = {i: w for i, w in enumerate(word_list)} # number_dict = {0: '灰', 1: '太', 2: '狼', 3: '喜', 4: '羊', 5: '爱', 6: '你', 7: '我'}
  26. # 确定词汇表的大小。
  27. n_class = len(word_dict) # 词汇表的大小 n_class = 8
  28. # NNLM 参数
  29. n_step = 2 # 步数
  30. # 将句子列表转换为神经网络模型训练所需的输入批次和目标批次。输入输出 one-hot 编码
  31. def make_batch(sentences): # sentences = ['我爱你', '喜羊羊', '灰太狼']
  32. input_batch = []
  33. target_batch = []
  34. # 遍历句子列表,对每个句子进行中文分字处理,得到汉字列表。
  35. for sen in sentences: # sen = '灰太狼'
  36. # 对于每个句子,将汉字列表中的前n-1个字符作为输入,最后一个字符作为目标。
  37. word = seg_char(sen) # word = ['灰', '太', '狼']
  38. input = [word_dict[n] for n in word[:-1]] # 使用词典将汉字转换为对应的索引。input = [0, 1]
  39. target = word_dict[word[-1]] # target = 2
  40. # 对输入和目标进行 one-hot 编码,生成输入批次和目标批次。
  41. # [tensor([[0., 0., 0., 0., 0., 0., 0., 1.], [0., 0., 0., 0., 0., 1., 0., 0.]]),
  42. # tensor([[0., 0., 0., 1., 0., 0., 0., 0.], [0., 0., 0., 0., 1., 0., 0., 0.]]),
  43. # tensor([[1., 0., 0., 0., 0., 0., 0., 0.], [0., 1., 0., 0., 0., 0., 0., 0.]])]
  44. input_batch.append(torch.eye(n_class)[input])
  45. # [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.])]
  46. target_batch.append(torch.eye(n_class)[target])
  47. return input_batch, target_batch
  48. # 将所有输入批次和目标批次合并为一个张量,并整理成模型需要的形状。
  49. input_batch, target_batch = make_batch(sentences)
  50. # tensor:(3, 16)
  51. # tensor([[0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 1., 0., 0.],
  52. # [0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0.],
  53. # [1., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0.]])
  54. input_batch = torch.cat(input_batch).view(-1, n_step * n_class)
  55. # tensor:(3, 8)
  56. # tensor([[0., 0., 0., 0., 0., 0., 1., 0.],
  57. # [0., 0., 0., 0., 1., 0., 0., 0.],
  58. # [0., 0., 1., 0., 0., 0., 0., 0.]])
  59. target_batch = torch.cat(target_batch).view(-1, n_class)
  60. # 定义模型
  61. class NNLM(nn.Module):
  62. # 初始化函数: 定义了模型的各个层和激活函数
  63. def __init__(self):
  64. super(NNLM, self).__init__()
  65. self.linear1 = nn.Linear(n_step * n_class, 2) # 全连接层, 输入大小为 n_step * n_class,输出大小为 2
  66. self.tanh = nn.Tanh() # tanh 激活函数
  67. self.linear2 = nn.Linear(2, n_class) # 另一个全连接层,输入大小为 2,输出大小为 n_class
  68. self.softmax = nn.Softmax(dim=1) # softmax 激活函数,用于输出层
  69. # 前向传播函数: 定义了数据流的传递方式
  70. def forward(self, x):
  71. x = self.linear1(x) # 输入 x 经过第一个全连接层 self.linear1 得到中间表示
  72. x = self.tanh(x) # 中间表示经过 tanh 激活函数
  73. x = self.linear2(x) # 经过第二个全连接层 self.linear2 得到输出
  74. x = self.softmax(x) # 输出经过 softmax 激活函数,得到最终的预测结果
  75. return x
  76. # 准备训练数据
  77. train_dataset = TensorDataset(input_batch, target_batch)
  78. train_loader = DataLoader(train_dataset, batch_size=1)
  79. # NNLM(
  80. # (linear1): Linear(in_features=16, out_features=2, bias=True)
  81. # (tanh): Tanh()
  82. # (linear2): Linear(in_features=2, out_features=8, bias=True)
  83. # (softmax): Softmax(dim=1)
  84. # )
  85. model = NNLM()
  86. # 定义损失函数和优化器
  87. # 损失函数使用交叉熵损失函数 nn.CrossEntropyLoss(),用于计算模型预测结果与真实标签之间的差异
  88. criterion = nn.CrossEntropyLoss() # criterion = CrossEntropyLoss()
  89. # 优化器使用 Adam 优化器 optim.Adam,用于更新模型的参数以最小化损失函数
  90. # Adam (
  91. # Parameter Group 0
  92. # amsgrad: False
  93. # betas: (0.9, 0.999)
  94. # capturable: False
  95. # differentiable: False
  96. # eps: 1e-08
  97. # foreach: None
  98. # fused: None
  99. # lr: 0.001
  100. # maximize: False
  101. # weight_decay: 0
  102. # )
  103. optimizer = optim.Adam(model.parameters())
  104. # 训练模型: 使用了一个循环来迭代执行多个 epoch(训练轮数)
  105. epochs = 5000
  106. for epoch in tqdm(range(epochs), desc='训练进度'): # epoch = 0,..., epoch = 4
  107. total_loss = 0.0
  108. correct = 0
  109. total_samples = 0
  110. for inputs, targets in train_loader:
  111. optimizer.zero_grad() # 首先,使用优化器的 zero_grad() 方法将模型参数的梯度归零,以准备计算新一轮的梯度。
  112. # 然后,通过模型前向传播计算得到模型的输出 outputs。
  113. # epoch = 0时:
  114. # outputs = tensor([[0.1091, 0.0567, 0.0587, 0.0967, 0.1380, 0.1759, 0.1786, 0.1863],
  115. # [0.1626, 0.0645, 0.0532, 0.1406, 0.0927, 0.1947, 0.1429, 0.1487],
  116. # [0.1081, 0.0481, 0.0837, 0.1257, 0.1359, 0.1466, 0.1929, 0.1590]],
  117. # grad_fn=<SoftmaxBackward0>)
  118. # epoch = 4时:
  119. # outputs = tensor([[0.1272, 0.1309, 0.1559, 0.0674, 0.1287, 0.0707, 0.1293, 0.1898],
  120. # [0.1423, 0.1347, 0.1282, 0.0570, 0.1251, 0.0887, 0.1523, 0.1716],
  121. # [0.1320, 0.1184, 0.1521, 0.0699, 0.1312, 0.0632, 0.1283, 0.2050]],
  122. # rad_fn=<SoftmaxBackward0>)
  123. outputs = model(input_batch)
  124. # 接着,计算模型的预测结果与真实标签之间的交叉熵损失,即模型在当前轮次的损失值 loss。
  125. # epoch = 0时:
  126. # loss = tensor(2.0923, grad_fn=<NllLossBackward0>)
  127. # epoch = 4时:
  128. # loss = tensor(2.0697, grad_fn=<NllLossBackward0>)
  129. loss = criterion(outputs, torch.max(target_batch, 1)[1])
  130. # 使用损失函数的 backward() 方法计算损失关于模型参数的梯度。
  131. loss.backward()
  132. # 最后,使用优化器的 step() 方法更新模型的参数,以最小化损失函数。
  133. optimizer.step()
  134. total_loss += loss.item() * inputs.size(0)
  135. _, predicted = torch.max(outputs, 1)
  136. correct += (predicted == torch.max(targets, 1)[1]).sum().item()
  137. total_samples += inputs.size(0)
  138. accuracy = correct / total_samples
  139. avg_loss = total_loss / total_samples
  140. # 每隔 100 个 epoch 打印一次当前轮次的损失值。
  141. if (epoch+1) % 1000 == 0:
  142. print(f'Epoch {epoch + 1}/{epochs}')
  143. print(f'Loss: {avg_loss:.4f} - Accuracy: {accuracy:.4f}\n')
  144. # print('Epoch [{}/{}], Loss: {:.4f}'.format(epoch+1, epochs, loss.item()))
  145. # 预测测试
  146. predict = model(input_batch) # 使用训练好的模型对测试数据进行预测; 将测试数据输入模型,得到模型的预测结果
  147. _, predict = torch.max(predict, 1) # 通过 torch.max() 函数找到每个预测结果中概率最大的类别索引
  148. # 将预测结果转换为汉字,并打印出原始输入数据和模型预测得到的结果。
  149. print('输入的是:', [seg_char(sen)[:2] for sen in sentences])
  150. print('预测得到:', [number_dict[n.item()] for n in predict])

三、结果

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/天景科技苑/article/detail/919389
推荐阅读
相关标签
  

闽ICP备14008679号