Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

键值缓存

前面两章,我们探讨了怎样控制模型生成:采样策略和停止条件。接下来,研究一下怎样提升模型推理的性能。

GPT 模型自回归生成有一个性能瓶颈:每生成一个新词元,都要重新计算所有词元的注意力。假设已经生成了 100 个词元,要生成第 101 个词元就要计算 101 个词元的注意力,生成每个词元的时间复杂度为 O(n2)O(n^2)。

键值缓存

键值缓存(KV Cache)的核心思想:把已生成词元的键(Key)和值(Value)缓存起来。生成新词元时只计算查询(Query),再和缓存的键和值一起做注意力。

实现原理

自注意力中,每个词元的键和值只取决于它自身及之前的词元,与后续词元无关。因此:

  • 已生成词元的键和值可以缓存,不需要重复计算;

  • 新词元只需要计算自己的查询,和缓存的键和值一起做注意力;

  • 缓存随着生成过程不断增加,但是每个词元只计算一次。

实现要点

  • 缓存结构:每个 Transformer 模块存一份键和值,其中键已转置,格式为 (批大小, 头数, 每头嵌入尺寸, 已生成长度);值的格式为 (批大小, 头数, 已生成长度, 每头嵌入尺寸);

  • 增量计算:新词元的键和值和缓存拼接,再计算注意力;

  • 位置编码:新词元的位置编码要加上偏移量(已生成长度)。

模型

GPT 缓存嵌入层

GPT 缓存嵌入层(GPTEmbeddingWithCache)需要支持位置偏移:新词元的位置编码从 offset 开始,而不是从 0 开始。

GPT 缓存注意力层

GPT 缓存注意力层(GPTAttentionWithCache)是键值缓存的核心:

  • 无缓存:输入值是当前位置之前的整个上下文尺寸,正常计算;

  • 有缓存:输入值只有当前位置的新词元,键和值需要和缓存拼接,再计算注意力。

有缓存时不要因果掩码,因为新词元只与已生成词元计算注意力,天然满足因果关系。

GPT 缓存 Transformer 模块

GPT 缓存 Transformer 模块(GPTTransformerWithCache)把缓存作为参数传递给注意力层,并返回注意力层产生的新缓存。

GPT 缓存模型

GPT 缓存模型(GPTWithCache)管理所有 Transformer 模块的缓存:

  • 每个模块一份缓存,用列表存储;

  • 前向传播时逐模块传递缓存,收集新的缓存。

GPT 缓存训练器

GPT 缓存训练器 GPTTrainerWithCache 的 generate 函数:

  • 首次生成:无缓存,计算全部词元;

  • 后续生成:有缓存,只计算新词元;

  • 缓存重置:如果序列长度超过上下文尺寸,重置缓存。

超参数

模型参数

模型参数需要保持和预训练阶段一致。

建模

加载模型

无缓存

ROMEO:
When I pray.

CAMILLO:
In my liest, I have done drunk.

CAMILLO:
Ay, since the speak, my doubt, fainners!
I am too, as to a kind in honourity,
Can a very disentent till take from here other
out, strike than 'Which children choistones
That would how have m
4.93294787 seconds

有缓存

ROMEO:
When I pray.

CAMILLO:
In my liest, I have done drunk.

CAMILLO:
Ay, since the speak, my doubt, fainners!
I am too, as to a kind in honourity,
Can a very disentent till take from here other
out, strike than 'Which children choistones
That would how have m
0.53253603 seconds

本章,我们实现了键值缓存:把已生成词元的键和值缓存起来。新词元只计算和缓存的注意力。生成每个词元的时间复杂度从 O(n2)O(n^2) 降到 O(n)O(n),生成速度大幅提升。

课后练习

  1. 调整最大生成长度 steps,观察无缓存和有缓存的速度差异。是否生成长度越长,缓存的优势越明显?