版权声明:博客文章都是作者辛苦整理的,转载请注明出处,谢谢!http://blog.csdn.net/m0_37306360/article/details/79318644
简介
在这个项目中,我们将使用PyTorch框架实现一个神经网络,这个网络实现法文翻译成英文。这个项目是Sean Robertson写的稍微复杂一点的教程,但对学习PyTorch还是有很大的帮助。

本文通过序列网络的这种简单而强大的思想来实现的,其中包括两个循环神经网络一起工作以将一个序列转换为另一个序列。 编码器网络(Encode)将输入序列压缩成矢量,解码器网络(Decode)将该矢量展开为新的序列。为了改进这个模型,我们将使用一个注意机制,让解码器学习把注意力集中在输入序列的特定范围上。

关于这些技术,更多的学习资料可以在下面网址学习:http://pytorch.org/tutorials/intermediate/seq2seq_translation_tutorial.html

数据集
这个项目的数据是一组数以千计的英语到法语的翻译对。作者选取了其中部分数据构建本文的训练数据集(data / eng-fra.txt)。 该文件是一个制表符分隔的翻译对列表(下载地址:https://download.pytorch.org/tutorial/data.zip):

我们才有one-hot vector初始化词,与前面分类名词不同的是,这里把单词看作一个独立的语言粒度:

我们需要每个单词的唯一索引作为以后网络的输入(inputs)和目标(targets)。 为此,我们使用名为Lang的助手类,它具有词→索引(word2index)和索引→词(index2word)字典,以及每个单词word2count的计数以用于稍后替换罕见词语。

SOS_token = 0
EOS_token = 1

class Lang:
def __init__(self, name):
self.name = name
self.word2index = {}
self.word2count = {}
self.index2word = {0: "SOS", 1: "EOS"}
self.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:
self.word2index[word] = self.n_words
self.word2count[word] = 1
self.index2word[self.n_words] = word
self.n_words += 1
else:
self.word2count[word] += 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
要读取数据文件,我们将文件分割成几行,然后将行分成两部分。 这些文件都是英文→其他语言,所以如果我们想从其他语言翻译→英文,我添加了reverse标志来反转对。

def readLangs(lang1, lang2, reverse=False):
print("Reading lines...")

# Read the file and split into lines
lines = open('data/%s-%s.txt' % (lang1, lang2), encoding='utf-8').\
read().strip().split('\n')

# Split every line into pairs and normalize
pairs = [[normalizeString(s) for s in l.split('\t')] for l in lines]

# Reverse pairs, make Lang instances
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
本文数据预处理过程是:
1.读取文本文件并拆分成行,将行拆分成对
2.使文本标准化,按照长度和内容进行过滤
3.从成对的句子中构建单词列表

Seq2Seq模型
Seq2Seq(Sequence to Sequence network or Encoder Decoder network)是由两个称为编码器和解码器的RNN组成的模型。 编码器读取输入序列并输出单个矢量,解码器读取该矢量以产生输出序列。

与单个RNN的序列预测不同,每个输入对应于一个输出,seq2seq模型无需考虑序列长度和顺序,这使得它成为两种语言之间翻译的理想选择。使用seq2seq模型,编码器会创建一个单一的矢量,在理想的情况下,将输入序列的“含义”编码为单个矢量 - 句子的N维空间中的单个点。

The Encoder
seq2seq网络的编码器是一个RNN,它为输入句子中的每个单词输出一些值。 对于每个输入单词,编码器输出一个向量和一个隐藏状态,这个隐藏状态和下一个单词构成下一步的输入。

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)
self.gru = nn.GRU(hidden_size, hidden_size)

def forward(self, input, hidden):
embedded = self.embedding(input).view(1, 1, -1)
output = embedded
output, hidden = self.gru(output, hidden)
return output, hidden

def initHidden(self):
result = Variable(torch.zeros(1, 1, self.hidden_size))
return result
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
The Decoder
解码器是另一个RNN,它接收编码器输出向量并输出一个字序列来创建翻译。

在最简单的seq2seq解码器中,我们只使用编码器的最后一个输出。 这个最后的输出有时被称为上下文向量,因为它从整个序列编码上下文。 该上下文向量被用作解码器的初始隐藏状态。如果仅在编码器和解码器之间传递上下文向量,则该单个向量承担编码整个句子的负担。注意力(Attention 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_size
self.output_size = output_size
self.dropout_p = dropout_p
self.max_length = max_length

self.embedding = nn.Embedding(self.output_size, self.hidden_size)
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)
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_weights

def initHidden(self):
result = Variable(torch.zeros(1, 1, self.hidden_size))
return result
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
训练和测试模型
loss 图:

评估与训练大部分相同,但没有目标(target),因此我们只是将解码器的预测反馈给每一步的自身。 每当它预测到一个单词时,我们就会将它添加到输出字符串中,并且当生成EOS字符就停止。 我们还存储解码器的注意力输出以供稍后显示。

可视化Attention,这个机制的一个有用特性是其高度可解释的输出。 因为它用于对输入序列的特定编码器输出进行加权,所以我们可以想象在每个时间步骤中网络最集中的位置。这里将注意力输出显示为矩阵,其中列是输入步骤,行是输出步骤:

更好的观看体验,我们额外用了几个数据对:

注意:所以的代码基本上为教程上的,我跑通的代码稍微会上传到github上。

参考:http://pytorch.org/tutorials/intermediate/seq2seq_translation_tutorial.html
---------------------
作者:yuquanle
来源:CSDN
原文:https://blog.csdn.net/m0_37306360/article/details/79318644
版权声明:本文为博主原创文章,转载请附上博文链接!

PyTorch: 序列到序列模型(Seq2Seq)实现机器翻译实战的更多相关文章

  1. TensorFlow文本与序列的深度模型

    TensorFlow深度学习笔记 文本与序列的深度模型 Deep Models for Text and Sequence 转载请注明作者:梦里风林Github工程地址:https://github. ...

  2. 序列!序列!- 零基础入门学习Python016

    序列!序列! 让编程改变世界 Change the world by program 你可能发现了,小甲鱼把列表.元组和字符串放在一块儿来讲解是有道理的,我们发现Ta们之间有很多共同点: 1. 都可以 ...

  3. [HNOI2009]双递增序列(动态规划,序列dp)

    感觉这个题还蛮难想的. 首先状态特别难想.设\(dp[i][j]\)表示前i个数,2序列的长度为j的情况下,2序列的最后一个数的最小值. 其中1序列为上一个数所在的序列,2序列为另外一个序列. 这样设 ...

  4. Oracle 序列(查询序列的值,修改序列的值)

    1.序列的语法形式 create sequence 序列名 increment by n start with n maxvalue n | nomaxvalue minvalue n | nomin ...

  5. MindSpore模型精度调优实战:常用的定位精度调试调优思路

    摘要:在模型的开发过程中,精度达不到预期常常让人头疼.为了帮助用户解决模型调试调优的问题,我们为MindSpore量身定做了可视化调试调优组件:MindInsight. 本文分享自华为云社区<技 ...

  6. MindSpore模型精度调优实战:如何更快定位精度问题

    摘要:为大家梳理了针对常见精度问题的调试调优指南,将以"MindSpore模型精度调优实战"系列文章的形式分享出来,帮助大家轻松定位精度问题,快速优化模型精度. 本文分享自华为云社 ...

  7. TensorFlow深度学习笔记 文本与序列的深度模型

    Deep Models for Text and Sequence 转载请注明作者:梦里风林 Github工程地址:https://github.com/ahangchen/GDLnotes 欢迎st ...

  8. pytorch对可变长度序列的处理

    主要是用函数torch.nn.utils.rnn.PackedSequence()和torch.nn.utils.rnn.pack_padded_sequence()以及torch.nn.utils. ...

  9. 用序列到序列和注意模型实现的:Translation with a Sequence to Sequence Network and Attention

    In this project we will be teaching a neural network to translate from French to English. 最后效果: [KEY ...

随机推荐

  1. bzoj 3872 [ Poi 2014 ] Ant colony —— 二分

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3872 从食蚁兽所在的边向叶节点推,会得到一个渐渐放大的取值区间,在叶子节点上二分有几群蚂蚁符 ...

  2. Oracle “CONNECT BY” 用法

    Oracle “CONNECT BY”是层次查询子句,一般用于树状或者层次结果集的查询.其语法是: [ START WITH condition ] CONNECT BY [ NOCYCLE ] co ...

  3. 虚拟机安装hadoop

    1.用VMware建立两台虚拟机(Centos6.5)系统,并设立主机名为node1与node2 2.设置虚拟机网络两台都是设置为如图: 3.修改两台虚拟机的/etc/hosts的文件为 (其中192 ...

  4. #if、#ifdef、#if defined之间的区别(转载)

    转自:http://www.yucoat.com/c_program/difference_if_ifdef_if_defined.html #if的使用说明 #if的后面接的是表达式 #if (MA ...

  5. bzoj 2525: [Poi2011]Dynamite【二分+树上贪心】

    一眼二分.然后重点是树上贪心部分 长得像dp一样,设mn为子树内已炸点的最浅点,mx为子树内没有炸并且需要炸的最深点,然后转移直接从子树继承即可 然后是判断当前u点是否需要炸,当mx[u]+mn[u] ...

  6. js 调试方法两种

    JS的错误捕获一般有下面两种方式: 1. 异常捕获常用方法是 try/catch/ throw /finally 2. 全局捕获window.onerror 1. try/catch/throw/fi ...

  7. vue中使用element写点击input内部标签(使用模态框传值)

    首先附上源码地址 https://files.cnblogs.com/files/maruihua/vue-tagsinput-master.zip 这个是我修改后的代码.取消了部分功能,添加的一些功 ...

  8. VS 2017 产品密钥

    Visual Studio 2017(VS2017) 企业版 Enterprise 注册码:NJVYC-BMHX2-G77MM-4XJMR-6Q8QFVisual Studio 2017(VS2017 ...

  9. mysql 循环批量插入

    背景 前几天在MySql上做分页时,看到有博文说使用 limit 0,10 方式分页会有丢数据问题,有人又说不会,于是想自己测试一下.测试时没有数据,便安装了一个MySql,建了张表,在建了个whil ...

  10. 基于.Net Core的API框架的搭建(1)

    目标 我们的目标是要搭建一个API控制器的项目,API控制器提供业务服务. 一.开发框架搭建 1.开发前准备 开发前,我们需要下载如下软件,安装过程略: (1) 开发工具:VS2017 (2) 数据库 ...