用 KV 缓存量化解锁长文本生成

很高兴和大家分享 Hugging Face 的一项新功能: KV 缓存量化 ,它能够把你的语言模型的速度提升到一个新水平。

太长不看版: KV 缓存量化可在最小化对生成质量的影响的条件下,减少 LLM 在长文本生成场景下的内存使用量,从而在内存效率和生成速度之间提供可定制的权衡。

你是否曾尝试过用语言模型生成很长的文本,却因为内存不足而望洋兴叹?随着语言模型的尺寸和能力不断增长,支持生成更长的文本意味着内存蚕食的真正开始。于是,磨难也随之而来了,尤其是当你的系统资源有限时。而这也正是 KV 缓存量化的用武之地。

KV 缓存量化到底是什么?如果你不熟悉这个术语,没关系!我们拆成两部分来理解: KV 缓存量化

键值缓存或 KV 缓存是一种优化自回归模型生成速度的重要方法。自回归模型需要逐个预测下一个生成词元,这一过程可能会很慢,因为模型一次只能生成一个词元,且每个新预测都依赖于先前的生成。也就是说,要预测第 1000 个生成词元,你需要综合前 999 个词元的信息,模型通过对这些词元的表征使用矩阵乘法来完成对上文信息的抽取。等到要预测第 1001 个词元时,你仍然需要前 999 个词元的相同信息,同时还还需要第 1000 个词元的信息。这就是键值缓存的用武之地,其存储了先前词元的计算结果以便在后续生成中重用,而无需重新计算。

具体来讲,键值缓存充当自回归生成模型的内存库,模型把先前词元的自注意力层算得的键值对存于此处。在 transformer 架构中,自注意力层通过将查询与键相乘以计算注意力分数,并由此生成值向量的加权矩阵。存储了这些信息后,模型无需冗余计算,而仅需直接从缓存中检索先前词元的键和值。下图直观地解释了键值缓存功能,当计算第 K+1 个词元的注意力分数时,我们不需要重新计算所有先前词元的键和值,而仅需从缓存中取出它们并串接至当前向量。该做法可以让文本生成更快、更高效。

0471a97991639bbeb9febc57cd05df48.png

下一个名词是量化,它是个时髦词,主要用于降低数值的精度以节省内存。量化时,每个数值都会被舍入或截断以转换至低精度格式,这可能会导致信息丢失。然而,仔细选择量化参数和技术可以最大限度地减少这种损失,同时仍取得令人满意的性能。量化方法多种多样,如果你想知道更多信息以更深入了解量化世界,可查阅我们之前的博文。

  • 用 bitsandbytes、4 比特量化和 QLoRA 打造亲民的 LLMhttps://hf.co/blog/zh/4bit-transformers-bitsandbytes

有一利必有一弊,KV 缓存能够加速自回归生成,但在文本长度或者 batch size 变大时,它也随之带来了内存瓶颈。估算一下,当用 7B Llama-2 模型处理 10000 个词元的输入时,我们需要多少内存来存储 KV 缓存。存储一个词元的 KV 缓存所需的内存大致为 2 * 2 * 层数 * 键值抽头数 * 每抽头的维度 ,其中第一个 2 表示键和值,第二个 2 是我们需要的字节数 (假设模型加载精度为 float16 )。因此,如果上下文长度为 10000 词元,仅键值缓存所需的内存我们就要:

2 * 2 * 32 * 32 * 128 * 10000 ≈ 5GB

该内存需求几乎是半精度模型参数所需内存的三分之一。

因此,通过将 KV 缓存压缩为更紧凑的形式,我们可以节省大量内存并在消费级 GPU 上运行更长上下文的文本生成。实验表明,通过将 KV 缓存量化为较低的精度,我们可以在不牺牲太多质量的情况下显著减少内存占用。借助这一新的量化功能,我们现在可以用同样的内存支持更长的生成,这意味着你可以扩展模型的上下文长度,而不必担心遇到内存限制。

实现细节

Transformers 中的键值缓存量化很大程度上受启发于KIVI: A Tuning-Free Asymmetric 2bit Quantization for kv Cache论文。该论文对大语言模型引入了 2 比特非对称量化,且不会降低质量。KIVI 采用按通道的量化键缓存以及按词元量化值缓存的方法,因为研究表明,就 LLM 而言,键在某些通道上容易出现高幅度的异常值,而值并无此表现。因此,采用按通道量化键和按词元量化值的方法,量化精度和原始精度之间的相对误差要小得多。

  • KIVI: A Tuning-Free Asymmetric 2bit Quantization for kv Cachehttps://arxiv.org/abs/2402.02750

在我们集成至 transformers 时,键和值都是按通道量化的 [译者注: 原文为按词元量化,比照代码后改为按通道量化]。量化的主要瓶颈是每次添加新词元 (即每个生成步骤) 时都需要对键和值进行量化和反量化,这可能会减慢生成速度。为了解决这个问题,我们决定保留固定大小的余留缓存 (residual cache),以原始精度存储键和值。当余留缓存达到其最大容量时,存储在里面的键和值都会被量化,然后将其内容从余留缓存中清空。这个小技巧还有助于保持准确性,因为一些最新的键和值始终以其原始精度存储。设置余留缓存长度时主要需要考虑内存效率的权衡。虽然余留缓存以其原始精度存储键和值,但这可能会导致总体内存使用量增加。我们发现使用余留长度 128 作为基线效果不错。

  • 修改为按通道量化参考代码https://github.com/huggingface/transformers/blob/main/src/transformers/cacheutils.py#L404

因此,给定形状为 batch size, num of head, num of tokens, head dim 的键或值,我们将其分组为 num of groups, group size 并按组进行仿射量化,如下所示:

X_Q = round(X / S) - Z

这里:

  • XQ 是量化后张量

  • S 是比例,计算公式为 (maxX - minX) / (maxvalforprecision - minvalforprecision)

  • Z 是零点,计算公式为 round(-minX / S)

目前,支持 KV 量化的后端有:quanto后端支持 int2int4 量化;HQQ后端支持 int2int4int8 量化。如欲了解 quanto 的更多详情,可参阅之前的博文。尽管我们目前尚不支持其它量化后端,但我们对社区贡献持开放态度,我们会积极集成新后端相关的 PR。我们的设计支持社区贡献者轻松将不需要校准数据且可以动态计算低比特张量的量化方法集成进 transformers。此外,你还可以在配置中指定缺省量化参数,从而自主调整你的量化算法,如: 你可根据你的用例决定是使用按通道量化还是按词元量化。

  • quantohttps://github.com/huggingface/quanto

  • HQQhttps://github.com/mobiusml/hqq/tree/master

  • Quanto: PyTorch 量化工具包https://hf.co/blog/zh/quanto-introduction

比较 FP16 缓存和量化缓存的性能

一图胜千言,我们准备了几幅图,以让大家一目了然了解量化缓存与 FP16 缓存的表现对比。这些图向大家展示了当我们调整 KV 缓存的精度设置时,模型生成的质量是如何随之变化的。我们在PG-19数据集上测量了Llama2-7b-chat的困惑度。实验中使用的量化参数为: nbits=4, groupsize=64, resilduallength=128, pertoken=True

  • PG-19https://hf.co/datasets/emozilla/pg19-test

  • Llama2-7b-chathttps://hf.co/meta-llama/Llama-2-7b-chat-hf

可以看到,两个后端的 int4 缓存的生成质量与原始 fp16 几乎相同,而使用 int2 时出现了质量下降。你可在此处获取重现脚本。

  • 复现脚本链接https://gist.github.com/zucchini-nlp/a7b19ec32f8c402761d48f3736eac808

5cfd46a4d5fea539121bcc4668829024.png

我们还在LongBench基准上测量了生成质量,并将其与 KIVI 论文的结果进行比较,结论与上文一致。下表的结果表明,在所有测试数据集中, Quanto int4 的精度与 fp16 相当甚至略优 (数值越高越好)。

  • LongBenchhttps://hf.co/datasets/THUDM/LongBench

数据集KIVI fp16KIVI int2Transformers fp16Quanto int4Quanto int2
TREC63.067.563.063.055.0
SAMSum41.1242.1841.1241.314.04
TriviaQANANA84.2884.7663.64
HotPotQANANA30.0830.0417.3
PassageretrievalenNANA8.59.54.82

现在,我们来谈谈内存节省和速度之间的权衡。当我们量化模型中的 KV 缓存时,对内存的需求减少了,但有时这同时也会降低生成速度。虽然将缓存量化为 int4 可以节省大约 2.5 倍内存,但生成速度会随着 batch size 的增加而减慢。用户必须自己权衡轻重: 是否值得牺牲一点速度以换取内存效率的显著提高,这由你的实际用例的需求及其优先级排序决定。

以下给出了原始精度版和量化版 KV 缓存在各性能指标上的对比,复现脚本见此处。

  • 复现脚本链接https://gist.github.com/zucchini-nlp/56ce57276d7b1ee666e957912d8d36ca

a85d90ec9665d6b37308ad6fd4c477b2.png 69c4dcab732f5f5e44270efbb234ccde.png 79b227e04d9aff7187a87a5eaa8f5a09.png

想知道再叠加权重量化会发生什么吗?当然,把这些技术结合使用可以进一步减少模型的内存占用,但也带来一个问题 - 它可能会进一步减慢速度。事实上,我们的实验表明,权重量化与 KV 缓存量化一起使用会导致速度降低三倍。但我们并未放弃,我们一直在努力寻找让这个组合无缝运行的方法。目前 quanto 库中缺少相应的优化算子,我们对社区任何有助于提高计算效率的贡献持开放态度。我们的目标是确保你的模型平稳运行,同时保持高水准的延迟和准确性。

还需要注意的是,对输入提示的首次处理 (也称为预填充阶段) 仍然需要一次性计算整个输入的键值矩阵,这可能是长上下文的另一个内存瓶颈。这就是为什么生成第一个词元相关的延迟往往比后续词元更高的原因。还有一些其他策略可以通过优化注意力计算来减少预填充阶段的内存负担,如局部加窗注意力、Flash Attention等。如果预填充阶段内存不足,你可以使用 🤗 Transformers 中的 FlashAttention 以及 KV 缓存量化来进一步减少长输入提示的内存使用量。更多详情,请参阅文档。

  • 局部加窗注意力https://arxiv.org/abs/2004.05150

  • Flash Attentionhttps://arxiv.org/abs/2307.08691

  • Transformers 文档https://hf.co/docs/transformers/main/en/perfinfergpuone#flashattention-2

如果你想知道如果将内存使用量推至极限,我们最长可以支持多少个词元的上下文,那么在 80GB A100 中启用 Flash Attention 时,量化 KV 缓存可以支持多达 128k 个词元。而使用半精度缓存时,最长为 40k 个词元。

如何在 🤗 Transformers 中使用量化 KV 缓存?

要在 🤗 Transformers 中使用 KV 缓存量化,我们必须首先运行 pip install quanto 安装依赖软件。要激活 KV 缓存量化,须传入 cacheimplementation="quantized" 并以字典格式在缓存配置中设置量化参数。就这么多!此外,由于 quanto 与设备无关,因此无论你使用的是 CPU/GPU/MPS (苹果芯片),都可以量化并运行模型。

你可在此找到一个简短的Colab 笔记本及使用示例。

  • Colab 笔记本https://colab.research.google.com/drive/1YKAdOLoBPIore77xR5Xy0XLN8Etcjhui?usp=sharing

>>> import torch
>>> from transformers import AutoTokenizer, AutoModelForCausalLM>>> tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b-chat-hf")
>>> model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-chat-hf", torch_dtype=torch.float16, device_map="cuda:0")
>>> inputs = tokenizer("I like rock music because", return_tensors="pt").to(model.device)>>> out = model.generate(**inputs, do_sample=False, max_new_tokens=20, cache_implementation="quantized", cache_config={"backend": "quanto", "nbits": 4})
>>> print(tokenizer.batch_decode(out, skip_special_tokens=True)[0])
I like rock music because it's loud and energetic. It's a great way to express myself and rel>>> out = model.generate(**inputs, do_sample=False, max_new_tokens=20)
>>> print(tokenizer.batch_decode(out, skip_special_tokens=True)[0])
I like rock music because it's loud and energetic. I like to listen to it when I'm feeling

总结

还有很多可以减少键值缓存内存占用的方法,如MultiQueryAttention、GroupedQueryAttention以及最近的KV 缓存检索等等。虽然其中一些方法与模型架构相耦合,但还是有不少方法可以在训后阶段使用,量化只是此类训后优化技术其中一种。总结一下本文:

  • MultiQueryAttentionhttps://arxiv.org/abs/1911.02150

  • GroupedQueryAttentionhttps://arxiv.org/abs/2305.13245

  • KV 缓存检索https://arxiv.org/abs/2403.09054

  1. 需要在内存与速度之间折衷: 通过将 KV 缓存量化为较低精度的格式,内存使用量可以显著减少,从而支持更长的文本生成而不会遇到内存限制。但,用户必须根据实际用例决定能不能接受放弃一点点生成速度的代价。

  2. 保持准确性: 尽管精度有所降低, int4 KV 缓存量化仍可将模型准确性保持在令人满意的程度,确保生成的文本保持上下文相关性和一致性。

  3. 灵活性: 用户可以根据自己的具体要求灵活地选择不同的精度格式,以为不同的用例及需求进行定制。

  4. 进一步优化的潜力: 虽然 KV 缓存量化本身具有显著的优势,但它也可以与其他优化技术 (例如权重量化) 结合使用,以进一步提高内存效率和计算速度。

致谢

特别感谢Younes和Marc在量化技术上的帮助和建议,他们的专业知识极大地促进了此功能的开发。

  • Youneshttps://hf.co/ybelkada

  • Marchttps://hf.co/marcsun13

此外,我还要感谢Joao的宝贵支持。

  • Joaohttps://hf.co/joaogante

更多资源

  1. Zirui Liu, Jiayi Yuan, Hongye Jin, Shaochen Zhong, Zhaozhuo Xu, Braverman, V., Beidi Chen, & Hu, X. (2023).KIVI : Plug-and-play 2bit KV Cache Quantization with Streaming Asymmetric Quantization.https://arxiv.org/abs/2402.02750

  2. Databricks 博文:LLM Inference Performance Engineering: Best Practiceshttps://www.databricks.com/blog/llm-inference-performance-engineering-best-practices

  3. Coleman Hooper, Sehoon Kim, Hiva Mohammadzadeh, Michael W. Mahoney, Yakun Sophia Shao, Kurt Keutzer, & Amir Gholami. (2024).KVQuant: Towards 10 Million Context Length LLM Inference with KV Cache Quantization.https://arxiv.org/abs/2401.18079

  4. T. Dettmers, M. Lewis, Y. Belkada, and L. Zettlemoyer, (2022).LLM.int8(): 8-bit Matrix Multiplication for Transformers at Scale.https://arxiv.org/abs/2208.07339

  5. A. Gholami, S. Kim, Z. Dong, Z. Yao, M. W. Mahoney, and K. Keutzer, (2021). A Survey of Quantization Methods for Efficient Neural Network Inference.


英文原文: https://hf.co/blog/kv-cache-quantization

原文作者: Raushan Turganbay 

译者: Matrix Yao (姚伟峰),英特尔深度学习工程师,工作方向为 transformer-family 模型在各模态数据上的应用及大规模模型的训练推理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/26313.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于STM32和人工智能的智能交通管理系统

目录 引言环境准备智能交通管理系统基础代码实现:实现智能交通管理系统 4.1 数据采集模块4.2 数据处理与分析4.3 控制系统4.4 用户界面与数据可视化应用场景:智能交通管理与优化问题解决方案与优化收尾与总结 1. 引言 随着城市化进程的加快&#xff0…

算法第六天:力扣第977题有序数组的平方

一、977.有序数组的平方的链接与题目描述 977. 有序数组的平方的链接如下所示:https://leetcode.cn/problems/squares-of-a-sorted-array/description/https://leetcode.cn/problems/squares-of-a-sorted-array/description/ 给你一个按 非递减顺序 排序的整数数组…

【C++】STL中stack和queue(适配器版)的模拟实现

前言:在此之前我们讲到了stack和queue还有deque的常见的使用方法,并且也在数据结构的时候用C语言去实现过栈和队列,今天我们将进一步的用C去模拟实现stack和queue 💖 博主CSDN主页:卫卫卫的个人主页 💞 👉 …

vue 之 vuex

目录 vuex 是什么 Vuex管理哪些状态呢? Vuex 页面刷新数据丢失怎么解决 1. 使用浏览器的本地存储 2. 使用 Vuex 持久化插件 3. 使用后端存储 注意事项 Vuex 为什么要分模块并且加命名空间 vuex 是什么 vuex 是专门为 vue 提供的全局状态管理系统&#xff0c…

【应用案例】如何解决无人驾驶车辆的动力转向问题

埃尔朗根-纽伦堡大学名称为高能赛车运动队(High-Octane Motorsports e.V.)的学生方程式车队都设计、构建和制造具有创新意义且独特的赛车。然后,他们将参加三种不同类别的大学生方程式比赛;该项赛事中的参赛队伍来自于世界各地。 电动、无人驾驶和燃油车…

Windows 11 24H2版首发体验!附详细更新升级安装教程

Windows 11 24H2 版首发体验!这是微软2024年的大版本更新,新增超多新功能,以下会给你细细道来。这个版本目前小编亲测,使用非常流畅,没有什么明显问题。系统是已经集成了VB6/VC2005/VC2008/VC2010/VC2012/VC2013/VC201…

Dorkish:一款针对OSINT和网络侦查任务的Chrome扩展

关于Dorkish Dorkish是一款功能强大的Chrome扩展工具,该工具可以为广大研究人员在执行OSINT和网络侦查任务期间提供强大帮助。 一般来说,广大研究人员在执行网络侦查或进行OSINT信息收集任务过程中,通常会使用到Google Dorking和Shodan&…

2024年高考:计算机相关专业还值得选择吗?

🍎个人博客:个人主页 🏆个人专栏:日常聊聊 ⛳️ 功不唐捐,玉汝于成 目录 前言 正文 行业竞争现状 市场饱和与新兴技术的影响 如何保持竞争力 专业与个人的匹配度判断 专业核心课程与技术能力 个人兴趣与职业…

使用开源的zip.cpp和unzip.cpp实现压缩包的创建与解压(附源码)

目录 1、使用场景 2、压缩包的创建 3、压缩包的解压 4、CloseZipZ和CloseZipU两接口的区别 5、开源zip.cpp和unzip.cpp文件的下载 VC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)https://blog.csdn.net/chenlycly/article/details/124272585C++软件异常排…

【C语音 || 数据结构】二叉树--堆

文章目录 前言堆1.1 二叉树的概念1.2 满二叉树和完美二叉树1.3 堆的概念1.4 堆的性质1.4 堆的实现1.4.1堆的向上调整算法1.4.1堆的向下调整算法1.4.1堆的接口实现1.4.1.1堆的初始化1.4.1.2堆的销毁1.4.1.3堆的插入1.4.1.4堆的删除1.4.1.4堆的判空1.4.1.4 获取堆的数据个数 前言…

单体架构改造为微服务架构之痛点解析

1.微服务职责划分之痛 1.1 痛点描述 微服务的难点在于无法对一些特定职责进行清晰划分,比如某个特定职责应该归属于服务A还是服务B? 1.2 为服务划分原则的痛点 1.2.1 根据存放主要数据的服务所在进行划分 比如一个能根据商品ID找出商品信息的接口,把…

随手记:uniapp图片展示,剩余的堆叠

UI效果图&#xff1a; 实现思路&#xff1a; 循环图片数组&#xff0c;只展示几张宽度就为几张图片边距的宽度&#xff0c;剩下的图片直接堆叠展示 点击预览的时候传入当前的下标&#xff0c;如果是点击堆叠的话&#xff0c;下标从堆叠数量开始计算 <template><…

pycharm基本使用(常用快捷键)

0.下载 pycharm官网下载 选择合适的版本&#xff0c;本文以2024.1为例 1.简单应用 常用快捷键 ctrlD 复制当前行 ctrlY 删除当前行 ctrlX 剪切当前行&#xff08;可用作删除&#xff0c;更顺手&#xff09; shift↑ 选中多行ctrlshiftF10 运行 shiftF9 调试ctrl/ 注释当前…

数据结构入门:探索数据结构第一步

0.引言 在我们的日常生活中&#xff0c;经常需要管理大量的数据&#xff0c;就譬如学校中有好几千个学生&#xff0c;中国有十三亿人口&#xff0c;对于那么多的数据进行查找、插入、排序等操作就会比较慢。人们为了解决这些问题&#xff0c;提高对数据的管理效率&#xff0c;…

docker被封禁,怎么拉取镜像,打包所有镜像

因为docker被国内封禁了&#xff0c;所以我把电脑上之前的镜像全部打包出来了 你们也可以打包&#xff0c;我提供一个脚本&#xff0c;你运行即可 export_docker.sh #!/bin/bash# 导出目录 EXPORT_DIR"docker_images_backup" mkdir -p "$EXPORT_DIR"# 获…

Calibre版图验证工具调用_笔记

Siemens EDA Calibre版图验证工具调用 采用Cadence Virtuoso Layout Editor直接调用Siemens EDA Calibre工具需要进行文件设置&#xff0c; 在用户的根目录下&#xff0c;找到.cdsinit文件&#xff0c; 在文件的结尾处添加以下语句即可&#xff0c;其中&#xff0c;calibre.skl…

电表抄表软件是什么?

一、电表抄表软件的概念和作用 电表抄表软件&#xff0c;是一种致力于电力企业定制的数字化工具&#xff0c;用以远程控制搜集、管理方法与分析电表数据信息。它取代了传统人工抄表方法&#xff0c;大大提高了工作效率&#xff0c;降低了人为失误&#xff0c;并且能实时监控系…

flask基础3-蓝图-cookie-钩函数-flask上下文-异常处理

目录 一&#xff1a;蓝图 1.蓝图介绍 2.使用步骤 3.蓝图中的静态资源和模板 二.cookie和session 1.cookie 2.flask中操作cookie 3.session 4.session操作步骤 三.请求钩子 四.flask上下文 1.介绍 2.请求上下文&#xff1a; 3.应用上下文 3.g对象 五&#xff1a;…

【Linux】进程控制2——进程等待(waitwaitpid)

1. 进程等待必要性 我们知道&#xff0c;子进程退出&#xff0c;父进程如果不管不顾&#xff0c;就可能造成"僵尸进程”的问题&#xff0c;进而造成内存泄漏。另外&#xff0c;进程一旦变成僵尸状态&#xff0c;那就刀枪不入&#xff0c;“杀人不眨眼”的kill -9 也无能为…

香港户口需要什么条件?有学历要求吗?最新香港落户途径详解!

香港户口需要什么条件&#xff1f;有学历要求吗&#xff1f;最新香港落户途径详解&#xff01; 由于香港放开“落户”窗口&#xff0c;想去香港发展或者想拿香港身份的朋友都想抓住这个机会赶紧申请。 只是&#xff0c;香港户口办理是有条件的&#xff0c;而且有学历要求&…