【NLP练习】使用seq2seq实现文本翻译

使用seq2seq实现文本翻译

  • 🍨 本文为🔗365天深度学习训练营 中的学习记录博客
  • 🍖 原作者:K同学啊
from __future__ import unicode_literals, print_function, division
from io import open
import unicodedata
import string
import re
import randomimport torch
import torch.nn as nn
from torch import optim
import torch.nn.functional as Fdevice = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(device)

输出:

cpu

一、前期准备工作

1. 搭建语言类

定义了两个常量SOS_token和EOS_token,其分别代表序列的开始和结束。
Lang类,用于方便对语料库进行操作:

  • word2index是一个字典,将单词映射到索引
  • word2count是一个字典,记录单词出现的次数
  • index2word是一个字典,将索引映射到单词
  • n_words是单词的数量,初始值为2,因为序列开始和结束的单词已经被添加
  • addSentence方法:用于向Lang类中添加一个句子,它会调用addWord方法将句子中的每个添加到Lang类中
  • addWord方法:将单词添加到word2index、word2count和index2word中,则将word2count中对应的计数器加1
SOS_token = 0
EOS_token = 1# 语言类,方便对语料库进行操作
class Lang:def __init__(self, name):self.name = nameself.word2index = {}self.word2count = {}self.index2word = {0: "SOS", 1: "EOS"}self.n_words    = 2  # Count SOS and EOSdef 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_wordsself.word2count[word] = 1self.index2word[self.n_words] = wordself.n_words += 1else:self.word2count[word] += 1

2. 文本处理函数

def unicodeToAscii(s):return ''.join(c for c in unicodedata.normalize('NFD', s)if unicodedata.category(c) != 'Mn')# 小写化,剔除标点与非字母符号
def normalizeString(s):s = unicodeToAscii(s.lower().strip())s = re.sub(r"([.!?])", r" \1", s)s = re.sub(r"[^a-zA-Z.!?]+", r" ", s)return s

3. 文件读取函数

def readLangs(lang1, lang2, reverse=False):print("Reading lines...")# 以行为单位读取文件lines = open('data 2/%s-%s.txt'%(lang1,lang2), encoding='utf-8').\read().strip().split('\n')# 将每一行放入一个列表中# 一个列表中有两个元素,A语言文本与B语言文本pairs = [[normalizeString(s) for s in l.split('\t')] for l in lines]# 创建Lang实例,并确认是否反转语言顺序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

.startswith(eng_prefixes) 是字符串方法 startswith() 的调用。它用于检查一个字符串是否以指定的前缀开始。

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[1].startswith(eng_prefixes)def filterPairs(pairs):# 选取仅仅包含 eng_prefixes 开头的语料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))

输出:

Reading lines...
Read 135842 sentence pairs
Trimmed to 10599 sentence pairs
Counting words...
Counted words:
fra 4345
eng 2803
['je suis desole nous avons tout vendu .', 'i m sorry we re completely sold out .']

二、Seq2Seq模型

1. 编码器(Encoder)

class EncoderRNN(nn.Module):def __init__(self, input_size, hidden_size):super(EncoderRNN, self).__init__()self.hidden_size = hidden_sizeself.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         = embeddedoutput, hidden = self.gru(output, hidden)return output, hiddendef initHidden(self):return torch.zeros(1, 1, self.hidden_size, device=device)

2. 解码器(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)

三、训练

1. 数据预处理

# 将文本数字化,获取词汇index
def indexesFromSentence(lang, sentence):return [lang.word2index[word] for word in sentence.split(' ')]# 将数字化的文本,转化为tensor数据
def tensorFromSentence(lang, sentence):indexes = indexesFromSentence(lang, sentence)indexes.append(EOS_token)return torch.tensor(indexes, dtype=torch.long, device=device).view(-1, 1)# 输入pair文本,输出预处理好的数据
def tensorsFromPair(pair):input_tensor  = tensorFromSentence(input_lang, pair[0])target_tensor = tensorFromSentence(output_lang, pair[1])return (input_tensor, target_tensor)

2. 训练函数

teacher_forcing_ratio = 0.5def train(input_tensor, target_tensor, encoder, decoder, encoder_optimizer, decoder_optimizer, criterion, max_length=MAX_LENGTH):# 编码器初始化encoder_hidden = encoder.initHidden()# grad属性归零encoder_optimizer.zero_grad()decoder_optimizer.zero_grad()input_length  = input_tensor.size(0)target_length = target_tensor.size(0)# 用于创建一个指定大小的全零张量(tensor),用作默认编码器输出encoder_outputs = torch.zeros(max_length, encoder.hidden_size, device=device)loss = 0# 将处理好的语料送入编码器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)decoder_hidden = encoder_hiddenuse_teacher_forcing = True if random.random() < teacher_forcing_ratio else False# 将编码器处理好的输出送入解码器if use_teacher_forcing:# Teacher forcing: Feed the target as the next inputfor di in range(target_length):decoder_output, decoder_hidden = decoder(decoder_input, decoder_hidden)loss         += criterion(decoder_output, target_tensor[di])decoder_input = target_tensor[di]  # Teacher forcingelse:# Without teacher forcing: use its own predictions as the next inputfor di in range(target_length):decoder_output, decoder_hidden = decoder(decoder_input, decoder_hidden)topv, topi    = decoder_output.topk(1)decoder_input = topi.squeeze().detach()  # detach from history as inputloss         += criterion(decoder_output, target_tensor[di])if decoder_input.item() == EOS_token:breakloss.backward()encoder_optimizer.step()decoder_optimizer.step()return loss.item() / target_length
import time
import mathdef 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 / (percent)rs = 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 = 0  # Reset every print_everyplot_loss_total  = 0  # Reset every plot_everyencoder_optimizer = optim.SGD(encoder.parameters(), lr=learning_rate)decoder_optimizer = optim.SGD(decoder.parameters(), lr=learning_rate)# 在 pairs 中随机选取 n_iters 条数据用作训练集training_pairs    = [tensorsFromPair(random.choice(pairs)) for i in range(n_iters)]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 = 0return plot_losses

四、训练与评估

hidden_size   = 256
encoder1      = EncoderRNN(input_lang.n_words, hidden_size).to(device)
attn_decoder1 = DecoderRNN(hidden_size, output_lang.n_words).to(device)plot_losses = trainIters(encoder1, attn_decoder1, 20000, print_every=5000)

输出:

6m 50s (- 20m 30s) (5000 25%) 2.9215
14m 27s (- 14m 27s) (10000 50%) 2.3530
20m 23s (- 6m 47s) (15000 75%) 2.0427
26m 51s (- 0m 0s) (20000 100%) 1.7899
import matplotlib.pyplot as plt
#隐藏警告
import warnings
warnings.filterwarnings("ignore")               # 忽略警告信息
# plt.rcParams['font.sans-serif']    = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False      # 用来正常显示负号
plt.rcParams['figure.dpi']         = 100        # 分辨率epochs_range = range(len(plot_losses))plt.figure(figsize=(8, 3))plt.subplot(1, 1, 1)
plt.plot(epochs_range, plot_losses, label='Training Loss')
plt.legend(loc='upper right')
plt.title('Training Loss')
plt.show()

输出:
在这里插入图片描述

五、总结

Teacher Forcing可通过将目标序列的真实值作为解码器的输入,帮助解码器更快的学习到正确的输出

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3029983.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

Ubuntu/Linux 安装Docker + PyTorch

文章目录 1. 提前准备2. 安装Docker2.1. 卸载冲突软件&#xff08;非必要&#xff09;2.2. 在Ubuntu系统上添加Docker的官方GPG密钥2.3. 将Docker的仓库添加到Ubuntu系统的APT源列表中2.4. 安装最新Docker2.5. 检查 3. 安装Nvidia Container Toolkit3.1. 在Ubuntu系统上添加官方…

1688一键采购1000+商品||1688API数据采集接口||1688官方合作伙伴如何实现1688代采

货源采购是跨境电商卖家日常工作的一个重要部分&#xff0c;1688平台是很多卖家常用的货源采购平台。在1688平台采购时&#xff0c;很多卖家会进行批量采购&#xff0c;可能会达到上百甚至上千单&#xff0c;如果一件一件的采购&#xff0c;可能会浪费卖家大量的时间。我们可以…

【java9】java9新特性之改进JavaDocs

Java9在JavaDocs方面的主要新特性是&#xff0c;其输出现在符合兼容HTML5标准。在之前的版本中&#xff0c;默认的HTML版本是 HTML4.01&#xff0c;但在Java9及之后的版本中&#xff0c;JavaDocs命令行工具将默认使用HTML5作为输出标记语言。这意味着&#xff0c;使用JavaDocs工…

MemoryModule - exp - test

文章目录 MemoryModule - exp - test概述笔记测试环境GetModuleFileName不能正常执行GetModuleFileNameWntdll_LdrGetDllFullName猜测原因用LoadLibrary载入的DLL中功能是正常的 gLog可以正常使用内存载入DLL无法支持的功能的折中方法COM操作正常调用方代码接口代码 接口入参测…

Visual Studio的使用方法

目录 1. 下载软件 2. 软件安装 3. 软件使用 4. VS工具的字体背景美化 5. 程序调试 1. 下载软件 官网地址&#xff1a;Visual Studio 2022 IDE - 适用于软件开发人员的编程工具 (microsoft.com) 2. 软件安装 1.选中vs_Professional&#xff0c;鼠标右击选择“以管理员身份…

Capl复合数据类型:结构

结构是由一系列的相同或不同的数据类型构成的整体。结构中的每一项数据成为一个成员。每个成员可以有各自的数据类型。所有成员一起表示一个整体结构。 1.定义结构体类型 运行结果 2.修改结构体变量的成员。自定义一个常量给结构体变量的成员重新赋值即可。 3.定义一个结构体类…

【平时工作中的各种术语__持续更新~~~~】

中文&#xff1a; 1、jar包 JAR包&#xff08;Java Archive Package&#xff09;是一种将多个Java类文件以及与它们相关的元数据和资源&#xff08;如文本、图片等&#xff09;打包到一个单一文件中的归档工具。它基于ZIP文件格式。JAR文件主要用于分发和部署Java应用程序。J…

java期末复习

java jdk jre jvm .java-------->.class----jvm---->机器语言 编写源文件 编译源文件生成字节码 加载运行字节码 java语句执行顺序 顺序 选择 循环 异常处理 基本语法 方法格式 权限修饰符 返回值声明 方法名称(参数列表){方法中封装的逻辑功能;return 返回值;}–权…

Mybatis-Plus常用的增删改查坑

添加依赖 <!--实体类上加上Data注解就不用写get&#xff0c;set&#xff0c;toString&#xff0c;equals等方法了--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional…

Xshell连接提示“SSH服务器拒绝了密码”

原因1&#xff1a;数字锁没有打开 没有打开NumLock&#xff08;数字小键盘上面有一个【Num】按键&#xff09;&#xff0c;需要按键开启。 注意要检查NumLock灯是否亮起。 或者改成用字母键上面的数字键输入就好了。 原因2&#xff1a;root密码设置错误&#xff08;这个是比较常…

linux上安装Jmeter环境

以前都是在Windows本机上使用界面版Jmeter&#xff0c;今天试一下安装到linux上在linux中使用&#xff0c;Jmeter的使用需要先安装jdk环境然后再配置jmeter。 1.配置环境 linux环境&#xff1a;Centos 8.2 64位 JDK版本&#xff1a;jdk-8u221-linux-x64.tar.gz &#xff08;…

Python尝试安装 pyaudio 时遇到的错误信息表示安装过程失败,原因是找不到 Python.h 头文件

环境&#xff1a; Python 3.8.10 WSL2 问题描述&#xff1a; 尝试安装 pyaudio 时遇到的错误信息表示安装过程失败&#xff0c;原因是找不到 Python.h 头文件 error: subprocess-exited-with-error Building wheel for pyaudio (pyproject.toml) did not run successfully…

一篇详解Git版本控制工具

华子目录 版本控制集中化版本控制分布式版本控制 Git简史Git工作机制Git和代码托管中心局域网互联网 Git安装基础配置git的--local&#xff0c;--global&#xff0c;--system的区别 创建仓库方式1git init方式2git clone git网址 工作区&#xff0c;暂存区&#xff0c;本地仓库…

程序找茬:统计字符个数问题

【题目描述】 下面的程序意图在于统计字符串中字符1的个数&#xff0c;可惜有瑕疵&#xff1a; #include<stdio.h> #define maxn 10000000 10 int main() {char s[maxn];scanf("%s", s);int tot 0;for(int i 0; i < strlen(s); i)if(s[i] 1) tot;prin…

67万英语单词学习词典ACCESS\EXCEL数据库

这似乎是最多记录的英语单词学习词典&#xff0c;包含复数、过去分词等形式的单词。是一个针对想考级的人员辅助背单词学英语必备的数据&#xff0c;具体请自行查阅以下的相关截图。 有了数据才能想方设法做好产品&#xff0c;结合权威的记忆理论&#xff0c;充分调动用户的眼…

智慧公厕解决什么问题?实现了什么样的价值?

公共厕所一直是城市管理的难题&#xff0c;常常面临着卫生条件不佳、管理不善以及使用体验差等问题。为了解决这些困扰城市的难题&#xff0c;智慧公厕应运而生。智慧公厕不仅应用了信息化和数字化技术&#xff0c;还通过全方位的智能化应用&#xff0c;彻底改变了传统公厕的面…

(九)JSP教程——pageContext对象

pageContext对象是由JSP容器创建并初始化的&#xff0c;相当于当前页面的容器&#xff0c;它可以访问当前页面中的所有对象。它的主要作用是为JSP页面包装上下文&#xff0c;并用于管理属于JSP的特殊可见部分中已命名对象的访问。 一般情况下&#xff0c;使用该对象的应用并不多…

AScript纯本地离线文字识别插件

目的 AScript是一款可以模拟鼠标和键盘操作的自动化工具。它可以帮助用户自动完成一些重复的、繁琐的任务&#xff0c;节省大量人工操作的时间。但按键精灵是不包含图色功能&#xff0c;无法识别屏幕上的图像&#xff0c;根据图像的变化自动执行相应的操作。本篇文章主要讲解下…

java对象互换工具类

1:将Object类型转成json字符串 /*** 将对象转为字符串* param obj* return*/public static String toString(Object obj) {if(obj null) {return null;}if ("".equals(obj.toString())) {return null;}if (obj instanceof String) {return obj.toString();}try {Ob…

QT--5

1> 将网络聊天室重新实现一遍 服务器端 #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);ser new QTcpServer(this); }Widget::~Widget() {delete ui; }vo…