#AI#inference

1

LLM推理:使用transformer解码器生成token

2

输出 logits 的最后一层通常被称为LM头

文本生成的两个阶段:

  • 预填充阶段:将prompt的所有tokens表示作为输入,生成第一个输出token。
  • 解码阶段:将生成的token加到输入序列后面,整体作为输入生成第二个输出token。如此重复,直到生成结束token(如EOS)或达到配置的最大序列长度。

3

单注意力头

我们为序列中的每个token生成一个相同维度的表示,这个表示包含了其他token的信息,叫做上下文表示。

由于掩码的存在,对于给定的token,其输出表示仅由前序tokens的表示生成。由于前序tokens在迭代中是相同的,该給定token的输出表示在所有后续迭代中也将是相同的,这意味着冗余计算。

图:解码阶段注意力层中的冗余计算(浅红色和浅紫色)

KV缓存

举个例子,在使用 “What color is the sky? The sky is” 作为输入的迭代中,我们之前步骤中唯一还没有计算的表示是输入序列中的最后一个词 “is”。 更具体地,需要什么材料来计算?

  • A query vector for “is“.
  • Key vectors for “What”, “color”, “is”, “the”, “sky”, “?”, “The” “sky” and “is” to compute attention scores.
  • Value vectors for “What”, “color”, “is”, “the”, “sky”, “?”, “The” “sky” and “is” to compute the output.

除了 “is” 以外的健和值向量已经在之前的迭代中计算过,可以缓存并重用它们,这个优化就叫 KV caching。这时如下计算 “is” 的输出表示:

  1. Computing a query, a key and a value for “is ”.
  2. Fetching key and value vectors for “What”, “color”, “ is”, “ the”, “sky”, “?”, “The” and “sky” from the cache and concatenating them with the key and value we just computed for “is”.
  3. Computing the attention scores using the “is” query and all the keys.
  4. Computing the output vector for “is” using the attention scores and all the values.

观察输入,实际上不再需要先前的tokens,只需要它们的Key和Value向量。当使用KV缓存时,模型的实际输入是 最后生成的token 和 KV缓存。

图:启用KV缓存的生成步骤

4

尝试减少KV缓存的内存占用

减少注意力头的数量?

GQA:把查询头分为g组,一组内的查询头共享一个KV头

量化

只有那些量化权重和“激活”(即任何不是权重的项)的算法,才能生成量化后的KV缓存。

注意,在同时处理权重和激活的量化算法中,其中一个目的是以较低的精度执行计算密集型的矩阵乘法。这在计算受限的情况下(如训练期间)会带来性能提升,但推理的自回归阶段实际上是内存带宽受限的,因此能够更快地计算并不会带来太多价值。由于推理是内存带宽受限的,我们实际上只对减少内存占用感兴趣,因为这意味着更少的数据传输。

将负载卸载到更丰富但速度较慢的存储(CPU内存、磁盘)

由于它涉及使用速度较慢的存储,卸载会以较大的延迟为代价,因此显然不应优先考虑对延迟敏感的使用场景。卸载系统通常用于优化吞吐量的使用场景,如离线批处理。

用多个GPU,模型分片

  • 流水线并行:模型和KV缓存在层维度上分片
  • 张量并行:KV缓存在(多头注意力中的)头维度上分片

5

训练和推理的预填充阶段通常计算受限,推理的解码阶段通常内存带宽受限。

参考