2024-11-26

Qserve 是在 Atom 之后做的工作
不幸的是,这种预期的性能提升在当前的 GPU 平台上并未得到一致的观察。例如,最先进的 W4A4 服务系统 Atom 在 TensorRT-LLM 上运行 Llama-2-7B 模型时,在 A100GPU 上表现出 20-25% 的较低性能,与它的 W4A16 和 W8A8 对应版本相比。

另一方面,对于 W4A4 量化,为了达到合理的精度,W4A4 方法必须对权重和激活应用分组量化,同时在子通道基础上共享 FP16 缩放因子

W4A4 会造成严重的精度下降,需要用其他方式优化这个精度下降而远不能达到无损的环节:因此,减少 CUDA 内核的开销对于实现 LLM 服务的最优吞吐量至关重要。基于这一原则,我们引入了 QoQ(Quattuor-Oct̄o-Quattuor,或拉丁语中的 4-8-4) 算法,将 LLM 量化为 W4A8KV4 精度:4 位权重位激活和 4 位 KV 缓存。此外,我们还提出了 QServe,它为 W4A8KV4 量化提供了高效的系统支持。
因此 Qserve 实际上是与 Tender 类似的系统解决方案

渐进量化 (progressive group and quantization)

在 QoQ 算法中,我们引入了 progressive group 和 quantization。此方法首先使用每通道 FP16 尺度将权重量化为 8 位,然后将这些 8 位中间值量化为 4 位。这种方法确保所有 GEMMs 都在 INT8 张量核心上执行。此外,我们通过 SmoothAttention 减轻了 KV4 量化带来的精度损失,将激活量化的问题从键转移到查询上,后者并未进行量化。
似乎也是为了更好利用其 cuda 并行性,涉及硬件信息

提出的原因

为了提高低比特量化精度,通常使用 group quantization。然而,如第 III-B 节所述,系统实现中的解量化开销可能会抵消这些精度改进.

group-wise

对于 Per-group 量化,进一步通过在每个行内的每 g 列使用不同的 s 和 z 来减少参数共享的程度,其中 g 是组大小。

寄存器压力和并行性

如图 5d 所示。我们采用两层 progressive group quantization 方法以确保所有计算都在 INT8 张量核心上进行。我们选择权重去量化而不是部分求和去量化, 因为这样可以降低寄存器压力。此外,我们应用了 4 路 register-level parallelism 来同时解码四个 INT4 权重,进一步减少了主循环的开销。

寄存器压力

因此,主循环主要由慢速 CUDA 核心操作主导,而不是快速的张量核心操作。其次,Atom 创建了两组寄存器 (一组用于 FP32,一组用于 INT32) 来持有部分求和。由于 GPU 输出静止数据流的本性,较大的 GEMM 问题 (例如预填充阶段) 通常受限于寄存器,导致存储 partialsums 时消耗大量寄存器。每个线程块内消耗大量寄存器限制了可以同时执行的线程块数量。值得注意的是,GPU 依赖于大量在飞行的线程块之间的低成本上下文切换来隐藏延迟。因此,同时执行的线程块数量较少限制了延迟隐藏的机会,进一步加剧了主循环的开销。

小结

  • 在主循环进行量化:Fast Dequantization in Per-Channel W4A8GEMM: 如图 5d 所示,当权重和激活的位精度不同时,在主循环内对权重进行去量化变得必要
  • 进量化算法确保了在乘法计算顺序之后的所有减法中间结果都不会溢出,从而实现了寄存器级别的并行化并减少了主循环的开销
  • General Optimizations: 在我们的 W4A8 内核中,我们 还采用了通用的 GEMM 优化技术。

最后实现了一套以 QoQ 算法为上层,Qserve 系统为下层的加速器(太多看不懂了,扫描搁置);实现了一套在软件层面的算法和系统协同。

一些问题

  • 此外,我们提出 compute-aware weight reordering 以最小化 CUDA 内核在 W4A8 GEMM 操作中的指针算术开销。
  • 对于 m × n × k 问题,每个线程块通过按 顺序遍历减少维度 k 计算一个 tm × tn 输出瓷砖。这个顺序 循环被称为主循环
  • W4A16 需要 INT4 到 FP16 的权重转换,而 Atom-W4A4 需要 INT32 到 FP32 的部分求和转换和累加.为什么后者会需要从 int32->fp32 的转换开销
  • Weight Clipping: 权重裁剪是另一种流行的量化优化技术。它通过让 Wmax=αmax(W) 和 Wmin=αmin(W) 将动态范围在等式 2 中应用了一个剪切比α

2024-11-28

ATOM 和 Qserve 的主循环样式

对于 问题,每个线程块通过按顺序遍历减少维度 k 计算一个 输出瓷砖。这个顺序循环被称为主循环。主循环包含超过 100 次迭代,并主导了 GEMM 内核的运行时间。在 FP16 和 W8A8GEMM 中,主循环完全在张量核心上执行。TensorRT-LLM-W4A16 和 Atom-W4A4(图 5c) 两者都需要在主循环中执行解量化操作。
Pasted image 20241128155215.webp

  • 因此,主循环主要由慢速 CUDA 核心操作主导,而不是快速的张量核心操作
  • 其次,Atom 创建了两组寄存器 (一组用于 FP32,一组用于 INT32) 来持有部分求和。由于 GPU 输出静止数据流的本性,较大的 GEMM 问题 (例如预填充阶段) 通常受限于寄存器,导致存储 partialsums 时消耗大量寄存器。每个线程块内消耗大量寄存器限制了可以同时执行的线程块数量。值得注意的是,GPU 依赖于大量在飞行的线程块之间的低成本上下文切换来隐藏延迟。因此,同时执行的线程块数量较少限制了延迟隐藏的机会,进一步加剧了主循环的开销。

相对来说,Qserve 的主循环如下图所示:使用 2 阶段的渐进量化方法,使得所有计算在张量核心上运行。可以看到是 INT4 量化,然后张量核心上是 INT 的计算
Pasted image 20241128155459.webp

对于 W4A8 GEMM 计算,4 位量化权重张量 将首先根据公式 5 解量化为中间的 8 位量化权重张量 ,然后执行类似于 W8A8 通道量化方式的 INT8 矩阵乘法。

旋转矩阵

为了消除平滑注意力缩放中平滑化内核调用开销的额外内核调用开销,将缩放融合到前一个线性层的权重中是首选的。然而,现代大语言模型 (LLM) 使用旋转位置嵌入 (RoPE) 同时应用于键和查询,这需要额外的处理

如图 8 所示,受到 [2]、[4] 的启发,我们通过乘以旋转矩阵来旋转块输入激活。为了保持线性层的数学等价性,我们相应地在反向方向旋转对应的权重。旋转后,每个通道的激活是所有其他通道的线性组合,因此有效地抑制了异常通道。此外,由于旋转是一种单位变换,我们可以将旋转矩阵与之前的线性层的权重融合。我们简单地选择缩放后的汉达矩阵作为旋转矩阵。

小结

原文没有看懂的地方挺多的,可以看到一些优化方法的影子,如逐组量化,GEMM 优化等,还有不少不知道的概念,如主循环开销的优化,计算感知和内存绑定等,本笔记也基本上是记录了一点认为当时理解了一点的东西,文件没有彻底弄明白,只能说作为软件和系统级别的观察还不够。