主要关注:
- LLM 的基础原理
- KVCache
Attention 机制
NLP 对 token 序列 X 的三种编码方式:
RNN
RNN 是递归的结构,所以只能串行计算。1
y_t = f(y_{t-1}, x_t)
CNN
CNN 能够并行计算,但是因为引入了窗口,所以只能看到局部信息。1
y_t = f(x_{t-1}, x_t, x_{t+1})
Attention
Q、K、V
从定义上看,对于 token 流
1 | x1, x2, x3, ... xn |
每个 xi 通过三组线性变换生成:
1 | Qi = xi * Wq |
考虑下面的句子
1 | The animal didn’t cross the street because it was too tired. |
句子中的每一个 token,都有一个自己的 Q。用 Wq 可以提取出这个 Q,如下:
- animal → 它在问:后面有没有补充信息?
- because → 它在问:因果关系是什么?
- it → 它在问:我指的是谁?
- tired → 它在问:谁在 tired?
对于 K,则告诉了这个 token 可以回答什么样的 Q:
- animal → 我是一个名词、可能是指代目标
- street → 我是一个地点名词
- because → 我是因果连接词
- tired → 我是状态形容词
- cross → 我是动作
对于 V,承载了语义信息的本体:
- animal → 动物这个实体的语义
- street → 街道的概念
- tired → 疲劳的状态语义
- cross → 穿越动作
Self-Attention
Self-Attention 指的是 Q、K、V 都来自同一组 token 的 attention。即
1 | X → Q = XWq |
然后
1 | Attention(Q, K, V) |
为什么叫 Self?
- 不是去外部文档查
- 不是去另一段文本查
- 而是在自己这段序列内部相互对齐
对应的是 Cross-Attention:
- Q 来自 Decoder
- K/V 来自 Encoder
容易发现,Cross-Attention 更适合翻译或者对齐另一段文本。而 Self-Attention 更适合理解一句话内部关系。
Multi-Head Attention
如果一个 token 同时想问多种不同类型的问题怎么办?引入多组问题呗。所以上面的三个矩阵会变成三组矩阵。
1 | Wq¹ Wk¹ Wv¹ |
还是对上面的例子而言
对 it 这个 token:
- Head1 问“我指代谁?”,会关注 animal(指代)
- Head2 问“是否有因果关系?”,会关注 because(因果)
- Head3 问“我与哪个动词相关?”,会关注 cross(动作)
KVCache
Why
Token 是模型处理文本的最小离散单位。所以 LLM 并不是直接处理文字,而是直接处理 token。Token 是通过分词器从文本切出来的子串单位。
1 | "Hello world" → [15496, 2159] |
但是
1 | "refund" = 1 token |
不同的模型能够接受不同的上下文长度,因此,它们的 KVCache 也要更大:
- GPT-3.5 4k tokens
- GPT-4 8k / 32k
- Claude 100k
那么 token 是不是特指用户 prompt输入的 token 或者模型输出的 token 呢?其实根据下面的自回归生成,这两个是一个东西。
1 | prompt1 → prompt2 → prompt3 → output1 → output2 ... |
自回归生成:模型按顺序生成 token,每个 token 都只依赖之前已经生成的 token。
例如,下面的 token 序列中,x1 到 x3 是用户的 prompt 输入
1 | x1 → x2 → x3 → x4 → ... → xT |
则 xT 生成的方式是
1 | P(x_t | x_1, x_2, ..., x_{T-1}) |
由此可见,自回归生成导致推理是串行的。为什么要自回归生成呢?原因比较深入,可以理解为:
- 语言本质是序列,唯一通用可行的分解方式就是 chain rule
- 自回归训练极其稳定
输入是前缀,目标是预测下一个 token,loss 是交叉熵。不需要强化学习。 - 从历史演化角度来看,n-gram、RNN、LSTM 等都是自回归的
因为自回归生成,所以导致了 KVCache 的出现。KVCache 把 O(n²) 变成 O(n)。
KVCache 具有如下的形式:
1 | KVCache[layer][token_index] = (K, V) |
layer 是 Transformer 架构的层
现在的 LLM 大都是 Decoder only 的架构,所以这里的层如下所示。1
2
3
4
5
6
7
8
9
10
11
12
13Input tokens
↓
Embedding
↓
Decoder Block 1
↓
Decoder Block 2
↓
...
↓
Decoder Block N
↓
LM Head不同层的 schema 都不同:
- 第一层:按字形索引
- 中间层:按语法索引
- 高层:按语义索引
每一层内部包含:
- Masked Self-Attention
让每个 token 从历史 token 中选择性地读取信息。
当前 token 只能看到自己和之前的 token,不能看到未来的 token。 - FFN
这里就是前馈神经网络,目的是在单个 token 维度上做语义升维和重映射。可以看成是在理解输入的 token。 - Residual / Norm
token_index 表示这是第几个 token
因为 attention 在第 t 步需要:当前 token 的 Q、对比所有历史 token 的 K、加权读取所有历史 token 的 V。所以这些 K 和 V 需要按照 token_index 来存储。K 和 V
K 是我提供什么信息给别人关注。
V 是别人关注我时能读到什么内容。为什么不需要缓存 Q?
因为 Q 只在当前步骤被使用。
在第 t 步,会用Q_t去访问K_{0..t-1},V_{0..t-1}。但是在未来,不会再去访问Q_t了。
如果没有 KVCache,每生成一个新 token 需要重新计算所有历史 token 的 K/V 复杂度是 O(n²)
相关场景
- 训练 infra
分布式训练、参数同步、checkpoint、通信优化
DeepSpeed, Megatron-LM, FSDP, NCCL, ZeRO - 推理 infra
模型加载、KV Cache 管理、动态批处理、并发调度
vLLM, TensorRT-LLM, TGI, Ray Serve - 模型存储与加载
权重分片、lazy loading、权重格式
Safetensors, GGUF, Tensor Parallel - 向量检索
向量数据库、索引结构、量化 FAISS, Milvus, ScaNN, HNSW, IVF - 资源编排与调度
相比传统 k8s 多了 GPU 调度、混部、弹性伸缩。
相关技术:K8S, Ray, RunPod, vGPU - 数据管线与特征存储
数据清洗、分片、版本控制
Petastorm, Delta Lake, Feature Store