💡

文章摘要

2026 年 4 月,DeepSeek 开源 DeepGEMM——专为 FP8 精度设计的高性能 GEMM 内核库。FP8 推理正在从「实验性优化」变为「行业标准」。本文从 FP8 的数学原理、硬件支持、主流推理框架集成到 DeepGEMM 源码级解析,全面梳理 FP8 推理基础设施的技术全景,并附 Python 实战代码。

一、FP8 为什么成为 2026 年推理的事实标准?

2026 年是 FP8(8-bit 浮点数)推理的转折之年。从 NVIDIA 的路线图到各大大模型的部署策略,FP8 已经从「可选优化」变成了「默认配置」

FP8 的数学本质

FP8 不是一个新的概念——IEEE 754 标准早在 2008 年就定义了 8-bit 浮点格式。但直到 2022 年 NVIDIA Hopper 架构(H100)引入 FP8 Tensor Core,FP8 才真正具备了实用价值。

FP8 有两种主流格式:

格式 符号位 指数位 尾数位 动态范围 精度
E4M3 1 4 3 ±448 ~2 位有效数字
E5M2 1 5 2 ±57344 ~1.5 位有效数字

E4M3 适合权重和激活值——它有更大的尾数位,精度更高,适合需要数值稳定性的场景。
E5M2 适合梯度——它有更大的动态范围,可以容纳更大范围的数值,适合反向传播。

为什么是 FP8 而不是 FP16/INT8?

对比 FP16:FP8 将显存占用和计算量减半,精度损失在 LLM 推理中通常 <1%perplexity 差异 <0.1)。对于 70B 模型,FP16 需要 140GB 显存,FP8 只需 70GB——从需要 8×H100 降到 4×H100,成本直接减半。

对比 INT8: INT8 是定点数,没有指数位,动态范围有限。对于 LLM 中的激活值(可能跨越多个数量级),INT8 需要复杂的缩放策略(per-token + per-channel 缩放),实现复杂且容易出错。FP8 自带指数位,天然支持大动态范围,实现更简洁。

对比 INT4: INT4 的精度损失在推理中已经比较显著(perplexity 增加 0.5-2.0),而且需要复杂的量化校准流程。FP8 在精度和效率之间取得了更好的平衡。

图表加载中…

二、DeepGEMM 源码级解析:FP8 GEMM 的核心技术

GEMM(General Matrix Multiplication)是深度学习中最核心的计算操作。LLM 的每一层 Transformer 都在大量执行矩阵乘法:Q·K^T、注意力输出投影、FFN 层的两个线性变换。可以说,优化了 GEMM 就优化了 LLM 推理的 80%

DeepSeek 的 DeepGEMM 正是瞄准了这个核心痛点——提供一个专为 FP8 优化的高性能 GEMM 内核库。

DeepGEMM 的核心设计

DeepGEMM 的关键创新在于细粒度缩放(Fine-grained Scaling)。传统 FP8 量化使用 per-tensor 或 per-channel 缩放——整个张量或每个通道共享一个缩放因子。但 LLM 的激活值在不同 token、不同位置上的分布差异巨大,粗粒度缩放会导致精度损失。

DeepGEMM 支持 per-token + per-channel 双维度缩放:

FP8 GEMM: C = (A_fp8 × S_A) × (B_fp8 × S_B)
其中 S_A 是 per-token 缩放因子,S_B 是 per-channel 缩放因子

这种设计让每个 token 和每个输出通道都有独立的缩放因子,最大限度保留精度,同时保持了 FP8 的显存和计算优势。

与 cuBLAS/cuBLASLt 的对比

NVIDIA 的 cuBLAS 库也支持 FP8 GEMM,但 DeepGEMM 在以下方面做了针对性优化:

  1. 缩放因子融合:将 per-token/per-channel 缩放操作融合到 GEMM 内核中,避免额外的 CUDA kernel 启动开销
  2. Tile 策略优化:针对 LLM 推理中常见的矩阵形状(如 batch×seq×hidden)优化了 block tiling 策略
  3. Clean API:提供了比 cuBLAS 更简洁的 Python 接口,易于集成到现有推理框架
python
import torch
import deep_gemm

# 创建 FP8 矩阵(模拟 LLM 推理中的 Q·K^T 操作)
# batch_size=2, seq_len=1024, hidden_dim=4096
batch, seq, dim = 2, 1024, 4096

# 输入矩阵 A (query): [batch, seq, dim]
A_fp32 = torch.randn(batch, seq, dim, device="cuda", dtype=torch.float32)
# 输入矩阵 B (key): [batch, dim, seq]
B_fp32 = torch.randn(batch, dim, seq, device="cuda", dtype=torch.float32)

# 转换为 FP8 (E4M3 格式)
A_fp8 = A_fp32.to(torch.float8_e4m3fn)
B_fp8 = B_fp32.to(torch.float8_e4m3fn)

# DeepGEMM FP8 GEMM 调用
# m=batch*seq (总 token 数), n=seq (输出序列长度), k=dim (hidden 维度)
m, n, k = batch * seq, seq, dim
C_fp8 = deep_gemm.fp8_gemm(
    A=A_fp8,
    B=B_fp8,
    m=m, n=n, k=k,
    # per-token 缩放因子(对 A)
    scale_a=torch.ones(m, device="cuda", dtype=torch.float32),
    # per-channel 缩放因子(对 B)
    scale_b=torch.ones(n, device="cuda", dtype=torch.float32),
)

# 输出转回 FP32 进行后续计算
C_fp32 = C_fp8.to(torch.float32)
print(f"输出形状: {C_fp32.shape}")  # [2048, 1024]
python
import torch
import time
import deep_gemm

def benchmark_gemm(m, n, k, iterations=100):
    """对比 DeepGEMM FP8 与 cuBLAS FP16 的性能"""
    
    # 准备 FP8 数据
    A_fp8 = torch.randn(m, k, device="cuda", dtype=torch.float8_e4m3fn)
    B_fp8 = torch.randn(k, n, device="cuda", dtype=torch.float8_e4m3fn)
    
    # 准备 FP16 数据(cuBLAS 基准)
    A_fp16 = torch.randn(m, k, device="cuda", dtype=torch.float16)
    B_fp16 = torch.randn(k, n, device="cuda", dtype=torch.float16)
    
    # DeepGEMM FP8 GEMM
    torch.cuda.synchronize()
    start = time.perf_counter()
    for _ in range(iterations):
        _ = deep_gemm.fp8_gemm(A_fp8, B_fp8, m, n, k,
                               torch.ones(m, device="cuda"),
                               torch.ones(n, device="cuda"))
    torch.cuda.synchronize()
    fp8_time = (time.perf_counter() - start) / iterations
    
    # cuBLAS FP16 GEMM
    torch.cuda.synchronize()
    start = time.perf_counter()
    for _ in range(iterations):
        _ = torch.mm(A_fp16, B_fp16)
    torch.cuda.synchronize()
    fp16_time = (time.per*counter() - start) / iterations
    
    print(f"矩阵形状: {m}×{k} × {k}×{n}")
    print(f"DeepGEMM FP8: {fp8_time*1000:.2f}ms")
    print(f"cuBLAS FP16:  {fp16_time*1000:.2f}ms")
    print(f"加速比: {fp16_time/fp8_time:.2f}x")
    print(f"显存节省: 50%")

# 模拟 GPT-5.5 推理场景
# Attention: Q·K^T, batch=4, seq=2048, dim=8192
benchmark_gemm(8192, 2048, 8192)

# FFN: 第一个线性层, batch*seq=8192, dim=8192, ff_dim=22016
benchmark_gemm(8192, 22016, 8192)

三、FP8 推理的硬件支持全景

FP8 推理的普及离不开硬件层面的支持。以下是 2026 年主流 GPU 的 FP8 支持情况:

NVIDIA 阵营

GPU 架构 FP8 Tensor Core FP8 GEMM 吞吐量 备注
H100 Hopper 1,979 TFLOPS 首次引入 FP8
H200 Hopper 1,979 TFLOPS H100 + HBM3e
B200 Blackwell ~3,000 TFLOPS FP8 性能翻倍
GB200 Blackwell ~3,000 TFLOPS 双芯片封装
RTX 5090 Blackwell ~1,200 TFLOPS 消费级支持 FP8
A100 Ampere N/A 仅支持 FP16/INT8

其他厂商

厂商 产品 FP8 支持 备注
AMD MI300X CDNA 3 架构
AMD MI350X CDNA 4 架构
Intel Gaudi 3 ⚠️ 部分支持
华为 昇腾 910C ⚠️ 实验性支持

关键结论:H100 及以上(或 B200/GB200)是使用 FP8 推理的最低硬件要求。如果你的部署环境是 A100 或更老的 GPU,FP8 只能退化为软件模拟,反而会变慢。

FP8 推理的显存收益实战

以一个 70B 参数的 LLM 为例:

精度 权重显存 KV Cache (8K seq, batch=32) 总显存需求 H100 数量
FP16 140 GB 64 GB 204 GB 8
FP8 70 GB 32 GB 102 GB 4
INT4 35 GB 32 GB 67 GB 2

FP8 相比 FP16,显存需求减半,所需 GPU 数量减半——这直接转化为 50% 的推理成本节省

图表加载中…

四、主流推理框架的 FP8 支持对比

2026 年,主流 LLM 推理框架都已支持或正在积极支持 FP8。以下是各框架的 FP8 支持状态:

vLLM

vLLM 是最受欢迎的开源 LLM 推理框架,FP8 支持成熟度最高

启用方式:

TensorRT-LLM

NVIDIA 官方推理框架,FP8 支持最底层、最优化:

  • 硬件级 FP8:直接调用 FP8 Tensor Core
  • Auto FP8:自动为每层选择最优精度(FP8/FP16/INT8 混合)
  • DeepGEMM 兼容:可以作为 DeepGEMM 的宿主框架

SGLang

新兴推理框架,以高吞吐量和低延迟著称:

  • FP8 KV Cache:支持 FP8 格式的 KV Cache 压缩
  • FP8 推理:实验性支持,性能接近 vLLM

TGI (Text Generation Inference)

HuggingFace 官方推理框架:

python
from vllm import LLM

llm = LLM(
    model="meta-llama/Llama-3-70B",
    quantization="fp8",  # 一行代码启用 FP8
    tensor_parallel_size=4,
)
框架FP8 权重FP8 激活FP8 KV CacheDeepGEMM 集成成熟度

vLLM

✅ 成熟

✅ 成熟

✅ 实验性

🔄 推进中

⭐⭐⭐⭐⭐

TensorRT-LLM

✅ 成熟

✅ 成熟

✅ 成熟

✅ 兼容

⭐⭐⭐⭐⭐

SGLang

✅ 实验性

⚠️ 部分

✅ 成熟

❌ 无

⭐⭐⭐⭐

TGI

✅ bitsandbytes

❌ 无

❌ 无

❌ 无

⭐⭐⭐

llama.cpp

❌ 无

❌ 无

❌ 无

❌ 无

⭐⭐

五、FP8 推理的精度-性能权衡实战

FP8 推理不是「开了就行」——你需要根据具体场景做精度和性能的权衡。以下是实战中总结的最佳实践:

1. 混合精度策略

最聪明的做法不是全模型 FP8,而是分层选择精度

  • Attention 层:FP8(数值稳定,精度损失 <0.5%)
  • FFN 第一层(上投影):FP8(输入范围可控)
  • FFN 第二层(下投影):FP16(输出精度敏感)
  • 输出层(LM Head):FP16(logits 需要高精度)
  • 嵌入层:FP16(低频 token 的嵌入向量对精度敏感)

这种混合策略在几乎不损失精度的前提下,能实现约 40% 的显存节省和 30% 的加速

2. 校准数据的选择

FP8 量化的精度高度依赖于校准数据的质量:

  • 最少样本数:512 个校准样本通常足够
  • 数据多样性:覆盖不同领域、不同长度、不同语言
  • 避免偏差:校准数据应该与目标推理场景的分布一致

3. 精度监控

在生产环境中持续监控 FP8 推理的精度:

  • Perplexity 监控:定期在验证集上计算 FP8 vs FP16 的 perplexity 差异
  • 输出一致性:抽样对比 FP8 和 FP16 的输出相似度
  • 回退机制:当精度下降超过阈值时,自动切换回 FP16
python
import torch
import torch.nn as nn
from typing import Dict, Optional

class FP8HybridInference:
    """FP8 混合精度推理引擎
    
    策略:
    - Attention 层: FP8 (E4M3)
    - FFN 上投影: FP8
    - FFN 下投影: FP16
    - LM Head: FP16
    - Embedding: FP16
    """
    
    def __init__(self, model: nn.Module, calibration_data: torch.Tensor):
        self.model = model
        self.fp8_layers = self._identify_fp8_layers(model)
        self.scales = self._calibrate_scales(calibration_data)
    
    def _identify_fp8_layers(self, model: nn.Module) -> Dict[str, bool]:
        """识别哪些层可以用 FP8"""
        fp8_config = {}
        for name, module in model.named_modules():
            if isinstance(module, nn.Linear):
                # LM Head 和 Embedding 用 FP16
                if "lm_head" in name or "embed" in name:
                    fp8_config[name] = False
                # FFN 下投影用 FP16
                elif "down_proj" in name:
                    fp8_config[name] = False
                # 其他用 FP8
                else:
                    fp8_config[name] = True
        return fp8_config
    
    def _calibrate_scales(self, data: torch.Tensor) -> Dict[str, float]:
        """基于校准数据计算每层的 FP8 缩放因子"""
        scales = {}
        for name, module in self.model.named_modules():
            if name in self.fp8_layers and self.fp8_layers[name]:
                # 用校准数据的前向传播统计激活值范围
                with torch.no_grad():
                    # 简化版:用输入数据的 max 绝对值作为缩放因子
                    abs_max = data.abs().max().item()
                    scales[name] = abs_max / 448.0  # E4M3 最大值为 448
        return scales
    
    def forward(self, input_ids: torch.Tensor) -> torch.Tensor:
        """混合精度前向传播"""
        x = self.model.embed_tokens(input_ids)  # FP16
        
        for layer in self.model.layers:
            # Attention (FP8)
            attn_out = self._fp8_attention(layer.self_attn, x)
            x = x + attn_out
            
            # FFN 上投影 (FP8) + 下投影 (FP16)
            ff_out = self._hybrid_ffn(layer.mlp, x)
            x = x + ff_out
        
        # LM Head (FP16)
        logits = self.model.lm_head(x)
        return logits
    
    def _fp8_attention(self, attn_module, x: torch.Tensor) -> torch.Tensor:
        """FP8 注意力计算"""
        q = attn_module.q_proj(x).to(torch.float8_e4m3fn)
        k = attn_module.k_proj(x).to(torch.float8_e4m3fn)
        v = attn_module.v_proj(x).to(torch.float8_e4m3fn)
        
        # FP8 GEMM (用 DeepGEMM 或 cuBLASLt)
        # 简化版:torch.mm 自动降级到 FP16
        attn_scores = (q.to(torch.float16) @ k.transpose(-1, -2).to(torch.float16)) / (q.shape[-1]  0.5)
        attn_weights = torch.softmax(attn_scores, dim=-1)
        return attn_weights @ v.to(torch.float16)
    
    def _hybrid_ffn(self, mlp_module, x: torch.Tensor) -> torch.Tensor:
        """混合精度 FFN:上投影 FP8 + 下投影 FP16"""
        # 上投影:FP8
        hidden = mlp_module.up_proj(x).to(torch.float8_e4m3fn)
        hidden = mlp_module.act_fn(hidden.to(torch.float16))
        # 下投影:FP16
        return mlp_module.down_proj(hidden.to(torch.float16))


# 使用示例
# 1. 校准
calibration_data = torch.randn(512, 4096, device="cuda")
engine = FP8HybridInference(model, calibration_data)

# 2. 推理
output = engine.forward(input_ids)
print(f"输出形状: {output.shape}")  # [batch, seq, vocab]

六、生产部署指南:从开发到上线

将 FP8 推理部署到生产环境,需要关注以下几个关键环节:

1. 模型准备

2. 服务配置

3. 监控与告警

  • GPU 利用率:FP8 推理应该达到 60%+ 的 GPU 利用率
  • 显存使用:确认 FP8 量化后显存占用减半
  • 延迟分布:P50 < 100ms/token, P99 < 300ms/token
  • 精度监控:每小时抽样 100 个请求,对比 FP8 vs FP16 输出相似度

4. 常见问题排查

问题 原因 解决方案
FP8 推理反而更慢 GPU 不支持 FP8 Tensor Core 降级到 FP16
输出质量显著下降 校准数据不具代表性 增加校准样本多样性
OOM 批处理过大 减小 max_num_seqs
NaN 输出 缩放因子计算错误 检查 per-token/per-channel 缩放

5. 成本收益分析

以月均 1000 万次推理请求为例(每次 2K input + 1K output tokens):

方案 GPU 配置 月成本 单次延迟 P50 备注
FP16 8×H100 $56,000 120ms 基准方案
FP8 4×H100 $28,000 95ms 推荐
INT4 2×H100 $14,000 85ms 精度略低

FP8 方案在成本(节省 50%)和精度(损失 <1%)之间取得了最佳平衡

图表加载中…
bash
# 使用 vLLM 一键导出 FP8 量化模型
python -m vllm.entrypoints.openai.api_server \\
    --model meta-llama/Llama-3-70B \\
    --quantization fp8 \\
    --export-model ./llama3-70b-fp8
yaml
# docker-compose.yml
services:
  vllm-fp8:
    image: vllm/vllm-openai:latest
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: 4
              capabilities: [gpu]
    command: >
      --model ./llama3-70b-fp8
      --tensor-parallel-size 4
      --max-num-seqs 256
      --gpu-memory-utilization 0.9
    ports:
      - "8000:8000"

七、总结:FP8 推理的 2026 年路线图

2026 年 4 月 DeepSeek 开源 DeepGEMM,标志着 FP8 推理基础设施进入了成熟期。以下是我们对 FP8 推理未来发展的预测:

短期(2026 Q2-Q3):

  • vLLM 完成 DeepGEMM 集成,FP8 成为 vLLM 默认量化选项
  • TensorRT-LLM 推出 Auto-FP8,自动为每层选择最优精度
  • 更多开源模型提供 FP8 量化版本

中期(2026 Q4-2027 Q1):

  • FP4 推理开始实用化(NVIDIA Rubin 架构支持)
  • 端侧 FP8 推理(手机、IoT)成为主流
  • FP8 训练(不仅仅是推理)开始探索

长期(2027+):

  • FP8 成为 LLM 推理的事实标准,FP16 退居次要地位
  • 混合精度推理引擎成熟,自动为每层、每 token 选择最优精度
  • FP8 硬件普及到消费级 GPU(RTX 50 系列已支持)

行动建议:

  1. 如果你有 H100/B200 集群,立即开始 FP8 推理迁移——显存成本减半的收益太大了
  2. 如果你只有 A100,关注 INT8/INT4 量化,FP8 暂时不可用
  3. 如果你是推理服务提供商,FP8 是你的成本竞争力核心
  4. 如果你是模型开发者,在模型发布时同时提供 FP8 量化版本

DeepGEMM 的开源降低了 FP8 推理的技术门槛——现在你只需要几行 Python 代码就能享受 FP8 带来的性能提升。2026 年,不会用 FP8 推理的 LLM 工程师,就像 2020 年不会用 CUDA 的深度学习工程师一样——不是不能用,而是效率差了整整一个时代。

🎯 相关面试题

巩固本篇知识点,备战 AI 岗位面试。