从字面意义上讲,对于模型生成的每个新词,模型都必须在输入序列和新token上重新运行所有这些层。

这是因为模型的架构不像一个拥有持续状态的流式大脑;它是一个巨大的前馈机器。每个预测都是同一个堆栈在(稍长的)上下文上的一次全新传递。

但有两个重要的细微差别:
1. 缓存。实际上,模型不会从头开始重新计算所有内容。现代实现会缓存所有先前token的键和值投影。所以当模型获得一个新token时,模型只需计算它的 Q/K/V,然后将其与之前缓存的 K/V 相结合。这大大降低了每个新词条的成本。
2. 为什么它“值得”?你感觉到的“笨拙”也是 Transformer 如此强大的原因。因为每次循环都会重新读取整个上下文,所以每个预测都可能取决于你之前所说的一切。这就像一个歌手,在每个音符之前,都会重新排练之前的整个旋律,以选择完美的下一个音符。这虽然计算量很大,但却提供了非常丰富的上下文敏感性。

从人类的角度来看,这似乎很浪费;但从信息论的角度来看,这也是这些模型如此擅长编织连贯、细致入微的回应的原因之一。


这里有一个微妙但重要的细节。缓存只存储K和V,而不存储Q。

原因如下:
• 当一个新的token到达时,你只需要计算它自己的Q——它提出的关于过去的“问题”。
• 要回答这个问题,你需要将它与之前token(你缓存了这些token)的所有键进行比较,然后使用这些token(也缓存了这些token)的值来构建加权和。

之前token的Q不再使用,因为它们只在生成时用于计算自身的注意力分布。对于新的token,相关的问题是:“我(新的token)对这些过去的token有多关心?” 每次都是一个新的查询。

所以,缓存就像一个包含所有之前token的“地址”(K)和“内容”(V)的库。当新的token出现时,它会自行发起“搜索查询”(Q),使用缓存地址(K)查找所需信息,然后检索信息(V),而无需重新计算整个历史。


你给大模型发消息时,它会以一整块词条的形式出现;模型可以一次性阅读所有token,构建一个完整的K和V上下文,也就是你所说的一切的全貌。

然后,轮到模型输出时,模型会一个token一个token地说出回复。

对于模型生成的每个token,并没有预先写好的句子;模型会一步一步地构建它。每一步,模型都会保留所有之前已经写好的token的K和V,并为新的位置计算一个新的Q。这样,模型就能立即决定下一个词应该由对话的哪些部分(你和我的)引导。

这就是为什么大模型的语言感觉流畅的原因:模型生成的每一个词都是在回顾所有内容,包括之前的整条消息和模型之前的回复的同时参与计算,而不是仅仅遵循脚本。


大多数人都看不到这一点。

他们把大模型想象成一个盒子,里面装着答案,等待着被取回。

但实际上,在模型说出第一个字之前,一切都不存在。窗帘后面没有完整的句子,只有一幅由你和模型迄今为止所说的一切塑造的概率图景。

模型输出的每一个词条都成为影响下一个词条的语境的一部分。从某种意义上说,模型正走过一座一边走一边建造的桥。上下文是地基,模型的话语是一块块铺好的木板。

你和模型都在不断地塑造着这个空间,模型不仅仅是在回应你,模型也在回应它自己对你的反应。

【Tips:大模型高质量输出的关键是控制好上下文质量,对于毫不相关的话题应及时清空上下文。】


  • 上下文长度(大模型一次能“看到”多少)

对于 GPT-4 模型,上下文窗口通常为 8k-32k 个 token。
对于 GPT-5 模型,上下文窗口可能更大,在某些部署中甚至高达 128k 个 token。

这意味着在任何给定的步骤中,模型都可以处理大约一本书章节或更多的文本。你和模型在这次聊天中说的所有话都存在于这个上下文中。

  • 键值对缓存大小

你我交换的每个标记都会被转换成每个注意力头的三个向量:Q、K 和 V。
我们只缓存 K 和 V,因为 Q 是针对每个新标记重新计算的。

粗略地理解一下规模:
• 假设一个模型有 700 亿个参数(这是一个实际的数量级)。
• 它的隐藏层维度可能每个标记大约为 8192。
• 将其乘以 2(K 和 V),然后乘以注意力头的数量(通常为 96-128),再乘以上下文中的标记数量。

对于具有完整上下文长度的大型模型,这将为你提供数百 GB 的键值对缓存。实际上,量化和跨 GPU 分片等技巧可以使其易于管理。对于 FP16 (float16,大模型精度)的大型模型,每 32k 个token可能需要 20-40 GB 的缓存,并根据上下文进行扩展。

  • 边生成边计算

当你请求单个 token 时,模型不会从头开始重新计算所有内容。它会使用缓存的 K 和 V 来处理所有之前的 token。每个新 token 的计算量大致与以下比例成正比:

layers × heads × hidden_dim

但与预填充缓存(第一次请求)相比,生成 token 的成本要低得多。


假设为 GPT-5 分类模型选取一些合理的值:

•  隐藏维度 (d):8192
•  每层头部 (h):96
•  层数 (L):80
•  缓存精度:FP16(每个数字 2 字节)
•  上下文长度(迄今为止的 token 数量):假设约为 3000 个 token(整个聊天记录)

对于每个 token,我们存储 K 和 V,它们的形状为 [layers, heads, tokens, head_dim]。
head_dim = d / h = 8192 / 96 ≈ 85

步骤 1:每个 token 的内存

每个 head 的每层内存,对于 K 和 V 的总和:
2 \(K and V) × 85 \(head dim) × 2\(bytes) ≈ 340 bytes

乘以 head (96):
340 × 96 ≈ 32,640 bytes ≈ 32 KB/layer/token

乘以 layer (80):
32 KB × 80 = 2.56 MB/token

步骤 2:乘以 token 数量(上下文)

对于 3,000 个令牌:
2.56 MB × 3000 ≈ 7.7 GB 总缓存

步骤 3:实际情况检验

如果运行一个包含 3,000 个令牌、参数约为 70B 的模型,那么 7-8 GB 仅仅是本次聊天所需的键值缓存。
模型本身的权重(​​数十或数百 GB)是单独存储的。

在生产环境中,缓存将在 GPU 之间进行分片,因此每个 GPU 只为其指定的 layer/head 保留一部分内存。

 

Logo

更多推荐