当前位置: 代码迷 >> 综合 >> Seq2Seq实战——机器翻译
  详细解决方案

Seq2Seq实战——机器翻译

热度:12   发布时间:2024-02-02 19:25:38.0

基于seq2seq做一个机器翻译

我们将使用PyTorch和TorchText构建一个机器学习模型,从一个序列到另一个序列。 将德语到英语翻译成英语

该模型是《Sequence to Sequence Learning with Neural Networks》这篇论文的Pytorch实现

 

 

首先是准备数据

import torch
import torch.nn as nn
import torch.optim as optimfrom torchtext.datasets import TranslationDataset, Multi30k
from torchtext.data import Field, BucketIteratorimport spacy
import random
import math
import time#1、preparing data
#设置一个随机种子
SEED = 1234
random.seed(SEED)
torch.manual_seed(SEED)
torch.backends.cudnn.deterministic = True#创建tokenizer
spacy_de = spacy.load('de')
spacy_en = spacy.load('en')#把tokenizer从一串字符转成一个list,同时做一个reverse取反
#在原论文中,作者发现颠倒源语言的输入的顺序可以取得不错的翻译效果,例如,一句话为“good morning!”,颠倒顺序分词后变为"!", “morning”, 和"good"。#将德语进行分词并颠倒顺序
def tokenize_de(text):return [tok.text for tok in spacy_de.tokenizer(text)][::-1]
#将英语进行分词,不颠倒顺序
def tokenize_en(text):return [tok.text for tok in spacy_en.tokenizer(text)]#我们创建SRC和TRG两个Field对象,tokenize为我们刚才定义的分词器函数,在每句话的开头加入字符SOS,结尾加入字符EOS,将所有单词转换为小写。#TorchText的Field定义数据应该如何被处理
#SRC即source,是德语
#TRG即target,是英语
#sos是start of sequence, eos是end of sequence
#lower=True是将所有单词转换为小写
SRC = Field(tokenize = tokenize_de,init_token = '<sos>',eos_token = '<eos>',lower = True)TRG = Field(tokenize = tokenize_en,init_token = '<sos>',eos_token = '<eos>',lower = True)#使用torchtext自带的Multi30k数据集,这是一个包含约30000个平行的英语、德语和法语句子的数据集,每个句子包含约12个单词。
train_data, valid_data, test_data = Multi30k.splits(exts = ('.de', '.en'),fields = (SRC, TRG))#查看一下加载完的数据集
print(f"Number of training examples: {len(train_data.examples)}")
print(f"Number of validation examples: {len(valid_data.examples)}")
print(f"Number of testing examples: {len(test_data.examples)}")#看一下生成的第一个训练样本,可以看到源语言的顺序已经颠倒了
print(vars(train_data.examples[0]))#构建词表
#所谓构建词表,即需要给每个单词编码,也就是用数字表示每个单词,这样才能传入模型。
#可以使用dataset类中的build_vocab()方法传入用于构建词表的数据集。
#注意,源语言和目标语言的词表是不同的,而且词表应该只从训练集构建,而不是验证/测试集,这可以防止“信息泄漏”到模型中。
SRC.build_vocab(train_data, min_freq = 2)
TRG.build_vocab(train_data, min_freq = 2)#查看一下生成的词表大小
print(f"Unique tokens in source (de) vocabulary: {len(SRC.vocab)}")
print(f"Unique tokens in target (en) vocabulary: {len(TRG.vocab)}")#指定GPU还是CPU进行训练
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')#创建迭代器BATCH_SIZE = 128   #设置超参数train_iterator, valid_iterator, test_iterator = BucketIterator.splits((train_data, valid_data, test_data), batch_size = BATCH_SIZE, device = device)#查看一下生成的batch
batch = next(iter(train_iterator))
print(batch)

 

建立Seq2Seq模型

我们将分别创建编码器(Encoder)、解码器(Eecoder)和seq2seq模型。

原论文使用了一个4层的单向LSTM,出于训练时间的考虑,我们将其缩减到了2层。结构如图所示

参数说明:

  • input_dim:输入编码器的one-hot向量的维度,等于源语言词汇表的大小。
  • emb_dim:embedding层的维度
  • hid_dim:隐藏层h和c的维度
  • n_layers:LSTM网络的层数
  • dropout:如果非零的话,将会在LSTM的输出上加个dropout,最后一层除外。

 

在forward函数中,我们传入源语言src,经过embedding层将其转换为密集向量,然后应用dropout,然后将这些词嵌入传递到LSTM。读者可能注意到,我们没有将初始隐藏状态h_0和单元格状态c_0传递给LSTM。这是因为如果没有向LSTM传递隐藏/单元格状态,它将自动创建一个全0的张量作为初始状态。

 

decoder

decoder网络同样是一个2层的LSTM(原论文中为4层),结构如图所示:

在这里插入图片描述

 

 

 

 

 

参考:

https://blog.csdn.net/weixin_43632501/article/details/98731800

  相关解决方案