深度学习实践(一)基于Transformer英译汉模型

news2024/11/24 20:45:58

本文目录

  • 前述
  • 一、环境依赖
  • 二、数据准备
    • 1. 数据加载
    • 2. 构建单词表
      • 程序解析
        • (1)将列表里每个子列表的所有单词合并到一个新列表(没有子列表)中。
        • (2)Counter()-- 统计迭代对象各元素出现次数,并按次数从多到少排序
        • (3)获取出现频率最高的前 50000 个元素及其个数。
        • (4) 建立字典word_dict{ }:存放元素及其索引号
        • (5) 建立字典index_dict{ }---{ 索引号:元素 }
    • 3. 将英文、中文单词列表转为单词索引列表
    • 4. 划分batch
  • 三、模型搭建

前述

基础请查看:Transformer基础查看地址!

一、环境依赖

nltk==3.5
numpy==1.18.5
seaborn==0.11.1
matplotlib==3.3.2
psyco==1.6
zhtools==0.0.5

#torch==1.12.1 安装torch时使用下面的命令
pip install torch==1.12.1+cu113 torchvision==0.13.1+cu113 torchaudio==0.12.1 --extra-index-url https://download.pytorch.org/whl/cu113 -i https://pypi.tuna.tsinghua.edu.cn/simple

代码导入包 :

import copy
import math
import matplotlib.pyplot as plt
import numpy as np
import os
import seaborn as sns
import time
import torch
import torch.nn as nn
import torch.nn.functional as F

from collections import Counter
from langconv import Converter
from nltk import word_tokenize
from torch.autograd import Variable

二、数据准备

  数据集可以去网络上下载,下面的是train.txt文件部分内容,前面为英文,后面为繁体中文,中间以'\t'隔开。其他数据文件也相同。
这里数据集是英文和繁体中文,所以第一步我们需要将繁体中文变为简体中文。
在这里插入图片描述

转换代码如下:

def cht_to_chs(sent):
"""" zh-hans" 是一个语言代码,用于指代中文(汉语)的简体字形式。在国际化和本地化领域,语言代码用于标识特定语言或语言变体。
     在这里,"zh" 表示汉语(中文),"hans" 表示简体字形式。因此,"zh-hans" 表示简体中文。"""
    sent = Converter("zh-hans").convert(sent) 
    sent = sent.encode("utf-8")
    return sent

1. 数据加载

作用:读取数据路径下的完整句子,将每个句子分割为一个一个的单词,并存到子列表中。返回含有子列表的列表,

"""参数参数path 为数据的路径,如下
	train_file= 'nmt/en-cn/train.txt'  # 训练集
	dev_file= "nmt/en-cn/dev.txt"      # 验证集
	load_data(train_file)
"""

def load_data(self, path):
    """
    读取英文、中文数据
    对每条样本分词并构建包含起始符和终止符的单词列表
    """
    en = []    #定义英文列表
    cn = []    #定义中文列表
    with open(path, mode="r", encoding="utf-8") as f:     #只读的形式打开文件路径,文件描述符为f。
        for line in f.readlines():          #按行读取
            sent_en, sent_cn = line.strip().split("\t")  #以‘\t’进行分割,前面的赋给sent_en,后面的赋给sent_cn 。
            sent_en = sent_en.lower()    #将英文转换为小写。
            sent_cn = cht_to_chs(sent_cn)  #将繁体中文转为简体中文。
            """	word_tokenize() 是 NLTK库中的一个函数,用于将文本分词成单词(token)。
				它可以将一个句子或文本分解成一个个单词或标点符号,用于处理英文句子"""
            sent_en = ["BOS"] + word_tokenize(sent_en) + ["EOS"]
            # 中文按字符切分
            sent_cn = ["BOS"] + [char for char in sent_cn] + ["EOS"]
            en.append(sent_en)  #将切割好的英文 存入英文列表。包含['BOS', 'i', 'love', 'you', 'EOS']
            cn.append(sent_cn)  #将切割好的中文 存入中文列表。
    return en, cn    #返回两个单词列表
    
"""
输出列表格式如下:
     en = [
					    ['BOS','I', 'love', 'natural', 'language', 'processing', '.', 'EOS'] ,
					    ['BOS', 'Natural', 'language', 'processing', 'is', 'fascinating', '.', 'EOS']
		  ]
"""	            

2. 构建单词表

"""输入参数
	train_en, train_cn = load_data(train_file)
	build_dict(train_en)  这里的输入为单词列表。
	
	输入列表如下:
		train_en= [
					    ['BOS','I', 'love', 'natural', 'language', 'processing', '.', 'EOS'] ,
					    ['BOS', 'Natural', 'language', 'processing', 'is', 'fascinating', '.', 'EOS']
		          ]
"""
PAD = 0                             # padding占位符的索引
UNK = 1                             # 未登录词标识符的索引
def build_dict(self, sentences, max_words=5e4):
     """
     构造分词后的列表数据
     构建单词-索引映射(key为单词,value为id值)
     """
     # 统计数据集中单词词频
     word_count = Counter([word for sent in sentences for word in sent])
    
     # 按词频保留前max_words个单词构建词典
     # 添加UNK和PAD两个单词
     ls = word_count.most_common(int(max_words))
     total_words = len(ls) + 2
     word_dict = {word [0]: index + 2 for index, word in enumerate(ls)}
     word_dict['UNK'] = UNK
     word_dict['PAD'] = PAD
     # 构建id2word映射
     index_dict = {v: k for k, v in word_dict.items()}
     return word_dict, total_words, index_dict

程序解析

(1)将列表里每个子列表的所有单词合并到一个新列表(没有子列表)中。

将sentences里面每句话的每个单词组合形成一个新的列表。

sentences = [
			    ['BOS''I', 'love', 'natural', 'language', 'processing', '.', 'EOS'] ,
			    ['BOS', 'Natural', 'language', 'processing', 'is', 'fascinating', '.', 'EOS']
		  ]
		     
word_list = [word for sent in sentences for word in sent]
"""
另一种写法:
	word_list = []
	for sent in sentences:
	    for word in sent:
	        word_list.append(word)
"""
print(word_list )
"""
	输出: ['BOS', 'I', 'love', 'natural', 'language', 'processing', '.', 'EOS', 'BOS', 'Natural', 'language', 'processing', 'is', 'fascinating', '.', 'EOS']
"""
(2)Counter()-- 统计迭代对象各元素出现次数,并按次数从多到少排序
from collections import Counter
#Python 中的一个内置数据结构
# 定义一个列表
word_list = ['BOS', 'I', 'love', 'natural', 'language', 'processing', '.', 'EOS', 'BOS', 'Natural', 'language', 'processing', 'is', 'fascinating', '.', 'EOS']
# 使用 Counter 统计列表中各元素的出现次数
word_count = Counter(word_list)
print(word_count )

"""
	输出: Counter({'BOS': 2, 'language': 2, 'processing': 2, '.': 2, 'EOS': 2, 'I': 1, 'love': 1, 'natural': 1, 'Natural': 1, 'is': 1, 'fascinating': 1})
"""

(3)获取出现频率最高的前 50000 个元素及其个数。
from collections import Counter

word_count = Counter({'BOS': 2, 'language': 2, 'processing': 2, '.': 2, 'EOS': 2, 'I': 1, 'love': 1, 'natural': 1, 'Natural': 1, 'is': 1, 'fascinating': 1})

ls = word_count.most_common(int(5e4))#返回列表中频率最高的元素和它们的计数,按照计数从高到低排序。频率最高的前 50000 个元素。
print(ls)
"""
输出:
	[('BOS', 2), ('language', 2), ('processing', 2), ('.', 2), ('EOS', 2), ('I', 1), ('love', 1), ('natural', 1), ('Natural', 1), ('is', 1), ('fascinating', 1)]

"""
(4) 建立字典word_dict{ }:存放元素及其索引号

enumerate(可迭代元素),返回的第一个值为索引,第二个值为元素。

ls = [('BOS', 2), ('language', 2), ('processing', 2), ('.', 2), ('EOS', 2), ('I', 1), ('love', 1), ('natural', 1), ('Natural', 1), ('is', 1), ('fascinating', 1)]

word_dict = {word [0]: index + 2 for index, word in enumerate(ls)}

"""另一种写法:
	word_dict = {}
	for index, word  in enumerate(ls):
	    word_dict[ word[0] ] = index + 2
	print(word_dict)
"""
print(word_dict)  #存放元素及其索引号
"""
	输出: {'BOS': 2, 'language': 3, 'processing': 4, '.': 5, 'EOS': 6, 'I': 7, 'love': 8, 'natural': 9, 'Natural': 10, 'is': 11, 'fascinating': 12}
"""

word_dict['UNK'] = 1
word_dict['PAD'] = 0
print(word_dict)
"""
	输出:{'BOS': 2, 'language': 3, 'processing': 4, '.': 5, 'EOS': 6, 'I': 7, 'love': 8, 'natural': 9, 'Natural': 10, 'is': 11, 'fascinating': 12, 'UNK': 1, 'PAD': 0}
"""
(5) 建立字典index_dict{ }—{ 索引号:元素 }
word_dict= {'BOS': 2, 'language': 3, 'processing': 4, '.': 5, 'EOS': 6, 'I': 7, 'love': 8, 'natural': 9, 'Natural': 10, 'is': 11, 'fascinating': 12, 'UNK': 1, 'PAD': 0}

index_dict = {v: k for k, v in word_dict.items()}
print(index_dict)

"""
	输出:{2: 'BOS', 3: 'language', 4: 'processing', 5: '.', 6: 'EOS', 7: 'I', 8: 'love', 9: 'natural', 10: 'Natural', 11: 'is', 12: 'fascinating', 1: 'UNK', 0: 'PAD'}
"""

3. 将英文、中文单词列表转为单词索引列表

  def word2id(self, en, cn, en_dict, cn_dict, sort=True):
        """
        将英文、中文单词列表转为单词索引列表
        `sort=True`表示以英文语句长度排序,以便按批次填充时,同批次语句填充尽量少
        """
        length = len(en)
        # 单词映射为索引
        out_en_ids = [[en_dict.get(word, UNK) for word in sent] for sent in en]
        out_cn_ids = [[cn_dict.get(word, UNK) for word in sent] for sent in cn]

        # 按照语句长度排序
        def len_argsort(seq):
            """
            传入一系列语句数据(分好词的列表形式),
            按照语句长度排序后,返回排序后原来各语句在数据中的索引下标
            """
            return sorted(range(len(seq)), key=lambda x: len(seq[x]))

        # 按相同顺序对中文、英文样本排序
        if sort:
            # 以英文语句长度排序
            sorted_index = len_argsort(out_en_ids)
            out_en_ids = [out_en_ids[idx] for idx in sorted_index]
            out_cn_ids = [out_cn_ids[idx] for idx in sorted_index]
        return out_en_ids, out_cn_ids

4. 划分batch

    def split_batch(self, en, cn, batch_size, shuffle=True):
        """
        划分批次
        `shuffle=True`表示对各批次顺序随机打乱
        """
        # 每隔batch_size取一个索引作为后续batch的起始索引
        idx_list = np.arange(0, len(en), batch_size)
        # 起始索引随机打乱
        if shuffle:
            np.random.shuffle(idx_list)
        # 存放所有批次的语句索引
        batch_indexs = []
        for idx in idx_list:
            """
            形如[array([4, 5, 6, 7]), 
                 array([0, 1, 2, 3]), 
                 array([8, 9, 10, 11]),
                 ...]
            """
            # 起始索引最大的批次可能发生越界,要限定其索引
            batch_indexs.append(np.arange(idx, min(idx + batch_size, len(en))))
        # 构建批次列表
        batches = []
        for batch_index in batch_indexs:
            # 按当前批次的样本索引采样
            batch_en = [en[index] for index in batch_index]
            batch_cn = [cn[index] for index in batch_index]
            # 对当前批次中所有语句填充、对齐长度
            # 维度为:batch_size * 当前批次中语句的最大长度
            batch_cn = seq_padding(batch_cn)
            batch_en = seq_padding(batch_en)
            # 将当前批次添加到批次列表
            # Batch类用于实现注意力掩码
            batches.append(Batch(batch_en, batch_cn))
        return batches

三、模型搭建

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

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

相关文章

【Spring AOP】@Aspect结合案例详解(一): @Pointcut使用@annotation + 五种通知Advice注解(已附源码)

文章目录 前言AOP与Spring AOPAspect简单案例快速入门 一、Pointcutannotation 二、五种通知Advice1. Before前置通知2. After后置通知3. AfterRunning返回通知4. AfterThrowing异常通知5. Around环绕通知 总结 前言 在微服务流行的当下,在使用SpringCloud/Springb…

Mogdb双网卡同步最佳实践

大家都知道Oracle数据库无论是单机还是RAC集群在进行生产部署实施时,我们都会对网卡做冗余考虑,比如使用双网卡,比如public、心跳网络。这样的目的主要是为了安全,避免淡点故障。当然也网卡Bond不仅是可以做主备还可以支持负载均衡…

redis分布式锁+redisson框架

目录 🧂1.锁的类型 🌭2.基于redis实现分布式 🥓3. 基于redisson实现分布式锁 1.锁的类型 1.本地锁:synchronize、lock等,锁在当前进程内,集群部署下依旧存在问题2.分布式锁:redis、zookeeper等…

OLAP介绍

OLAP OLAP介绍 Rollup OLAP(在线分析处理)的上下文中,"Rollup"是一个重要的概念,它指的是在多维数据集中自动地聚合数据到更高的层次或维度的过程。这种操作通常用于快速计算和展示汇总数据,以便于用户进…

包和final.Java

1,包 包就是文件夹。用来管理不同功能的Java类,方便后期代码的维护。 (1)包名的规则是什么? 公司域名反写报的作用,需要全部英文小写,见名知意。com.itheima.domain (2&#xff…

15.队列集

1.简介 在使用队列进行任务之间的“沟通交流”时,一个队列只允许任务间传递的消息为同一种数据类型,如果需要在任务间传递不同数据类型的消息时,那么就可以使用队列集。FreeRTOS提供的队列集功能可以对多个队列进行“监听”,只要…

Redis高级-分布式缓存

分布式缓存 – 基于Redis集群解决单机Redis存在的问题 单机的Redis存在四大问题: 0.目标 1.Redis持久化 Redis有两种持久化方案: RDB持久化AOF持久化 1.1.RDB持久化 RDB全称Redis Database Backup file(Redis数据备份文件)…

QT drawPixmap和drawImage处理图片模糊问题

drawPixmap和drawImage显示图片时,如果图片存在缩放时,会出现模糊现象,例如将一个100x100 的图片显示到30x30的区域,这个时候就会出现模糊。如下: 实际图片: 这个问题就是大图显示成小图造成的像素失真。 当…

FPGA(Verilog)实现按键消抖

实现按键消抖功能: 1.滤除按键按下时的噪声和松开时的噪声信号。 2.获取已消抖的按键按下的标志信号。 3.实现已消抖的按键的连续功能。 Verilog实现 模块端口 key_filter(input wire clk ,input wire rst_n ,input wire key_in , //按下按键时为0output …

[NKCTF2024]-PWN:leak解析(中国剩余定理泄露libc地址,汇编覆盖返回地址)

查看保护 查看ida 先放exp 完整exp: from pwn import* from sympy.ntheory.modular import crt context(log_leveldebug,archamd64)while True:pprocess(./leak)ps[101,103,107,109,113,127]p.sendafter(bsecret\n,bytes(ps))cs[0]*6for i in range(6):cs[i]u32(p…

6.模板初阶(函数模板、类模板、类模板声明与定义分离)

1. 泛型编程 如何实现一个通用的交换函数呢? 使用函数重载虽然可以实现,但是有一下几个不好的地方: 重载的函数仅仅是类型不同,代码复用率比较低,只要有新类型出现时,就需要用户自己增加对应的函数代码的…

线性、逻辑回归算法学习

1、什么是一元线性回归 线性:两个变量之间的关系是一次函数,也是数据与数据之间的关系。 回归:人们在测试事物的时候因为客观条件所限,求的都是测试值,而不是真实值,为了无限接近真实值,无限次的…

HarmonyOS开发实例:【状态管理】

状态管理 ArkUI开发框架提供了多维度的状态管理机制,和UI相关联的数据,不仅可以在组件内使用,还可以在不同组件层级间传递,比如父子组件之间,爷孙组件之间等,也可以是全局范围内的传递,还可以是…

【考研数学】1800还是660还是880?

关于这几本习题册如何选择,肯定是根据他们的不同特点以及我们的需求结合选择,给大家的建议如下: 1800适合初期,可以帮助你熟悉数学公式和基础定义,迅速上手用。刚开始觉得难很正常,存在一个上手的过程&…

VRRP虚拟路由实验(思科)

一,技术简介 VRRP(Virtual Router Redundancy Protocol)是一种网络协议,用于实现路由器冗余,提高网络可靠性和容错能力。VRRP允许多台路由器共享一个虚拟IP地址,其中一台路由器被选为Master,负…

【Erlang】【RabbitMQ】Linux(CentOS7)安装Erlang和RabbitMQ

一、系统环境 查版本对应,CentOS-7,选择Erlang 23.3.4,RabbitMQ 3.9.16 二、操作步骤 安装 Erlang repository curl -s https://packagecloud.io/install/repositories/rabbitmq/erlang/script.rpm.sh | sudo bash安装 Erlang package s…

扫描IP开放端口该脚本用于对特定目标主机进行常见端口扫描(加载端口字典)或者指定端口扫描,判断目标主机开

扫描IP开放端口该脚本用于对特定目标主机进行常见端口扫描(加载端口字典)或者指定端口扫描,判断目标主机开 #/bin/bash #该脚本用于对特定目标主机进行常见端口扫描(加载端口字典)或者指定端口扫描,判断目标主机开放来哪些端口 #用telnet方式 IP$1 #IP119.254.3.28 #获得IP的前…

【STL】顺序容器与容器适配器

文章目录 1顺序容器概述1.1array1.2forward_list1.3deque 2.如何确定使用哪种顺序容器呢?3.容器适配器的概念4.如何定义适配器呢? 1顺序容器概述 给出以下顺序容器表: 顺序容器类型作用vector可变大小的数组,支持快速访问&#…

UML学习

UML(Unified Modeling Language):统一建模语言,提供了一套符号和规则来帮助分析师和设计师表达系统的架构、行为和交互 类图:描绘类、接口之间的关系(继承、实现、关联、依赖等)以及类的内部结构(属性和方法),直观展现系统的静态…

2024年3月电子学会青少年软件编程 中小学生Python编程等级考试一级真题解析(判断题)

2024年3月Python编程等级考试一级真题解析 判断题(共10题,每题2分,共20分) 26、turtle 画布的坐标系原点是在画布的左上角 答案:错 考点分析:考查turtle相关知识,turtle画布坐标系是在画布的…