Knowledge from reading a paper is shallow;
to truly understand, you must run the code yourself.
纸上得来终觉浅,绝知此事要躬行. —— 陆游
目录
为什么写这篇文章?
回顾我学习Transformer的过程, 我用过以下几种方法:
- 读paper: 我读过原始的Transformer paper和一些其他的paper(例如BERT, T5, GPT等). 这种方法的缺点一是效率比较低, paper里经常使用比较难懂的语言来解释很简单的问题, 并且有大段我并不关心的内容. 二是paper会忽略掉大量的细节, 从而产生并不准确的理解.
- 读blog, 看教学视频等: 例如 The Illustrated Transformer. Blog比paper易懂, 但是二手信息, 来源也不可靠, 信息准确度难以保证.
- 看sample code: 比较有名的是 Transformer from scratch. 动手实现transformer, 对理解非常有帮助, 缺点是这是一个用来教学的code base, 和实际公司在用的代码有不少区别, 没法直接用这个代码来做项目.
有没有一个办法, 既能准确理解Transformer的原理, 又能把它用到工作里呢? 我想到的办法就是读懂一个真正在生产中应用的, 效果达到世界先进水平的Transformer代码. 这里我选择了Meta开源的LLaMA.
Prerequisites
本文假设读者已经理解原始的Transformer了. 如果没有, 可以先去看Attention is all you need.
LLaMA和原始Transformer的不同
- LLaMA是一个decoder-only transformer, 它没有encoder, 也没有cross attention. 注意在下面这张模型架构图里, 模型的输入叫做 "outputs shifted right", 因为decoder的input和output其实是同一个东西, 当前step的output是下一个step的input.

- Pre-normalization. 上面这张图是原始的transformer, 它的normalization是加在output上的. 现代的transformer会把normalization加在input上. 用伪代码来表示:
# 原始transformer
h = norm(x + attn(x))
out = norm(h + ffn(h))
# pre-normalization
h = x + attn(norm(x))
out = h + ffn(norm(x))
- Rotary Positional Embedding (RoPE). 目前主流都比较喜欢相对位置的positional embedding, 我猜想一方面目前context length越来越大, 如果采用绝对位置来计算, 有可能因为训练数据的长度分布不均导致PE在某些位置没有充分的训练; 另一方面如果考虑某一个短语它在句子中平移时它的意思不会改变, 相对位置的embedding感觉也更符合直觉一些.
RoPE的直觉想法: 假设有一个positional embedding函数 f(x, l) 表示input x 在位置l处的embedding, 我们希望 f(q, m)和 f(k, n) 的点积只跟相对位置 (m-n)相关. 所以, 只要我们可以把embedding表示成复数 f(x, l) = xe^il, 位置l是复数的转角, 就可以保证上面这点.
- activation function和normalization function和原始transformer不同. 这个我认为是小细节了, 不再展开.
LLaMA代码解析