版权声明:博客文章都是作者辛苦整理的,转载请注明出处,谢谢!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. 表单中的readOnly 和disabled

    readonly和Disabled是用在表单中的两个属性,它们都能够做到使用户不能够更改表单域中的内容.但是它们之间有着微小的差别,总结如下: disabled也可以禁用按钮和链接: <butt ...

  2. RestTemplate中headers中添加Host不生效

    在使用restTemplate访问内网接口时,不打算指host,支持ip访问,所以我们需要再header中指定host.但经调试,发现HttpURLConnection中Host无法覆盖.解决方案: ...

  3. 转载别人的ognl

    一.循环遍历集合 1.在jsp中引入标准函数声明<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix=" ...

  4. infuxdb时序数据库的下载(windows)一

    因为众所周知的原因,点击上图的 “v1.7.6” 发现根本不起作用,其实真正的下载链接就在页面中. 把链接复制下来,拷贝到浏览器中即可下载. 这里面是最新版,如果要下载旧版本的,将链接中的1.7.6替 ...

  5. Jedis线上的一个小坑:Redis有并发访问的数据错乱的问题

    问题现象: 业务数据有错乱,A的一些数据有好几个都是B的数据 这些业务数据在保存在Redis缓存中,怀疑是并发情况下Jedis错乱的问题 原因分析: JedisUtil里面在使用完Jedis 后释放资 ...

  6. Luogu P1396 营救【最小生成树/二分答案/最短路】 By celur925

    题目描述 “咚咚咚……”“查水表!”原来是查水表来了,现在哪里找这么热心上门的查表员啊!小明感动的热泪盈眶,开起了门…… 妈妈下班回家,街坊邻居说小明被一群陌生人强行押上了警车!妈妈丰富的经验告诉她小 ...

  7. poj 3159 Candies dijkstra + queue

    题目链接: http://poj.org/searchproblem 题目大意: 飞天鼠是班长,一天班主任买了一大包糖果,要飞天鼠分发给大家,班里面有n个人,但是学生A认为学生B比自己多的糖果数目不应 ...

  8. glassfish的启动

    一.Glassfish v3 的安装  1. chmod 775/+x glassfish-v3.zip 改权限  2.unzip glassfish-v3.zip  3../asadmin star ...

  9. 准确计算CoreText高度的方法:

    - (int)getAttributedStringHeightWithString:(NSAttributedString *) string WidthValue:(int) width { ; ...

  10. 445 Add Two Numbers II 两数相加 II

    给定两个非空链表来代表两个非负整数.数字最高位位于链表开始位置.它们的每个节点只存储单个数字.将这两数相加会返回一个新的链表.你可以假设除了数字 0 之外,这两个数字都不会以零开头.进阶:如果输入链表 ...