数据集下载地址:

https://download.pytorch.org/tutorial/data.zip​

download.pytorch.org

数据集在eng-fra.txt文件中,每一行是一对儿英语和法语之间的互译。

运行以下代码,请确保

PyTorch=1.9.0

torchtext=0.10.0

Encoder中的数据流:

Decoder中的数据流:

带有注意力机制Decoder的数据流:

# Encoder-Decoder实现英法互译
from __future__ import unicode_literals, print_function, divisionimport random
import re
from io import openimport torch
import torch.nn as nn
import torch.nn.functional as F
import unicodedata
from torch import optim# 获取可用设备
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
# 一句话的开始标志 start of string
SOS_token = 0
# 一句话的结尾标志 end of string
EOS_token = 1# 要翻译的语言的包装类,包含了常用工具
class Lang:def __init__(self, name):# 名称self.name = name# 词语->索引self.word2index = {}# 词语->计数self.word2count = {}# 索引->词语# 默认添加SOS,EOSself.index2word = {0: "SOS", 1: "EOS"}# 词语数# 因为现在已经有 SOS,EOS 所以=2self.n_words = 2  # Count SOS and EOS# 添加一句话def addSentence(self, sentence):# 以空格分割这句话# 然后取出每一个词语for word in sentence.split(' '):# 添加词语self.addWord(word)def addWord(self, word):# 如果以前没有添加过这个词语if word not in self.word2index:# 索引从0开始# 所以先赋值# 最后self.n_words+=1self.word2index[word] = self.n_wordsself.word2count[word] = 1self.index2word[self.n_words] = wordself.n_words += 1else:# 已经存在则计数+=1self.word2count[word] += 1# 将一个Unicoide编码的字符
# 转换为ASCII编码的字符
# 统一字符编码方便处理
# 将一个Unicode字符串(数据集中的)转换为一个ASCII字符串(输入模型中的)
# 数据标准化
# 一个Unicode字符可以用多种不同的ASCII字符表示
# 转换为统一的形式方便模型处理
def unicodeToAscii(s):return ''.join(# normalize() 第一个参数指定字符串标准化的方式。# NFC表示字符使用单一编码优先,# 而NFD表示字符应该分解为多个组合字符表示# 先将输入的字符转换# 然后再过滤# Mn表示Mark# 如果不是特殊标记c for c in unicodedata.normalize('NFD', s)if unicodedata.category(c) != 'Mn')# 将字符串规范化
def normalizeString(s):# s.lower()先转换为小写# .strip()去除首尾的空格# 转换为ASCII编码的形式s = unicodeToAscii(s.lower().strip())# 去除标点符号s = re.sub(r"([.!?])", r" \1", s)# 去除非字母s = re.sub(r"[^a-zA-Z.!?]+", r" ", s)return s# 从数据集中读取一行数据
def readLangs(lang1, lang2, reverse=False):print("Reading lines...")# Read the file and split into lines# 首先以utf-8的方式打开数据集文件# read()读取# strip()去除多余的空格# 以\n分割读取到的内容,也就是分割出每一行lines = open('data/%s-%s.txt' % (lang1, lang2), encoding='utf-8'). \read().strip().split('\n')# Split every line into pairs and normalize# 对于数据集中的每一行for l in lines# 将每一行以\t分割for s in l.split('\t')# 对于分割出来的每一句话s,进行规范化pairs = [[normalizeString(s) for s in l.split('\t')] for l in lines]# Reverse pairs, make Lang instances# 如果要翻转数据集# 什么意思呢,就是如果原数据集存放的是英语->法语# 如果指定reverse# 那么将它进行翻转,变成法语->英语if reverse:pairs = [list(reversed(p)) for p in pairs]input_lang = Lang(lang2)output_lang = Lang(lang1)else:input_lang = Lang(lang1)output_lang = Lang(lang2)return input_lang, output_lang, pairs# 一句话的最大长度
MAX_LENGTH = 10
# 选取数据集中的一部分进行训练
# 选取带有一以下前缀的句子
eng_prefixes = ("i am ", "i m ","he is", "he s ","she is", "she s ","you are", "you re ","we are", "we re ","they are", "they re "
)# 按照最大长度
# 指定前缀
# 筛选数据集
def filterPair(p):return len(p[0].split(' ')) < MAX_LENGTH and len(p[1].split(' ')) < MAX_LENGTH and (p[0].startswith(eng_prefixes) or p[1].startswith(eng_prefixes))def filterPairs(pairs):return [pair for pair in pairs if filterPair(pair)]# 读取数据集
def prepareData(lang1, lang2, reverse=False):input_lang, output_lang, pairs = readLangs(lang1, lang2, reverse)print("Read %s sentence pairs" % len(pairs))pairs = filterPairs(pairs)print("Trimmed to %s sentence pairs" % len(pairs))print("Counting words...")for pair in pairs:input_lang.addSentence(pair[0])output_lang.addSentence(pair[1])print("Counted words:")print(input_lang.name, input_lang.n_words)print(output_lang.name, output_lang.n_words)return input_lang, output_lang, pairsinput_lang, output_lang, pairs = prepareData('eng', 'fra', True)
print(random.choice(pairs))# 定义Encoder
class EncoderRNN(nn.Module):def __init__(self, input_size, hidden_size):super(EncoderRNN, self).__init__()self.hidden_size = hidden_size# 词嵌入self.embedding = nn.Embedding(input_size, hidden_size)# GRU# 因为前面将输入进行了词嵌入,所以输入维度是hidden_sizeself.gru = nn.GRU(hidden_size, hidden_size)# 前向传递,建立计算图def forward(self, input, hidden):# 改成[长度,批大小,嵌入维度]的格式# 为什么这里长度,批大小都是1呢# 因为后面我们是将一句话中的每一个词逐一输入到Encoder中的# Decoder同理embedded = self.embedding(input).view(1, 1, -1)output = embeddedoutput, hidden = self.gru(output, hidden)return output, hiddendef initHidden(self):return torch.zeros(1, 1, self.hidden_size, device=device)# 定义Decoder
class DecoderRNN(nn.Module):def __init__(self, hidden_size, output_size):super(DecoderRNN, self).__init__()self.hidden_size = hidden_sizeself.embedding = nn.Embedding(output_size, hidden_size)self.gru = nn.GRU(hidden_size, hidden_size)self.out = nn.Linear(hidden_size, output_size)self.softmax = nn.LogSoftmax(dim=1)def forward(self, input, hidden):output = self.embedding(input).view(1, 1, -1)output = F.relu(output)output, hidden = self.gru(output, hidden)output = self.softmax(self.out(output[0]))return output, hiddendef initHidden(self):return torch.zeros(1, 1, self.hidden_size, device=device)# 定义带有注意力机制的Decoder
class AttnDecoderRNN(nn.Module):def __init__(self, hidden_size, output_size, dropout_p=0.1, max_length=MAX_LENGTH):super(AttnDecoderRNN, self).__init__()self.hidden_size = hidden_sizeself.output_size = output_sizeself.dropout_p = dropout_pself.max_length = max_lengthself.embedding = nn.Embedding(self.output_size, self.hidden_size)# attention的输入是词嵌入向量和隐状态# 所以输入维度是self.hidden_size*2# 因为Decoder输出的句子长度不确定# 所以这里输出维度直接取最大了self.attn = nn.Linear(self.hidden_size * 2, self.max_length)self.attn_combine = nn.Linear(self.hidden_size * 2, self.hidden_size)self.dropout = nn.Dropout(self.dropout_p)self.gru = nn.GRU(self.hidden_size, self.hidden_size)self.out = nn.Linear(self.hidden_size, self.output_size)def forward(self, input, hidden, encoder_outputs):embedded = self.embedding(input).view(1, 1, -1)embedded = self.dropout(embedded)attn_weights = F.softmax(self.attn(torch.cat((embedded[0], hidden[0]), 1)), dim=1)# 将encoder的输出乘以注意力权重attn_applied = torch.bmm(attn_weights.unsqueeze(0),encoder_outputs.unsqueeze(0))output = torch.cat((embedded[0], attn_applied[0]), 1)output = self.attn_combine(output).unsqueeze(0)output = F.relu(output)output, hidden = self.gru(output, hidden)output = F.log_softmax(self.out(output[0]), dim=1)return output, hidden, attn_weightsdef initHidden(self):return torch.zeros(1, 1, self.hidden_size, device=device)# 句子->索引
def indexesFromSentence(lang, sentence):return [lang.word2index[word] for word in sentence.split(' ')]# 将句子转换为张量
def tensorFromSentence(lang, sentence):indexes = indexesFromSentence(lang, sentence)indexes.append(EOS_token)return torch.tensor(indexes, dtype=torch.long, device=device).view(-1, 1)# 将数据集中的一个样本转换为张量
def tensorsFromPair(pair):input_tensor = tensorFromSentence(input_lang, pair[0])target_tensor = tensorFromSentence(output_lang, pair[1])return input_tensor, target_tensorteacher_forcing_ratio = 0.5def train(input_tensor, target_tensor, encoder, decoder, encoder_optimizer, decoder_optimizer, criterion,max_length=MAX_LENGTH):# 初始化Encoder的隐藏层encoder_hidden = encoder.initHidden()# 梯度清零encoder_optimizer.zero_grad()decoder_optimizer.zero_grad()# 输入输出的长度input_length = input_tensor.size(0)target_length = target_tensor.size(0)encoder_outputs = torch.zeros(max_length, encoder.hidden_size, device=device)loss = 0# 将一句话中的每个词语输入到Encoder中for ei in range(input_length):encoder_output, encoder_hidden = encoder(input_tensor[ei], encoder_hidden)# 获取每一步的输出encoder_outputs[ei] = encoder_output[0, 0]# decoder的输入是一个SOS标记decoder_input = torch.tensor([[SOS_token]], device=device)# 隐状态是Encoder的最后的隐状态输出decoder_hidden = encoder_hidden# 是否使用teacher_force的训练模式use_teacher_forcing = True if random.random() < teacher_forcing_ratio else Falseif use_teacher_forcing:# 如果指定了teacher_force训练模式# decoder每一步的输入是真实target中的词语for di in range(target_length):decoder_output, decoder_hidden, decoder_attention = decoder(decoder_input, decoder_hidden, encoder_outputs)loss += criterion(decoder_output, target_tensor[di])decoder_input = target_tensor[di]else:# 指没有指定teacher_force训练模式# decoder的下一步的输入是decoder上一步的输出for di in range(target_length):decoder_output, decoder_hidden, decoder_attention = decoder(decoder_input, decoder_hidden, encoder_outputs)topv, topi = decoder_output.topk(1)decoder_input = topi.squeeze().detach()loss += criterion(decoder_output, target_tensor[di])# 如果已经翻译完了if decoder_input.item() == EOS_token:break# 反向传播loss.backward()# 梯度更新encoder_optimizer.step()decoder_optimizer.step()return loss.item() / target_lengthimport time
import math# 秒到分钟转换
def asMinutes(s):m = math.floor(s / 60)s -= m * 60return '%dm %ds' % (m, s)# 获取运行时间间隔
def timeSince(since, percent):now = time.time()s = now - sincees = s / percentrs = es - sreturn '%s (- %s)' % (asMinutes(s), asMinutes(rs))def trainIters(encoder, decoder, n_iters, print_every=1000, plot_every=100, learning_rate=0.01):start = time.time()plot_losses = []print_loss_total = 0plot_loss_total = 0# 随机梯度下降优化encoder_optimiz.er = optim.SGD(encoder.parameters(), lr=learning_rate)decoder_optimizer = optim.SGD(decoder.parameters(), lr=learning_rate)# 获取训练数据training_pairs = [tensorsFromPair(random.choice(pairs))for i in range(n_iters)]# NLLLoss()+LogSoftmax()=CrossEntropy()criterion = nn.NLLLoss()for iter in range(1, n_iters + 1):training_pair = training_pairs[iter - 1]input_tensor = training_pair[0]target_tensor = training_pair[1]loss = train(input_tensor, target_tensor, encoder,decoder, encoder_optimizer, decoder_optimizer, criterion)print_loss_total += lossplot_loss_total += lossif iter % print_every == 0:print_loss_avg = print_loss_total / print_everyprint_loss_total = 0print('%s (%d %d%%) %.4f' % (timeSince(start, iter / n_iters),iter, iter / n_iters * 100, print_loss_avg))if iter % plot_every == 0:plot_loss_avg = plot_loss_total / plot_everyplot_losses.append(plot_loss_avg)plot_loss_total = 0showPlot(plot_losses)import matplotlib.pyplot as pltplt.switch_backend('agg')
import matplotlib.ticker as ticker# 画图
def showPlot(points):plt.figure()fig, ax = plt.subplots()loc = ticker.MultipleLocator(base=0.2)ax.yaxis.set_major_locator(loc)plt.plot(points)# 模型验证
def evaluate(encoder, decoder, sentence, max_length=MAX_LENGTH):with torch.no_grad():input_tensor = tensorFromSentence(input_lang, sentence)input_length = input_tensor.size()[0]encoder_hidden = encoder.initHidden()encoder_outputs = torch.zeros(max_length, encoder.hidden_size, device=device)for ei in range(input_length):encoder_output, encoder_hidden = encoder(input_tensor[ei],encoder_hidden)encoder_outputs[ei] += encoder_output[0, 0]decoder_input = torch.tensor([[SOS_token]], device=device)  # SOSdecoder_hidden = encoder_hiddendecoded_words = []decoder_attentions = torch.zeros(max_length, max_length)for di in range(max_length):decoder_output, decoder_hidden, decoder_attention = decoder(decoder_input, decoder_hidden, encoder_outputs)decoder_attentions[di] = decoder_attention.datatopv, topi = decoder_output.data.topk(1)if topi.item() == EOS_token:decoded_words.append('<EOS>')breakelse:decoded_words.append(output_lang.index2word[topi.item()])decoder_input = topi.squeeze().detach()return decoded_words, decoder_attentions[:di + 1]def evaluateRandomly(encoder, decoder, n=10):for i in range(n):pair = random.choice(pairs)print('>', pair[0])print('=', pair[1])output_words, attentions = evaluate(encoder, decoder, pair[0])output_sentence = ' '.join(output_words)print('<', output_sentence)print('')hidden_size = 256
encoder1 = EncoderRNN(input_lang.n_words, hidden_size).to(device)
attn_decoder1 = AttnDecoderRNN(hidden_size, output_lang.n_words, dropout_p=0.1).to(device)
trainIters(encoder1, attn_decoder1, 75000, print_every=5000)
evaluateRandomly(encoder1, attn_decoder1)
output_words, attentions = evaluate(encoder1, attn_decoder1, "je suis trop froid .")
plt.matshow(attentions.numpy())# 可视化注意力
def showAttention(input_sentence, output_words, attentions):fig = plt.figure()ax = fig.add_subplot(111)cax = ax.matshow(attentions.numpy(), cmap='bone')fig.colorbar(cax)ax.set_xticklabels([''] + input_sentence.split(' ') +['<EOS>'], rotation=90)ax.set_yticklabels([''] + output_words)ax.xaxis.set_major_locator(ticker.MultipleLocator(1))ax.yaxis.set_major_locator(ticker.MultipleLocator(1))plt.show()def evaluateAndShowAttention(input_sentence):output_words, attentions = evaluate(encoder1, attn_decoder1, input_sentence)print('input =', input_sentence)print('output =', ' '.join(output_words))showAttention(input_sentence, output_words, attentions)evaluateAndShowAttention("elle a cinq ans de moins que moi .")
evaluateAndShowAttention("elle est trop petit .")
evaluateAndShowAttention("je ne crains pas de mourir .")
evaluateAndShowAttention("c est un jeune directeur plein de talent .")

如何利用PyTorch实现一个Encoder-Decoder结构进行英法互译相关推荐

  1. 爬虫的一个小案例:python实现英汉互译

    什么是网络爬虫? 网络爬虫又称网络蜘蛛,是指按照某种规则在网络上爬取所需内容的脚本程序.众所周知,每个网页通常包含其他网页的入口,网络爬虫则通过一个网址依次进入其他网址获取所需内容. 一个小案例:py ...

  2. 如何利用PyTorch写一个Transformer实现英德互译

    数据集中每一行是一对英语,德语句子对 Transformer模型出处:2017 <Attention is all you need> Transformer中的位置编码是什么意思? ht ...

  3. 用python简易英汉互译界面_python之做一个简易的翻译器(一)

    平时经常在网上翻译一些单词,突发奇想,可不可以直接调某些免费翻译网站的接口呢?然后做一个图形界面的翻译小工具?下面开始实践 1.先找一下有哪些免费翻译的接口 百度了一下关键字"免费翻译接口& ...

  4. 用python设计一个简易的英汉互译界面_使用python一步一步搭建微信公众平台(二)----搭建一个中英互译的翻译工具...

    距离上次写使用python一步一步搭建微信公众平台(一)已经有几个月了,当中自已也搭建了一个中英文互译的小应用,可是由于英文翻中文好弄,中文翻译成英文一直有问题,知道是编码的问题,但是一直搞不定,于是 ...

  5. 【深度学习】——利用pytorch搭建一个完整的深度学习项目(构建模型、加载数据集、参数配置、训练、模型保存、预测)

    目录 一.深度学习项目的基本构成 二.实战(猫狗分类) 1.数据集下载 2.dataset.py文件 3.model.py 4.config.py 5.predict.py 一.深度学习项目的基本构成 ...

  6. 利用pytorch 做一个简单的神经网络实现sklearn库中莺尾花的分类

    本文针对本人学习pytorch的分类问题,自己写了一个简单的code import numpy as np from collections import Counter from sklearn i ...

  7. 利用有道翻译实现英汉互译

    以下程序需要google jason jar的辅助,你可以从 http://pan.baidu.com/s/17qSuq 这里下载. 程序如下: import java.io.BufferedRead ...

  8. Pytorch:Transformer(Encoder编码器-Decoder解码器、多头注意力机制、多头自注意力机制、掩码张量、前馈全连接层、规范化层、子层连接结构、pyitcast) part1

    日萌社 人工智能AI:Keras PyTorch MXNet TensorFlow PaddlePaddle 深度学习实战(不定时更新) Encoder编码器-Decoder解码器框架 + Atten ...

  9. encoder decoder模型_机器学习11 -- 无监督学习之Auto-Encoder

    1 什么是Auto-Encoder 自编码器Auto-Encoder是无监督学习的一种方式,可以用来做降维.特征提取等.它包括两部分 Encoder:对原始样本进行编码 Decoder:对经过编码后的 ...

  10. GPT模型介绍并且使用pytorch实现一个小型GPT中文闲聊系统

    文章目录 GPT模型介绍 无监督训练方式 模型结构 微调 下游任务输入形式 GPT-2 GPT-3 pytorch实现一个小型GPT中文闲聊系统 GPT模型介绍 GPT与BERT一样也是一种预训练模型 ...

最新文章

  1. BestCoder Round #80 1002
  2. 《JavaScript设计模式与开发实践》模式篇(5)—— 观察者模式
  3. 【收藏】vue3+vite+ts 封装axios踩坑记录
  4. 为什么Spring仍然会是云原生时代最佳平台之一?
  5. 《从零开始学Swift》学习笔记(Day 24)——枚举(Day 24)——枚举
  6. P3156 【深基15.例1】询问学号(20分)--python3实现
  7. java异常没有catch住_今天才真正了解Java的异常处理
  8. 两边填上相同的数_二年级必考题,在括号里填上相同的数~
  9. hive的安装和升级
  10. 表生成器@ TableGenerator
  11. Generic Netlink内核实现分析(二):通信
  12. kubenerte启动_老司机和你深聊Kubenertes 资源分配之 Request 和 Limit 解析
  13. 英特尔显卡驱动 Intel Graphics Driver for Windows 10 v30.0.101.1069 官方正式安装版 64位
  14. python实现猜数字游戏
  15. 计算机考研408专用笔记-----计算机组成原理
  16. 什么是LSI关键词?LSI关键词怎么用?2019
  17. 看完这篇,轻松解决FastReport合并单元格!
  18. 单细胞基础教程:跨条件整合分析
  19. 基于沉积学教材的自顶向下的概念抽取(以沉积相为例为例)
  20. 如何提高测试人员问题分析能力

热门文章

  1. pubg服务器未响应请求超时,PUBG进入游戏连接超时怎么办 | 手游网游页游攻略大全...
  2. 三星android文件传输,三星手机怎么连接电脑?三星手机连接电脑传输文件教程...
  3. 躲避球av_躲避球HTML!
  4. codewars练习(javascript)-2021/1/24
  5. linux下配置dnx地址,Linux上编译DNX失败
  6. 微擎 人人商城 对接京东vop 对接京东商品,同步商品 地址,库存,价格,上下架等。五 (下)京东后台提交订单,通知用户...
  7. 《炬丰科技-半导体工艺》通过蚀刻技术为LED衬底开发低成本、高通量的硅
  8. ccf认证--201809-1 卖菜(100分)
  9. RFID固定资产管理系统是如何盘点固定资产的?
  10. 2021年5大国货品牌引爆互联网背后的营销逻辑