attention 的本质:动态加权求和
项目目标
这一段路线把 token 序列变成一个真正的 decoder-only Transformer。
顺序不能乱。先有 token embedding,再加位置;先手写单头 scaled dot-product attention,再扩展到 multi-head;先拼一个 decoder block,再堆成 mini-former;最后再讨论 causal LM、masked LM、prefix LM、denoising objective 的差异。
如果直接从完整 Transformer 开始,很容易只记住一堆层名。按项目拆开之后,每个部件都能用一句话解释:它解决了哪一个缺陷。
项目 3:实现位置编码
attention 本身不认识顺序。如果没有位置,我打你 和 你打我 的 token 集合很接近,但语义截然不同。
要实现四类位置方法:
| 方法 | 思路 | 要观察的问题 |
|---|---|---|
| learned position embedding | 每个位置一行可学习向量 | 简单,但外推到更长上下文较弱 |
| sinusoidal | 用不同频率的 sin/cos 编码位置 | 不需要训练,经典 Transformer 方案 |
| RoPE | 在向量空间里按位置旋转 Q/K | 相对位置信息自然进入 attention |
| ALiBi | 给 attention score 加距离偏置 | 更偏向长度外推 |
最小实验:训练同一个小模型,只替换位置方法,比较训练 loss、验证 loss、超过训练长度后的生成质量。
破坏实验:完全去掉位置编码。观察模型是否更容易混淆顺序关系。
项目 4:手写单个 scaled dot-product attention
注意力的最小公式是:
scores = q @ k.transpose(-2, -1) / head_size**0.5
scores = scores.masked_fill(causal_mask == 0, float("-inf"))
weights = scores.softmax(dim=-1)
out = weights @ v
它只有三件事:
- Q 和 K 点积,得到匹配分数。
- causal mask 屏蔽未来 token。
- 用 softmax 后的权重对 V 加权求和。
必须画一张 attention heatmap。横轴是被看的 token,纵轴是当前位置。下三角之外应该全为零。如果未来位置有权重,说明 mask 写错了。
破坏实验:
- 去掉
head_size**0.5缩放,看 softmax 是否过早变尖。 - 去掉 causal mask,看训练 loss 是否异常变好、生成时是否变差。
- 把 Q/K/V 乱换,看模型是否还能学。
项目 5:扩展到 multi-head attention
单个 head 只能在一个子空间里匹配关系。multi-head 的直觉是:让不同 head 学不同关系。
实现方式是多个 head 并行,然后 concat,再过一个 projection:
out = torch.cat([head(x) for head in self.heads], dim=-1)
out = self.proj(out)
观察指标:
- 每个 head 的 attention heatmap 是否不同。
- head 数增加后训练 loss 如何变化。
- 固定 embedding 维度时,head 数过多是否导致单 head 维度太小。
破坏实验:只保留一个 head,或者把所有 head 的输出平均掉,观察表达能力变化。
项目 6:拼一个 decoder block
一个 GPT block 的最小结构:
x = x + self_attention(norm(x))
x = x + mlp(norm(x))
需要实现:
- token embedding
- position embedding 或 RoPE
- masked multi-head self-attention
- residual connection
- LayerNorm 或 RMSNorm
- feed-forward network
- output projection
这里要特别关注 residual 和 norm。如果去掉 residual,深层模型更难训练。如果 norm 放置位置不同,会影响稳定性。现代 decoder 常见的是 pre-norm。
破坏实验:
- 去掉 residual,看 loss 是否震荡或不收敛。
- 把 pre-norm 改成 post-norm,观察小模型是否更难训。
- 把 MLP 缩小到很小,看模型容量瓶颈。
项目 7:堆成 mini-former
堆多个 block 后,就可以训练一个真正的 tiny decoder-only language model。
建议先固定一个很小配置:
n_layer = 4
n_head = 4
n_embd = 128
block_size = 128
batch_size = 32
训练时必须记录:
- train loss
- val loss
- tokens/sec
- 显存占用
- 每隔固定 step 的生成样例
这里的目标不是让模型有用,而是理解训练循环:数据 batch、forward、loss、backward、optimizer step、eval、generate。
项目 8:对比训练目标
GPT 走 causal LM:只看过去,预测下一个 token。
BERT 走 masked LM:遮住一部分 token,让模型根据左右上下文恢复。
T5 一类模型把任务转成 text-to-text,并使用 denoising objective。
要做一个小实验:
- 同一份小语料。
- 同等规模模型。
- 分别实现 causal LM、masked LM、prefix LM。
- 对比 loss 曲线和生成/恢复样例。
这会帮助理解:模型架构相似,不代表训练目标相同;训练目标直接决定模型擅长补全、生成、理解还是转换。
本项目交付物
- 4 种位置编码的最小实现。
- 单头 attention heatmap。
- multi-head attention heatmap 对比。
- 一个 decoder block。
- 一个 mini-former 训练脚本。
- train/val loss 曲线。
- 至少 3 组破坏实验记录。
和本站已有内容的连接
mini-gpt/05-注意力机制让模型看见上下文mini-gpt/06-拼出一个真正的GPT结构mini-gpt/07-完整训练看它从胡言乱语到像模像样ml-basics/注意力机制ml-basics/Transformer
延伸阅读
版权声明: 如无特别声明,本文版权归 sshipanoo 所有,转载请注明本文链接。
(采用 CC BY-NC-SA 4.0 许可协议进行授权)
本文标题:项目 3-8:位置、注意力与 Transformer Block
本文链接:https://www.sshipanoo.com/blog/ai/llm-roadmap/03-PositionAttentionTransformer项目/
本文最后一次更新为 天前,文章中的某些内容可能已过时!