跳到主内容
@wquguru
精选75Avi Chawla技巧与观点

为什么 KV 缓存只存 K 和 V 向量而不存 Q?

Why KV cache stores K and V vectors but never Q?

原文
发到 X

为什么KV缓存存储K和V向量,却从不存储Q?(一个流行的技术型LLM面试问题)LLM是自回归的,因此每个token都是根据它之前的所有token逐个预测出来的。这种自回归特性在模型内部有一个直接后果。对tokens的一次前向传播会产生隐藏状态,但只有最后一个隐藏状态被投影到logits,并用于生成下一个token。所以,要理解为什么KV缓存只存储K和V向量,我们必须回溯,看看最后一个隐藏状态究竟是如何产生的。让我们用一个10个token的提示来走一遍这个过程。1) 预填充:所有10个token在一次前向传播中并行通过模型(带有因果掩码),因为整个提示已经已知。在每一层,10个位置中的每一个都会产生一个查询、一个键和一个值向量,并且每个位置的注意力都会针对它之前的所有位置运行。这次传播是计算密集型的,这就是为什么第一个token比之后的token明显更慢的原因。TTFT(首token生成时间)主要是预填充。2) 第一个输出token:要生成第11个token,只需要第10个token的隐藏状态。因此,这个隐藏状态从隐藏维度投影到词汇维度,以生成词汇表上的logits。然后这些logits经过softmax和采样,生成第11个token。3) 回溯隐藏状态:最后一个隐藏状态是前馈网络块输出的最后一行。前馈网络块是逐位置的(它独立应用于每一行),所以那一行来自它之前的注意力输出的最后一行。所以现在我们需要看看注意力的最后一行是如何计算的。4) 注意力矩阵:对于一个10个token的提示,QKᵀ会得到一个10×10的矩阵。每一行将是查询与每个键的点积。因此,第10行是Q₁₀·K₁,Q₁₀·K₂,一直到Q₁₀·K₁₀。注意,其中只出现了Q₁₀。Q₁到Q₉只属于它们对应的第1到第9行,而那些行的隐藏状态我们早已丢弃,因为它们从未被需要。注意力的最后一行经过softmax,然后乘以完整的值向量堆栈,即V₁到V₁₀,从而得到注意力输出的最后一行。因此,最后一个隐藏状态恰好依赖于三样东西:Q₁₀、每一个键和每一个值。5) 生成第12个token:第11个token被追加进来,这次我们需要第11行的隐藏状态来生成第12个token。从数学上讲,注意力操作结果是Q₁₁与K₁到K₁₁的点积,然后乘以V₁到V₁₁。K₁到K₁₁和V₁到V₁₁是逐位精确的,因为预填充加第一个token产生的,在因果掩码下,一个token的键和值依赖于该token及其之前的token,绝不依赖于之后的任何内容,所以追加第11个token不会改变位置3的任何内容。6) 缓存状态:总体而言,这意味着你只需要在每一步解码时保留键和值,并且只计算新位置的Q、K和V。每一步解码需要一个查询向量,它永远不会再被使用,所以它们在整个解码过程中不会被缓存。下面的图示解释了整个过程。也就是说,KV缓存只是LLM栈中四个独立缓存层之一。其他三个是服务器上的前缀缓存、由提供商计费的提示缓存,以及完全跳过模型的语义缓存。我写了一篇关于LLM服务中你应该知道的四种缓存的完整解析,每种都附有代码。在下面阅读。

更进一步:量化金融体系

看懂新闻只是起点——沿量化金融路径,把它变成能交付的工程能力

进入量化体系 →

相似阅读

关联信息,但可能不是同一事件