在生产环境中优化LLM:精度、注意力和架构
在生产环境中部署大型语言模型(LLM)需要克服两个主要瓶颈:数十亿参数带来的巨大VRAM需求以及长输入序列相关的二次内存增长。为了解决这些问题,Hugging Face 建议采用降低精度的量化、优化的注意力算法以及战略性的架构选择相结合的方法。
通过降低精度减少内存占用
降低数值精度可以减少加载模型权重所需的VRAM,使得更大的模型能够在更小或更易获取的硬件上运行。
按精度划分的VRAM需求
加载模型权重是短文本输入(低于1024个token)的主要内存成本。VRAM需求的一般经验法则是:
- float32: 大约为参数量为X十亿的模型需要4 * X GB的VRAM。
- bfloat16/float16: 大约为参数量为X十亿的模型需要2 * X GB的VRAM。
例如,Llama-2-70b 在 bfloat16 下大约需要140 GB的VRAM,这超过了单个A100(80GB)的容量,因此需要使用张量或流水线并行。
量化(8位和4位)
量化将精度进一步降低到8位或4位,显著降低内存使用量,同时对文本生成的准确性影响甚微。这是因为文本生成依赖于下一个token logits的相对分布,而不是确切的数值。
- 8-bit 量化:显著降低VRAM使用量(例如,OctoCoder的峰值内存从约32GB降至约15GB)。由于在计算过程中需要动态反量化,可能会导致推理轻微变慢。
- 4-bit 量化:进一步降低VRAM(例如,OctoCoder降至约9.5GB),使得模型能够在消费级GPU如RTX 3090上运行。然而,相比8-bit量化,它可能导致更明显的准确性下降和推理速度变慢。
使用Flash Attention加速推理
标准自注意力相对于序列长度($N$)具有二次计算和内存复杂度,这使得在长上下文(例如16,000+个token)时变得极其昂贵。
Flash Attention算法
Flash Attention通过将计算分割成更小的块并遍历多个softmax步骤来优化注意力机制。它避免了大型$QK^T$矩阵的创建,导致内存成本随着$N$的增加呈线性而非二次增长。
性能提升
尽管Flash Attention由于重新计算softmax归一化统计量而需要更多的FLOPs,但在实际中它更快,因为它最小化了对慢速高带宽内存(VRAM)的访问,并最大化了快速片上SRAM的使用。它产生的输出与默认自注意力算法在数值上完全相同。
适用于长上下文和聊天的架构优化
训练期间的架构选择决定了模型处理长序列和多轮对话的效率。两个关键领域是位置嵌入和键值(KV)缓存。
相对位置嵌入
绝对位置嵌入(正弦或学习得到的)在处理长文本时往往表现不佳,且难以超越其训练长度进行外推。相对位置嵌入更为有效:
- 旋转位置嵌入(RoPE):通过旋转query-key对来编码位置。它被用于Falcon、Llama和PaLM。
- ALiBi:将一个由预定义值缩放的负整数添加到$QK^T$矩阵中。它被用于MPT和BLOOM,并且通常相比RoPE能够更有效地外推到更长的序列。
优化键值(KV)缓存
自回归生成使用KV缓存来存储所有先前token的键值向量,从而避免在每一步重新计算它们。这将$QK^T$的计算转换为向量-矩阵乘法($\text{query} \times \text{KV cache}$),从而显著提高速度。
然而,KV缓存可能成为内存瓶颈。两种架构可以减少此开销:
- 多查询注意力(MQA):在所有注意力头之间共享单个键值投影头。这将缓存大小大幅减少(例如,对于OctoCoder中的16,000个token序列,从15GB降至低于400MB),并减少内存带宽瓶颈。用于Falcon、PaLM、MPT和BLOOM。
- 分组查询注意力(GQA):在MQA和标准多头注意力之间的折中方案。它使用少量的KV投影头(例如,2、4或8)来保持比MQA更大的模型容量,同时保留其大部分效率。用于Llama-2。