大家好,这里是好评笔记,公主号:Goodnote,专栏文章私信限时Free。本文详细介绍面试过程中可能遇到的Transformer知识点,由于字数限制,分为上下篇发布。
文章目录
上篇
遮蔽(Mask)
填充遮蔽(Padding Masking)与未来遮蔽(Future Masking)介绍
Transformer模型中的遮蔽机制是确保模型在处理不定长序列或自回归生成任务时能够正确工作的重要技术。
其中,填充遮蔽和未来遮蔽是两种关键的遮蔽方法,它们的目的是避免模型在不适当的位置关注无意义的填充值或未来的词。下面我们将详细介绍这两种遮蔽机制的作用、工作原理、公式表示、具体作用举例和总结。
1. 填充遮蔽(Padding Masking)与未来遮蔽(Future Masking)的作用
填充遮蔽的作用
主要作用是处理变长输入序列。为了使得批量处理中的所有句子具有相同的长度,较短的句子会使用 padding 填充,并且确保序列中用来填充(如[PAD]
标记)的部分不会在注意力机制中被模型关注。
在自然语言处理中,由于输入的序列长度可能不同,较短的序列通常需要填充到固定长度。这些填充的部分是无意义的,占位符而已。因此,填充遮蔽用于忽略这些填充值,防止它们影响模型的训练和推理过程。
为什么需要填充(padding)?
- 循环神经网络(RNN, LSTM, GRU)
- 批处理的高效性:在处理批次数据时,也需要将序列填充到固定长度,以便所有序列能够一起进行计算。将序列填充到相同长度后,数据就能构建成相同维度的张量,便于在批处理时并行运算。
- 硬件加速的需求:依赖GPU或TPU等硬件加速器,变长序列如果不进行填充,会导致批处理中的张量形状不一致,从而无法高效利用并行计算的优势。
卷积神经网络(CNN)在处理文本或序列任务时、语音识别模型、时间序列预测模型都需要进行padding。
- Transformer在其他领域的变长输入
- 批处理的需求:Transformer在处理变长输入时,无论是文本、图像还是视频任务,都需要确保输入的长度一致,以便模型能够进行批处理和高效计算。
未来遮蔽的作用
- 未来遮蔽,也称为自回归遮蔽,用于生成任务中的解码器部分。它的作用是防止模型在生成过程中“看到”当前词之后的未来词,确保每个时间步的输出只能依赖于当前时间步及之前的词。
- 未来遮蔽在生成任务(如文本生成、机器翻译等)中尤为重要。
2. 填充遮蔽与未来遮蔽的工作原理
填充遮蔽的工作原理
- 填充遮蔽通过生成一个遮蔽矩阵/向量,标记哪些位置是填充值(例如,
[PAD]
标记通常用0
填充)。然后,在计算注意力得分时,将这些位置的注意力分数设置为极小值(通常为负无穷),从而确保填充值不会影响模型的注意力计算。
例如,假设有一个序列长度为 5 的输入句子,填充部分用[PAD]
标记表示,填充遮蔽向量会如下所示:
Mask = [1,1,1,0,0]
- 这里的
1
表示实际输入,0
表示填充值([PAD]
),对应的注意力得分在计算时会被设置为极小值(如负无穷),从而在softmax中不再产生影响。
未来遮蔽的工作原理
- 未来遮蔽通过生成一个上三角矩阵,确保每个时间步只能关注当前时间步及之前的词,避免“偷看”未来的词。例如,序列长度为 5 时的未来遮蔽矩阵为:
Mask future = [ 0 − ∞ − ∞ − ∞ − ∞ 0 0 − ∞ − ∞ − ∞ 0 0 0 − ∞ − ∞ 0 0 0 0 − ∞ 0 0 0 0 0 ] \text{Mask}_{\text{future}}=\left[\begin{matrix} 0&-\infty&-\infty&-\infty&-\infty\\ 0&0&-\infty&-\infty&-\infty\\ 0&0&0&-\infty&-\infty\\ 0&0&0&0&-\infty\\ 0&0&0&0&0 \end{matrix}\right] Maskfuture= 00000−∞0000−∞−∞000−∞−∞−∞00−∞−∞−∞−∞0
- 这个上三角矩阵确保模型在时间步 ( i ) 只能看到之前的词,而不能看到未来的词。被设置为负无穷的部分表示未来词被屏蔽,从而在softmax计算后,未来词的注意力分数会为零。
3. 公式表示
填充遮蔽的公式表示
在填充遮蔽中,掩码矩阵 ( M pad M_{\text{pad}} Mpad ) 会被添加到注意力分数上。注意力机制的公式为:
Attention
(
Q
,
K
,
V
)
=
softmax
(
Q
K
T
d
k
+
M
pad
)
V
\text{Attention}(Q,K,V)=\text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}+M_{\text{pad}}\right)V
Attention(Q,K,V)=softmax(dk
QKT+Mpad)V
其中:
- Q Q Q 是查询向量(Query), K K K 是键向量(Key), V V V 是值向量(Value)。
- M pad M_{\text{pad}} Mpad 是填充遮蔽矩阵,对于填充部分的值为负无穷,其他部分为 0 0 0。
- 通过 softmax \text{softmax} softmax 归一化后,填充值位置的注意力权重会被压缩为接近零,确保模型忽略这些填充值。
未来遮蔽的公式表示
在未来遮蔽中,同样需要将未来遮蔽矩阵 ( M future M_{\text{future}} Mfuture ) 添加到注意力得分上:
Attention ( Q , K , V ) = softmax ( Q K T d k + M future ) V \text{Attention}(Q,K,V)=\text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}+M_{\text{future}}\right)V Attention(Q,K,V)=softmax(dk QKT+Mfuture)V
- M future M_{\text{future}} Mfuture 是一个上三角矩阵,用于确保当前位置 i i i 之后的词的注意力得分被设置为负无穷,从而避免模型“看到”未来的词。
Q&A
为什么填充遮蔽的填充矩阵不使用未来遮蔽的负无穷表示填充值?
填充遮蔽需要参与到注意力计算点积( Q ⋅ K T Q \cdot K^T Q⋅KT )中(对原始句子进行填充,之后进行点积计算),所以需要考虑下面的部分:
- 效率:使用布尔或 0/1 掩码可以更灵活地计算,并减少负无穷值在早期引入带来的数值问题。
- 数值稳定性:在某些硬件和计算精度下,直接处理负无穷值可能会导致数值不稳定。通过布尔值等手段间接表示负无穷,有助于提高稳定性。
- 代码兼容性和可维护性:布尔掩码或 0/1 掩码的表示更简单,适用于不同的框架和优化需求。
为什么未来遮蔽使用负无穷?不使用填充遮蔽的0/1?
未来遮蔽不需要参与到注意力计算点积(
Q
⋅
K
T
Q \cdot K^T
Q⋅KT )中,只作用于负无穷值是在计算注意力得分之后,softmax之前的注意力得分矩阵。
1. 计算位置固定和小矩阵
- 未来遮蔽的掩码矩阵大小较小:
- 在模型的解码器自注意力层使用。
- 矩阵的大小等于序列长度,比较小。
2. 未来遮蔽的矩阵形状固定
未来遮蔽是一个静态生成的上三角矩阵,形状是固定的(例如 (5 \times 5)),且负无穷只应用于未来词的位置。
相比之下,填充遮蔽需要动态生成掩码矩阵,以适应变长序列的不同填充位置,填充位置可能在序列的任意位置,这样的灵活性要求更高。因此,在填充遮蔽中,直接使用负无穷可能会导致效率问题,而未来遮蔽则不需要这种灵活性,矩阵是固定形状且规则的。
3. 负无穷在softmax之前的处理
负无穷值只作用于负无穷值是在计算注意力得分之后,softmax之前的注意力得分矩阵且其负无穷的引入非常明确和局部化,这使得计算较为高效。
总结
- 未来遮蔽直接使用负无穷值的原因是其计算位置固定、矩阵较小且形状规则,负无穷只影响局部注意力得分计算之后,不涉及复杂的动态生成和反向传播问题。
- 填充遮蔽其掩码矩阵需要动态生成,形状不固定,并且影响编码器和解码器的多个层次的计算,因此在实现中通常先使用布尔或 0/1 掩码,并在最后一步处理负无穷,避免早期引入极端数值而导致的数值稳定性问题。
如何做到多头?
目的:让每个注意力头可以在不同的子空间中独立地学习和关注序列中的不同特征和关系。
在多头自注意力机制中,每个头的输入是一样的,即每个头接收到的初始输入向量是相同的。但是每个头的权重矩阵都是不同的。在多头自注意力机制中,每个头都有自己的独立的权重矩阵来生成查询(Query)、键(Key)和值(Value),都会使用随机初始化(通常使用Xavier初始化)。
为什么Xavier初始化能确保不同头的权重不同?
Xavier初始化的随机性是使得每个头的权重矩阵初始化不同的关键:
- 虽然Xavier初始化方法是相同的,但随机数生成器为每个权重矩阵生成不同的初始值。每个矩阵的数值是通过从特定范围(由Xavier初始化确定的)内随机抽样得到的,而不是固定值。
- 由于每个头的权重矩阵是独立的可训练参数,这些矩阵会被单独初始化,即每个头的权重矩阵会独立生成自己的初始值,而不共享具体的数值。
具体解释:
假设我们有(h)个注意力头,每个头会有自己独立的线性变换权重矩阵: - 对于第(i)个头,有以下权重矩阵:
- (W_{Q}^{i}):用于将输入向量映射为查询向量(Q)的权重矩阵。
- (W_{K}^{i}):用于将输入向量映射为键向量(K)的权重矩阵。
- (W_{V}^{i}):用于将输入向量映射为值向量(V)的权重矩阵。
因此,对于每个头(i),都会有一组独立的权重矩阵(W_{Q}{i})、(W_{K}{i})、(W_{V}^{i})。这些权重矩阵的维度通常是:
(W_{Q}^{i}, W_{K}^{i}, W_{V}{i}\in\mathbb{R}{d_{\text{model}}\times d_{k}})
其中:
- (d_{\text{model}})是输入向量的维度(例如,Transformer模型中通常是512或768)。
- (d_{k})是每个头中查询和键的维度,通常为(d_{k}=d_{\text{model}}/h)(即每个头的维度是原始输入维度的(1/h))。
为什么每个头的权重矩阵是不同的?
- 不同的子空间:
- 每个注意力头独立学习查询、键和值的投影,使得每个头能够在不同的表示子空间中工作。由于每个头有自己独立的权重矩阵,意味着每个头可以关注输入序列中不同的特征。这样,模型能够从多个角度捕捉输入序列中丰富的依赖关系。
- 增强模型的表达能力:
- 如果所有头使用相同的权重矩阵,那么所有头将会计算出相同的注意力结果,这与单头自注意力没有区别。通过为每个头赋予独立的权重矩阵,模型可以学习到不同的模式或关系,使得输出的表示更加多样化和丰富。
具体解释:
假设我们有
h
h
h个注意力头,每个头会有自己独立的线性变换权重矩阵:
- 对于第
i
i
i个头,有以下权重矩阵:
- W Q i W_{Q}^{i} WQi:用于将输入向量映射为查询向量 Q Q Q的权重矩阵。
- W K i W_{K}^{i} WKi:用于将输入向量映射为键向量 K K K的权重矩阵。
- W V i W_{V}^{i} WVi:用于将输入向量映射为值向量 V V V的权重矩阵。
因此,对于每个头
i
i
i,都会有一组独立的权重矩阵
W
Q
i
W_{Q}^{i}
WQi、
W
K
i
W_{K}^{i}
WKi、
W
V
i
W_{V}^{i}
WVi。这些权重矩阵的维度通常是:
W
Q
i
,
W
K
i
,
W
V
i
∈
R
d
model
×
d
k
W_{Q}^{i}, W_{K}^{i}, W_{V}^{i}\in\mathbb{R}^{d_{\text{model}}\times d_{k}}
WQi,WKi,WVi∈Rdmodel×dk
其中:
- d model d_{\text{model}} dmodel是输入向量的维度(例如,Transformer模型中通常是512或768)。
- d k d_{k} dk是每个头中查询和键的维度,通常为 d k = d model / h d_{k}=d_{\text{model}}/h dk=dmodel/h(即每个头的维度是原始输入维度的 1 / h 1/h 1/h)。
为什么每个头的权重矩阵是不同的?
- 不同的子空间:
- 每个注意力头独立学习查询、键和值的投影,使得每个头能够在不同的表示子空间中工作。由于每个头有自己独立的权重矩阵,意味着每个头可以关注输入序列中不同的特征。这样,模型能够从多个角度捕捉输入序列中丰富的依赖关系。
- 增强模型的表达能力:
- 如果所有头使用相同的权重矩阵,那么所有头将会计算出相同的注意力结果,这与单头自注意力没有区别。通过为每个头赋予独立的权重矩阵,模型可以学习到不同的模式或关系,使得输出的表示更加多样化和丰富。
自注意力的时间复杂度
总的时间复杂度是O( n 2 d n^2 d n2d),来自计算自注意力机制。
QK矩阵乘法的复杂度是矩阵行列数乘以中间的维度d,即 n×n×d。
Transformer的时间复杂度主要由注意力机制决定。具体来说,给定输入序列长度为 n n n和嵌入维度为 d d d:
- 自注意力机制的时间复杂度:
- 自注意力机制涉及到查询、键和值之间的点积计算和softmax操作。这部分的计算量主要集中在计算 Q K T QK^{T} QKT,其时间复杂度为 O ( n 2 d ) O(n^{2}d) O(n2d)。这意味着,当序列长度 n n n增长时,计算量是二次增长的。
- 前馈神经网络的时间复杂度:
- 前馈神经网络是两个全连接层,时间复杂度为
O
(
n
d
2
)
O(nd^{2})
O(nd2)。
因此,Transformer每一层的总时间复杂度为 O ( n 2 d + n d 2 ) O(n^{2}d + nd^{2}) O(n2d+nd2)。由于通常 n > d n>d n>d,时间复杂度主要由 O ( n 2 d ) O(n^{2}d) O(n2d)控制。
- 前馈神经网络是两个全连接层,时间复杂度为
O
(
n
d
2
)
O(nd^{2})
O(nd2)。
与RNN相比,RNN的时间复杂度是 O ( n d 2 ) O(nd^{2}) O(nd2),因为RNN处理每个时间步是线性的。然而,Transformer通过并行处理所有时间步,虽然复杂度较高,但能更好地利用硬件资源进行加速。
O( n 2 d n^2 d n2d)的解释:
查询矩阵
Q
Q
Q和键矩阵
K
K
K的点积操作
Q
K
T
QK^{T}
QKT产生了一个大小为
n
×
n
n\times n
n×n的注意力分数矩阵,其中
n
n
n是输入序列的长度。
每个查询与每个键的点积是两个维度为
d
d
d的向量之间的点积,计算复杂度为
O
(
d
)
O(d)
O(d)。
因此,计算
Q
K
T
QK^{T}
QKT的总时间复杂度是
O
(
n
2
⋅
d
)
O(n^{2}\cdot d)
O(n2⋅d),这是因为我们总共需要计算
n
2
n^{2}
n2个查询 - 键点积,每个点积的复杂度为
O
(
d
)
O(d)
O(d)。
在许多自然语言处理任务中,序列长度 (n)(如一个句子或段落的单词数量)通常会比较大,而嵌入维度 (d) 的大小相对较小。因此,序列长度 (n) 经常远大于 嵌入维度 (d)。
所以,总的时间复杂度是O(
n
2
d
n^2 d
n2d)
常见的设置如下:
- 序列长度 (n):对于自然语言处理任务,句子或文本的长度可以是几十到几百个词。例如,在机器翻译、文本摘要生成等任务中,句子长度可能是 20 到 100+。
- 嵌入维度 (d):嵌入维度通常是一个较小的固定值,比如 256、512、768 等,依赖于任务的具体要求。嵌入维度表示每个词的特征空间大小,但它并不需要过大,因为过大的嵌入维度可能会导致过拟合和计算负担。
编码器-解码器注意力机制
编码器-解码器注意力机制(Encoder-Decoder Attention Mechanism)是Transformer模型中连接编码器(Encoder)和解码器(Decoder)的一种关键机制。该机制允许解码器在生成每个目标词时参考编码器提供的上下文信息,帮助生成更合适的输出。
与自注意力的不同
输入的不同
- 自注意力(Self-Attention):查询 ( Q )、键 ( K )、值 ( V ) 都来自同一个输入序列。
- 编码器-解码器注意力(Encoder-Decoder Attention):
- 查询 ( Q ) 来自解码器【Q 来自解码器当前层的输入 或 上一层的输出】;
- 键 ( K ) 和值 ( V ) 来自编码器的输出序列。
(当前层的输入==上一层的输出, 每次的输出比之前多一个词,之后当作下层的输入)。
作用的不同
- 自注意力:捕捉序列内部元素之间的依赖关系,帮助模型理解序列中的局部或全局信息。
- 编码器-解码器注意力:在输入序列和输出序列之间建立联系,帮助解码器根据编码器的输出生成更合适的目标词。
编码器-解码器多头注意力机制
编码器-解码器注意力机制通常采用多头注意力机制(Multi-Head Attention),即并行计算多个不同的注意力头,每个头有自己的 ( Q )、( K )、( V ) 权重矩阵。多头注意力允许解码器从多个角度关注编码器输出的不同部分,从而捕捉不同层次的特征。
编码器-解码器注意力机制的作用
- 上下文获取:解码器在生成目标序列时,可以动态地从
编码器
的不同位置获取上下文信息。这意味着生成每个词时,解码器可以灵活地关注源序列
中与当前生成词最相关的位置,而不必依赖于一个固定的上下文向量。 - 长距离依赖捕捉:编码器-解码器注意力机制能够捕捉到源序列中的长距离依赖关系。
- 处理不对齐问题:在很多自然语言处理任务中,源序列和目标序列的长度可能不同,并且它们之间的对齐关系也不一定是一一对应的。通过编码器-解码器注意力机制,解码器可以选择性地关注编码器输出的某些部分,解决了对齐问题。
在 Transformer 中,编码器-解码器注意力机制允许解码器在每一步生成目标词时,根据目标序列中已经生成的部分,动态地关注输入序列中的不同位置。这种机制可以根据上下文灵活选择输入信息,解决不对齐问题。
- 编码器部分:编码器处理输入序列(如源语言句子),并将其表示为上下文表示。每个输入词会被转换为一个上下文向量,这些上下文向量包含了输入序列中不同位置的信息。
- 解码器部分:解码器在生成目标序列的每一步时,利用编码器-解码器注意力机制来决定应该关注输入序列中的哪些部分。在每个时间步,解码器通过查询(Query)解码器中的状态向量,并与编码器输出的键(Key)向量进行注意力计算,从而生成注意力分数(即每个输入词的重要性)。然后,将这些注意力分数加权应用于输入的值(Value)向量,得到加权和作为解码器生成当前输出的依据。
这一机制使得模型在生成目标序列的每一步时都可以动态地从输入序列中“抽取”相关信息,而不需要固定的对齐方式。
前馈神经网络的双层结构
前馈神经网络的结构由两层全连接神经网络(Fully Connected Layer)组成
1. 前馈神经网络的结构
在Transformer的编码器和解码器中,每个层的前馈神经网络是独立于序列位置的,即对于每个输入位置 ( x i x_i xi ),前馈网络应用于该位置而不考虑其他位置。前馈网络的计算过程如下:
F
F
N
(
x
)
=
max
(
0
,
x
W
1
+
b
1
)
W
2
+
b
2
FFN(x)=\max(0,xW_{1}+b_{1})W_{2}+b_{2}
FFN(x)=max(0,xW1+b1)W2+b2
这里:
- x x x是输入向量(每个时间步上的词的表示)。
- W 1 W_{1} W1和 W 2 W_{2} W2是两层全连接网络的权重矩阵。
- b 1 b_{1} b1和 b 2 b_{2} b2是偏置项。
- max ( 0 , ⋅ ) \max(0,\cdot) max(0,⋅)是ReLU激活函数,用于引入非线性。
第一层的线性变换:
h
=
max
(
0
,
x
W
1
+
b
1
)
h = \max(0,xW_{1}+b_{1})
h=max(0,xW1+b1)
这里
W
1
W_{1}
W1将输入
x
x
x从原来的维度
d
model
d_{\text{model}}
dmodel投影到一个更高维的空间,通常称为扩展维度。这个投影过程通过线性变换,然后通过ReLU激活函数引入非线性。
- W 1 W_{1} W1的维度是 d model × d ff d_{\text{model}}\times d_{\text{ff}} dmodel×dff,其中 d ff d_{\text{ff}} dff是扩展后的维度,通常比 d model d_{\text{model}} dmodel大(例如,通常选择 d ff = 4 × d model d_{\text{ff}} = 4\times d_{\text{model}} dff=4×dmodel)。
- b 1 b_{1} b1是与 W 1 W_{1} W1对应的偏置项,维度是 d ff d_{\text{ff}} dff。
第二层的线性变换:
Output
=
h
W
2
+
b
2
\text{Output} = hW_{2}+b_{2}
Output=hW2+b2
在经过ReLU激活函数后的中间结果
h
h
h再次通过第二层的线性变换,投影回原来的维度
d
model
d_{\text{model}}
dmodel,使得最终的输出与输入的形状一致。
- W 2 W_{2} W2的维度是 d ff × d model d_{\text{ff}}\times d_{\text{model}} dff×dmodel,将 d ff d_{\text{ff}} dff维度投影回 d model d_{\text{model}} dmodel。
- b 2 b_{2} b2是与 W 2 W_{2} W2对应的偏置项,维度是 d model d_{\text{model}} dmodel。
2. 为什么需要两个权重矩阵和两个偏置项?
为了实现更强的表达能力,前馈神经网络有两层全连接层,具体来说:
- 第一层扩展维度:将输入从原始维度(如词向量的维度)扩展到一个更高的维度,这样网络能够表示更多的特征信息,并且在高维空间中进行更复杂的计算。【类似SVM核函数】
- ReLU 激活函数:引入非线性,使模型能够学习复杂的非线性关系。
- 第二层将回原始维度:将经过非线性处理后的结果映射回原始的维度,使得最终的输出可以与输入具有相同的形状,方便后续的操作。
两个偏置项 ( b 1 b_1 b1 ) 和 ( b 2 b_2 b2 ) 是为了进一步增加模型的灵活性和表达能力,它们帮助每一层的输出更加独立地进行调整,避免过度依赖输入的线性变换。
- 扩展特征表示能力:
- 第一层的权重 W 1 W_{1} W1将输入 x x x从 d model d_{\text{model}} dmodel维度投影到更高维度 d ff d_{\text{ff}} dff,这使得网络可以在一个更高维的空间中学习复杂的特征表示。
- ReLU激活函数引入了非线性,帮助网络学习非线性关系,这在表达复杂函数时非常重要。
- 回到原始维度:
- 第二层的权重 W 2 W_{2} W2再将中间结果从高维度 d ff d_{\text{ff}} dff投影回原始的 d model d_{\text{model}} dmodel维度。这样,前馈网络的输出可以与输入的形状一致,从而可以进行后续的层处理。
- 层次化特征学习:
- 前馈网络的这种两层结构可以看作是对特征的进一步提炼。第一层扩展维度,允许网络捕捉到更多复杂的信息,而第二层则将这些信息映射回较低维度,从而将重要的信息压缩回来。
- 这种设计使得网络能够学习多层次的特征。
3. 作用和重要性
Transformer 中的前馈神经网络使用两层全连接层,主要带来以下好处:
- 引入非线性:通过两层结构和激活函数,模型可以捕捉更复杂的非线性特征。
- 提升模型表达能力:扩展-压缩的结构提高了模型的容量,增强了其学习复杂模式的能力。
- 与多头注意力机制互补:前馈网络负责局部特征的深入处理,与注意力机制的全局特征捕捉形成互补。
- 独立于序列长度:前馈网络能够对每个位置的输入向量独立处理,灵活适应不同长度的输入。
4. 总结
- Transformer中的前馈神经网络(FFN)包含两个权重矩阵 ( W 1 W_1 W1 ) 和 ( W 2 W_2 W2 ) 【He初始化】以及相应的偏置项 ( b 1 b_1 b1 ) 和 ( b 2 b_2 b2 )【初始化为0】,这是因为它是一个由两层全连接层组成的网络。
- 第一层通过 ( W 1 W_1 W1 ) 和 ( b 1 b_1 b1 ) 将输入投影到一个更高的维度,经过非线性ReLU激活函数处理;第二层通过 ( W 2 W_2 W2 ) 和 ( b 2 b_2 b2 ) 将结果投影回原始维度。
- 这种结构允许网络在更高维空间中学习复杂的特征,并将结果映射回可操作的低维空间,从而提高网络的表达能力和性能。
残差网络
残差网络(Residual Network, ResNet)目的是解决深层网络在训练过程中出现的 梯度消失 和 退化 问题。
ResNet 的核心思想是引入残差连接(skip connections),让网络学习残差函数,而不是直接学习复杂的映射函数。
为什么需要 ResNet?
理论上更深的网络能够捕捉到更复杂的特征,效果应该更好。然而,在实际中,随着网络深度的增加,梯度消失 和 梯度爆炸 的问题加剧,导致模型难以收敛。即使通过适当的初始化或正则化缓解了梯度问题,退化问题 也会出现——更深的网络反而会比浅层网络表现更差。
为了解决这个问题,ResNet 引入了残差连接,使得网络可以更容易地训练超深层网络。
残差网络的核心思想
残差连接 是 ResNet 的关键,将输入直接绕过若干层传递给输出,使得网络可以学习输入和输出之间的 “残差” ,而不是直接学习输入到输出的映射 。
具体来说,假设某一层的输入为
x
x
x,传统的神经网络学习的是某种映射函数
H
(
x
)
H(x)
H(x),即:
y
=
H
(
x
)
y = H(x)
y=H(x)
而在ResNet中,网络不再直接学习
H
(
x
)
H(x)
H(x),而是学习残差函数
F
(
x
)
F(x)
F(x),使得输出为:
y
=
F
(
x
)
+
x
y = F(x)+x
y=F(x)+x
其中,
F
(
x
)
F(x)
F(x)是通过网络层学习的残差,
x
x
x是输入的跳跃连接。这一结构通过将输入直接传递给输出,构成了一条捷径(skip connection),减轻了网络的优化难度。
ResNet 的基本残差块
每个残差块包含两种路径:
- 主路径(main path):即通过两层(或三层)卷积操作对输入进行处理,生成 F ( x ) F(x) F(x) 。
- 捷径路径(shortcut path):直接将输入 x x x 传递给输出。
具体的残差块结构如下:
- 输入 ( x x x ) 通过主路径,生成 ( F ( x ) F(x) F(x) )。
- ( x x x ) 通过捷径连接直接加到 ( F ( x ) F(x) F(x) ) 上,得到输出: y = F ( x ) + x y = F(x) + x y=F(x)+x
这种结构使得即便某些层的 ( F ( x ) F(x) F(x) ) 学习不好,网络仍然可以通过捷径连接保留输入信息,确保网络深度的增加不会导致性能下降。
ResNet 的优势
- 缓解梯度消失问题:残差连接使得梯度能够在反向传播过程中通过捷径路径更好地传递,避免深层网络中的梯度消失问题。
- 解决退化问题:通过引入残差连接,网络可以学习到恒等映射(identity mapping),即使增加网络深度,也不会出现性能下降的问题,甚至可能获得更好的结果。
- 便于优化:残差网络使得更深的网络变得易于训练,在实践中,ResNet 能够轻松达到数百甚至上千层。
总结
残差网络(ResNet) 通过引入残差连接,使得深层神经网络能够在不产生梯度消失和退化问题的情况下进行训练。其基本思想是让网络学习残差函数,使得网络层数增加时不会显著增加优化难度。这个简单而有效的结构使得 ResNet 成为了现代深度学习中常用的网络架构之一,并广泛应用于计算机视觉等领域。
层归一化
Transformer 模型使用 层归一化(Layer Normalization, LN) 而不是 批归一化(Batch Normalization, BN),主要原因涉及到序列处理的需求、自回归生成任务的特性、模型并行化能力以及训练的稳定性。主要原因包括以下几点:
自回归生成任务、处理变长序列、并行化
- 处理变长序列:层归一化可以对每个样本的特征维度独立进行归一化,适合不同长度的序列,而批归一化依赖于整个批次的统计量,在变长序列中不适用。
- 自回归生成任务:在逐步生成目标序列时,层归一化能在每个时间步稳定工作,而批归一化则因依赖于批次数据无法适应。
- 并行化需求:层归一化的独立性使其非常适合并行计算,避免了批归一化在并行时的同步开销,提升了模型的训练效率。
- 稳定性与效率:层归一化在处理小批量数据或变长序列时训练更加稳定,避免了批归一化引入的训练不稳定问题。
因此,层归一化 更加适合 Transformer 模型中处理复杂的序列任务,确保模型在不同场景下的稳定性和训练效率。
归一化相关知识点参考:深度学习——优化算法、激活函数、归一化、正则化
Transformer的并行化(Decoder可以做并行化嘛?)
层级内的并行化
每一层内部(如自注意力、前馈神经网络、编码器-解码器注意力机制)的计算是并行的,可以同时处理所有的词,这大大提升了计算效率。
单层编码器的并行化情况
训练阶段和推理阶段的在所有层级都可以完全并行化处理输入序列,极大地提高了处理速度。
单层解码器的并行化情况
- 训练阶段:解码器可以并行化,因为使用了教师强制,整个目标序列是已知的,因此可以同时计算多个时间步的自注意力和编码器-解码器注意力。
- 推理阶段:解码器需要逐步串行生成目标序列,每个时间步依赖前一个时间步的输出,因此自注意力机制不能完全并行化。不过,编码器-解码器注意力部分可以并行进行,因为编码器的输出是已知的。
总之,Transformer 的并行化能力极大地提高了模型在大规模数据上的计算效率,而解码器在推理阶段由于逐步生成词汇的特性,限制了其完全并行化的能力。
层级之间的串行
- 编码器和解码器的所有层级之间是顺序执行的,因为每一层的输出是下一层的输入。
解决梯度消失和梯度爆炸方案
在 Transformer 模型中,梯度消失和梯度爆炸问题的解决方案涵盖了模型的多个层面,确保模型能够在深度学习训练中保持稳定的梯度传播。以下是主要的技术方法及其作用:
- 残差连接:通过为每层引入直接连接,确保梯度能够有效传播,缓解深层网络中的梯度消失问题。
- 层归一化:在每层的输入上进行归一化处理,避免输入分布波动过大,同时解决梯度消失和梯度爆炸问题。
- 缩放点积注意力:通过对点积结果进行缩放,防止点积值过大,避免在 softmax 计算时引发梯度爆炸。
- 权重初始化:通过 Xavier 或 He 初始化等策略,确保初始梯度处于合理范围,避免梯度在训练初期消失或爆炸。
- 学习率调度器:Transformer 在训练过程采用 warmup(学习率从一个非常小的值开始,并逐渐增大) 和 decay(学习率达到一个峰值,之后开始逐渐降低) 策略,通过动态调整学习率,目的是在模型训练的不同阶段动态调整学习率。
- Warmup 阶段:在训练的初期,学习率从一个非常小的值开始,并逐渐增大,称为 “warmup” 。这一阶段的目的是防止模型在训练开始时的梯度过大或过小,导致梯度消失或梯度爆炸问题。通过缓慢增加学习率,可以帮助模型稳定地找到合适的训练方向。
- 学习率衰减(Decay)阶段:经过 warmup 后,学习率达到一个峰值,之后开始逐渐降低。这是为了避免在训练的中后期由于学习率过大而导致参数更新剧烈,从而引发梯度爆炸。学习率逐步减小,可以让模型在接近最优解时,进行更细致的优化,从而避免训练不稳定。
- 梯度裁剪:在每次参数更新之前,当梯度过大时,限制梯度的范数,确保训练过程中不会出现梯度爆炸。
- 正则化技术:在前向传播过程中,通过 L2 正则化限制权重增长和 Dropout 防止过拟合,间接防止梯度爆炸。
这些技术共同作用,使得 Transformer 能够在大规模训练和深层结构中有效应对梯度消失和梯度爆炸问题,从而确保其在自然语言处理、机器翻译等任务中的出色表现。
Softmax在transformer中的什么作用
- 归一化注意力权重:通过应用softmax函数,注意力权重被归一化,使其和为1,从而形成有效的概率分布。这确保了模型在计算注意力时,能对每个位置的关注程度进行衡量。
- 输出阶段生成概率分布:将最后的线性层输出转换为概率分布,以便进行词预测或分类任务。
Transformer模型中,Dropout的位置
- 在Transformer模型中,Dropout通常被应用于以下位置:
- 在自注意力层和前馈网络之间。
- 在前馈网络内部,即在两个全连接层之间。
- 在残差连接和层归一化之后。
使用Dropout时,通常会在训练过程中启用它,而在模型评估或推理阶段则禁用,以确保所有的神经元都能参与到最终的预测中。通过这种方式,Dropout有助于Transformer模型在多种不同的任务上实现更好的性能。
Transformer 输入总结
Transformer 的输入主要包括以下几个关键部分:
- 源序列:原始的输入序列(如句子),经过嵌入层映射为词向量。
- 目标序列:解码器的输入序列(训练时已知,推理时逐步生成)。
- 词嵌入(Word Embedding):将源序列和目标序列的词转化为固定维度的向量表示。可学习的嵌入(Learned Embeddings):通过嵌入层将词映射为向量,词嵌入矩阵是通过模型训练逐渐学习的。预训练的嵌入(Pre-trained Embeddings):可以使用如 Word2Vec、GloVe 等预训练词向量来初始化嵌入矩阵,帮助模型快速获取语义信息
- 位置编码(Positional Encoding):为词嵌入添加位置信息,确保模型感知序列中的顺序。
- 遮蔽机制(Masking):
- 填充遮蔽:忽略输入中的填充值。
- 未来遮蔽:确保解码器在生成目标序列时,只能看到当前和过去的词,不能看到未来的词。
- 特殊标记:如
<START>
、<END>
、<PAD>
等,用于标记序列的起始、结束或填充。
这些输入内容共同作用,保证 Transformer 模型能够正确处理序列数据并生成高质量的输出。
ROPE位置编码方法
ROPE(Rotary Position Embedding) 是一种新的位置编码方法,最早应用于一些改进的 Transformer 模型(如 GPT-NeoX 和 GPT-J),用于替代传统的绝对位置编码(如 Transformer 中的正弦-余弦位置编码)。它通过引入旋转不变性(rotary invariance),使模型能够更好地捕捉相对位置信息。
ROPE 的特点总结
- 相对位置编码:ROPE 不仅编码词的绝对位置,还能够捕捉词之间的相对位置信息。
- 旋转不变性:通过对查询(Q)和键(K)向量的旋转操作隐式注入位置信息,不需要额外的位置编码向量。
- 提高长序列处理能力:相比于传统的正弦-余弦位置编码,ROPE 在处理长序列时更加有效,能够捕捉远距离的依赖关系。
- 计算高效:无需显式地为每个词计算位置编码,直接对向量进行旋转操作,节省了计算资源。
- 可扩展性:ROPE 对于处理变长序列具有很好的扩展性,能够在训练时未见过的序列长度上表现良好。
这些特点使得 ROPE 在改进 Transformer 模型(如 GPT-J、GPT-NeoX)中被广泛应用,尤其在需要处理长序列的任务中表现出色。
历史文章
机器学习
机器学习笔记——损失函数、代价函数和KL散度
机器学习笔记——特征工程、正则化、强化学习
机器学习笔记——30种常见机器学习算法简要汇总
机器学习笔记——感知机、多层感知机(MLP)、支持向量机(SVM)
机器学习笔记——KNN(K-Nearest Neighbors,K 近邻算法)
机器学习笔记——朴素贝叶斯算法
机器学习笔记——决策树
机器学习笔记——集成学习、Bagging(随机森林)、Boosting(AdaBoost、GBDT、XGBoost、LightGBM)、Stacking
机器学习笔记——Boosting中常用算法(GBDT、XGBoost、LightGBM)迭代路径
机器学习笔记——聚类算法(Kmeans、GMM-使用EM优化)
机器学习笔记——降维
深度学习
深度学习笔记——优化算法、激活函数
深度学习——归一化、正则化
深度学习笔记——前向传播与反向传播、神经网络(前馈神经网络与反馈神经网络)、常见算法概要汇总
深度学习笔记——卷积神经网络CNN
深度学习笔记——循环神经网络RNN、LSTM、GRU、Bi-RNN