昨天有同学后台私信我,觉得对现在大模型有哪些架构,哪些特别的不懂,所以这是一节补充课,偏向工程原理。
第一部分:现代 LLM 的标准“骨架” (The "Llama-like" Architecture)
早期的 Transformer(2017年那篇论文)和现在我们用的 Llama 3、Qwen 等模型,虽然名字都叫 Transformer,但细节已经大不相同了。现在反复提到一个词叫 "Llama-like" ,意思是现在的模型越来越像 Llama 的架构。
主要有以下几个关键的改动:
1. 归一化位置变了:Pre-N orm vs Post-Norm
以前 (Post-Norm): 在原始 Transformer 中,LayerNorm 是放在残差连接(Add)之后的 。
现在 (Pre-Norm): 几乎所有现代模型(如 Llama, GPT-3, PaLM)都把 LayerNorm 放在了主路径之前
为什么改?
-
稳定性: Pre-Norm 能让梯度的传播更顺畅,训练更稳定,不需要那么多“预热”(warm-up)技巧 。
-
缺点: 理论上 Pre-Norm 可能会稍微限制模型的表达能力,但为了能训练得动这种超深的模型,大家都选了 Pre-Norm 。
2. 归一化方式变了:RMSNorm
以前 (LayerNorm): 需要减去均值(Mean),再除以方差(Variance) 。
现在 (RMSNorm): 不减均值了,直接除以均方根(RMS) 。
为什么改?
速度快: 少算一步均值,运算量变小 。
效果没差: 实验证明 RMSNorm 和 LayerNorm 效果差不多,但跑得更快 。
代表模型: Llama 系列、PaLM、Gemma 等都用这个 。
3. 激活函数变了:从 ReLU 到 SwiGLU
-
以前 (ReLU): 简单粗暴,小于0就归零。
-
现在 (SwiGLU): 这是一种“门控”(Gated)激活函数。
-
公式稍微复杂一点,它引入了一个额外的线性层(门),用来控制信息流过的大小 。
-
注意点: 因为多了一个门,参数量变大了。为了保持参数总量不变,通常会把中间层的维度(
)缩小到原来的 2/3 。
-
-
为什么改? 实验数据表明,SwiGLU 或者 GeGLU 的效果在几乎所有任务上都比 ReLU 好 。Llama, Mistral, PaLM 都在用 。
4. 偏置项 (Bias) 消失了
现象: 以前的全连接层(Linear)公式是 y = xW + b。现在的模型大多把 b去掉了
为什么? 为了省显存,而且对优化稳定性有帮助。虽然提升不大,但反正加了也没啥大用,不如省点资源 。
5. 并行层 (Parallel Layers) —— 一个特例
大多数模型是串行的(先算 Attention,再算 MLP)。
但有些模型(如 GPT-J, Falcon 2)采用并行计算:同时算 Attention 和 MLP,最后把结果加起来
好处: 大规模训练时速度能快 15% 左右 。
第二部分:位置编码与超参数 (RoPE & Hyperparameters)
1. 旋转位置编码 (RoPE)
这是 Llama、Mistral、PaLM 等现代模型都在用的技术。
为什么要改?
以前的 Transformer 用正弦波(Sinusoidal)或者绝对位置向量相加。但我们希望模型能更好理解“相对位置”:即单词 A 和单词 B 隔了多远,而不是它们具体在第几个位置。
RoPE 的核心思想:
不要把位置信息“加”在向量上,而是把向量在空间里“转”一个角度。转的角度大小取决于你的位置。
公式:
假设你的词向量是二维的(为了简化),位置是。RoPE 就是用一个旋转矩阵
去乘你的 Query (
) 或 Key (
) 向量:
2. 超参数的“黄金比例” (The "Boring" Consensus)
做大模型就像做菜,有些比例是大家都遵守的“菜谱”。
(1) 前馈网络 (FFN) 的维度: vs
dff指的是 Transformer 结构中 前馈神经网络 (Feed-Forward Network, FFN) 的内部隐藏层维度
我们在 Transformer 里总会看到一个变宽又变窄的 MLP 层。这个宽应该宽多少?
-
标准规则 (ReLU时代): 通常是 4倍。
-
现代规则 (SwiGLU时代):
因为 SwiGLU 有两个线性层(一个做变换,一个做门控),为了保持参数量和计算量不暴涨,大家通常会把倍数缩小到 8/3 (约 2.67倍) 或 3.5倍。
例子: Llama 2, Mistral, Qwen 都遵循这个比例 。
(2) 注意力头数与维度
如果你在设计模型,怎么决定要把模型切成多少个头 ()?
-
基本共识: 头的维度 (
) 通常固定在 128 左右。
-
公式:
这表示如果你把所有头的输出拼起来,刚好等于模型的隐藏层维度。虽然不是必须这么做,但绝大多数模型(GPT-3, Llama 2)都遵守这个 1:1 的比例 。
(3) 词表大小 (Vocabulary Size)
单语言模型: 30k - 50k 左右就够了 (如 Llama 1, GPT-2) 。
多语言模型: 需要更大的词表来容纳不同语言,通常在 100k - 250k (如 GPT-4, Qwen, PaLM) 。
第三部分:高级优化与稳定性 (Efficiency & Stability)
1. 显存不够用:MQA 和 GQA
这是为了解决大模型推理(Inference)时的瓶颈而发明的。
痛点: 当我们生成文本时,模型需要把之前算过的 Key (K) 和 Value (V) 存起来,这就叫 KV Cache 。 随着序列变长,KV Cache 占用的显存极其巨大,搬运这些数据非常消耗显存带宽,甚至比计算本身还慢 。
解决方案: 能不能少存点 K 和 V?
MHA (标准的多头注意力 Multi-Head Attention):
做法: 每个头(Head)都有自己独享的 Q, K, V。
缺点: K 和 V 太多了,显存搬运工累死。
MQA (多查询注意力 Multi-Query Attention):
做法: 哪怕有 8 个头,所有的头共用同一组 K 和 V,只有 Q 是独立的 。
效果: K/V 的数据量直接除以了头数(比如除以8),推理速度飞快。
缺点: 效果可能会稍微掉一点点 。
GQA (分组查询注意力 Grouped-Query Attention):
做法: 这是现在的主流选择(Llama 2/3 都在用)。它是 MHA 和 MQA 的折中。
逻辑: 把头分成几组(Group),组内共享 K 和 V,组间不共享 。
优点: 速度比 MHA 快很多,效果比 MQA好,达到了完美平衡 。
假设我们有 4 个头 (Head 1-4)
1. MHA (标准版 - 有钱任性)
Q1 Q2 Q3 Q4
| | | |
K1 K2 K3 K4 <-- 存 4 份 K,显存压力大
V1 V2 V3 V4 <-- 存 4 份 V
2. MQA (省钱版 - 极限压缩)
Q1 Q2 Q3 Q4
\ \ / /
\ \/ /
K <-- 全员共享 1 份 K
V <-- 全员共享 1 份 V
3. GQA (平衡版 - 现在的标配)
[组A] [组B]
Q1 Q2 Q3 Q4
\ / \ /
K_A K_B <-- 每组共享 1 份
V_A V_B
2. 滑动窗口注意力 (Sliding Window Attention, SWA)
原理: 一个 token 不再看所有的上下文,只看它自己附近的 窗口(Window)。比如只看最近的 4096 个词 。
好处: 计算量从 变成
,处理超长文本时非常省资源。
混合模式: 最近的模型(如 Command A, Gemma)喜欢“插花”:大部分层用滑动窗口(省钱),每隔几层用一次全注意力(Full Attention,保证全局理解能力)
3. 稳定性技巧:防止 Loss 炸掉
训练几千亿参数的模型,最pa的就是 Loss 突然变成 NaN(Not a Number),俗称“炸了”。为了稳住它,有这几招:
(1) QK Norm (Query-Key Normalization)
问题: Attention 里的 Q 和 K 向量如果数值太大,点积之后出来的分数就会极其巨大,导致 Softmax 算出来的概率过于极端(one-hot),梯度就消失了。
解决: 在 Q 和 K 做点积之前,先给它们分别做一个 LayerNorm 。
公式:
谁在用? ViT, Baichuan 2, Gemma 2 。
(2) Z-Loss
问题: Softmax 的分母(配分函数 Z)如果太大,计算起来不稳定。
解决: 强行在 Loss 里加一项惩罚,让 尽量接近 0
谁在用? PaLM 。
(3) Logit Soft-Capping
问题: 还是怕 Logit(进入 Softmax 前的数值)太大。
解决: 用 Tanh 函数把数值强行压缩到一个范围内(比如 -50 到 50 之间)。
谁在用? Gemma 2, Grok 。
总结
-
整体架构: Pre-Norm (为了稳) + RMSNorm (为了快) 。
-
激活函数: SwiGLU 。
-
位置编码: ROPE (旋转位置编码) 。
-
FFN 维度:
(约 2.67倍) 。
-
Attention 优化: 使用 GQA (分组查询) 来加速推理 。
-
词表: 多语言模型选 100k+ 。
-
防炸技巧: 用 QK Norm 或 Logit Soft-capping 。
-
Dropout: 不要加
================================================================================
MODERN LLM (LLAMA-LIKE) INFERENCE FLOW
================================================================================
输入 (Input): "The cat sat on the"
|
v
[ 1. Tokenizer (分词器) ]
| 操作:查表
| 输出:Token IDs [101, 856, 221, ...]
v
[ 2. Embedding (嵌入层) ]
| 操作:将 ID 映射为向量
| 形状:[Batch, Seq_Len, d_model] <-- 此时还没有位置信息!
v
+------------------------------------------------------------------------------+
| 3. Transformer Block (堆叠 N 层,例如 32 层) |
| |
| 数据流 x (Residual Stream) |
| | |
| +---[ 分支 A: Attention ]-----------------------------------------+ |
| | | | |
| | [ RMSNorm ] <-- :Pre-Norm,且去掉了均值计算 | |
| | | | |
| | [ Q, K, V Projections ] <-- :GQA (K,V 头数少于 Q) | |
| | | | |
| | [ RoPE 旋转位置编码 ] <-- :只旋转 Q 和 K,注入相对位置 | |
| | | | |
| | [ Flash Attention 计算 ] <-- Softmax(QK^T / sqrt(d)) * V | |
| | | | |
| | [ Output Projection ] <-- 线性层,无 Bias | |
| | | | |
| |<----+ (加回主路) | |
| | |
| [ Add ] (残差连接 x = x + attn_out) |
| | |
| +---[ 分支 B: FFN / MLP ]-----------------------------------------+ |
| | | | |
| | [ RMSNorm ] <-- 再次归一化 | |
| | | | |
| | [ Gate_Proj & Up_Proj ] <-- :SwiGLU (带门控的宽层) | |
| | | (维度膨胀:d_model * 2.67) | |
| | | | |
| | [ Activation: SiLU/Swish ] <-- 激活函数作用在 Gate 上 | |
| | | | |
| | [ Element-wise Multiply ] <-- Gate * Up | |
| | | | |
| | [ Down_Proj ] <-- 线性层 (维度压缩回 d_model | |
| | | | |
| |<----+ (加回主路) | |
| | |
| [ Add ] (残差连接 x = x + ffn_out) |
| |
+------------------------------------------------------------------------------+
|
| (经过 N 层重复处理后...)
v
[ 4. Final RMSNorm ] <-- :最后的归一化不能忘
|
v
[ 5. LM Head (Unembedding) ] <-- 考点:通常没有 Bias
| 操作:线性映射 (d_model -> vocab_size)
| 形状:[Batch, Seq_Len, Vocab_Size] (Logits)
| (可选:这里可能会用 Logit Soft-capping 防止数值过大)
v
[ 6. Softmax ]
| 操作:将数值转化为概率分布
v
输出 (Output): Next Token Probabilities
| (例如: "mat": 0.7, "floor": 0.2 ...)
v
采样 (Sampling): 选出 "mat"
772

被折叠的 条评论
为什么被折叠?



