量化是推理降本的第一选择:显存减半、速度翻倍、成本直降。但低精度推理有个隐蔽的坑,藏在循环网络的状态写回里——量化后的状态被存下来,下一步又被读回去,误差会跨时间步累积,悄悄改变模型行为。

这篇拆解这个机制,给出低精度推理的避坑方案和接入验证清单。

一、开篇痛点

量化看着是白捡的钱:权重从 FP16 压到 INT8,模型照样能跑,显存和成本都下降。

但真实场景里,量化后模型行为变化的情况不少:输出质量下降、长上下文表现变差、某些任务准确率跳水。排查起来很麻烦,因为问题不在单次调用,而在状态在时间步之间的累积。

二、循环状态写回是什么

循环网络(RNN、状态空间模型、部分 Transformer 变体)有一个特点:每一步的输出状态,会作为下一步的输入。

第 1 步:输入 x1 -> 计算 -> 状态 s1(量化后存储)
    |
    v
第 2 步:输入 x2 + 状态 s1'(量化误差) -> 计算 -> 状态 s2
    |
    v
第 3 步:输入 x3 + 状态 s2'(误差累积) -> ...

问题出在"量化后存储"这一步。量化会引入舍入误差,这个误差写进状态后,下一步会被读回来继续计算。误差不消失,而是逐层、逐时间步累积。

三、误差为什么会累积

三个机制叠加:

机制一:舍入误差
状态从高精度压到低精度,每一步都丢一点信息

机制二:反馈回路
误差写回状态,参与下一步计算,再放大再写回

机制三:长序列放大
序列越长,累积越明显,长上下文任务最先暴露

对比前馈层:前馈层算完就结束,量化误差是"一次性"的;循环层把误差变成"持续性"的。这是循环结构在低精度下更脆弱的根本原因。

四、哪些层不能低精度

不是所有层都适合压到低精度。我的经验分层:

层类型 低精度风险 建议
前馈层(FFN) 可以压到 INT8
注意力计算 可以压,但注意数值范围
状态传递层 保持高精度或混合精度
归一化层 保持高精度,它放大误差
嵌入层 可以压,显存收益明显

核心原则:参与跨步状态传递的层,精度要保守;一次性计算的层,可以激进量化。

五、混合精度的接入方案

不需要全量低精度,混合精度是更稳的做法:

高精度部分:状态传递、归一化、关键注意力
    |
    v
低精度部分:前馈层、嵌入层、非关键计算
    |
    v
整体收益:大部分显存与算力收益,行为变化最小
from openai import OpenAI

client = OpenAI(api_key="4sapi-key", base_url="https://4sapi.com/v1")

# 量化模型通过本地推理端点接入,业务代码不变
resp = client.chat.completions.create(
    model="local-llama-70b-int8-mixed",  # 混合精度量化版本
    messages=[
        {"role": "user", "content": "总结这份长文档的要点"},
    ],
)
print(resp.choices[0].message.content)

模型名区分精度档位,业务代码不用改。量化版本出问题,切回高精度版本只需改一个字段。

六、量化前的验证清单

量化不是"压完就上线",至少验证这些:

  1. 用同一条长序列跑高精度与低精度版本,逐段对比输出差异;
  2. 观察差异是否随序列长度增长——增长说明状态误差在累积;
  3. 跑一组数值敏感任务(数学、代码、事实问答),看准确率变化;
  4. 检查归一化层与状态层的精度设置,必要时单独保持高精度;
  5. 记录显存、速度、成本的收益,和输出质量的损失做权衡。
差异随长度增长 -> 状态写回有问题,调整精度配置
差异稳定不增长 -> 可以接受,继续压

七、实测案例:一个长上下文任务的量化回退

我记录过一个典型回退案例,可以说明这个坑的隐蔽性。

场景是一个长文档总结任务,输入是 200 页的技术手册。量化版本在短段落测试时表现正常,接入生产后长文档总结频繁出现前后矛盾:前文引用的关键数据,后文总结时对不上。

排查过程:

第一步:怀疑提示词 -> 调整后无效
    |
    v
第二步:怀疑温度参数 -> 固定后仍复现
    |
    v
第三步:对比高精度版本 -> 问题消失
    |
    v
结论:量化状态写回导致跨步信息丢失

根因是文档太长,状态在时间步之间传递了几百次,量化误差持续累积,后文的"记忆"已经失真。修复方案不是放弃量化,而是把状态传递层切回高精度,其他层保留低精度——问题消失,显存收益保留了大部分。

这个案例的教训:短序列测试通过不等于量化可用,长序列场景必须专门验证。

八、成本与风险提示

九、接入检查清单

  1. 先跑长序列对比测试,确认状态误差累积程度;
  2. 识别模型中的状态传递层,标记为高精度保护区;
  3. 配置混合精度量化,保留多个精度档位的模型版本;
  4. 通过统一接入层按需切换精度档位;
  5. 上线后监控长上下文任务的质量指标;
  6. 记录量化前后的显存、速度、成本与质量数据。

十、量化收益的记账方式

量化的收益要记账,不然省没省钱说不清。我的记账口径:

项目 量化前 量化后
显存占用 基准 约一半
推理吞吐 基准 提升
单次调用成本 基准 下降
长序列质量 基准 需监控

记账的关键是把"质量损失"也当成成本:输出质量下降导致的重试、返工、人工修正,都要折算进总账。有些量化方案显存省了一半,但长任务重试率翻倍,总成本反而上升。

判断量化是否划算,看的是"总成本 = 算力成本 + 重试成本 + 人工修正成本",而不是单看显存或单价。

十一、我的判断

低精度推理的正确姿势不是"全压"或"不压",而是"按层压"。状态写回机制决定了循环结构必须保守,一次性计算可以激进。混合精度让收益和风险可控,是量化接入的默认选项。

总结

量化省下的钱是真的,状态写回带来的误差累积也是真的。识别状态传递层、配置混合精度、保留可回退版本,是低精度推理的避坑三件套。通过 4sapi(https://4sapi.com)统一接入层,不同精度档位只是不同的模型名,切换与回退都干净利落。欢迎在评论区聊聊量化踩过的坑。