Appearance
Transformer 推理图 — 练习
练习 1:绘制单层计算图
阅读 llm_build_llama 函数,为单层 Transformer 绘制完整的计算图(从输入到输出),标注每个 GGML 操作。
参考答案
单层计算图(简化):
input → rms_norm → mul_mat(Wq) → rope → ─┐
↓ │
mul_mat(Wk) → rope → store_K ────────┤
↓ │
mul_mat(Wv) → store_V ───────────────┤
│
attention(Q, K_cache, V_cache) ←──────┘
↓
mul_mat(Wo) → add(residual) ─┐
│
rms_norm → mul_mat(Wgate) → silu → mul → mul_mat(Wdown) → add(residual)
mul_mat(Wup) ──┘练习 2:理解 RoPE 的维度变换
RoPE 作用于 Q 和 K 的 head 维度上。对于一个 hidden_dim=4096, n_heads=32 的模型,计算每个 head 的维度和 RoPE 作用的部分。
参考答案
- head_dim = hidden_dim / n_heads = 4096 / 32 = 128
- RoPE 作用于 head_dim 的一半:n_rot = 128 / 2 = 64 对旋转
- 对于 GQA 模型(如 n_kv_heads < n_heads),K/V 的 head_dim 相同但 head 数不同
- RoPE 只影响 Q 和 K,不影响 V
练习 3:对比不同架构的 FFN
在 llama-model.cpp 中找到至少两种不同的 FFN 实现(如 LLaMA 的 SwiGLU 和 GPT-2 的 GeLU),对比差异。
参考答案
LLaMA (SwiGLU):
cpp
gate = ggml_mul_mat(ctx, layers[il].ffn_gate, cur);
up = ggml_mul_mat(ctx, layers[il].ffn_up, cur);
gate = ggml_silu(ctx, gate);
cur = ggml_mul(ctx, gate, up);
cur = ggml_mul_mat(ctx, layers[il].ffn_down, cur);GPT-2 (GeLU):
cpp
cur = ggml_mul_mat(ctx, layers[il].ffn_up, cur);
cur = ggml_gelu(ctx, cur);
cur = ggml_mul_mat(ctx, layers[il].ffn_down, cur);差异:SwiGLU 使用两个投影(gate + up)做门控,GeLU 使用单个投影 + 激活。
拓展挑战
- 阅读
ggml_rope的实现,理解旋转矩阵的构造方式 - 对比 LLaMA 和 Mistral 架构在代码中的差异
- 理解 GQA (Grouped Query Attention) 如何减少 KV Cache 大小