Seq2Sep机器训练

Seq2Sep机器训练

  1 import numpy as np
  2 import torch
  3 import random
  4 import torch.nn as nn
  5 
  6 # 构建语料库,每行包含中文、英文(解码器输入)和翻译成英文后的目标输出 3 个句子
  7 sentences = [
  8     # sos:start of sentence, 模型翻译的起始位置。
  9     # eos:end of sentence,模型翻译的结束位置。
 10 
 11     # 原始文本使用 空格 划分为token
 12 
 13     # 原始文本、 解码输入、 解码输出
 14     ['黄老师 喜欢 人工智能', '<sos> TeacherMao likes AI', 'TeacherMao likes AI <eos>'],
 15     ['我 爱 学习 世界', '<sos> I love studying world', 'I love studying world <eos>'],
 16     ['深度学习 改变 世界', '<sos> DL changed the world', 'DL changed the world <eos>'],
 17     ['自然 语言 处理 很 强大', '<sos> NLP is so powerful', 'NLP is so powerful <eos>'],
 18     ['神经网络 非常 复杂', '<sos> Neural-Nets are complex', 'Neural-Nets are complex <eos>']
 19 ]
 20 
 21 # 遍历每一个句子并将单词添加到词汇表中
 22 word_list_cn, word_list_en = [], []
 23 for s in sentences:
 24     word_list_cn.extend(s[0].split())
 25     word_list_en.extend(s[1].split())
 26     word_list_en.extend(s[2].split())
 27 
 28 # 去重,得到没有重复单词的词汇表
 29 word_list_cn = list(set(word_list_cn)) # 词典 包含所有的单词,唯一一次就够
 30 word_list_en = list(set(word_list_en))
 31 
 32 # 构建单词到索引的映射(embeeding、rnn、lstm)
 33 # 构建词汇表
 34 word2idx_cn = {w: i for i, w in enumerate(word_list_cn)}
 35 word2idx_en = {w: i for i, w in enumerate(word_list_en)}
 36 
 37 # 构建索引到单词的映射
 38 idx2word_cn = {i: w for i, w in enumerate(word_list_cn)}
 39 idx2word_en = {i: w for i, w in enumerate(word_list_en)}
 40 
 41 # 计算词汇表的大小
 42 voc_size_cn = len(word_list_cn)
 43 voc_size_en = len(word_list_en)
 44 
 45 # 定义一个函数,随机选择一个句子和词汇表生成输入、输出和目标数据
 46 def make_data(sentences):
 47     # 随机选择一个句子进行训练
 48     random_sentence = random.choice(sentences)
 49     # 将输入句子中的单词转换为对应的索引
 50     encoder_input = np.array([[word2idx_cn[n] for n in random_sentence[0].split()]])
 51     # 将输出句子中的单词转换为对应的索引
 52     decoder_input = np.array([[word2idx_en[n] for n in random_sentence[1].split()]])
 53     # 将目标句子中的单词转换为对应的索引
 54     target = np.array([[word2idx_en[n] for n in random_sentence[2].split()]])
 55     # 将输入、输出和目标批次转换为 LongTensor
 56     encoder_input = torch.LongTensor(encoder_input)
 57     decoder_input = torch.LongTensor(decoder_input)
 58     target = torch.LongTensor(target)
 59     return encoder_input, decoder_input, target
 60 
 61 
 62 # 使用 make_data 函数生成输入、输出和目标张量
 63 encoder_input, decoder_input, target = make_data(sentences)
 64 for s in sentences:  # 获取原始句子
 65     if all([word2idx_cn[w] in encoder_input[0] for w in s[0].split()]):
 66         original_sentence = s
 67 
 68 print(" 原始句子:", original_sentence)  # 打印原始句子
 69 print(" 编码器输入张量的形状:", encoder_input.shape)  # 打印输入张量形状
 70 print(" 解码器输入张量的形状:", decoder_input.shape)  # 打印输出张量形状
 71 print(" 目标张量的形状:", target.shape)  # 打印目标张量形状
 72 print(" 编码器输入张量:", encoder_input)  # 打印输入张量
 73 print(" 解码器输入张量:", decoder_input)  # 打印输出张量
 74 print(" 目标张量:", target)  # 打印目标张量
 75 
 76 
 77 # 定义编码器类,继承自 nn.Module
 78 class Encoder(nn.Module):
 79     # 将输入的序列编码成一个包含其全部语义信息的上下文向量
 80     def __init__(self, input_size, hidden_size):
 81         super(Encoder, self).__init__()
 82         self.hidden_size = hidden_size  # 设置隐藏层大小
 83         self.embedding = nn.Embedding(input_size, hidden_size)  # 创建词嵌入层 input_size 词表大小
 84         self.rnn = nn.RNN(hidden_size, hidden_size, batch_first=True)  # 创建 RNN 层
 85 
 86     def forward(self, inputs, hidden):  # 前向传播函数
 87         embedded = self.embedding(inputs)  # 将输入转换为嵌入向量
 88         output, hidden = self.rnn(embedded, hidden)  # 将嵌入向量输入 RNN 层并获取输出
 89         return output, hidden
 90 
 91 
 92 class Decoder(nn.Module):
 93     def __init__(self, hidden_size, output_size):
 94         super(Decoder, self).__init__()
 95         self.hidden_size = hidden_size
 96         self.embedding = nn.Embedding(output_size, hidden_size)
 97         self.rnn = nn.RNN(hidden_size, hidden_size, batch_first=True)
 98 
 99         # 全链接层,维度转换
100         self.out = nn.Linear(hidden_size, output_size) # 全连接层, 目标词汇表的大小
101 
102     def forward(self, inputs, hidden):
103         embedded = self.embedding(inputs)
104         output, hidden = self.rnn(embedded, hidden)
105         output = self.out(output)
106         return output, hidden
107 
108 
109 n_hidden = 128  # 设置隐藏层数量
110 # 创建编码器和解码器
111 encoder = Encoder(voc_size_cn, n_hidden)
112 decoder = Decoder(n_hidden, voc_size_en)
113 print(' 编码器结构:', encoder)  # 打印编码器的结构
114 print(' 解码器结构:', decoder)  # 打印解码器的结构
115 
116 
117 class Seq2Seq(nn.Module):
118     def __init__(self, encoder, decoder):
119         super(Seq2Seq, self).__init__()
120         # 初始化编码器和解码器
121         self.encoder = encoder
122         self.decoder = decoder
123 
124     def forward(self, enc_input, hidden, dec_input):  # 定义前向传播函数
125         # enc_input 中文输入
126         # hidden 初始化状态
127         encoder_output, encoder_hidden = self.encoder(enc_input, hidden)
128 
129         # encoder_hidden 最终隐藏状态
130         decoder_hidden = encoder_hidden
131 
132         # 英文输入序列
133         decoder_output, _ = self.decoder(dec_input, decoder_hidden)
134         return decoder_output
135 
136 
137 model = Seq2Seq(encoder, decoder)
138 print('模型结构:', model)
139 
140 
141 # 定义训练函数
142 def train_seq2seq(model, criterion, optimizer, epochs):
143     for epoch in range(epochs): # epoch
144         # 文本 -》 id
145         encoder_input, decoder_input, target = make_data(sentences)
146 
147         # 初始化编码器的初始隐藏状态
148         hidden = torch.zeros(1, encoder_input.size(0), n_hidden)
149 
150         optimizer.zero_grad()  # 梯度清零
151         output = model(encoder_input, hidden, decoder_input)
152         loss = criterion(output.view(-1, voc_size_en), target.view(-1)) # 分类
153 
154         if (epoch + 1) % 100 == 0:  # 打印损失
155             print(f"Epoch: {epoch + 1:04d} cost = {loss:.6f}")
156         loss.backward()  # 反向传播
157         optimizer.step()  # 更新参数
158 
159 
160 # 训练模型
161 epochs = 500  # 训练轮次
162 criterion = nn.CrossEntropyLoss()  # 损失函数
163 optimizer = torch.optim.Adam(model.parameters(), lr=0.001)  # 优化器
164 train_seq2seq(model, criterion, optimizer, epochs)  # 调用函数训练模型
165 
166 
167 # 定义测试函数
168 def test_seq2seq(model, source_sentence):
169     # 将输入的句子转换为索引
170     encoder_input = np.array([[word2idx_cn[n] for n in source_sentence.split()]])
171 
172     # 构建输出的句子的索引,以 '<sos>' 开始,后面跟 '<eos>',长度与输入句子相同
173     decoder_input = np.array([word2idx_en['<sos>']] + [word2idx_en['<eos>']] * (len(encoder_input[0]) - 1))
174 
175     # 转换为 LongTensor 类型
176     encoder_input = torch.LongTensor(encoder_input)
177     decoder_input = torch.LongTensor(decoder_input).unsqueeze(0)
178 
179     hidden = torch.zeros(1, encoder_input.size(0), n_hidden)
180     predict = model(encoder_input, hidden, decoder_input)
181     predict = predict.data.max(2, keepdim=True)[1] # 概率最大的单词
182 
183     # 打印输入的句子和预测的句子
184     print(source_sentence, '->', [idx2word_en[n.item()] for n in predict.squeeze()])
185 
186 
187 # 测试模型
188 test_seq2seq(model, '黄老师 喜欢 人工智能') # 没有解码器输入

 

posted @ 2026-07-22 00:20  Marksion  阅读(2)  评论(0)    收藏  举报