大型语言模型(llm)虽然性能强劲,但动辄几百上千亿的参数量,对计算设备还是内存的需求量之大,都不是一般公司能承受得住的。
量化(quantization)是常见的压缩操作,通过降低模型权重的精度(如32bit降为8bit),牺牲一部分模型的性能来换取更快的推理速度,更少的内存需求。
但对于超过1000亿参数量的llm来说,现有的压缩方法都无法保持模型的准确率,也无法在硬件上高效地运行。
最近,麻省理工学院和英伟达的研究人员联合提出了一个通用后训练的量化(gpq, general-purpose post-training quantization)方案smoothquant,对大型语言模型可以高效实现8-bit权重,8-bit激活(w8a8)的量化,无需训练也能保持模型的准确率。
论文链接:https://arxiv.org/pdf/2211.10438.pdf
代码链接:https://github.com/mit-han-lab/smoothquant
由于激活相比权重更难量化,smoothquant通过数学等价变换将较难量化的激活迁移到权重上,实现了对激活异常值(activation outliers)的平滑处理。
smoothquant能够对所有llm的各种层中权重和激活量化到int8,包括opt-175b, bloom-176b和glm-130b。
相比现有方法仅对权重进行靓货,或者对激活进行混合精度的量化,smoothquant有更高的硬件效率,实现了1.56倍加速,内存需求仅为原始llm的一半,并且在准确率上几乎没有损失。
smoothquant同时具有硬件友好的设计,研究人员将smoothquant集成进了llm服务框架fastertransformer中,实现了更快的推理速度,相比fp16的精度仅需一半数量的gpu
文章的第一作者肖光烜是mit eecs的一年级博士生,本科毕业于清华大学计算机科学与技术学院。
导师song han是mit eecs的副教授,博士毕业于斯坦福大学,主要研究方向为高效深度学习,曾提出深度压缩(deep compression)技术,可以将神经网络的尺寸降低一个数量级,而不损失准确率。
smoothquant量化(quantization)就是把高精度的值映射到更低精度的离散值,在这篇论文中研究人员主要关注对硬件更高效的整数均匀量化(integer uniform quantization),尤其是int8。
量化操作可以在不同的粒度上执行,如per-tensor量化应用于整个权重矩阵,per-token量化应用于激活中的每个token,per-channel量化应用于权重的每个输出通道。
通过对激活的量化结果进行观察,研究人员总结出了几个模式:
1、量化比权重更难量化。
权重的分布相对更加均匀和平坦,之前的研究结果已经证明将大型语言模型的权重降低到int8,甚至到int4对准确率的影响都不大。
2、异常值是激活量化中的主要难点。
激活中的异常值通常比正常值要高出100倍左右,导致没有异常值通道中的量化bits/levels效率很低。
3、异常值固定在某一通道中出现。
异常值只在很小一部分的通道中才会出现,但如果一个通道中有一个异常值,那该异常值可能会在所有的token中出现。
给定一个token中所有通道的方差会很大(一些通道会非常大,但大部分很小),但是给定一个通道在所有token度中的方差会很小(异常值通道会很大)。
由于异常值具有持续出现和每个通道内小方差的特点,那如果对激活执行per-channel量化,其量化误差将会远远小于per-tensor量化。
通过一个简单的实验,其结果再次验证了研究人员的想法,量化到int8时,per-channel的准确率远远高于per-tensor和per-token量化,和fp16基线准确率相差无几。
研究人员通过使用一个per-channel平滑因子s来将输入激活进行平滑(smooth)。为了保持线性层的数学等价,还需要反向缩放权重。
由于输入x通常是由之前的线性操作生成的(如线性层、层norms等),所以就可以很容易地将平滑因子融合到之前层的参数offline,而且不会产生额外缩放的内核调用开销。对于其他情况,比如当输入来自残差add时,可以向残差分支添加一个额外的缩放。
将量化难度从激活转移到权重smooth的目标是选择一个per-channel的平滑因子s,使该逆操作更易于量化。
为了减少量化误差,应该增加所有通道的有效量化比特。当所有通道的最大magnitude相同时,总的有效量化位数将是最大的。
因此,一个最直接的平滑因子选择就是输入中每个通道的最大值,可以保证在划分之后,所有的激活通道都有相同的最大值,从而实现更容易的量化。
但需要注意的是,激活的范围是动态的,对于不同的输入样本是不同的。所以研究人员使用预训练数据集中的校准样本来估计激活通道的规模。
由于这个公式将所有的量化困难迁移给了权重,可以发现在这种情况下,权重的量化误差会很大,导致准确性下降很多。
另一方面,也可以通过选择sj = 1/ max(|wj |),将所有的量化难度从权重推到激活上。同样,由于激活量化误差过大,模型的性能也不好。因此需要在权重和激活之间分割量化难度,使它们都易于量化。
研究人员引入一个超参数迁移强度α,来控制要从激活迁移到权重的难度。
可以发现,对于大多数模型,例如opt和bloom模型,α=0.5是一个很好的平衡点,可以平均分配量化难度,特别是使用相同的量化器进行权重和激活。
该公式保证了相应通道的权重和激活具有相似的最大值,从而共享相同的量化难度。
对于其他一些激活异常值比较大的模型,例如glm-130b有30%的异常值,这对激活量化来说比较困难,可以选择一个较大的α(如0.75),将更多的量化难度迁移到权重上。
smoothquant应用于transformer块
线性层占据了llm模型的大部分参数和计算。在默认情况下,smoothquant对transformer中所有线性层的输入激活进行比例平滑,并用w8a8对线性层进行量化,在注意力计算中启用了bmm运算符的量化。
在流程中,首先用int8对线性层和注意力层中的bmm等计算量大的运算符的输入和权重进行量化,而对其他轻量级元素的运算,如softmax和layernorm,保持激活为fp16,这样的设计有助于平衡准确性和推理效率。
实验部分研究人员选择了三个大型语言模型用来评估smoothquant,包括opt, bloom和glm-130b;并使用七个zero-shot任务,包括lambada, hellaswag, piqa, winogrande, openbookqa, rte, copa等。
实验结果显示smoothquant可以处理非常大的llm的量化问题,其激活更难量化。
smoothquant可以在所有评估数据集上匹配fp16的准确性,而w8a8、zeroquant和outlier suppression基线产生的结果几乎是随机的。
并且smoothquant可以无损地量化所有超过100b参数的开放式llms
smoothquant的o1和o2级成功地保持了浮点精度,而o3级(per-tensor static)使平均精度下降了0.8%,可能是因为静态收集的统计数据与真实评估样本的激活统计数据之间的差异。
尽管如此,smoothquant-o1可以与fp16的准确性相匹配,而smoothquant-o3只降低了1%的准确性,明显优于基线。
smoothquant不仅对超过100b参数的非常大的llm有效,而且对较小的llm也有稳定的效果,smoothquant可以在所有规模的opt模型上工作,并与int8量化的fp16精度相匹配。
为了展示集成到pytorch和fastertransformer中的smoothquant-o3的速度提升和内存节省,研究人员我们测量了一次生成一批4个句子的所有隐藏状态的端到端延迟,也就是context阶段的延迟,并记录了这个过程中gpu内存使用的峰值。
由于huggingface缺乏对模型并行的支持,所以研究人员只测量了smoothquant在单个gpu上的pytorch实现的性能,因此选择了opt-6.7b、opt-13b和opt-30b进行评估。
在fastertransformer库中,smoothquant可以与tensor parallelism算法无缝对接,因此研究人员在opt-13b、opt-30b、opt-66b和opt-175b上测试smoothquant的单gpu和多gpu基准。
在nvidia a100 80gb gpu服务器上进行的实验结果显示,基于pytorch实现的推理延迟和峰值内存使用上,smoothquant始终比fp16基线快,当序列长度为256时,在opt-30b上获得了1.51倍的速度提升。
还可以看到一个趋势,即模型越大,加速越明显,但llm.int8()几乎总是比fp16基线慢,这也是由于混合精度激活表示的巨大开销造成的。
在内存方面,smoothquant和llm.int8()都可以将fp16模型的内存用量几乎减半,而smoothquant由于完全使用int8 gemm,所以节省的内存稍多。
与fastertransformer对opt的fp16实现相比,smoothquant-o3在使用单个gpu时可以进一步降低opt-13b和opt-30b的执行延迟,最高可达1.56倍。
以上就是100亿参数的语言模型跑不动?mit华人博士提出smoothquant量化,内存需求直降一半,速度提升1.56倍!的详细内容。