目录
前言
书接上文。
一、大模型激活函数
参考大模型结构细节。
1、ReLU
原始的Transformer采用的是ReLU,后面的T5,OPT采用的激活函数也是ReLU,此时 FFN 可以表示为:
F F N ( x , W 1 , W 2 , b 1 , b 2 ) = R e L U ( x W 1 + b 1 ) W 2 + b 2 FFN(x,W_{1},W_{2},b_{1},b_{2})=ReLU(xW_{1}+b_{1})W_{2}+b_{2} FFN(x,W1,W2,b1,b2)=ReLU(xW1+b1)W2+b2
2、GeLU
GPT-1、GPT-2、GPT-3、BLOOM采用的激活函数就是GeLU(Gaussian Error Linear Unit)。GeLU的表达式如下:
G e L U ( x ) = x Φ ( x ) GeLU(x)=x\Phi(x) GeLU(x)=xΦ(x)
其中:
Φ ( x ) = ∫ − ∞ x e − t 2 / 2 2 π d t \Phi(x)=\int_{-\infty}^{x}\frac{e^{-t^{2}/2}}{\sqrt{2\pi}}dt Φ(x)=∫−∞x2πe−t2/2dt
原论文中给出了GeLU的两个近似计算:
x Φ ( x ) ≈ x σ ( 1.702 x ) x\Phi(x)\approx x\sigma(1.702x) xΦ(x)≈xσ(1.702x)
其中 σ \sigma σ是 s i g m o i d sigmoid sigmoid函数。或者:
x Φ ( x ) ≈ 1 2 x [ 1 + t a n h ( 2 π ( x + 0.044715 x 3 ) ) ] x\Phi(x)\approx \frac{1}{2}x[1+tanh(\sqrt\frac{2}{\pi}(x+0.044715x^{3}))] xΦ(x)≈21x[1+tanh(π2(x+0.044715x3))]
此时 FFN 可以表示为:
F F N ( x , W 1 , W 2 , b 1 , b 2 ) = G e L U ( x W 1 + b 1 ) W 2 + b 2 FFN(x,W_{1},W_{2},b_{1},b_{2})=GeLU(xW_{1}+b_{1})W_{2}+b_{2} FFN(x,W1,W2,b1,b2)=GeLU(xW1+b1)W2+b2
3、GLU
GLU Variants Improve Transformer提出,可以利用门控线形单元:GLU(Gated Linear Units)对激活函数进行改进。首先,GLU的基本形式是:对输入做双线性变换(多了一个矩阵 V),并且其中一个添加 s i g m o i d sigmoid sigmoid变换:
G L U ( x , W , V , b , c ) = σ ( x W + b ) ⊗ ( x V + c ) GLU(x,W,V,b,c)=\sigma(xW+b)\otimes(xV+c) GLU(x,W,V,b,c)=σ(xW+b)⊗(xV+c)
此时 FFN 可以表示为:
F F N ( x , W 1 , W 2 , V , b 1 , b 2 , c ) = ( σ ( x W 1 + b 1 ) ⊗ ( x V + c ) ) W 2 + b 2 FFN(x,W_{1},W_{2},V,b_{1},b_{2},c)=(\sigma(xW_{1}+b_{1})\otimes(xV+c))W_{2}+b_{2} FFN(x,W1,W2,V,b1,b2,c)=(σ(xW1+b1)⊗(xV+c))W2+b2
4、GeGLU
将GLU中的 s i g m o i d sigmoid sigmoid换成GeLU激活函数,就得到了GLU的一个变体:GeGLU,GLM-130B采用的激活函数就是GeGLU,具体表达式如下所示:
G e G L U ( x , W , V , b , c ) = G e L U ( x W + b ) ⊗ ( x V + c ) GeGLU(x,W,V,b,c)=GeLU(xW+b)\otimes(xV+c) GeGLU(x,W,V,b,c)=GeLU(xW+b)⊗(xV+c)
此时 FFN 可以表示为:
F F N ( x , W 1 , W 2 , V , b 1 , b 2 , c ) = ( G e L U ( x W 1 + b 1 ) ⊗ ( x V + c ) ) W 2 + b 2 FFN(x,W_{1},W_{2},V,b_{1},b_{2},c)=(GeLU(xW_{1}+b_{1})\otimes(xV+c))W_{2}+b_{2} FFN(x,W1,W2,V,b1,b2,c)=(GeLU(xW1+b1)⊗(xV+c))W2+b2
5、SwiGLU
将GLU中的 s i g m o i d sigmoid sigmoid换成另一种激活函数,就得到了GLU的又一个变体:SwiGLU,LLaMA采用的激活函数就是SwiGLU,具体表达式如下所示:
S w i G L U ( x , W , V , b , c ) = S w i s h β ( x W + b ) ⊗ ( x V + c ) SwiGLU(x,W,V,b,c)=Swish_{\beta}(xW+b)\otimes(xV+c) SwiGLU(x,W,V,b,c)=Swishβ(xW+b)⊗(xV+c)
此时 FFN 可以表示为:
F F N ( x , W 1 , W 2 , V , b 1 , b 2 , c ) = ( S w i s h β ( x W 1 + b 1 ) ⊗ ( x V + c ) ) W 2 + b 2 FFN(x,W_{1},W_{2},V,b_{1},b_{2},c)=(Swish_{\beta}(xW_{1}+b_{1})\otimes(xV+c))W_{2}+b_{2} FFN(x,W1,W2,V,b1,b2,c)=(Swishβ(xW1+b1)⊗(xV+c))W2+b2
其中, S w i s h β ( x ) = x ⋅ σ ( β x ) Swish_{\beta}(x)=x\cdot\sigma(\beta x) Swishβ(x)=x⋅σ(βx), β \beta β是指定的常数,一般为1。相较于原始的ReLU激活函数,由于涉及到多一维度的线性表示,所以会面临着带来参数量新增和计算量增加。而LLaMA中怎么克服这一点的呢?LLaMA是把SwiGLU中的 W 1 、 W 2 、 V W_{1}、W_{2}、V W1、W2、V的矩阵维度从 ( d i m , d i m ) (dim, dim) (dim,dim)变成 ( d i m , 2 3 d i m ) (dim, \frac{2}{3}dim) (dim,32dim),从而打平参数量和计算量。
二、位置编码
1、旋转位置编码
旋转位置编码(Rotary Position Embedding,RoPE)来源于苏剑林的Rotary Transformer。传统的位置编码通常是在输入时与token embedding进行加和,在进行后续Attention计算时,公式如下:
Q K T = x W Q ⋅ W K T x T + x W Q ⋅ W K T p T + p W Q ⋅ W K T x T + p W Q ⋅ W K T p T O = A ⋅ V = A ⋅ ( x W V + p W V ) \begin{aligned} QK^{T}&=xW_{Q}\sdot W_{K}^{T}x^{T}+xW_{Q}\sdot W_{K}^{T}p^{T}+pW_{Q}\sdot W_{K}^{T}x^{T}+pW_{Q}\sdot W_{K}^{T}p^{T}\\ O&=A\sdot V=A\sdot(xW_{V}+pW_{V}) \end{aligned} QKTO=xWQ⋅WKTxT+xWQ⋅WKTpT+pWQ⋅WKTxT+pWQ⋅WKTpT=A⋅V=A⋅(xWV+pWV)
其中 A = s o f t m a x ( Q K T d k ) A=softmax(\frac{QK^{T}}{\sqrt{d_{k}}}) A=softmax(dkQKT)是注意力矩阵, x x x是输入的token embedding, p p p是position embedding。
事实上,位置向量不一定非要加在输入的token embedding上才能起作用,由上式可知,只要在 Q Q Q、 K K K矩阵上加上位置编码,同样可以作用在注意力矩阵 A A A上,进而作用在 V V V上。旋转位置编码就是采用的这种思想。
- 旋转位置编码公式:对于 Q Q Q的第 m m m个向量 q q q、 K K K的第 n n n个向量 k k k,通过以下方法注入位置编码:
- 二维:假定词嵌入维度是2维。
f ( q , m ) = ( c o s ( m θ ) − s i n ( m θ ) s i n ( m θ ) c o s ( m θ ) ) ( q 1 q 2 ) f(q,m)= \begin{pmatrix} cos(m\theta) & -sin(m\theta) \\ sin(m\theta) & cos(m\theta) \end{pmatrix} \begin{pmatrix} q_{1} \\ q_{2} \end{pmatrix} f(q,m)=(cos(mθ)sin(mθ)−sin(mθ)cos(mθ))(q1q2)
f ( k , n ) = ( c o s ( n θ ) − s i n ( n θ ) s i n ( n θ ) c o s ( n θ ) ) ( k 1 k 2 ) f(k,n)= \begin{pmatrix} cos(n\theta) & -sin(n\theta) \\ sin(n\theta) & cos(n\theta) \end{pmatrix} \begin{pmatrix} k_{1} \\ k_{2} \end{pmatrix} f(k,n)=(cos(nθ)sin(nθ)−sin(nθ)cos(nθ))(k1k2)
其中, q = ( q 1 q 2 ) q=\begin{pmatrix} q_{1} \\ q_{2} \end{pmatrix} q=(q1q2)是 Q Q Q的第 m m m个向量, k = ( k 1 k 2 ) k=\begin{pmatrix} k_{1} \\ k_{2} \end{pmatrix} k=(k1k2)是 K K K的第 n n n个向量, f ( q , m ) f(q,m) f(q,m)、 f ( k , n ) f(k,n) f(k,n)分别是经过旋转位置编码后的 q q q和 k k k。可以发现,旋转位置编码其实就是对 q q q和 k k k分别乘以了一个旋转矩阵(向量乘以旋转矩阵后,模(向量大小)不变,方向改变),这就是为什么叫做旋转式位置编码的原因。此时 Q K T QK^{T} QKT的计算公式为(仅以 q q q和 k k k相乘为例):
( q 1 q 2 ) ( c o s ( ( m − n ) θ ) − s i n ( ( m − n ) θ ) s i n ( ( m − n ) θ ) c o s ( ( m − n ) θ ) ) ( k 1 k 2 ) \begin{pmatrix} q_{1} & q_{2} \end{pmatrix} \begin{pmatrix} cos((m-n)\theta) & -sin((m-n)\theta) \\ sin((m-n)\theta) & cos((m-n)\theta) \end{pmatrix} \begin{pmatrix} k_{1} \\ k_{2} \end{pmatrix} (q1q2)(cos((m−n)θ)sin((m−n)θ)−sin((m−n)θ)cos((m−n)θ))(k1k2) - 多维:上面的计算是假定词嵌入维度是2维,而对于 d ≥ 2 d\ge2 d≥2的通用情况,则是将 q q q向量中的元素按照两两一组分组,每组应用同样的旋转操作,具体计算公式如下:
f ( q , m ) = ( c o s ( m θ 0 ) − s i n ( m θ 0 ) 0 0 ⋯ 0 0 s i n ( m θ 0 ) c o s ( m θ 0 ) 0 0 ⋯ 0 0 0 0 c o s ( m θ 1 ) − s i n ( m θ 1 ) ⋯ 0 0 0 0 s i n ( m θ 1 ) c o s ( m θ 1 ) ⋯ 0 0 ⋮ ⋮ ⋮ ⋮ ⋱ ⋮ ⋮ 0 0 0 0 ⋯ c o s ( m θ d / 2 − 1 ) − s i n ( m θ d / 2 − 1 ) 0 0 0 0 ⋯ s i n ( m θ d / 2 − 1 ) c o s ( m θ d / 2 − 1 ) ) ( q 0 q 1 q 2 q 3 ⋮ q d − 2 q d − 1 ) f(q,m)= \begin{pmatrix} cos(m\theta_{0}) & -sin(m\theta_{0}) & 0 & 0 & \cdots & 0 & 0 \\ sin(m\theta_{0}) & cos(m\theta_{0}) & 0 & 0 & \cdots & 0 & 0 \\ 0 & 0 & cos(m\theta_{1}) & -sin(m\theta_{1}) & \cdots & 0 & 0 \\ 0 & 0 & sin(m\theta_{1}) & cos(m\theta_{1}) & \cdots & 0 & 0 \\ \vdots & \vdots & \vdots & \vdots & \ddots & \vdots & \vdots \\ 0 & 0 & 0 & 0 & \cdots & cos(m\theta_{d/2-1}) & -sin(m\theta_{d/2-1}) \\ 0 & 0 & 0 & 0 & \cdots & sin(m\theta_{d/2-1}) & cos(m\theta_{d/2-1}) \\ \end{pmatrix} \begin{pmatrix} q_{0} \\ q_{1}\\ q_{2}\\ q_{3}\\ \vdots\\ q_{d-2}\\ q_{d-1} \end{pmatrix} f(q,m)= cos(mθ0)sin(mθ0)00⋮00−sin(mθ0)cos(mθ0)00⋮0000cos(mθ1)sin(mθ1)⋮0000−sin(mθ1)cos(mθ1)⋮00⋯⋯⋯⋯⋱⋯⋯0000⋮cos(mθd/2−1)sin(mθd/2−1)0000⋮−sin(mθd/2−1)cos(mθd/2−1) q0q1q2q3⋮qd−2qd−1
其中, θ j = 1000 0 − 2 j / d \theta_{j}=10000^{-2j/d} θj=10000−2j/d, j ∈ { 0 , 1 , … , d / 2 − 1 } j\in \{0,1,\dots,d/2-1\} j∈{ 0,1,…,d/2−1}。 k k k的计算类似,这里不予展示。 - 高效计算:由于上述旋转矩阵的稀疏性,所以直接用矩阵乘法来实现会很浪费算力,推荐通过下述方式来实现RoPE:
f ( q , m ) = ( q 0 q 1 q 2 q 3 ⋮ q d − 2 q d − 1 ) ⊗ ( c o s ( m θ 0 ) c o s ( m θ 0 ) c o s ( m θ 1 ) c o s ( m θ 1 ) ⋮ c o s ( m θ d / 2 − 1 ) c o s ( m θ d / 2 − 1 ) ) + ( − q 1 q 0 − q 3 q 2 ⋮ − q d − 1 q d − 2 ) ⊗ ( s i n ( m θ 0 ) s i n ( m θ 0 ) s i n ( m θ 1 ) s i n ( m θ 1 ) ⋮ s i n ( m θ d / 2 − 1 ) s i n ( m θ d / 2 − 1 ) ) f(q,m)= \begin{pmatrix} q_{0} \\ q_{1}\\ q_{2}\\ q_{3}\\ \vdots\\ q_{d-2}\\ q_{d-1} \end{pmatrix}\otimes \begin{pmatrix} cos(m\theta_{0}) \\ cos(m\theta_{0}) \\ cos(m\theta_{1}) \\ cos(m\theta_{1}) \\ \vdots \\ cos(m\theta_{d/2-1}) \\ cos(m\theta_{d/2-1}) \\ \end{pmatrix}+ \begin{pmatrix} -q_{1} \\ q_{0}\\ -q_{3}\\ q_{2}\\ \vdots\\ -q_{d-1}\\ q_{d-2} \end{pmatrix}\otimes \begin{pmatrix} sin(m\theta_{0}) \\ sin(m\theta_{0}) \\ sin(m\theta_{1}) \\ sin(m\theta_{1}) \\ \vdots \\ sin(m\theta_{d/2-1}) \\ sin(m\theta_{d/2-1}) \\ \end{pmatrix} f(q,m)= q0q1q2q3⋮qd−2qd−1 ⊗ cos(mθ0)cos(mθ0)cos(mθ1)cos(mθ1)⋮cos(mθd/2−1)cos(mθd/2−1) + −q1q0−q3q2⋮−qd−1qd−2 ⊗ sin(mθ0)sin(mθ0)sin(mθ1)sin(mθ1)⋮sin(mθd/2−1)sin(mθd/2−1) - 直观展示:论文中有个很直观的图片展示了旋转变换的过程。
- 远程衰减:RoPE形式上和传统transformer的三角式位置编码有点相似,只不过三角式位置编码是加性的,而RoPE可以视为乘性的。在 θ i \theta_{i} θi的选择上,RoPE 同样沿用了三角式位置编码的方案,即 θ j = 1000 0 − 2 j / d \theta_{j}=10000^{-2j/d} θj=10000−2j/d, j ∈ { 0 , 1 , … , d / 2 − 1 } j\in\{0,1,\dots,d/2-1\} j∈{
0,1,…,d/2−1},它可以带来一定的远程衰减性。如下图所示:
从图中我们可以看到随着相对距离的变大,内积结果有衰减趋势的出现。因此,选择 θ j = 1000 0 − 2 j / d \theta_{j}=10000^{-2j/d} θj=10000−2j/d,确实能带来一定的远程衰减性。论文中还试过以 θ j = 1000 0 − 2 j / d \theta_{j}=10000^{-2j/d} θj=10000−2j/d为初始化,将 θ j \theta_{j} θj视为可训练参数,然后训练一段时间后发现 θ j \theta_{j} θj并没有显著更新,因此干脆就直接固定 θ j = 1000 0 − 2 j / d \theta_{j}=10000^{-2j/d} θj=10000−2j/d了。 - RoPE实践:后续看看LLaMA、ChatGLM的源码。
- ChatGLM2:每个 q q q、 k k k向量只有前一半的位置添加了旋转位置编码;
- LLaMA:实现了苏剑林版本的旋转位置编码。
- 优缺点:
- 优点:RoPE是通过绝对位置编码实现相对位置编码,优点是这种方法不仅可以处理位置信息,还可以处理距离信息,因为旋转操作可以很好地反映出元素之间的相对位置关系;
- 缺点:缺点是它需要更多的计算资源,因为旋转操作比简单的向量加法更复杂。
- 参考资料:十分钟读懂旋转编码(RoPE)、一文看懂LLaMA中的旋转式位置编码。
- 二维:假定词嵌入维度是2维。
三、Decoder-only模型
1、生成任务
- 有条件文本生成:进行文本生成任务时,给定前置的生成条件,例如输入是:给定文本内容:春天真美好,进行故事续写;
- 无条件文本生成:进行文本生成任务时,不给定前置的生成条件,例如输入是:写一篇作文。
2、推理流程
- Casual LM:
- 原始输入构成:对于类GPT模型,无论是有条件文本生成任务,还是无条件文本生成任务,都是将原始输入整体喂入模型;
- 新输入构成:一个一个的生成token,生成的token会拼接在原始输入后面,构成新的输入喂入模型,继续生成新的token;
- Attention计算:输入之间满足Mask Attention机制(后面的token可以看见前面的token,前面的token无法看到后面的token);
- token生成:新token的生成机制,是将输出层的最后一列logits拿去做全词表分类;而最终选取哪个词进行输出,有多种方式,参考下面的解码生成方式。
- Prefix LM:
- 原始输入构成:对于类GLM模型,无论是有条件文本生成任务,还是无条件文本生成任务,都是将原始输入整体喂入模型;
- 新输入构成:一个一个的生成token,生成的token会拼接在原始输入后面,构成新的输入喂入模型,继续生成新的token;
- Attention计算:输入之间满足Prefix Attention机制(原始输入token之间可以互相看见,新拼接的token只能看见前面的token,看不到后面的token);
- token生成:新token的生成机制,是将输出层的最后一列logits拿去做全词表分类;最终选取哪个词进行输出,有多种方式,参考下面的解码生成方式。
3、解码生成方式
- Greedy Search:贪婪搜索。
- 方式:每个时间步都选择概率最大的词;
- 参数设置:
do_sample = False, num_beams = 1
; - 缺点:
- 生成文本重复;
- 不支持生成多条结果。 当
num_return_sequences
参数设置大于1时,代码会报错,说greedy search不支持这个参数大于1。
- Beam Search:束搜索,对贪心策略的一种改进,当num_beams = 1时会退化成贪心搜索策略。
- 方式:每个时间步选择概率最高的num_beams个词;
- 参数设置:
do_sample = False, num_beams > 1
; - 缺点:虽然结果比贪心搜索更流畅,但是仍然存在生成重复的问题。
- Top-K sampling:
- 方式:每个时间步,会保留top-k个token,然后对top-k个token的概率重新归一化,最后在重新归一化后的这k个token中进行采样;
- 参数:
do_sample = True, num_beams = 1
,设定top_k
; - 缺点:在分布陡峭的时候仍会采样到概率小的token,或者在分布平缓的时候只能采样到部分可用token;
- Top-P sampling:
- 方式:每个时间步,按照token出现的概率由高到底排序,当概率之和大于top-p的时候,就不取后面的样本了。然后对取到的这些token的概率重新归一化后,进行采样;
- 参数:
do_sample = True, num_beams = 1
,设定top-p
,在0-1之间取值; - 备注:top-p采样方法往往与top-k采样方法结合使用,每次选取两者中最小的采样范围进行采样,可以减少预测分布过于平缓时采样到极小概率token的几率。
- Temperature sampling:
- 方式:温度调整严格来说不是一种采样方式,只是一种概率改变方法,需要与其他采样方式相结合才可以发挥作用。具体来说,温度调整通过在 s o f t m a x softmax softmax中添加温度系数 t t t来改变每个token输出的概率:
s o f t m a x ( x i ) = e x i / t ∑ j = 1 n e x j / t softmax(x_{i})=\frac{e^{x_{i}}/t}{\sum_{j=1}^{n}e^{x_{j}}/t} softmax(xi)=∑j=1nexj/texi/t
其中, n n n是词表大小, x j x_{j} xj表示词表中每个token对应的logits值, x i x_{i} xi是当前token的logits值, t t t是温度系数。 - 参数:
temperature
; - 备注:由上面公式可知,当 t t t趋近于0时,会增加token之间概率的差值,所有token的概率分布会更陡峭,如下图所示。如果采用top-p采样模式,那么最终输出的token可选范围会缩小(因为只需要更少的token,概率和即可满足条件),模型输出更稳定;当 t t t趋近于无穷大时,会降低大概率token之间概率的差值,所有token的概率分布会更平缓,也就是说,最终输出的token可选范围会增大,模型输出随机性更大。
- 方式:温度调整严格来说不是一种采样方式,只是一种概率改变方法,需要与其他采样方式相结合才可以发挥作用。具体来说,温度调整通过在 s o f t m a x softmax softmax中添加温度系数 t t t来改变每个token输出的概率:
总结
了解LLM,再看这一篇就够了!!!