目录
一、前言
1.1什么是Transformer?
1.2Transfomer的基本结构
1.2Transformer的重要组成部分
1.2.1位置编码(Positional Encode)
1.2.2 自注意力机制(Self-Attention)
1.2.3多头注意力(Multi-Head Attention)
1.2.4位置感知前馈层(Position-wise FFN)
1.2.5残差连接与层归一化
二、AutoDL云服务器的使用
三、具体实现
3.1 实验准备
3.1.1导入本次实验需要用到的包
3.1.2数据集准备
3.2数据处理
3.2.1分词器的准备
3.2.2词汇表的构建
3.2.3预处理训练数据
3.2.4DataLoader 对象的创建
3.3Transformer模型的构建
3.3.1Transformer基本结构的构建
3.3.2词嵌入和位置编码
3.3.3创建mask(掩码)
3.3.4初始化Transformer模型
3.4模型训练
3.5模型使用
3.6词汇表、模型保存
Transformer 模型是由谷歌在2017 年提出并首先应用于机器翻译的神经网络模型结构。机器翻译的目标是从源语言(Source Language)转换到目标语言(Target Language)。Transformer 结构完全通过注意力机制完成对源语言序列和目标语言序列全局依赖的建模。
大多数竞争性神经序列转导模型具有编码器-解码器结构。Transformer遵循这个整体架构,使用堆叠(如图Nx表示进行了N次堆叠)的self-attention和position-wise,完全连接编码器和解码器层。
如图所示,可以看到基于Transfomer结构的编码器和解码器,左侧对应着编码器(Encode),右侧对应解码器(Decoder)。它们均由若干个基本的Transformer块组成(对应图中的方框)。
由于Transformer模型不再使用基于循环的方式建模文本输入,没有额外的位置编码来表达输入序列中的单词的位置顺序,必须注入一些关于序列中标记的相对或绝对位置的信息,一个重要的操作就是加入位置编码(Positional Encode)这个特征。
自注意力机制的基本思想是,对于序列中的每个元素,自注意力机制计算其与其他元素之间的相似度,并将这些相似度归一化为注意力权重。然后,通过将每个元素与对应的注意力权重进行加权求和,可以得到自注意力机制的输出。左下图为Self-Attention的架构。
其计算过程为:首先,计算矩阵Q和K每一行向量的内积,为了防止内积过大,除以d_k的平方根;其次,使用Softmax对上述内积的结果进行归一化;最后得到Softmax矩阵之后和V相乘,得到最终的输出。
Transformer中的自注意力机制被扩展为多个注意力头。使用多头注意力(Multi-Head Attention)机制整合上下文语义,它使得序列中任意两个单词之间的依赖关系可以直接被建模而不基于传统的循环结构,从而更好地解决文本的长程依赖。
可以用独立学习得到的h组不同的线性投影来变换查询、键和值。 然后,这h组变换后的查询、键和值将并行地送到注意力汇聚中。 最后,将这h个注意力汇聚的输出拼接在一起, 并且通过另一个可以学习的线性投影进行变换, 以产生最终输出。基本架构如右上图所示。
除了注意子层之外,编码器和解码器中的每一层都包含一个完全连接的前馈网络,位置感知前馈层过全连接层对输入文本序列中的每个单词表示进行更复杂的变换。
残差连接对应图一中的Add 部分。它是一条分别作用在上述两个子层当中的直连通路,被用于连接它们的输入与输出。从而使得信息流动更加高效,有利于模型的优化。
层归一化对应图一中的Norm 部分。作用于上述两个子层的输出表示序列中,对表示序列进行层归一化操作,同样起到稳定优化的作用。
由于该模型对算力的要求较大,对电脑的配置要求较高。因此我借助AutoDL平台实现模型的训练。我根据自己的需求租用了我所需要的服务器。
然后跟Pyhcarm进行连接,输入自己的SSH信息进行配置连接。连接完成后也可以在Pycharm中查看远程主机信息。
实现环境:
python3.10
torch 2.1.2+cu118
torchdata 0.7.1
torchtext 0.6.0
torchvision 0.16.2+cu118
tqdm 4.64.1
numpy 1.26.4
pandas 2.2.2
sentencepiece 0.1.96
GPU:NVIDIA GeForce RTX 4090D
根据本次实验的需要导入实验所需用到的包并检测GPU
import math
import torchtext
import torch
import torch.nn as nn
from torch import Tensor
from torch.nn.utils.rnn import pad_sequence
from torch.utils.data import DataLoader
from collections import Counter
from torchtext.vocab import Vocab
from torch.nn import TransformerEncoder, TransformerDecoder, TransformerEncoderLayer, TransformerDecoderLayer
import io
import time
import pandas as pd
import numpy as np
import pickle
import tqdm
import sentencepiece as spm
torch.manual_seed(0) # 设置PyTorch随机种子,保证结果可复现
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # 检测是否有GPU,如果有GPU则使用cuda,否则使用cpu
print(torch.cuda.get_device_name(0))
可以检测到GPU情况如下:
使用 JParaCrawl 提供的日英平行数据集进行训练,可以看到本段代码删除了数据集中的最后一个数据,因为它包含缺失值。并且将df中的第三列赋值给trainen变量,第四列赋值给trainja变量。然后打印指定索引位置的数据。
df = pd.read_csv('./zh-ja/zh-ja.bicleaner05.txt', sep='\\t', engine='python', header=None)
trainen = df[2].values.tolist()#[:10000]
trainja = df[3].values.tolist()#[:10000]
trainen.pop(5972)
trainja.pop(5972)
print(trainen[500])
print(trainja[500])
打印出的数据如下:
与英语或其他字母语言不同,日语句子不包含空格来分隔单词。我们可以使用JParaCrawl提供的分词器,该分词器是使用SentencePiece创建的日语和英语,SentencePiece 是一种基于子词的分词模型,能够处理多语言的文本,通过学习语料库中的频繁子词来进行分词,这种方法在处理语言的多样性和灵活性方