per_tenor_quant_fp8和per_token_quant_fp8算法解读

在大型语言模型(LLM)和高性能计算领域,模型量化技术正变得越来越重要。FP8(8位浮点数)作为一种新兴的数据类型,正在成为AI加速器(如NVIDIA H100)的关键特性。本文将深入剖析两种FP8量化算法:per_tensor_quant_fp8(张量级量化)和per_token_quant_fp8(令牌级量化),通过源代码解读其实现原理、数学本质和工程考量。

源代码参考sglang的实现添加链接描述

E4M3格式解析

在深入量化算法之前,我们需要理解FP8 E4M3格式。E4M3表示:

E4: 4位指数位(exponent)

M3: 3位尾数位(mantissa)

这种格式能表示的最大值为448.0,计算方式如下:

最大值 = 1.111(二进制)× 2^(14) = 1.875 × 16 = 448.0

其中指数最大值为14(指数位全1但排除特殊值),尾数最大值为0.875(3位全1)

FP8相比FP16和BF16:

存储节省: 内存占用减少50%

带宽效率: 数据传输量减半

计算吞吐: 理论上计算密度可提升2倍

per_tensor_quant_fp8

per_tensor_quant_fp8采用全局统一的量化尺度,对输入张量的所有元素使用相同的缩放因子。这种设计的核心思想是:保持张量整体的统计特性,以最简单的形式实现量化。

python代码参考

python 复制代码
FP8_E4M3_MAX = 448.0


def per_tensor_quant_fp8_torch(x, symmetric):
    if symmetric == False:
        return
    else:
        absmax = x.flatten().abs().max()

        if absmax == 0:
            scale = torch.tensor(1.0, device=x.device, dtype=torch.float32)
            q = torch.zeros_like(x, dtype=torch.float8_e4m3fn)
            return q, scale, None

        # 2. scale = absmax / FP8_MAX
        scale = absmax / FP8_E4M3_MAX

        # 3. 量化(注意:CUDA 里用的是 x * (1 / scale))
        inv_scale = 1.0 / scale
        x_scaled = x * inv_scale

        # 4. clip 到 FP8 可表示范围
        x_clamped = torch.clamp(x_scaled, -FP8_E4M3_MAX, FP8_E4M3_MAX)

        # 5. cast to fp8 e4m3
        q = x_clamped.to(torch.float8_e4m3fn)

        return q, scale.float(), None

输入特性:

形状:任意维度(1D、2D、3D、4D等)

数据类型:通常为float32、float16或bfloat16

数值范围:理论上任意实数范围

输出特性:

q形状:与输入x完全相同

q数据类型:torch.float8_e4m3fn(FP8 E4M3格式)

scale形状:标量(0维张量)

scale数据类型:torch.float32

per_tensor量化优缺点

优点:

计算简单,只需一次reduce操作

存储开销小,只需一个scale值

适合整体分布均匀的张量

缺点:

对异常值敏感,可能导致量化分辨率下降

无法适应局部特征的差异性

适合per_tensor的场景:

激活值分布相对均匀

对计算延迟极度敏感

存储带宽受限的部署环境

我针对sglang的代码做了一个实现得到对应的cuda代码,参考
添加链接描述

per_token_quant_fp8

python代码参考

python 复制代码
FP8_E4M3_MAX = 448.0


def per_token_quant_fp8_torch(x, symmetric):
    if symmetric == False:
        return
    else:
        assert x.dim() == 2, "per-token quant expects [num_tokens, hidden_dim]"

        # ------------------------------------------------------------
        # Pass-1: per-token absmax (对齐 CUDA 的 warpReduceMax)
        # ------------------------------------------------------------
        # CUDA: max_value = max_j |x[token_id, j]|
        absmax = x.abs().amax(dim=1)  # [num_tokens]

        # ------------------------------------------------------------
        # scale = absmax / FP8_E4M3_MAX
        # CUDA 中 scale 是 per-token 写入 output_s[token_id]
        # ------------------------------------------------------------
        scale = absmax / FP8_E4M3_MAX  # [num_tokens]

        inv_scale = 1.0 / scale
        inv_scale[scale == 0] = float("inf")  # [num_tokens]

        # ------------------------------------------------------------
        # Pass-2: x * inv_scale
        # CUDA: val = input * scale_inv
        # ------------------------------------------------------------
        x_scaled = x * inv_scale.unsqueeze(1)  # broadcast to [N, H]

        # ------------------------------------------------------------
        # clip 到 FP8 E4M3 可表示范围
        # CUDA: fmaxf(fminf(val, FP8_E4M3_MAX), -FP8_E4M3_MAX)
        # ------------------------------------------------------------
        x_clamped = torch.clamp(x_scaled, -FP8_E4M3_MAX, FP8_E4M3_MAX)

        # ------------------------------------------------------------
        # cast to FP8
        # CUDA: static_cast<DST_DTYPE>(val)
        # ------------------------------------------------------------
        q = x_clamped.to(torch.float8_e4m3fn)

        return q, scale.float(), None

输入形状要求:

必须为2维张量:[num_tokens, hidden_dim]

num_tokens:序列中的token数量

hidden_dim:每个token的特征维度

设计理由:

这种形状要求源于Transformer架构:

第一维(token维度):序列中的不同位置

第二维(特征维度):每个token的嵌入表示

输出特性:

q形状:[num_tokens, hidden_dim](与输入相同)

q数据类型:torch.float8_e4m3fn

scale形状:[num_tokens](每个token一个缩放因子)

scale数据类型:torch.float32

per_token量化优缺点

优点:

更好的适应性,每个token获得最优分辨率

对长尾分布有更好的处理能力

在Transformer类模型中表现优异

缺点:

计算开销大,需要per-token的reduce

存储多个scale值,增加元数据开销

实现复杂度高

适合per_token的场景:

Transformer-based语言模型

激活值存在明显的token间差异

对模型精度要求高

我针对sglang的代码做了一个实现得到对应的cuda代码,参考
添加链接描述

per_tensor_quant_fp8和per_token_quant_fp8代表了两种不同的量化哲学:统一性与适应性。前者追求简单高效,后者强调精度保持。在实际应用中,选择哪种算法需要权衡计算效率、存储开销和模型精度。随着AI硬件对FP8支持的成熟,这些量化技术将在模型部署中发挥越来越重要的作用。

相关推荐
机器之心6 分钟前
Generalist之后,罗剑岚团队推出LWD,也要变革具身智能训练范式
人工智能·openai
IT_陈寒11 分钟前
Vite的public文件夹放静态资源?这坑我替你踩了
前端·人工智能·后端
传说故事11 分钟前
【论文阅读】Diffusion Forcing: Next-token Prediction Meets Full-Sequence Diffusion
论文阅读·人工智能·diffusion
xixixi7777715 分钟前
三重筑基:5G-A超级上行提速千兆,电联低频共享扫平盲点,800V HVDC算电协同破局
人工智能·5g·ai·大模型·算力·通信·信通院
jkyy201416 分钟前
AI运动数字化:以技术重塑场景,健康有益赋能全域运动健康管理
大数据·人工智能·健康医疗
金融小师妹24 分钟前
4月30日多因子共振节点:鲍威尔“收官效应”与权力结构重塑的预期重构
大数据·人工智能·重构·逻辑回归
2601_9499251829 分钟前
AI Agent如何重构跨境物流的决策?
大数据·人工智能·重构·ai agent·geo优化·物流科技
AI木马人36 分钟前
1.人工智能实战:大模型推理接口响应慢?从模型加载到 FastAPI 部署的完整优化方案
人工智能·python·fastapi
Black蜡笔小新1 小时前
私有化本地化AI模型训推工作站DLTM训推一体工作站赋能多行业智能化落地
人工智能
qq_411262421 小时前
四博 AI 智能音箱 + ESPC3 Tasmota 计量通断器方案
人工智能·智能音箱