NLP实战6:seq2seq翻译实战-Pytorch复现-小白版

news2024/12/28 12:58:54

目录

一、前期准备

1. 搭建语言类

2. 文本处理函数

3. 文件读取函数

二、Seq2Seq 模型

1. 编码器(Encoder)

2. 解码器(Decoder)

三、训练

1. 数据预处理

2. 训练函数

四、训练与评估


🍨 本文为[🔗365天深度学习训练营]内部限免文章(版权归 *K同学啊* 所有)
🍖 作者:[K同学啊]

📌 本周任务:
●结合训练中N5周的内容理解本文代码

数据集:eng-fra.txt

一、前期准备

from __future__ import unicode_literals, print_function, division
from io import open
import unicodedata
import string
import re
import random

import torch
import torch.nn as nn
from torch import optim
import torch.nn.functional as F

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(device)

cuda

1. 搭建语言类

定义了两个常量 SOS_token 和 EOS_token,其分别代表序列的开始和结束。 Lang 类,用于方便对语料库进行操作:
●word2index 是一个字典,将单词映射到索引
●word2count 是一个字典,记录单词出现的次数
●index2word 是一个字典,将索引映射到单词
●n_words 是单词的数量,初始值为 2,因为序列开始和结束的单词已经被添加

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

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('%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
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, pairs

input_lang, output_lang, pairs = prepareData('eng', 'fra', True)
print(random.choice(pairs))

二、Seq2Seq 模型

1. 编码器(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)
        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):
        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_size
        self.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, hidden

    def initHidden(self):
        return torch.zeros(1, 1, self.hidden_size, device=device)

三、训练

1. 数据预处理

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.5

def 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_hidden

    use_teacher_forcing = True if random.random() < teacher_forcing_ratio else False
    
    # 将编码器处理好的输出送入解码器
    if use_teacher_forcing:
        # Teacher forcing: Feed the target as the next input
        for 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 forcing
    else:
        # Without teacher forcing: use its own predictions as the next input
        for 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 input

            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_length
import time
import math

def asMinutes(s):
    m = math.floor(s / 60)
    s -= m * 60
    return '%dm %ds' % (m, s)

def timeSince(since, percent):
    now = time.time()
    s = now - since
    es = s / (percent)
    rs = es - s
    return '%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_every
    plot_loss_total  = 0  # Reset every plot_every

    encoder_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 += loss
        plot_loss_total  += loss

        if iter % print_every == 0:
            print_loss_avg   = print_loss_total / print_every
            print_loss_total = 0
            print('%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_every
            plot_losses.append(plot_loss_avg)
            plot_loss_total = 0

    return 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, 100000, print_every=5000)

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()

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

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

相关文章

【算法集训之线性表篇】Day 02

文章目录 题目一思路分析代码实现效果 题目二思路分析代码实现效果 题目一 01.设置一个高效算法&#xff0c;将顺序表L的所有元素逆置&#xff0c;要求其空间复杂度为O(1)。 思路分析 首先&#xff0c;根据题目要求&#xff0c;空间复杂度度为O(1),则不能通过空间换时间的方…

为什么编程更关注内存而很少关注CPU?

我们知道&#xff0c;我们编写的程序&#xff0c;不管是什么编程语言&#xff0c;最后执行的时候&#xff0c;基本上都是CPU在完成。之所以说基本上&#xff0c;是因为还有GPU、FPGA等特殊情况。 但不知道大家发现没有&#xff0c;我们编程的时候&#xff0c;经常在关注内存问…

大促转化率精准预估优化论文随笔记

这是一篇阿里妈妈的论文【KDD’23 | 转化率预估新思路&#xff1a;基于历史数据复用的大促转化率精准预估】 常规的销量预测&#xff0c;遇到一些特大事件&#xff0c;直播、大促&#xff0c;一般很难预估得准确。而且现在电商机制也比较多样&#xff0c;预售、平台折扣等。 本…

初识MySQL:了解MySQL特性、体系结构以及在Linux中部署MySQL

目录 MySQL简介 MySQL特性 MySQL体系结构 SQL的四个层次&#xff1a; 连接层&#xff1a; SQL层&#xff1a; 插件式存储引擎&#xff1a; 物理文件层&#xff1a; 一条SQL语句的执行流程&#xff1a; MySQL在Linux中的安装、部署 首先需要下载mysql软件包&#xff…

月入9000+的CSGO游戏搬砖项目操作细节和疑问 ?给您一一解答

科思创业汇 大家好&#xff0c;这里是科思创业汇&#xff0c;一个轻资产创业孵化平台。赚钱的方式有很多种&#xff0c;我希望在科思创业汇能够给你带来最快乐的那一种&#xff01; 01 海外CSGO游戏搬砖项目是什么&#xff1f; csgo搬砖是在外服steam上购买包含印花枪皮等等…

9.2、增量表数据同步

1、数据通道 2、Flume配置 1&#xff09;Flume配置概述 Flume需要将Kafka中topic_db主题的数据传输到HDFS&#xff0c;故其需选用KafkaSource以及HDFSSink&#xff0c;Channel选用FileChannel。 需要注意的是&#xff0c; HDFSSink需要将不同mysql业务表的数据写到不同的路径…

2023.7.4 Dataloader切分

一、 如果文件夹路径是 path/to/folder with spaces/&#xff0c;使用以下方式输入 path/to/folder\ with\ spaces/或者使用引号包裹路径&#xff1a; "path/to/folder with spaces/"这样可以确保命令行正确解析文件夹路径&#xff0c;并将空格作为路径的一部分进…

ADB自动化测试框架

一、介绍 adb的全称为Android Debug Bridge&#xff0c;就是起到调试桥的作用&#xff0c;利用adb工具的前提是在手机上打开usb调试&#xff0c;然后通过数据线连接电脑。在电脑上使用命令模式来操作手机&#xff1a;重启、进入recovery、进入fastboot、推送文件功能等。简单来…

Intellij IDEA 初学入门图文教程(八) —— IDEA 在提交代码时 Performing Code Analysis 卡死

在使用 IDEA 开发过程中&#xff0c;提交代码时常常会在碰到代码中的 JS 文件时卡死&#xff0c;进度框上显示 Performing Code Analysis&#xff0c;如图&#xff1a; 原因是 IDEA 工具默认提交代码时&#xff0c;分析代码功能是打开的&#xff0c;需要通过配置关闭下就可以了…

Linux高性能网络编程:TCP底层的收发过程

今天探索高性能网络编程&#xff0c;但是我觉得在谈系统API之前可以先讲一些Linux底层的收发包过程&#xff0c;如下这是一个简单的socket编程代码&#xff1a; int main() {... fd socket(AF_INET, SOCKET_STREAM, 0);bind(fd, ...);listen(fd, ...);// 如何建立连接...afd …

冒泡排序法(优化与实例演示)

冒泡排序法 冒泡排序法基本介绍 冒泡排序是一种简单而经典的排序算法&#xff0c;它的原理是通过不断比较相邻元素的大小并交换位置&#xff0c;将较大&#xff08;或较小&#xff09;的元素逐渐“冒泡”到数组的末尾。这个过程持续进行多轮&#xff0c;直到整个数组按照顺序…

【Zabbix 6.0 监控系统安装和部署】

目录 一、Zabbix 介绍1、zabbix 是什么&#xff1f;2、zabbix 监控原理&#xff08;重点&#xff09;3、Zabbix 6.0 新特性4、Zabbix 6.0 功能组件1、Zabbix Server2、数据库3、Web 界面4、Zabbix Agent5、Zabbix Proxy6、Java Gateway 二、Zabbix 6.0 部署1、部署 zabbix 服务…

idea goland 插件 struct to struct

go-struct-to-struct idea goland 插件。实现自动生成 struct 间 转换代码。 https://plugins.jetbrains.com/plugin/22196-struct-to-struct/ IntelliJ plugin that Automatically generate two struct transformations through function declarations Usage define func …

【怎么实现多组输入之EOF】

C语言怎么实现多组输入之EOF C语言之EOF介绍1、什么是EOF&#xff1f;2、EOF的用法3、EOF的扩展3.1、scanf返回值之EOF3.2、scanf函数的返回值有以下几种情况 4、如何是实现多组输入&#xff1f;4.1、多组输入---- 常规写法例程14.2、多组输入---- 实现多组输入的打印例程24.3、…

不想被卷的程序员们,应该学什么?

我真的好像感慨一下&#xff0c;这个世界真的给计算机应届生留活路了吗&#xff1f; 看着周围的同学&#xff0c;打算搞前端、JAVA、C、C的&#xff0c;一个两个去跑去应聘。你以为是00后整治职场&#xff1f; 真相是主打一个卑微&#xff1a;现阶段以学习为主&#xff08;工…

探寻日本区块链游戏的未来潜力

日本的区块链游戏 日本是全球范围内游戏市场人均利润最高的国家之一。其中&#xff0c;《My Crypto Heroes》的首次公售金额达到了 16,000 ETH。 关键要点&#xff1a; 日本具有强大的游戏基础&#xff0c;使其成为加密游戏发展的理想地区。 日本流行的加密货币游戏包括《My…

Python中jsonpath库使用,及与xpath语法区别

jsonpath库使用 pip install jsonpath 基本语法 JSONPath语法元素和对应XPath元素的对比

Work20230705

//main.c #include "uart4.h" extern void printf(const char *fmt, ...); void delay_ms(int ms) {int i,j;for(i 0; i < ms;i)for (j 0; j < 1800; j); }int main() {while(1){//将获取到的字符1发送到终端//hal_put_char(hal_get_char()1);hal_put_string…

POSTGRESQL SQL 执行用 IN 还是 EXISTS 还是 ANY

开头还是介绍一下群&#xff0c;如果感兴趣polardb ,mongodb ,mysql ,postgresql ,redis 等有问题&#xff0c;有需求都可以加群群内有各大数据库行业大咖&#xff0c;CTO&#xff0c;可以解决你的问题。加群请联系 liuaustin3 &#xff0c;在新加的朋友会分到3群&#xff08;共…

【后端面经-计算机基础】HTTP和TCP的区别

【后端面经-计算机基础】HTTP和TCP的区别 文章目录 【后端面经-计算机基础】HTTP和TCP的区别1. OSI七层模型和相关协议2. TCP协议2.1 特点&#xff1a;2.2 报文格式2.3 三次握手和四次挥手 3. HTTP协议3.1 特点3.2 报文格式3.2 https和http 4. HTTP vs TCP5. 面试模拟参考资料 …