前言
本文是在学习Transformer过程中记录的笔记,可能有一些为了理解方便写得不准确的地方,也有可能有一些没有发现的错误。望指正。
序列到序列(Seq2Seq)模型通过编码器-解码器(Encoder-Decoder)结构实现序列转换。编码器将输入序列转化为高维空间中的一个固定维度的向量表示,即上下文向量(Context Vector)。这个向量代表了输入序列的压缩语义信息,类似于一个摘要。解码器随后利用这个上下文向量,逐步生成与输入序列相对应的输出序列,实现从摘要向量到完整序列的映射。
Seq2Seq 模型
Seq2Seq模型,全称Sequence to Sequence模型。即:输入一个序列,输出另一个序列。
这种结构最重要的地方在于输入序列和输出序列的长度是可变的。
在处理可变长度的序列时,使用 BOS 和 EOS 可以减少对 填充(padding)的依赖,因为模型可以根据这些标记来识别序列的边界。
背景:
在 Seq2Seq 框架提出之前,深度神经网络在图像分类等问题上取得了非常好的效果。在其擅长解决的问题中,==输入和输出通常都可以表示为固定长度的向量==,如果长度稍有变化,会使用填充(Padding)等操作,其目的是将序列数据转换成固定长度的格式,以便于输入到需要固定长度输入的神经网络中。但是,Padding可能引入的问题:例如在计算损失时可能需要特殊的处理来忽略这些补零的元素,以免它们影响模型的训练效果。这通常通过使用掩码(Mask)来实现,掩码可以指示哪些位置是补零的,以便在计算过程中忽略这些位置。然而许多重要的问题,例如机器翻译、语音识别、对话系统等,表示成序列后,其长度事先并不知道。
(简单来说,就是Seq2Seq 前,输出和输入都是固定长度的向量,需要用到填充,但是很多问题事前不知道序列的固定长度是多少,无法准确处理这些填充的元素)
优势
- 简单:能直接从原始的文本或语音等数据中学习,然后直接输出我们想要的结果,整个过程不需要人工去提取特征或进行复杂的预处理。
- 灵活:不管输入的序列有多长,或者输出的序列需要多长,它都能够适应。
- 高效:编码器将大段文字变成上下文向量,解码器根据上下文向量,输出目标序列,构建完整内容。
- 易扩展:可以轻松地与其他神经网络技术(比如卷积神经网络或循环神经网络)结合,可以处理更加复杂和多样化的任务。
缺点
- 上下文向量信息压缩:输入序列的全部信息需要被编码成一个固定维度的上下文向量,这导致了信息压缩和信息损失的问题,尤其是细粒度细节的丢失。
- 短期记忆限制:由于循环神经网络(RNN)的固有特性,Seq2Seq模型在处理长序列时存在短期记忆限制,难以有效捕获和传递长期依赖性。这限制了模型在处理具有长距离时间步依赖的序列时的性能。
- 暴露偏差(Exposure Bias):在Seq2Seq模型的训练过程中,经常采用“teacher forcing”策略,即在每个时间步提供真实的输出作为解码器的输入。然而,这种训练模式与模型在推理时的自回归生成模式存在不一致性,导致模型在测试时可能无法很好地适应其自身的错误输出,这种现象被称为暴露偏差。
Seq2Seq 模型的暴露偏差(Exposure Bias)是指在训练和推断(测试/预测)阶段,模型处理数据的方式不一致,导致模型在推断阶段性能下降的一种现象。这种不一致主要体现在解码器(Decoder)的输入上。
训练阶段:解码器在生成每个时间步的输出时,不会使用前一个时间步自身预测的输出作为输入,而是使用 真实目标序列 中前一个时间步的 真实值 作为输入。
在推断阶段:没有真实的目标序列。解码器在生成每个时间步的输出时,必须使用前一个时间步自己预测的输出作为输入。
Encoder-Decoder模型
Encoder-Decoder将现实问题转化为数学问题,通过求解数学问题,从而解决现实问题。 Encoder 又称作编码器。它的作用就是“将现实问题转化为数学问题”。 Decoder 又称作解码器,他的作用是“求解数学问题,并转化为现实世界的解决方案”。
特点:
- 不论输入和输出的长度是什么,中间的“上下文向量 ” 长度都是固定的(这也是它的缺陷,下文会详细说明)
- 根据不同的任务可以选择不同的编码器和解码器(可以是一个 RNN ,但通常是其变种 LSTM 或者 GRU ) 只要是符合上面的框架,都可以统称为 Encoder-Decoder 模型
编码器(Encoder)
编码器是一个循环神经网络(RNN),由多个循环单元(如 LSTM 或 GRU)堆叠而成。每个单元通过依次处理输入序列中的一个元素,生成一个上下文向量。这个上下文向量汇总了输入序列的全部信息,它通过在单元间传递当前元素的信息,逐步构建对整个序列的理解。 工作流程:
词序列转换
在Seq2Seq模型的初始阶段,输入文本(例如一个句子)通过一个嵌入层(embedding layer)进行转换。这一层将每个词汇映射到一个高维空间中的稠密向量,这些向量携带了词汇的语义信息。这个过程称为词嵌入(word embedding),它使得模型能够捕捉到词汇之间的内在联系和相似性。
序列处理
随后,这些经过嵌入的向量序列被送入一个基于循环神经网络(RNN)的结构中,该结构可能由普通的RNN单元、长短期记忆网络(LSTM)单元或门控循环单元(GRU)组成。RNN的递归性质允许它处理时序数据,从而捕捉输入序列中的顺序信息和上下文关系。在每个时间步,RNN单元不仅处理当前词汇的向量,还结合了来自前一个时间步的隐藏状态信息。
生成上下文向量
经过一系列时间步的计算,RNN的最后一个隐藏层输出被用作整个输入序列的表示,这个输出被称为“上下文向量(context vector)”。上下文向量是一个固定长度的向量,它通过汇总和压缩整个序列的信息,有效地编码了输入文本的整体语义内容。这个向量随后将作为Decoder端的重要输入,用于生成目标序列。
解码器(Decoder)
解码器同样采用递归神经网络(RNN)架构,它接收编码器输出的上下文向量作为其初始输入,并依次合成目标序列的各个元素。
工作流程:
初始化参数 在开始训练之前,解码器RNN及其相关输出层的参数需要被初始化。这些参数包括:
- 权重(Weights):连接不同神经网络层的参数,它们决定了层与层之间信息的传递方式。
- 偏置(Biases):在神经网络层中加入的固定值,用于调节激活函数的输出。
参数的初始化通常涉及对它们赋予随机的小数值,以防止网络在训练初期对特定输出产生偏好。常用的初始化策略包括Xavier初始化(适用于Sigmoid或Tanh激活函数)和He初始化(通常用于ReLU激活函数),这两种方法旨在维持各层激活值和梯度的大致稳定性,从而优化训练过程。
编码器输出
编码器的具体工作过程看前文。编码器在最后生成上下文向量,作为解码器的输入。
编码器的最后一个隐藏状态(或在注意力机制中,所有隐藏状态的加权平均)被用作上下文向量。这个向量是源序列的压缩表示,包含了序列的全部或关键信息。
解码器输入
解码器输出
应用
机器翻译、对话机器人、诗词生成、代码补全、文章摘要(文本 – 文本)
“文本 – 文本” 是最典型的应用,其输入序列和输出序列的长度可能会有较大的差异。
Google 发表的用Seq2Seq做机器翻译的论文《Sequence to Sequence Learning with Neural Networks》
语音识别(音频 – 文本)
Google 发表的使用Seq2Seq做语音识别的论文《A Comparison of Sequence-to-Sequence Models for Speech Recognition》
图像描述生成(图片 – 文本)
通俗的讲就是“看图说话”,机器提取图片特征,然后用文字表达出来。这个应用是计算机视觉和 NLP 的结合。
图像描述生成的论文《Sequence to Sequence – Video to Text》
缺陷
Encoder(编码器)和 Decoder(解码器)之间只有一个固定长度的“上下文向量 ”来传递信息。当文本太长时,压缩会丢掉很多信息。
Encoder-Decoder 就是面临类似的问题:当输入信息太长时,会丢失掉一些信息。
分词与分词器tokenizer
tokenizer 可以处理的原子操作:分词、转换为 ID 以及将 ID 转换回字符串。
将文本拆分成token
因为模型是无法直接处理文本的,只能处理数字,就跟ASCII码表、Unicode码表一样,计算机在处理文字时也是先将文字转成对应的字码,然后为每个字码编写一个对应的数字记录在表中,最后再处理。所以模型在处理文本时,第一步就是先将文本转换成对应的字码,也就是大模型中的token。
基于单词(word-based)的分词器
- 将文本拆分成单词(可以将文本按照空格或者标点分割成单词)
英文按空格分词:
E.g.
Let's do some NLP tasks.
Let's, do, some, NLP, tasks.
中文分词:
E.g.
我们来做一个自然语言处理任务。
我们,来,做,一个,自然语言处理,任务。
缺点是无法处理未登录词(Out-of-Vocabulary,简称OOV)。我们熟悉的jieba分词就是基于这种分词方式的。
- 评价:可能存在一些无法覆盖的单词,因为单词可能存在很多的变种情况,比如:dogs是dog的变种,running是run的变种。如果我们的标识符中没有覆盖所有的单词,那么当出现一个未覆盖的单词时,标记器将无法准确知道该单词的数字标记是多少,进而只能标记为未知:UNK。如果在文本转换的过程中有大量的文本被标记为UNK,那么也将影响后续模型推理。
基于字符(character-based)的分词器
评价:
- 词汇量要小得多。
- 未知的标记(token)要少得多,因为每个单词都可以从字符构建。
- 字符包含的信息量多少因语言而异;例如,在中文中,每个字符比拉丁语言中的字符包含更多的信息
- 使用基于单词的标记器(tokenizer),单词只会是单个标记,但当转换为字符时,它很容易变成 10 个或更多的词符(token)。
英文:
Let's do some NLP tasks.
L, e, t, ', s, d, o, s, o, m, e, N, L, P, t, a, s, k, s, .
中文:
我们来做一个自然语言处理任务。
我,们,来,做,一,个,自,然,语,言,处,理,任,务,。
基于子词的分词器
- 原则:不应将常用词拆分为更小的子词,而应将稀有词分解为有意义的子词。
英文:
Let's do Sub-word level tokenizer.
let's</ w>, do</ w>, Sub, -word</ w>, level</ w>, token, izer</ w>, .</ w>,
</ w>通常表示一个单词word的结尾。使用 "w" 是因为它是 "word" 的首字母,这是一种常见的命名约定。然而,具体的标记可能会根据不同的实现或者不同的分词方法有所不同。
Attention
如下图,Attention(注意力机制) 位于最内层,绿色方块,是整个架构的基础,注意力机制是 Transformer 模型的核心组成部分。
![[Pasted image 20250211112559.png]]
Attention 模型的特点是 Encoder 不再将整个输入序列编码为固定长度的“向量C” ,而是编码成一个向量(Context vector)的序列(“C1”、“C2”、“C3”),解决“信息过长,信息丢失”的问题。
Attention 的核心工作就是“关注重点”。
发展
时间 | 发展 | 描述 |
---|---|---|
早期 | 循环神经网络(RNNs) 长短期记忆网络(LSTMs) |
RNNs能够处理变长的序列数据,但由于梯度消失和梯度爆炸问题,它们在长序列上的表现并不理想。 LSTMs是对RNNs的改进,通过引入门控机制来解决长序列学习中的梯度消失问题。 |
2014年 | Seq2Seq模型的提出 | Seq2Seq模型由一个编码器和一个解码器组成,两者都是基于LSTM。该模型在机器翻译任务上取得了显著的成功。 历史地位: - 首次引入了编码器-解码器框架; - 端到端的学习成为可能; - 中间产生了上下文向量,把编码过程和解码过程进行了解耦。 |
2015年 | 注意力机制的引入 | 在Seq2Seq模型的基础上,Bahdanau等人提出了带注意力机制的Seq2Seq模型。 |
2017年 | 自注意力与Transformer模型 | Transformer模型完全基于自注意力机制,摒弃了传统的循环网络结构,在处理长距离依赖方面表现卓越。 |
2018年 | 多头注意力与BERT | Transformer模型进一步发展为多头注意力机制,并在BERT模型中得到应用,BERT在多项NLP任务上取得了突破性的成果。 |
分类
计算区域 | 所用信息 | 使用模型 | 权值计算方式 | 模型结构 |
---|---|---|---|---|
1. Soft Attention(Global Attention) | 1.General Attention | 1. CNN + Attention | 1.点乘算法 | 1. One-Head Attention |
2. Local Attention | 2. Self Attention | 2. RNN + Attention | 2. 矩阵相乘 | 2. Mutil-layer Attention |
3. Hard Attention | 3. LSTM + Attention | 3.Cos相似度 | 3.Mutil-head Attention | |
4. pure-Attention | 4. 串联方式 | |||
5. 多层感知 |
Attention 的优点
- 参数少:模型复杂度跟 CNN、RNN 相比,复杂度更小,参数也更少。所以对算力的要求也就更小。
- 速度快:Attention 解决了 RNN 不能并行计算的问题。Attention机制每一步计算不依赖于上一步的计算结果,因此可以和CNN一样并行处理。
- 效果好:在 Attention 机制引入之前,有一个问题大家一直很苦恼:长距离的信息会被弱化,就好像记忆能力弱的人,记不住过去的事情是一样的。
词嵌入 word embedding
举例,
- 有一句话“猫狗爱跑”。首先将文本进行分词,把文本转化成一系列的token。包含以下四个词:{“猫”,“狗”,“爱”,“跑”}。
- 分词后的每个 token 都会被映射到一个唯一的整数 ID,称为Input ID。这个 ID 是在预训练模型的词汇表中的索引。假设词汇表中 "猫" 的 ID 是 100,"狗" 的 ID 是 200,"爱" 的 ID 是 300,"跑" 的 ID 是 400,那么输入序列
["猫", "狗", "爱", "跑"]
就会被转换为[100, 200, 300, 400]
。 - 每个token词汇将会有一个对应的稠密向量。词嵌入层(Embedding Layer)将每个 Token ID 映射到一个固定维度的稠密向量(dense vector)。这个向量被称为词嵌入(Word Embedding)。词嵌入将离散的 Token ID 转换为连续的向量空间中的点,使得语义相似的词在向量空间中距离更近。这种稠密向量的表示方式使得词汇之间的关系可以通过向量之间的距离或角度来度量。例如,如果我们计算“猫”和“狗”的向量之间的距离,我们会发现它们比“猫”和“爱”的向量之间的距离要近,这反映了“猫”和“狗”在语义上的相似性。
Transformer 架构图
参考资料
https://github.com/datawhalechina/fun-transformer/blob/main/docs/chapter1/introduction.md
https://tech.dewu.com/article?id=109
https://huggingface.co/learn/nlp-course/zh-CN/chapter2/4?fw=pt#tokenization
https://juejin.cn/post/7428778584883396618
https://arxiv.org/pdf/1706.03762#page=2.21