当前位置:   article > 正文

python Seq2Seq模型源码实战,超详细Encoder-Decoder模型解析实战;早期机器翻译模型源码demo_encoder decoder模型

encoder decoder模型

1.Seq2Seq(Encoder-Decoder)模型简介

Seq2Seq(Encoder-Decoder)模型是一种常用于序列到序列(sequence-to-sequence)任务的深度学习模型。它由两个主要的组件组成:编码器(Encoder)和解码器(Decoder)。

编码器负责将输入序列编码成一个固定长度的向量,该向量包含了输入序列的语义信息。常用的编码器模型有循环神经网络(RNN)和Transformer。RNN编码器通过逐个时间步处理输入序列,并将最后一个时间步的隐藏状态作为向量输出。而Transformer编码器则将输入序列同时输入到多个注意力头中,从而捕捉输入的全局依赖关系。

解码器将编码器输出的向量作为输入,逐步生成目标序列。在每一个时间步,解码器通过学习到的语境信息和当前的输入,预测下一个输出的标记。常用的解码器模型也有RNN和Transformer。RNN解码器通常使用循环单元,每个时间步依次生成输出。而Transformer解码器可以同时计算目标序列中每个位置的输出,从而并行生成序列。

Seq2Seq模型适用于多种任务,如机器翻译、文本摘要、对话生成等。在机器翻译任务中,输入序列是源语言句子,目标序列是目标语言句子,模型的目标是学习源语言到目标语言的翻译规则。在训练阶段,给定源语言句子,模型通过编码器将其编码为一个向量表示,然后通过解码器生成目标语言句子。在测试阶段,给定一个源语言句子,模型使用编码器生成其向量表示,然后利用解码器生成目标语言句子。

Seq2Seq模型的一些改进包括使用注意力机制(Attention)来解决长序列问题,以及引入更复杂的网络结构和训练技巧来提升模型性能。此外,Seq2Seq模型也可以通过引入强化学习技术进行训练优化,以更好地适应特定任务需求。

2.Seq2Seq(Encoder-Decoder)模型代码实战

机器翻译任务

2.1构建语料库 

  1. # 构建语料库,每行包含中文、英文(解码器输入)和翻译成英文后的目标输出 3 个句子
  2. sentences = [
  3. ['成哥 喜欢 小冰', '<sos> ChengGe likes XiaoBing', 'ChengGe likes XiaoBing <eos>'],
  4. ['我 爱 学习 人工智能', '<sos> I love studying AI', 'I love studying AI <eos>'],
  5. ['深度学习 改变 世界', '<sos> DL changed the world', 'DL changed the world <eos>'],
  6. ['自然 语言 处理 很 强大', '<sos> NLP is so powerful', 'NLP is so powerful <eos>'],
  7. ['神经网络 非常 复杂', '<sos> Neural-Nets are complex', 'Neural-Nets are complex <eos>']]
  8. word_list_cn, word_list_en = [], [] # 初始化中英文词汇表
  9. # 遍历每一个句子并将单词添加到词汇表中
  10. for s in sentences:
  11. word_list_cn.extend(s[0].split())
  12. word_list_en.extend(s[1].split())
  13. word_list_en.extend(s[2].split())
  14. # 去重,得到没有重复单词的词汇表
  15. word_list_cn = list(set(word_list_cn))
  16. word_list_en = list(set(word_list_en))
  17. # 构建单词到索引的映射
  18. word2idx_cn = {w: i for i, w in enumerate(word_list_cn)}
  19. word2idx_en = {w: i for i, w in enumerate(word_list_en)}
  20. # 构建索引到单词的映射
  21. idx2word_cn = {i: w for i, w in enumerate(word_list_cn)}
  22. idx2word_en = {i: w for i, w in enumerate(word_list_en)}
  23. # 计算词汇表的大小
  24. voc_size_cn = len(word_list_cn)
  25. voc_size_en = len(word_list_en)
  26. print(" 句子数量:", len(sentences)) # 打印句子数
  27. print(" 中文词汇表大小:", voc_size_cn) # 打印中文词汇表大小
  28. print(" 英文词汇表大小:", voc_size_en) # 打印英文词汇表大小
  29. print(" 中文词汇到索引的字典:", word2idx_cn) # 打印中文词汇到索引的字典
  30. print(" 英文词汇到索引的字典:", word2idx_en) # 打印英文词汇到索引的字典

2.2数据预处理

  1. import numpy as np # 导入 numpy
  2. import torch # 导入 torch
  3. import random # 导入 random 库
  4. # 定义一个函数,随机选择一个句子和词汇表生成输入、输出和目标数据
  5. def make_data(sentences):
  6. # 随机选择一个句子进行训练
  7. random_sentence = random.choice(sentences)
  8. # 将输入句子中的单词转换为对应的索引
  9. encoder_input = np.array([[word2idx_cn[n] for n in random_sentence[0].split()]])
  10. # 将输出句子中的单词转换为对应的索引
  11. decoder_input = np.array([[word2idx_en[n] for n in random_sentence[1].split()]])
  12. # 将目标句子中的单词转换为对应的索引
  13. target = np.array([[word2idx_en[n] for n in random_sentence[2].split()]])
  14. # 将输入、输出和目标批次转换为 LongTensor
  15. encoder_input = torch.LongTensor(encoder_input)
  16. decoder_input = torch.LongTensor(decoder_input)
  17. target = torch.LongTensor(target)
  18. return encoder_input, decoder_input, target
  19. # 使用 make_data 函数生成输入、输出和目标张量
  20. encoder_input, decoder_input, target = make_data(sentences)
  21. for s in sentences: # 获取原始句子
  22. if all([word2idx_cn[w] in encoder_input[0] for w in s[0].split()]):
  23. original_sentence = s
  24. break
  25. print(" 原始句子:", original_sentence) # 打印原始句子
  26. print(" 编码器输入张量的形状:", encoder_input.shape) # 打印输入张量形状
  27. print(" 解码器输入张量的形状:", decoder_input.shape) # 打印输出张量形状
  28. print(" 目标张量的形状:", target.shape) # 打印目标张量形状
  29. print(" 编码器输入张量:", encoder_input) # 打印输入张量
  30. print(" 解码器输入张量:", decoder_input) # 打印输出张量
  31. print(" 目标张量:", target) # 打印目标张量

2.3定义编码层和解码层

  1. import torch.nn as nn # 导入 torch.nn 库
  2. # 定义编码器类,继承自 nn.Module
  3. class Encoder(nn.Module):
  4. def __init__(self, input_size, hidden_size):
  5. super(Encoder, self).__init__()
  6. self.hidden_size = hidden_size # 设置隐藏层大小
  7. self.embedding = nn.Embedding(input_size, hidden_size) # 创建词嵌入层
  8. self.rnn = nn.RNN(hidden_size, hidden_size, batch_first=True) # 创建 RNN 层
  9. def forward(self, inputs, hidden): # 前向传播函数
  10. embedded = self.embedding(inputs) # 将输入转换为嵌入向量
  11. output, hidden = self.rnn(embedded, hidden) # 将嵌入向量输入 RNN 层并获取输出
  12. return output, hidden
  13. # 定义解码器类,继承自 nn.Module
  14. class Decoder(nn.Module):
  15. def __init__(self, hidden_size, output_size):
  16. super(Decoder, self).__init__()
  17. self.hidden_size = hidden_size # 设置隐藏层大小
  18. self.embedding = nn.Embedding(output_size, hidden_size) # 创建词嵌入层
  19. self.rnn = nn.RNN(hidden_size, hidden_size, batch_first=True) # 创建 RNN 层
  20. self.out = nn.Linear(hidden_size, output_size) # 创建线性输出层
  21. def forward(self, inputs, hidden): # 前向传播函数
  22. embedded = self.embedding(inputs) # 将输入转换为嵌入向量
  23. output, hidden = self.rnn(embedded, hidden) # 将嵌入向量输入 RNN 层并获取输出
  24. output = self.out(output) # 使用线性层生成最终输出
  25. return output, hidden
  26. n_hidden = 128 # 设置隐藏层数量
  27. # 创建编码器和解码器
  28. encoder = Encoder(voc_size_cn, n_hidden)
  29. decoder = Decoder(n_hidden, voc_size_en)
  30. print(' 编码器结构:', encoder) # 打印编码器的结构
  31. print(' 解码器结构:', decoder) # 打印解码器的结构

2.4创建 Seq2Seq 架构 

  1. class Seq2Seq(nn.Module):
  2. def __init__(self, encoder, decoder):
  3. super(Seq2Seq, self).__init__()
  4. # 初始化编码器和解码器
  5. self.encoder = encoder
  6. self.decoder = decoder
  7. def forward(self, enc_input, hidden, dec_input): # 定义前向传播函数
  8. # 使输入序列通过编码器并获取输出和隐藏状态
  9. encoder_output, encoder_hidden = self.encoder(enc_input, hidden)
  10. # 将编码器的隐藏状态传递给解码器作为初始隐藏状态
  11. decoder_hidden = encoder_hidden
  12. # 使解码器输入(目标序列)通过解码器并获取输出
  13. decoder_output, _ = self.decoder(dec_input, decoder_hidden)
  14. return decoder_output
  15. # 创建 Seq2Seq 架构
  16. model = Seq2Seq(encoder, decoder)
  17. print('S2S 模型结构:', model) # 打印模型的结构

2.5模型训练

  1. # 定义训练函数
  2. def train_seq2seq(model, criterion, optimizer, epochs):
  3. for epoch in range(epochs):
  4. encoder_input, decoder_input, target = make_data(sentences) # 训练数据的创建
  5. hidden = torch.zeros(1, encoder_input.size(0), n_hidden) # 初始化隐藏状态
  6. optimizer.zero_grad()# 梯度清零
  7. output = model(encoder_input, hidden, decoder_input) # 获取模型输出
  8. loss = criterion(output.view(-1, voc_size_en), target.view(-1)) # 计算损失
  9. if (epoch + 1) % 40 == 0: # 打印损失
  10. print(f"Epoch: {epoch + 1:04d} cost = {loss:.6f}")
  11. loss.backward()# 反向传播
  12. optimizer.step()# 更新参数
  13. # 训练模型
  14. epochs = 400 # 训练轮次
  15. criterion = nn.CrossEntropyLoss() # 损失函数
  16. optimizer = torch.optim.Adam(model.parameters(), lr=0.001) # 优化器
  17. train_seq2seq(model, criterion, optimizer, epochs) # 调用函数训练模型

 

2.6进行测试

  1. # 定义测试函数
  2. def test_seq2seq(model, source_sentence):
  3. # 将输入的句子转换为索引
  4. encoder_input = np.array([[word2idx_cn[n] for n in source_sentence.split()]])
  5. # 构建输出的句子的索引,以 '<sos>' 开始,后面跟 '<eos>',长度与输入句子相同
  6. decoder_input = np.array([word2idx_en['<sos>']] + [word2idx_en['<eos>']]*(len(encoder_input[0])-1))
  7. # 转换为 LongTensor 类型
  8. encoder_input = torch.LongTensor(encoder_input)
  9. decoder_input = torch.LongTensor(decoder_input).unsqueeze(0) # 增加一维
  10. hidden = torch.zeros(1, encoder_input.size(0), n_hidden) # 初始化隐藏状态
  11. predict = model(encoder_input, hidden, decoder_input) # 获取模型输出
  12. predict = predict.data.max(2, keepdim=True)[1] # 获取概率最大的索引
  13. # 打印输入的句子和预测的句子
  14. print(source_sentence, '->', [idx2word_en[n.item()] for n in predict.squeeze()])
  15. # 测试模型
  16. test_seq2seq(model, '成哥 喜欢 小冰')
  17. test_seq2seq(model, '自然 语言 处理 很 强大')

3.总结

        综上所述,Seq2Seq模型是一种用于序列到序列任务的深度学习模型,由编码器和解码器组成。编码器将输入序列编码为一个向量,解码器逐步生成目标序列。该模型在机器翻译、文本摘要、对话生成等任务中得到广泛应用,并有很多改进和扩展。 

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

闽ICP备14008679号