大模型——推理优化——KV Cache

在本文中,我们将详细介绍KV Cache,这是一种大模型推理加速的方法。
正如其名称所示,该方法通过缓存Attention中的K和V来实现推理优化。

一、大模型推理的冗余计算

我们先简单观察一下基于Decoder架构的大模型的生成过程
用户输入“中国的首都”,模型续写得到的输出为“是北京”,模型的生成过程如下:

  1. 将“中国的首都”输入模型,得到每个token的注意力表示(绿色部分)。使用“首都”的注意力表示,预测得到下一个token为“是”(实际还需要将该注意力表示映射成概率分布logits,为了方便叙述,我们忽略该步骤)。

  2. 将“是”拼接到原来的输入,得到“中国的首都是”,将其输入模型,得到注意力表示,使用“是”的注意力表示,预测得到下一个token为“北”。

  3. 将“北”拼接到原来的输入,依此类推,预测得到“京”,最终得到“中国的首都是北京”

存在的问题:
在每一步生成中,仅使用输入序列中的最后一个token的注意力表示,即可预测出下一个token。但模型还是并行计算了所有token的注意力表示,其中产生了大量冗余的计算(包含qkv映射,attention计算等),并且输入的长度越长,产生的冗余计算量越大。

例如:

  1. 在第一步中,我们仅需使用“首都”的注意力表示,即可预测得到“是”,但模型仍然会并行计算出“中国”,“的”这两个token的注意力表示。

  2. 在第二步中,我们仅需使用“是”的注意力表示,即可预测得到“北”,但模型仍然会并行计算“中国”,“的”,“首都”这三个token的注意力表示。

二、Self-Attention过程解析

2.1 公式解析

假设输入序列长度为 n,第 j个token对于整个输入序列的注意力表示如下公式: 

                                    b^{j} = \sum_{i=1}^{n}softmax(q^{j} \cdot k^{i})v^{i}

j个token对于整个输入序列的注意力表示的计算步骤大致如下:

  1. 向量映射:将输入序列中的每个token的词向量分别映射为q,k,v三个向量。

  2. 注意力计算:使用q^{j}分别与每个k进行点乘,得到第j个token对每个token的注意力分数。

  3. 注意力分数归一化:对注意力分数进行softmax,得到注意力权重。

  4. 加权求和:注意力权重与对应的向量v加权求和,最终得到第j个token的注意力表示。

2.2 过程实例

下面将以图像的方式帮助大家更形象地理解Self Attention。

假设:

  • a = a^{1}a^{2}a^{3}a^{4}
  • a^{1}对于整个输入序列a的注意力值是b^{1}

根据上面的Self-Attention公式得出:

 b^{1} = \sum_{i=1}^{4}softmax(q^{1} \cdot k^{i})v^{i}

继续观察a^{2}对于整个输入序列a的注意力b^{2}表示  ,即:
b^{2} = \sum_{i=1}^{4}softmax(q^{2} \cdot k^{i})v^{i}

三、KV Cache

3.1 原理

  • 在推理阶段,当输入长度为 n,我们仅需使用  即可预测出下一个token,但模型却会并行计算出  ,这部分会产生大量的冗余计算。
  • 而实际上b^{n}可直接通过公式b^{n} = \sum_{i=1}^{n}softmax(q^{n} \cdot k^{i})v^{i}算出,即b^{n}的计算只与  q^{n}、所有 k 和  v有关
  • KV Cache的本质是以空间换时间,它将历史输入的token的kv缓存下来,避免每步生成都重新计算历史token的k和 v 以及注意力表示  b^{1}...b^{n-1},而是直接通过b^{n} = \sum_{i=1}^{n}softmax(q^{n} \cdot k^{i})v^{i}的方式计算得到 b^{n} ,然后预测下一个token。

3.2 KV cache过程

第一步生成时,缓存  K,V均为空,输入为“中国的首都”,模型将按照常规方式并行计算:

  1. 并行计算得到每个token对应的  k,v,以及注意力表示b^{1},b^{2},b^{3}  。

  2. 使用 b^{3} 预测下一个token,得到“是”。

  3. 更新缓存,令 K=[k^{1},k^{2},k^{3}],V=[v^{1},v^{2},v^{3}] 。

第二步生成时,计算流程如下:

  1. 仅将“是”输入模型,对其词向量进行映射,得到 q^{4},k^{4},v^{4} 。

  2. 更新缓存,令 K=[k^{1},k^{2},k^{3},k^{4}],V=[v^{1},v^{2},v^{3},v^{4}]  。

  3. 计算  b^{4} = \sum_{i=1}^{4}softmax(q^{4} \cdot k^{i})v^{i},预测下一个token,得到“北”

第三步生成时,计算流程如下:

  1. 仅将“北”输入模型,对其词向量进行映射,得到q^{5},k^{5},v^{5}  。

  2. 更新缓存,令 K=[k^{1},k^{2},k^{3},k^{4},k^{5}],V=[v^{1},v^{2},v^{3},v^{4},v^{5}]   。

  3. 计算 b^{5} = \sum_{i=1}^{5}softmax(q^{5} \cdot k^{i})v^{i} ,预测下一个token,得到“京”

 

上述生成流程中,只有在第一步生成时,模型需要计算所有token的 k,v ,并且缓存下来。
此后的每一步,仅需计算当前token的 q^{n},k^{n},v^{n} ,更新缓存 K,V,然后使用 q^{n},K,V 即可算出当前token的注意力表示,最后用来预测一下个token。 

3.3 代码修改

这里参考gpt2里面的代码实现

https://github.com/huggingface/transformers/blob/main/src/transformers/models/gpt2/modeling_gpt2.py

query, key, value = self.c_attn(hidden_states).split(self.split_size, dim=2)

query = self._split_heads(query, self.num_heads, self.head_dim)  # 当前token对应的query
key = self._split_heads(key, self.num_heads, self.head_dim)  # 当前token对应的key
value = self._split_heads(value, self.num_heads, self.head_dim)  # 当前token对应的value

if layer_past is not None:
    past_key, past_value = layer_past  # KV Cache
    key = torch.cat((past_key, key), dim=-2)  # 将当前token的key与历史的K拼接
    value = torch.cat((past_value, value), dim=-2)  # 将当前token的value与历史的V拼接

if use_cache is True:
    present = (key, value)
else:
    present = None

# 使用当前token的query与K和V计算注意力表示
if self.reorder_and_upcast_attn:
    attn_output, attn_weights = self._upcast_and_reordered_attn(query, key, value, attention_mask, head_mask)
else:
    attn_output, attn_weights = self._attn(query, key, value, attention_mask, head_mask)

#参考
 图解大模型推理优化之KV Cache

### 大模型推理优化技术的发展趋势 #### 趋势一:行业特定大模型兴起 随着人工智能技术的进步,越来越多的企业和研究机构开始开发针对特定行业的大型语言模型。这些模型不仅具备广泛的知识库,还能够更好地适应具体业务场景的需求[^2]。 例如,在教育领域出现了像网易有道的子曰、好未来的MathGPT以及孩子王的KidsGPT;而在金融服务方面,则有蚂蚁集团推出的贞仪与百灵等产品。这种现象表明未来的大规模预训练模型将会更加注重垂直领域的应用和发展方向。 #### 趋势二:多维度性能提升策略的应用 为了提高大规模预训练模型的实际运行效率并降低其对计算资源的要求,研究人员正在探索多种有效的优化手段。这其中包括但不限于: - **剪枝**:通过去除神经网络中不重要的连接来减少参数量; - **量化**:利用低精度的数据类型代替高精度浮点数来进行运算操作; - **融合层间计算**:合并相邻层次间的某些处理过程以简化整体架构设计。 通过对上述几种方式的有效组合运用,可以在保持原有功能特性的前提下显著改善系统的响应速度及功耗表现[^3]。 #### 实验验证流程概述 当开展关于改进措施有效性的测试工作时,通常会遵循如下几个基本环节: 1. 明确待测目标——即选定具体的深度学习框架及其对应的版本号作为参照系; 2. 制定详细的实施方案——依据项目背景挑选恰当的技术路线图,并据此确立相应的调整方案细则; 3. 构建合理的评测体系——围绕着预期达成的关键绩效指标建立一套科学严谨的标准用于衡量最终成果的好坏优劣程度; 4. 执行严格的对照试验——分别记录未经任何改动前后的各项统计数据变化情况以便后续分析比较之用; 5. 得出结论并持续迭代完善——基于所得实证材料总结经验教训进而指导下一步行动计划的确立。 综上所述,当前阶段内有关于如何进一步增强此类算法结构稳定性和灵活性的研究课题正日益受到各界人士的高度关注和支持[^1]。 ```python def optimize_model(model, method='pruning'): """ Apply optimization techniques to a given model. Args: model (object): The neural network model instance. method (str): Optimization approach ('pruning', 'quantization'). Returns: object: Optimized version of the inputted model. """ if method == 'pruning': optimized_model = prune_network_connections(model) elif method == 'quantization': optimized_model = convert_to_low_precision(model) else: raise ValueError("Unsupported optimization method.") return optimized_model ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值