大模型应用开发之模型架构
一、Transformer 架构
1. 编码器Encoder(“阅读理解大师”)
1)核心任务:编码器的唯一目标就是彻底理解输入的句子。它要把输入的每个词(或者说词元 Token)都转化成一个充满上下文信息的“向量表示”(一串数字),这个向量里浓缩了这个词在整个句子里的意思
2)核心组件:Encoder由好几层完全相同的结构堆叠而成的。每一层都包含两个主要的处理单元
· 多头自注意力机制 (Multi-Head Self-Attention, MHA)
· 前馈神经网络 (Feed-Forward Network, FFN)
在每个注意力和前馈网络后,模型使用层归一化和残差连接来加强模型的训练稳定度,形式话来说,第 𝑙 层(𝑙 ∈ {1, . . . , 𝐿})的编码器的数据处理过程为:
-
X'_{l-1} = LayerNorm(MHA(X_{l-1}) + X_{l-1})
-
X_{l-1}: 第 l-1 层的输出,也是第 l 层的输入。
-
MHA(X_{l-1}): 输入经过多头自注意力处理。
-
MHA(X_{l-1}) + X_{l-1}: 第一个残差连接。
-
LayerNorm(...): 对残差连接的结果进行层归一化,得到中间表示 X'_{l-1}。
-
-
X_l = LayerNorm(FFN(X'_{l-1}) + X'_{l-1})
-
FFN(X'_{l-1}): 中间表示经过前馈网络处理。
-
FFN(X'_{l-1}) + X'_{l-1}: 第二个残差连接。
-
LayerNorm(...): 对残差连接的结果进行层归一化,得到第 l 层的最终输出 X_l。
-
最终经过所有编码器层的处理后,原始输入序列 X 中的每个词元都会得到一个最终的、深度融合了上下文信息的向量表示。这个向量集合(记为 X_L)就是编码器对输入的“理解成果”,它将被传递给解码器
2. 解码器 Decoder(“妙笔生花作家”)
1)核心任务: 解码器的目标是生成目标序列(比如翻译后的句子、问题的答案),利用encoder传来的对原始输入的理解成果和自己前面已经生成的词,一个词一个词地按顺序生成
2)核心组件:解码器也是由多层相同结构堆叠而成,但每一层比编码器多了一个处理单元,总共有三个主要单元:
· 带掩码的多头自注意力机制 (Masked Multi-Head Self-Attention)
· 多头交叉注意力机制 (Multi-Head Cross-Attention)
· 前馈神经网络 (FFN)
残差连接 (Add) 和层归一化 (Norm) 在解码器的每一层也都被广泛使用,围绕着上述三个处理单元,确保训练稳定和信息有效传递,数据流程为:
-
Y'_{l-1} = LayerNorm(MaskedMHA(Y_{l-1}) + Y_{l-1})
-
Y_{l-1}: 解码器第 l-1 层的输出,也是第 l 层的输入。
-
MaskedMHA(Y_{l-1}): 输入经过带掩码的多头自注意力处理。
-
残差连接和层归一化,得到中间表示 Y'_{l-1}。
-
-
Y''_{l-1} = LayerNorm(CrossMHA(Y'_{l-1}, X_L) + Y'_{l-1})
-
CrossMHA(Y'_{l-1}, X_L): Y'_{l-1} 作为 Query,编码器的输出 X_L 作为 Key 和 Value,进行交叉注意力处理。
-
残差连接和层归一化,得到中间表示 Y''_{l-1}。
-
-
Y_l = LayerNorm(FFN(Y''_{l-1}) + Y''_{l-1})
-
FFN(Y''_{l-1}): 中间表示经过前馈网络处理。
-
残差连接和层归一化,得到第 l 层的最终输出 Y_l
-
经过所有解码器层处理后, Y_L 会经过一个最后的线性层 (通常称为 LM Head),作用是将高维的 Y_L 向量投影到整个词汇表的大小 (V)。
O = softmax(W^L Y_L): O 就是最终的输出,代表下一个词元在词汇表上的概率分布。
W^L: 这个线性层的权重矩阵。
W^L Y_L: 得到的向量通常称为 logits,它的每个维度对应词汇表中的一个词元,值表示该词元是下一个词元的“原始得分”。 Logits 会通过一个 Softmax 函数,将其转换为一个概率分布。这个分布中,每个词元的概率值表示它作为下一个生成词元的可能性,所有概率加起来等于 1。
3. 流程总结概述
1) 首先通过输入编码输入文本,将词语和它们的位置信息结合成初始向量序列 X。
2) X 进入 Transformer 的核心层(Encoder 或 Decoder)。
3) 在每一层里,X 首先经过多头自注意力机制,实现词与词之间的信息交互和上下文理解,得到一个中间表示。
4) 然后,这个中间表示的每个位置再独立地通过前馈网络层 (FFN) 进行非线性变换和深化理解。
5) 在每一层的这两个子模块之后,通常都有残差连接和层归一化来帮助训练,整套流程(Attention + FFN + Add & Norm)重复 N 次(N 是模型的层数)。
4. 核心组件优化配置
1)输入编码(Input Encoding)
在我们把一句话喂给 Transformer 之前,需要将离散的词或字符转化为适合深度学习的向量表示,同时保留序列中的位置信息,融合语义和位置信息,将词嵌入向量 e 和对应的位置嵌入向量 P 相加生成统一的输入表示,为序列建模提供基础,过程包括:
· 词嵌入 (Token Embedding Module) :
目的:计算机无法识别单词或字,它只懂数字。所以将离散的词汇(例如“cat”、“dog”)变成连续的向量表示,使其可以被神经网络处理,捕捉词的语义信息。
作用:将输入序列(如句子或词序列) u=[u1,u2,…,ur] 中的每个词 ui 转换为一个高维向量。
具体操作:通过一个嵌入层(通常是一个查找表或神经网络层),每个词 ui 被映射为一个固定维度的向量 e,其维度为 d(例如 e∈Rd ),d 通常是模型设定的超参数(如 512 或 768)。
· 位置编码(Position Embedding, PE):
原因:Transformer 的核心(自注意力机制)在处理句子时,它通过并行处理所有词,是同时看到所有词的,本身并不直接关心词语的顺序,所以如果不加处理,“猫 在 地毯 上”和“地毯 在 猫 上”在它眼里可能差不多,因此需要额外的位置信息来区分词的前后关系。
作用:为句子中的每一个位置(第1个位置、第2个位置……第T个位置)生成一个专属的位置向量P,这个向量的维度与词嵌入向量维度相同,显式编码词在序列中的位置信息,告诉模型每个词在句子里的位置。
具体操作:通常,使用正弦和余弦函数计算(例如 P(t, 2i) = \sin(pos / 10000^{2i/d}),确保不同位置有独特的表示,且与维度 d 一致。
下面讨论几种位置编码方法:
a. 绝对位置(正余弦)编码(原始 Transformer)
使用正弦 (sin) 和余弦 (cos) 函数为每个绝对位置(0, 1, 2...)生成一个固定的向量。不同维度使用不同频率的三角函数,每个位置有固定地址。对于位置t和维度大小为d的位置嵌入:
优点: 实现简单,可以处理比训练时更长的序列(因为三角函数可以外插)。
缺点: 可能无法很好地泛化到远超训练长度的位置,对长文本能力有局限。
b. 相对位置编码
该方法不再给每个位置分配固定编码,而是在计算注意力分数时,额外考虑查询 (Query) 和键 (Key) 之间的相对距离,只关心相对距离。
Transformer-XL: 它对注意力分数的计算进行了修改,用相对位置信息替代了键的绝对位置信息。
T5:在计算注意力分数时,直接引入一个可学习的标量偏置(bias),这个偏置是基于查询和键的位置之间的距离计算的。
c. 旋转位置编码(Rotary Position Embedding, RoPE)
RoPE 是一种巧妙的相对位置编码方法,它通过对查询(Q)和键(K)向量应用旋转操作来融入位置信息。虽然旋转本身是基于绝对位置的,但其巧妙之处在于,在计算 Q 和 K 的点积(注意力核心步骤)时,位置信息会以相对的方式体现出来。
优点: 实现相对简洁,具有良好的外推性(处理长序列能力强),并且与自注意力机制结合得很好。已成为 LLaMA、PaLM 等主流大模型的标配。
d. ALiBi 位置编码
ALiBi 是一种特殊的相对位置编码方法,主要用于增强 Transformer 模型的长度外推能力。它不修改查询或键向量,也不学习位置嵌入。直接在计算注意力分数后,向注意力矩阵添加一个预设的、固定的偏置(bias)。这个偏置与查询和键之间的距离成线性关系,并且对于每个注意力头是特定的。
优点: 结构简单,不需要额外的位置编码层,并且也能很好地外推到长序列。
2)多头自注意力机制
在原始的 Transformer 模型中,注意力机制通过成对的方式进行序列数据的语义建模,充分考虑了序列中所有词元之间的相互关系。其中, 每个词元在注意力计算中都需要对于其前序的所有词元的键值对予以访问,因此 对于序列长度为 𝑇 的序列需要 𝑂(𝑇 ^2 ) 的计算复杂度。
之后,Transformer 引入多头注意力机制,通常由多个自注意力模块组成。每个自注意力模块i中,对输入的词元序列,通过不同语义空间的权重矩阵分别进行线性投影到查询(Query, 𝑸)、键(Key, 𝑲)和值(Value, 𝑽)空间:
然后计算每个模块i的注意力权重并且生成输出:
然后将每个头i的输出进行聚合并通过一个线性层融合形成最终的输出:
它解决了传统 RNN、CNN 在处理长距离依赖关系上的困难。 让模型在理解一个词的时候,能够同时关注到句子中所有其他词(包括它自己),并计算出每个其他词对理解当前词的重要性(注意力权重),直接建模任意距离的词元之间的交互关系
其他常见的注意力机制还有:
· 稀疏注意力机制:滑动窗口注意力 (Sliding Window Attention / Local Attention)是大语言模型中最长使用的一种稀疏注意力机制,完整注意力机制虽然能捕捉全局信息,但其计算复杂度是序列长度的平方级 (O(T^2)),在处理长序列时,计算和存储开销非常大。滑动窗口注意力机制旨在通过限制注意力的范围来降低这种复杂度,对每个词元只关注本身及其左右固定大小窗口内的词(比如左右各看 512 个词)。进一步,通过信息的逐层传递,模型实现了随着层数线性增长的感受野,从而获取远处词元的信息。
优点: 将注意力计算的复杂度从 O(T2) 显著降低到 O(wT),其中 w 是窗口大小,T 是序列长度。当 w 远小于 T 时,效率提升非常明显。
缺点: 丢失了全局信息,窗口外的词无法直接交互。
·多查询/分组查询注意力(Multi-Query / Grouped-Query Attention, MQA/GQA):在多头注意力中,计算量和内存的大头在于存储和计算大量的 Key (K) 和 Value (V) 向量(每个头都有一套)。MQA和GQA通过减少键值对(KV)缓存的大小和内存访问来加速,进一步提升注意力机制的效率
MQA 提出了一种简化方案,让所有的查询头共享同一组键 (K) 和值 (V) 的投影参数及计算结果。也就是说,模型仍然有多个查询头(例如 Q1,Q2,...,Qh),每个查询头负责从不同的表示子空间提问。但是,它们不再各自拥有独立的K和V,而是都使用同一套 K 和 V。
GQA 则将 Query 头分成几组,组内的头共享同一套 K 和 V。这是算是 MQA 和标准 MHA 之间的一个折衷。
·硬件优化的注意力机制(Hardware-Accelerated Attention):算法+硬件双管齐下, 进一步压榨注意力的计算和内存效率,充分利用现代硬件(如 GPU)特性。 代表:
FlashAttention: 通过优化 GPU 计算和内存访问模式(如分块计算、避免重复读写),在不改变数学结果的前提下,大幅提升标准注意力的计算速度并减少内存占用。
PagedAttention: 针对大模型推理时 KV 缓存(存储 K 和 V)的内存管理问题,借鉴操作系统分页的思想,更有效地管理 GPU 显存,减少内存碎片,支持更长的上下文和更高的并发。
3)前馈网络层
自注意力机制擅长捕捉序列中不同位置之间的依赖关系和信息流动(即“谁应该关注谁”)。它通过加权求和的方式聚合信息。虽然 softmax 本身是非线性的,但注意力机制的主要计算在很大程度上是基于线性变换和加权组合的。
如果模型中只有线性变换(或者近似线性的变换),那么无论堆叠多少层,其整体效果仍然等价于一个单一的线性变换。这会极大地限制模型的学习能力,因为它无法学习输入和输出之间复杂的、非线性的映射关系。而真实世界的数据(尤其是语言)充满了复杂的非线性模式。
目标: 对每个位置(每个词)的表示向量独立地进行一次非线性变换和特征提取,引入非线性,增强模型的表达能力, 对注意力层输出的信息进行进一步的提炼和转换。以学习更复杂的函数关系和特征。如果说自注意力是“横向”交互,那 FFN 更像是“纵向”深化。
结构 : FFN由两个线性变换(可以理解为全连接层)和一个非线性激活函数(如 ReLU)组成:
公式中 σ 代表激活函数 ReLU,W^U, b_1 是第一个线性变换的权重和偏置,W^D, b_2 是第二个线性变换的权重和偏置。
· 激活函数: 如果没有激活函数,神经网络无论多少层都只是线性变换的叠加,表达能力有限。激活函数引入非线性,使得网络能够学习和拟合复杂的数据模式。 常用激活函数:
a. ReLU (Rectified Linear Unit) -:ReLU(x) = max(0, x)。对于输入的每个神经元值,将其与“零”进行比较。如果值大于零,则输出该值本身;如果值小于或等于零,则输出零
优点: 计算非常简单,收敛速度快,是早期 Transformer 的选择。
缺点: “死亡 ReLU”问题:如果输入恒小于 0,神经元将永远不被激活,梯度为 0,无法学习。
b. GELU (Gaussian Error Linear Unit) - 平滑版 ReLU,可以理解为一种基于输入值大小进行概率性“门控”的机制。它利用了高斯误差函数,用一个服从高斯分布的随机变量乘以输入的线性变换,然后取期望。一个输入值越大,它被“激活”(乘以接近1的数)的概率就越大;输入值越小(尤其是负值),它被“抑制”(乘以接近0的数)的概率也越大,允许负值有一定程度的通过(概率性)。但这个过程是平滑的
优点: 在很多任务上表现优于 ReLU,通常能带来更好的性能和更平滑的收敛性,成为后来许多 Transformer 模型(如 BERT)的选择。
c. Swish - ReLU 的另一个改进,Swish 激活函数结合了输入的线性部分 (x) 和 Sigmoid 函数 (sigmoid(x)),具有自门控(self-gating)的特性,即函数本身会根据输入值的大小来调节输出的幅度,也是一个平滑的非线性函数。
Swish(x) = x · sigmoid(βx) (β 通常为 1)
优点: 有时性能优于 ReLU 和 GELU。
d. GLU (Gated Linear Unit) 及其变体(SwiGLU 和 GeGLU)- 其基本思路是,输入数据会经过两个独立的线性变换(即通过两个不同的线性层)。其中一个线性变换的输出会经过一个基础的激活函数(比如 Swish 或 GELU)。然后,这个经过激活的输出会与另一个线性变换的输出进行逐元素相乘 (element-wise multiplication, ⊙)。这个逐元素相乘的操作就是“门控”:一个分支的输出(经过激活)作为“门”,来动态地控制另一个分支信息流的通过程度
这些激活函数通常用在 Transformer 的前馈网络层 (FFN) 中,取代了传统的 FFN 结构。
4)归一化
深度神经网络(尤其是 Transformer )在训练时容易出现不稳定的情况,比如梯度爆炸或消失,导致模型难以收敛。 归一化层的作用就是稳定数据分布,让每一层网络的输入保持在一个相对固定的范围内,从而提升训练稳定性
· 归一化方法
a. 层归一化LayerNorm : 对每一个样本的每一层的所有神经元激活值计算均值 (μ) 和方差 (σ),然后用这两个值来归一化该层该样本的激活值。
b. 均方根层归一化RMSNorm: RMSNorm 是对 LayerNorm 的一种简化,旨在提高训练速度和效率。研究发现 LayerNorm 的成功主要归功于其重缩放的不变性,而均值归一化(即减去均值 μ 的那一步)对性能的贡献相对较小,甚至有时可以省略,然后用 RMS 省略了减去均值这一步,只做缩放。 这样计算更快,同时在很多大模型(如 Gopher, Chinchilla, LLaMA)上表现出与 LN 相当甚至更好的性能和稳定性。
c. DeepNorm : 对于极其深的 Transformer(比如上千层),即使是 LN 或 RMSNorm 也可能不够稳定。 DeepNorm通常结合特定的模型初始化策略和学习率调整,其关键思想是在 Transformer 的残差连接 (residual connection) 中,对输入到残差块的激活值 x 按照一个固定的比例常数 α 进行缩放。
· 归一化模块位置
除了选择哪种归一化方法外,将归一化层放置在 Transformer 子模块(如自注意力层和前馈网络层)的哪个位置,对模型的训练稳定性和最终性能也有显著影响。
a. Post-Norm (原始 Transformer): 先进行子层操作(Attention 或 FFN),然后做 Add & Norm。
优点: 梯度路径更直接,训练初期可能收敛更快。
缺点: 训练过程对学习率等超参数更敏感,容易发散,需要精心的 warmup 策略。
b. Pre-Norm: 先做 Norm,再进行子层操作,最后做 Add。
优点: 训练过程更稳定,对超参数不那么敏感,可以支持更大的学习率。这是目前大语言模型的主流选择。
缺点: 需要更长的 warmup 或者训练初期性能提升稍慢。
c. Sandwich-Norm: 结合两者,在子层操作前后各加一次 Norm,并在残差连接前再加一个 Norm。试图获得 Pre-Norm 的稳定性和 Post-Norm 的某些性能优势。
5. LLaMA 的详细配置举例
1)整体架构—Decoder-Only,架构通过带掩码的自注意力机制(因果注意力),使得每个词元在生成时只能关注到其前面的词元,天然符合语言生成的从左到右的特性
2)位置编码—RoPE,将相对位置信息通过向量旋转的方式融入到 Query 和 Key 向量中
3)激活函数—SwiGLU,一部分经过一个非线性变换(如 Swish),另一部分经过一个线性变换后通过 Sigmoid 函数形成“门”,两者相乘得到最终输出
4)归一化方法—Pre&RMSNorm,将归一化操作放在每个子模块之前,RMSNorm 省略了标准 LayerNorm 中的减去均值这一步,只进行基于均方根的缩放。这在计算上更高效
二、大模型主流架构
1. 编码器-解码器架构
编码器-解码器架构是自然语言处理领域里一种经典的模型结构,广泛应用于如机器翻译等多项任务。此架构在编码器端采用了双向自注意力机制对输入信息进行编码处理,而在解码器端则使用了交叉注意力与掩码自注意力机制,进而通过自回归的方式对输出进行生成。
基于编码器-解码器设计的预训练语言模型(如 T5 等)在众多自然语言理解与生成任务中展现出了优异的性能,但是目前只有如 FLAN-T5等少数大语言模型是基于编码器-解码器架构构建而成的
2. 因果解码器架构
当前,绝大部分主流的大语言模型采用了因果解码器架构。因果解码器采用了 Transformer 中的解码器组件,同时做出了几点重要改动。首先,因果解码器没有显式地区分输入和输出部分。该架构采用了单向的掩码注意力机制,使得每个输入的词元只关注序列中位于它前面的词元和它本身,进而自回归地预测输出的词元。此外,由于不含有编码器部分,经过自注意力模块后的词元表示将直接送入到前馈神经网络中。
在因果解码器架构中,最具有代表性的模型就是 OpenAI 推出的 GPT系列。其中,GPT-3 将模型参数拓展到了 100B 级别,并展现出了强大的零样本和 少样本学习能力。伴随着 GPT-3 的成功,因果解码器被广泛采用于各种大语言模型中,包括 BLOOM、LLaMA 和 Mistral 等
3. 前缀解码器架构
前缀解码器对于输入部分使用双向注意力进行编码,而对于输出部分利用单向的掩码注意力利用该词元本身和前面的词元进行自回归地预测。与编码器-解码器不同的是,前缀解码器在编码和解码过程中是共享参数的,并没有划分为独立的解码器和编码器。