AMD GPU 上 FP4 混合精度推理优化

随着前沿大语言模型(LLM)规模不断扩大,对 GPU 计算力和内存带宽的需求激增。GPU 厂商和模型开发者正转向低精度浮点格式,其中 FP4(4 位浮点)量化备受关注,例如 FP4 量化的 Llama 3.3 70B 模型体积缩小 3.5 倍,同时在 MMLU 等基准上质量损失最小。然而,现有的 AMD Instinct MI250 和 MI300 系列 GPU 缺乏原生 FP4 支持。为此,我们开发了 Petit——专为 AMD GPU 优化的 FP16/BF16 × FP4 混合精度内核集合。它在 MI200 和 MI300 系列上实现 FP4 模型高效推理:使用 SGLang 时端到端性能提升 1.74 倍,矩阵乘法比 hipBLASLt 快至 3.7 倍。Petit 已开源并集成至 SGLang 0.4.10,支持无缝部署 Llama 3.3 70B FP4 模型。(128 字)

引言

前沿大语言模型(LLM)规模持续扩大,对 GPU 的计算力和内存带宽需求日益高涨。GPU 厂商和模型开发者正转向低精度浮点格式,其中 FP4(4 位浮点)量化尤为引人注目。例如,FP4 量化的Llama 3.3 70B模型体积缩小 3.5 倍,在MMLU等基准测试中质量损失微乎其微。

然而,当前硬件支持存在明显短板。虽然 NVIDIA GB200 和 AMD MI350 等新一代 GPU 原生支持 FP4 矩阵乘法,但广泛部署的 AMD Instinct MI250 和 MI300 系列 GPU 尚无此能力,导致用户无法在现有 AMD 硬件上高效运行 FP4 模型。

为填补这一空白,我们开发了 Petit——专为 AMD GPU 设计的 FP16/BF16 × FP4 混合精度 GPU 内核集合。Petit 无需硬件升级,即可在 MI200 和 MI300 系列上服务 FP4 模型,带来显著性能提升:

  • 使用SGLang时,Llama 3.3 70B 端到端推理性能提升 1.74 倍
  • 等效矩阵乘法执行速度比 AMD 最先进的 GEMM 库 hipBLASLt 快至 3.7 倍

Petit 以 BSD 许可开源,已集成至 SGLang 0.4.10。用户可通过以下命令在 AMD MI250/MI300X 上启动 Llama 3.3 70B FP4 模型服务:

python -m sglang.launch_server --model-path nvidia/Llama-3.3-70B-Instruct-FP4 --host 0.0.0.0 --port 30000

本文详述优化历程和技术细节,Petit 充分利用 AMD 开源软件生态,并引入离线重排和硬件特定低级优化等创新。

Petit 中的优化概述
图 1:Petit 中的优化概述。

与硬件架构协同设计高效 GPU 内核

现代 GPU 通过堆叠紧凑的计算单元(CU)实现海量计算吞吐,但需应用与底层架构深度协同设计,方能发挥峰值性能。如图 1 所示,Petit 的开发遵循多项关键协同设计原则。

通过预处理实现高效去量化

Petit 高效利用 AMD GPU 的专用 MatrixCore 硬件加速矩阵乘法。一个 wavefront(64 个线程组)可高效集体乘以两个 BF16/FP16 16×16 矩阵。但 MI300X GPU 无原生 FP4 权重 MatrixCore 支持,因此需将 FP4 权重去量化至 BF16/FP16,同时保持内存加载和 MatrixCore 准备的高效性。

这带来核心挑战:内存加载和 MatrixCore 准备需不同数据布局。内存高效需连续加载 1024 字节块,而 MatrixCore 期望 16×16 瓦片分布于 wavefront。传统 GPU 端重排开销巨大。

NVIDIA GPU 的Marlin实现通过磁盘预排元素避免此问题。我们将 8 个连续 FP4 值打包至 32 位整数,需 31 条指令去量化。Petit 进一步定制位打包格式:前 4 个 FP4 以 BF8 布局重排,其余存于剩余位。借助 AMD 独有的 v_bfrev_b32v_cvt_pk_f32_bf8 指令(支持子双字寻址 SDWA),仅用 15 条指令去量化 8 个 FP4 值,乘法性能提升 30%。

掌握内存层次结构

MI300X 等 GPU 算术密度极高(>500),CU 需每字节执行数百操作以达峰值 FLOPS,因此最大化有效内存带宽至关重要。Petit 采用瓦片化和双缓冲等成熟技术,并针对 AMD 特性优化:

  • 避免 LDS Bank 冲突:AMD GPU LDS 分 32 银行,每周期允许 32 个唯一银行并发访问。冲突会导致序列化瓶颈,尤其 wavefront 有 64 线程。Petit 基于银行设计实现置换数据布局,实现无冲突 LDS 使用。
  • Chiplet 和互连:每个 MI300 chiplet(XCD)有 4MB 本地 L2 缓存,全 GPU 共享 256MB L3 缓存。互连带宽高但延迟大。Petit 实现拓扑感知工作负载分区,减少互连流量,优先朴素网格分区而非全局条带分区(当剖析显示互连开销更大时)。

生成高质量机器码

GPU 使用简单乱序执行单元最大化 CU 密度,但分支和管线停顿代价高昂。AMD GPU 提供条件移动和边界内存指令,完全消除分支。例如,Petit 利用指定范围的缓冲加载/存储指令,GPU 自动丢弃越界访问;LDS 超 64KB 访问亦自动处理,无性能罚则。此外,Petit 提供编译器提示,重叠 MFMA(矩阵融合乘加)指令与内存访问,有效隐藏内存延迟。

标准编译器可能未充分利用高级 GPU ISA(如有意越界访问为未定义行为)。这些优化需手动构建和验证。

性能结果

端到端推理性能

我们通过 FP4 与 BF16 模型端到端推理性能对比评估 Petit 实际效果。测试使用 Llama 3.3 70B 两种变体与 SGLang v0.4.10,测量批次大小 10 和 64 的输入/输出 token 吞吐量。环境为 AMD 开发者云 VM(1× MI300X GPU、240 GB RAM、5 TB SSD),运行 ROCm 6.4.2 于 Ubuntu 24.04.1。

SGLang 离线生成基准的输入输出 token 吞吐量
图 2:SGLang 离线生成基准的输入输出 token 吞吐量。

图 2 显示离线生成基准结果(使用真实 ShareGPT 痕迹,反映生产性能)。总体上,Petit 服务 Llama 3.3 70B FP4 模型比 SGLang 原生 BF16 模型快 1.74 倍(批次 10)和 1.60 倍(批次 64)。在小批次内存带宽受限的生产场景,Petit 高效利用 3.5 倍小体积的 FP4 模型,实现更高吞吐。可用以下命令复现:

python -m sglang.bench_offline_throughput --model-path nvidia/Llama-3.3-70B-Instruct-FP4 --num-prompts 10
python -m sglang.bench_offline_throughput --model-path nvidia/Llama-3.3-70B-Instruct-FP4 --num-prompts 64

详细性能分析

我们进一步对比 Petit 与 hipBLASLt(AMD 最先进的低级汇编 GEMM 库)性能。注意两库目标略异:

  • Petit:BF16 矩阵 × NVFP4 矩阵(16 元素共享 1 FP8 尺度)。
  • hipBLASLt:两个 BF16 矩阵。

虽非完全相同,但结果提供量化洞见。我们考察 Llama 3 70B 服务时实际权重矩阵尺寸,测量 m=16(解码工作负载)和 m=256(预填充工作负载)性能,平均 100 次运行(50 次预热后)。两库均调优至最佳配置。

m=16 的 GEMM 性能
m=256 的 GEMM 性能
图 3:m=16(解码工作负载)和 m=256(预填充工作负载)的 GEMM 性能。

图 3a 和 3b 显示 GEMM 性能。对于 m=16(解码主导),Petit 比 hipBLASLt 快至 3.7 倍,平均提升 2.56 倍。对于 m=256(预填充),Petit 快至 1.09 倍。