跳高运动员李明有个秘密训练法:每次训练,他都会在小腿上绑上两公斤的沙袋。沙袋一绑,起跳的爆发力被“压”住,腾空高度也打个折扣。但奇怪的是,教练每次都会用高速摄像机记录他所有的起跳动作——那台摄像机从不戴沙袋,记录的是毫米级别的精确轨迹。训练时身体体会“沉重”(低精度状态),测量时保留“精细”(全精度信息),等上了正式赛场卸下沙袋,李明反而比谁都跳得高。 这就是量化感知训练中的伪量化(Fake Quantization)。它让神经网络在训练时提前模拟 int8 低精度部署的痛苦,但又始终以 float32 全精度存储和更新参数。前向传播像“戴着沙袋跳”,反向传播像“用高清摄像机复盘”。这样训练出的模型,最终部署到真正 int8 环境时,精度损失极小,速度却能大幅提升。

岗位关联

对 AI 从业者而言,伪量化是打通“训练”与“部署”鸿沟的桥梁技能。掌握它,你就能让大型模型轻松塞进手机和嵌入式芯片,把算力效率拉满。

目录
  1. 可视化演示
  2. 伪量化原理
  3. 量化参数公式
  4. 梯度直通策略
  5. 校准策略
  6. 算子融合优化
  7. 模型序列化
  8. 工程实践要点
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

通过前向量化-反量化、STE梯度近似与量化折叠,直观展示伪量化如何在训练中模拟INT8量化效果。

本节配有交互动效(进入视口后自动加载,约 3KB)。

前向量化-反量化 clamp裁剪到范围 量化到INT8再还原 ⌊x/scale⌉·scale 模拟量化误差注入训练。

伪量化原理

跳高运动员李明训练时,小腿各绑着一只两公斤的沙袋。沙袋沉,起跳点就要更用力,腾空高度也打了个折扣。奇怪的是,每次试跳后教练都让他脱掉沙袋,用高速摄像机重新拍一遍起跳动作——真正用来调整技术动作的,永远是那条毫米级精度的运动轨迹。李明渐渐明白:训练时让身体处处体会“沉重”(int8 视角),测量时保留“精确”(float32 信息),才是应对正式比赛最高效的办法。这套“戴着沙袋训练、脱下沙袋分析”的流程,正是量化感知训练中伪量化(Fake Quantization)的本质。

伪量化算子可以用一句话概括:前向“狠狠压扁”数值再“拉回原位”,反向却原原本本按全精度梯度更新参数。具体实现里,伪量化会先把输入值 \(x\) 除以一个步长 \(s\),四舍五入成整数;再乘回 \(s\),还原成一个和原值很接近的浮点数。这一步对应的就是“戴沙袋起跳”——在 int8 刻度下感受数值的粗细粒度。因为权重和激活在内存中依然以 float32 存储,所以它只是“假装”被量化了,模型参数的真实精度从未丢失。

伪量化算子通常插在两类位置:权重参与卷积或矩阵乘法之前,以及激活值流入下一层之前。这相当于在神经网络的关键路径上放了一面“int8 哈哈镜”,让模型每一步都提前体验低精度设备的种种别扭,从而学会把重要信息塞进有限的量化刻度中。整个训练过程变成了一次“带负荷演练”。

训练结束时,李明脱掉沙袋,发现自己轻轻一跳就超过了此前的最佳成绩。伪量化也是一样:前向“负重”让模型适应了 int8 环境的误差,真实部署时移除模拟噪声,精度不降反升。这,就是“假动作”背后的真功夫。

x~=s⋅round⁡(xs)\tilde{x} = s \cdot \operatorname{round}\left(\frac{x}{s}\right)
这是对称伪量化算子的前向表达式:\(x\) 被除以步长 \(s\)、取整、再乘回 \(s\),得到与 \(x\) 近似的 \(\tilde{x}\),它模拟了低精度存储的“颗粒感”。
  1. 计算刻度位置把 \(x\) 按步长 \(s\) 分成若干份,算出它落在第几格。
    xs\frac{x}{s}
  2. 四舍五入取整用 \(\operatorname{round}\) 把结果变成最近的整格数,这就是量化的核心——不可导的取整操作。
    round⁡(xs)\operatorname{round}\left(\frac{x}{s}\right)
  3. 乘回步长还原把整格数乘回步长 \(s\),得到模拟的“低精度值” \(\tilde{x}\),完成一次伪量化的闭环。
    s⋅round⁡(xs)s \cdot \operatorname{round}\left(\frac{x}{s}\right)

量化参数公式

如果跳高场地上的刻度尺是“伪量化”,那么步长 \(s\) 就是刻度尺每一格的宽度,零点偏移 \(z\) 则是刻度起点对应的位置。把 \(x\) 放上这套尺子,首先要看它占据第几个刻度格,再根据起点位置纠正偏移,最终读出一个整数档位;反过来,把整数档位换算回真实高度,还需要先减去起点偏移,再乘以每格的实际宽度。这套“读数—换算”流程,对应量化与反量化两个互逆的公式。

当数据分布关于零点对称时,可以令 \(z = 0\),此时公式简化为 \(\hat{x} = s \cdot \operatorname{round}(x/s)\),称为对称量化;否则 \(z\) 不为 0,称为非对称量化。前者硬件实现更简洁,后者对分布不均衡的数据更友好。就像跳高场地如果起点本身就是零刻度,就不需要额外的偏移记号;如果地面有高低落差,就得额外记一个基准点。选对公式,刻度尺才能量得又准又省。

xq=round⁡(xs)+zx_q = \operatorname{round}\left(\frac{x}{s}\right) + z
x^=s⋅(xq−z)\hat{x} = s \cdot \left( x_q - z \right)
第一个公式把浮点数 \(x\) 转成整数刻度 \(x_q\),第二个公式把整数刻度还原成近似浮点数 \(\hat{x}\)。两者配合,构成了伪量化算子的完整前向传播。
  1. 归一化到刻度单位将 \(x\) 除以步长 \(s\),得到“以格为单位的原始位置”。
    xs\frac{x}{s}
  2. 取整并加零点四舍五入得到整数刻度,再加上零点偏移 \(z\),完成量化。
    round⁡(xs)+z\operatorname{round}\left(\frac{x}{s}\right) + z
  3. 反向平移从整数刻度 \(x_q\) 中减去零点 \(z\),消除起点偏移的影响。
    xq−zx_q - z
  4. 乘回步长将平移后的整数值乘回步长 \(s\),恢复为浮点近似值。
    s⋅(xq−z)s \cdot \left( x_q - z \right)

梯度直通策略

round 函数是一道悬崖:它的导数在几乎所有地方都是 0,偶尔还会“没有定义”。如果梯度的回头路被这道悬崖切断,神经网络的参数就再也无法更新,跳高运动员的教练也会彻底失去分析录像的依据。直通估计器(Straight-Through Estimator, STE) 的解法简单而大胆:把悬崖当成平路。前向传播照常经过 round,反向传播时却假装 round 根本没出现过,让梯度原封不动地穿过它,回到上游参数里去。

该方法的直觉很像教练处理李明的沙袋:起跳高度虽然被压低了(量化了),但教练分析动作时仍然使用没戴沙袋时的力学生理模型(全精度梯度)。因为量化误差对梯度的方向影响通常不大,把梯度近似为直通,既能更新参数,又不会让训练彻底跑偏。为了保证数值合理,STE 通常还会加一个“范围闸门”:当 \(x\) 超出量化范围时,梯度被截断为 0,避免极端值误导更新。

训练中常用该策略,有时也可用近似线性函数(如 tanh 的斜率)替代 round,但 STE 由于实现简单、收敛稳定,至今仍是量化感知训练的主流选择。它像一位聪明的陪练:你压了多少重量不打紧,关键是每次复盘都能从高清录像里找出可以修正的动作。

∂L∂x∣STE=∂L∂x^⋅1{xmin⁡≤x≤xmax⁡}\frac{\partial \mathcal{L}}{\partial x}\bigg|_{\text{STE}} = \frac{\partial \mathcal{L}}{\partial \hat{x}} \cdot \mathbb{1}_{\{x_{\min} \le x \le x_{\max}\}}
这个公式表示:梯度在反向传播时等于上游梯度本身,但对超出量化范围的部分乘以 0,实现“闸门截断”。
  1. 忽略取整导数跳过 \(\operatorname{round}\) 的不可导点,不做任何导数运算。
    ∂L∂x≈∂L∂x^\frac{\partial \mathcal{L}}{\partial x} \approx \frac{\partial \mathcal{L}}{\partial \hat{x}}
  2. 范围闸门用指示函数 \(\mathbb{1}_{\{\cdot\}}\) 判断 \(x\) 是否在量化范围 \([x_{\min}, x_{\max}]\) 内。
    1{xmin⁡≤x≤xmax⁡}\mathbb{1}_{\{x_{\min} \le x \le x_{\max}\}}
  3. 相乘截断将上游梯度乘以 0 或 1,界外的梯度归零。
    ∂L∂x^⋅1{xmin⁡≤x≤xmax⁡}\frac{\partial \mathcal{L}}{\partial \hat{x}} \cdot \mathbb{1}_{\{x_{\min} \le x \le x_{\max}\}}

校准策略

要给跳高场地画刻度线,必须先知道运动员日常跳高的高度范围。校准(Calibration) 就是先让模型跑一批真实样本,统计出权重和激活值的分布,从而确定合适的步长 \(s\) 和零点 \(z\)。最小最大值法是最朴素的思路:把观测到的最小值当作场地起点,最大值当作场地终点,把这段区间均匀切分成 \(2^b\) 份(\(b\) 为量化比特数)。这份“区间地图”一旦画好,模型再经过伪量化算子时,就能把数值映射到合理的刻度上。

但朴素方法有个隐患:如果数据里有一个异常跳高的离群点,刻度尺就得拉到极远端,导致大多数正常数据只能挤在很小的一段刻度上,精度反而变差。这时可以改用百分位截断法,只取 1% 到 99% 的数据范围,牺牲极端值、保住主流精度;更精细的做法则是用最优 MSE 遍历候选步长,找到让量化前后误差最小的那一个。各种方法没有绝对高下,关键看数据分布是否平稳。

校准数据的选择要尽量贴近真实部署场景,就像跳高教练不能只在室内馆量布置,还得到户外风天里测几次。校准集越有代表性,伪量化模拟出的“正式比赛”就越真实。

s=xmax⁡−xmin⁡2b−1,z=round⁡(−xmin⁡s)s = \frac{x_{\max} - x_{\min}}{2^b - 1}, \quad z = \operatorname{round}\left(-\frac{x_{\min}}{s}\right)
这是最小最大值校准公式:极差除以刻度数量得到步长,再用最小值反推零点偏移。
  1. 计算数值跨度用最大值减去最小值,得到数据的总范围。
    xmax⁡−xmin⁡x_{\max} - x_{\min}
  2. 确定刻度数量\(b\) 比特能表示 \(2^b\) 个档位,因此分母需要减 1 得到区间数。
    2b−12^b - 1
  3. 求步长总范围除以区间数,得到每一格刻度代表的数值宽度。
    xmax⁡−xmin⁡2b−1\frac{x_{\max} - x_{\min}}{2^b - 1}
  4. 反推零点将最小值除以步长并取整,得到零点偏移 \(z\)。
    round⁡(−xmin⁡s)\operatorname{round}\left(-\frac{x_{\min}}{s}\right)

算子融合优化

如果训练图的每个角落都插满伪量化算子,计算开销会成倍增加,就像把沙袋绑在手腕、脚踝、腰间十几个位置,反而影响动作连贯性。算子融合(Operator Fusion) 的思路是“合并同类项”:把卷积(Conv)、批归一化(BN)、激活函数(ReLU)等算子融合成一个大算子,只在融合单元的输入输出处保留量化节点。这样既保留了伪量化对模型精度的校准作用,又大幅减少了量化和反量化的切换次数。

训练时最典型的融合是 Conv 与 BN 的融合。BN 的缩放系数 \(\gamma\) 和方差 \(\sigma^2\) 都是固定值,可以在训练阶段直接“折”进卷积权重中,得到一个等效权重 \(W_{\text{fold}}\)。这样部署后我只需要做一次带量化权重的整数卷积,不需要在中间跳回浮点做 BN——省下了反复搬运数据的开销。

融合后,再对 \(W_{\text{fold}}\) 执行伪量化,就完成了“一套动作,两处效益”:训练模拟到位,部署也只保留最少的量化节点。正如教练把沙袋统一缝进比赛鞋的鞋底,而不是零零散散绑满全身——同一份训练效果,却换来了更轻便的奔跑。

Wfold=γσ2+ϵ⋅WW_{\text{fold}} = \frac{\gamma}{\sqrt{\sigma^2 + \epsilon}} \cdot W
批归一化的线性变换被吸收进卷积权重,得到一个更紧凑的等效权重,之后可以交给伪量化统一处理。
  1. 计算归一化系数用方差 \(\sigma^2\) 加上极小常数 \(\epsilon\),再开平方取倒数。
    1σ2+ϵ\frac{1}{\sqrt{\sigma^2 + \epsilon}}
  2. 乘缩放系数乘以 BN 的缩放参数 \(\gamma\),得到最终的缩放因子。
    γσ2+ϵ\frac{\gamma}{\sqrt{\sigma^2 + \epsilon}}
  3. 融合进权重将缩放因子逐元素乘上原始卷积权重 \(W\),得到等效权重 \(W_{\text{fold}}\)。
    γσ2+ϵ⋅W\frac{\gamma}{\sqrt{\sigma^2 + \epsilon}} \cdot W

模型序列化

训练结束,李明要去参加比赛,但他的沙袋不会跟着上赛场。部署时,我们需要把训练好的浮点模型真正变成“不带沙袋”的 int8 模型。模型序列化就是这个“换装”环节:把浮点权重 \(W\) 按照校准好的步长 \(s_w\) 和零点 \(z_w\) 量化成 int8 整数数组,并把 \(s_w\)、\(z_w\) 这两个关键参数一并保存进模型文件。没有它们,反序列化时就无法把整数权重还原成有意义的浮点数值——就像赛前把沙袋换了,却忘了带记分册。

一个典型的量化模型文件通常包含三部分:int8 权重张量、每个张量对应的量化参数(scale 和 zero_point)、以及图结构元信息。常见的做法是把它们放入 JSON 或二进制格式中,再配合推理框架加载。反序列化时,框架读取权重并重建整数卷积,只有在必要部位(如需要更高精度的残差连接)才临时反量化回浮点,形成“整主浮辅”的混合执行图。

加载模型时如果发现精度异常,工程师通常会先检查量化参数是否完整、scale 是否出现 0 或极端值。序列化是训练和推理之间的“护照盖章”——数据格式对齐了,模型才能顺利通关上线。

Wint8=round⁡(Wsw)+zwW_{\text{int8}} = \operatorname{round}\left(\frac{W}{s_w}\right) + z_w
这是权重序列化时的核心公式:浮点权重量化成 int8 整数数组,同时把 \(s_w\) 和 \(z_w\) 一起存储。
  1. 权重归一化将浮点权重 \(W\) 除以权重量化步长 \(s_w\),换算到整数刻度。
    Wsw\frac{W}{s_w}
  2. 取整并平移四舍五入后加上零点 \(z_w\),得到 int8 整数权重。
    round⁡(Wsw)+zw\operatorname{round}\left(\frac{W}{s_w}\right) + z_w
  3. 配套存储序列化时同时写出 \((W_{\text{int8}}, s_w, z_w)\) 三元组,供推理阶段反量化还原。
    W≈sw⋅(Wint8−zw)W \approx s_w \cdot (W_{\text{int8}} - z_w)

工程实践要点

伪量化虽好,但工程落地时仍有不少暗礁。最典型的是精度塌陷:当模型对量化误差特别敏感时,强行模拟训练反而会让损失震荡甚至发散。应对策略是混合量化——把对精度影响大的敏感层保留为 FP16 或 FP32,只对冗余层做 int8 量化。这就像教练只在起跳腿绑沙袋,手臂负重则完全去掉,让关键发力环节保持流畅。

微调流程的设计同样关键:通常先让模型在 float32 下收敛,再插入伪量化算子进行少量 epoch 的“二次精调”,学习率要比正常训练低 10 倍左右,避免大步幅破坏已收敛的权重。伪量化全程不改变参数更新的浮点本质,因此优化器依然按全精度执行梯度更新:

工程实践中还要注意:校准集不宜过小、量化前后输出分布应做一致性检查、部署前用端侧测试集做验收。正如李明登上赛场前试跳三次、检查鞋带、确认风向——一切细节到位,戴着沙袋训练的力量才能真正转化成赛场上的成绩。

W(t+1)=W(t)−η⋅∂L∂W(t)W^{(t+1)} = W^{(t)} - \eta \cdot \frac{\partial \mathcal{L}}{\partial W^{(t)}}
权重更新完全在浮点域完成:学习率 \(\eta\) 乘以梯度,再更新当前权重 \(W^{(t)}\),伪量化算子只参与前向模拟。
  1. 计算梯度反向传播得到损失对权重的梯度。
    ∂L∂W(t)\frac{\partial \mathcal{L}}{\partial W^{(t)}}
  2. 按学习率缩放梯度乘上学习率 \(\eta\) 决定更新的步伐。
    η⋅∂L∂W(t)\eta \cdot \frac{\partial \mathcal{L}}{\partial W^{(t)}}
  3. 执行权重更新从当前权重中减去缩放后的梯度,得到新权重。
    W(t)−η⋅∂L∂W(t)W^{(t)} - \eta \cdot \frac{\partial \mathcal{L}}{\partial W^{(t)}}

AI 应用场景

移动端视觉模型部署

阶段:模型压缩与推理优化

解决的问题:手机端跑视觉模型时,内存带宽和算力都极其有限。传统 float32 模型动辄上百 MB,推理延迟高;直接后训练量化又容易掉点。伪量化让模型在训练阶段就适应低精度,部署时直接替换为 int8 推理,体积缩小 4 倍、速度提升 2 到 3 倍,精度损失控制在 1% 以内。

具体案例:某安防厂商做人脸检测,原有 ResNet18 模型 45 MB,在手机端单帧推理 80 ms。通过量化感知训练微调 3 个 epoch 后,模型压缩到 12 MB,单帧推理降到 28 ms,精度仅从 98.2% 降到 97.6%,顺利通过验收。

AI编译器中的量化图优化

阶段:前端图优化与算子融合

解决的问题:编译器(如 TVM、MLIR)拿到训练好的模型后,需要把浮点计算图改写为带量化算子的优化图。伪量化算子作为“高保真模拟节点”被编译器识别,在编译阶段完成算子融合、常数折叠和内存布局调整,避免在运行时反复量化和反量化。

具体案例:某推理引擎团队在接入 QAT 模型时,利用编译器自动将 Conv+BN+ReLU 融合为一个 int8 计算单元,并在融合单元前后插入最小数量的量化节点。最终端到端延迟降低 34%,而手工插入量化算子时延迟只降低 18%。

模型格式与序列化工具链

阶段:模型导出与跨平台加载

解决的问题:量化模型要跨框架、跨设备部署,必须有一套统一格式保存 int8 权重和量化参数。伪量化训练产出的模型通过序列化工具包,将权重、scale、zero_point、图结构打包成通用格式,供不同平台反序列化加载。

具体案例:某团队基于 ONNX 扩展了量化模型协议,将 QAT 模型导出为 int8 权重 + 量化元数据的压缩包。另一端的 C++ 部署程序只需解析 JSON 元数据即可重建整数推理图,整个过程从两小时手工对接缩短到十分钟自动完成。

Python 演示

python57 行
import torchimport torch.nn as nn class FakeQuantize(nn.Module):    """模拟量化的训练模块:前向执行量化与反量化,反向使用直通估计"""     def __init__(self, bits=8):        super().__init__()        self.bits = bits        self.qmin = -(2 ** (bits - 1))        self.qmax = 2 ** (bits - 1) - 1        self.scale = None        self.zero_point = torch.zeros(1)     def calibrate(self, x):        min_val = x.min()        max_val = x.max()        level_scale = (max_val - min_val) / (self.qmax - self.qmin)        if level_scale.item() == 0:            level_scale = torch.ones_like(level_scale)        self.scale = level_scale        self.zero_point = torch.round(-min_val / level_scale)        self.zero_point = torch.clamp(self.zero_point, self.qmin, self.qmax)     def forward(self, x):        if self.scale is None:            self.calibrate(x)        xq = torch.round(x / self.scale) + self.zero_point        xq = torch.clamp(xq, self.qmin, self.qmax)        xdq = (xq - self.zero_point) * self.scale        return x + (xdq - x).detach()  def main():    torch.manual_seed(0)    model = nn.Sequential(        nn.Linear(16, 32),        FakeQuantize(bits=8),        nn.ReLU(),        nn.Linear(32, 1),    )    opt = torch.optim.Adam(model.parameters(), lr=0.02)    loss_fn = nn.MSELoss()     for epoch in range(5):        x = torch.randn(64, 16)        y = torch.sum(x, dim=1, keepdim=True)        pred = model(x)        loss = loss_fn(pred, y)        opt.zero_grad()        loss.backward()        opt.step()        print("epoch", epoch + 1, "loss", round(loss.item(), 4))  if __name__ == "__main__":    main()
目的:实现一个可独立运行的伪量化模块,演示训练时前向模拟量化、反向梯度直通的核心机制。
  1. FakeQuantize(bits=8)创建一个 8 比特伪量化层,量化范围为 [-128, 127]。
  2. self.zero_point = torch.zeros(1)初始化零点偏移;首次前向时通过校准确定。
  3. calibrate(self, x)用第一批数据的 min/max 估算出步长和零点,后续每次前向直接利用。
  4. level_scale = (max_val - min_val) / (self.qmax - self.qmin)极差除以刻度数量,得到步长 scale。
  5. xq = torch.round(x / self.scale) + self.zero_point量化公式:归一化、取整、加零点偏移。
  6. return x + (xdq - x).detach()梯度直通的核心技巧:前向返回量化值 xdq,反向让梯度从未量化的 x 原路通过。
  7. opt.step()权重更新时使用全精度浮点梯度,模型参数依然保持 float32。

常见误区

误区训练完伪量化模型,以为 `model.state_dict()` 里的权重已经是 int8 整数,可以直接部署。

正解伪量化训练期间,权重和激活始终以 float32 存储在内存中,量化仅在前向计算时被“模拟”出来。真正变成 int8 需要在部署阶段再做一次显式的量化和序列化。就像李明戴着沙袋训练,脱下沙袋后还是那双正常的腿;沙袋从来不会融入肌肉里。

为何常见:看到“量化”两个字,容易联想到“存储格式确实变了”;又因为伪量化算子会输出阶梯状的近似值,让人误以为内部状态也是阶梯的。

误区`round` 函数在数学上不可导,所以经过伪量化算子的梯度应当是 0,参数根本无法更新。

正解伪量化在反向传播中采用 STE(直通估计器),跳过 round 的导数,直接让上游梯度原样穿过量化节点,并配合范围闸门把界外梯度置零。因此训练依然可以正常进行,模型也会逐步适应量化噪声。

为何常见:初学自动微分时,我们默认“不可导 = 梯度为 0”,忘记了工程上可以用 STE 这类近似手段绕过数学障碍。

误区校准 min/max 时收集的数据越多越好,最好把训练集全跑一遍,这样统计出的范围和步长最权威。

正解校准数据的“代表性”比“数量”更重要。样本越多,越可能覆盖到离群点,导致量化范围被拉宽、正常数据细节被压碎,精度反而下降。实践中应使用贴近真实分布的子集,必要时用百分位截断法剔除极端值。

为何常见:直觉会误导我们以为“大数据 = 更准确”,但在量化范围统计中,极端值对 min/max 的影响是破坏性而非建设性的。

误区只要把权重保存成 int8,模型就能跑得更快,激活值依然是浮点也没关系。

正解推理时卷积的乘加运算要求激活与权重同为整数,否则不断进行 int8 与 float32 的转换,性能损失反而更大。因此部署时激活值也必须在伪量化中被模拟,并配合校准确定动态范围。

为何常见:权重在训练结束后是静态的,容易被人注意到;激活依赖输入动态变化,理解门槛更高,常被忽略。

面试题

Q1. 伪量化训练最核心的做法是下列哪一项?

单选题 · easy

  • A.训练时直接丢失部分权重数值
  • B.前向模拟量化且反向保留精度← 正确答案
  • C.只在推理阶段进行数值量化
  • D.用全精度权重且忽略量化误差

答案:B。伪量化在前向传播时模拟量化效果(像戴沙袋),反向传播却保留 float32 梯度(像高清摄像机回放)。A 错在真正丢失了权重精度,C 错在只用于推理,D 错在忽略了量化误差。

Q2. 量化公式中缩放因子 scale 的作用是什么?

单选题 · easy

  • A.表示量化的数值步长大小← 正确答案
  • B.表示量化前后零点的位置
  • C.表示神经网络的层数多少
  • D.表示训练时的学习率大小

答案:A。scale 决定每个整数档位代表多大的浮点数值,相当于刻度尺的格宽。零点由 zero_point 表示,网络层数和学习率和量化没有直接关系。

Q3. STE 直通估计中的核心思想是什么?

单选题 · mid

  • A.将梯度视为零并完全停止反向回传
  • B.近似为原始浮点梯度并回传← 正确答案
  • C.将梯度全部反转后进行方向回传
  • D.只对权重回传而不对激活回传

答案:B。STE 在反向传播时忽略 round 的不可导性,直接把上游梯度当作对浮点输入的梯度,像“假装台阶是斜坡”一样回传。A 会让参数无法更新,C 和 D 都扭曲了梯度正确的流向。

Q4. 对称量化与非对称量化最主要的区别是什么?

单选题 · mid

  • A.对称量化使用更少的量化比特数
  • B.对称量化将零点限制为零值← 正确答案
  • C.非对称量化不支持激活量化
  • D.非对称量化不需要缩放因子

答案:B。对称量化令 zero_point=0,映射关于零点对称,硬件实现简单;非对称量化允许零点偏移,能更好地适配分布偏移的数据。二者比特数可以一样,也都可以量化激活,且都需 scale。

Q5. 使用最小最大值法校准时,数据中出现离群点,最可能的结果是?

单选题 · hard

  • A.量化范围过大且多数数据精度降低← 正确答案
  • B.量化范围变小且多数数据精度提高
  • C.离群点被自动移除且量化不受影响
  • D.缩放因子变为零且输入全部溢出

答案:A。min/max 会被离群点拉大极差,使 scale 增大,正常数据只能挤占很少的整数档位,整体精度下降。因此工程上常改用百分位截断或 MSE 校准来削弱离群点影响。

Q6. 量化感知训练带来的主要收益是什么?

单选题 · mid

  • A.训练速度比全精度模型明显更快
  • B.模型参数自动适配量化误差← 正确答案
  • C.训练过程中的显存占用降为零
  • D.完全避免使用反向传播算法

答案:B。QAT 让模型在训练时“体验”量化噪声,从而把参数调整得更适应低精度部署。训练本身不追求速度提升,显存也不会为零,反向传播依然正常使用。

Q7. 伪量化算子通常插入在计算图的什么位置?

单选题 · easy

  • A.损失函数内部的各项计算中
  • B.权重与激活的关键传递节点上← 正确答案
  • C.优化器更新参数之后的阶段
  • D.训练数据加载与预处理流程中

答案:B。伪量化应插在权重参与矩阵乘之前和激活流入下一层之前,这样模型才能在关键路径上感受到精度损失。损失函数、优化器、数据预处理都不是模拟量化误差的最佳位置。

Q8. 关于伪量化训练的完整描述,正确的有哪些?

多选题 · mid

  • A.权重和激活始终以浮点数存储← 正确答案
  • B.前向传播会模拟取整量化误差← 正确答案
  • C.反向传播使用直通估计近似梯度← 正确答案
  • D.训练过程相当于给模型注入噪声← 正确答案

答案:ABCD。四个选项都是伪量化的重要属性:权重激活保持 float32(A)、前向模拟取整误差(B)、STE 回传梯度(C)、量化误差可视为对模型的噪声注入(D),因此全选。

Q9. 部署真实 int8 推理时需要完成哪些工作?

多选题 · hard

  • A.将权重量化并序列化保存为整型← 正确答案
  • B.保存量化的缩放参数和零点偏移← 正确答案
  • C.将卷积算子替换为整数实现版本← 正确答案
  • D.训练阶段的伪量化模块原样保留

答案:ABC。部署时需要把权重真正变成 int8(A)、保存 scale 和 zero_point 等元数据(B)、用整数算子替换浮点算子(C)。伪量化模块是训练期的模拟器,部署时不应保留在计算图中。

Q10. 关于激活与权重量化区别的正确认识有哪些?

多选题 · hard

  • A.权重量化可以在训练后准确确定← 正确答案
  • B.激活分布会随网络输入动态变化← 正确答案
  • C.激活需要采样校正来确定量化参数← 正确答案
  • D.权重和激活量化永远是同一比特精度

答案:ABC。权重训练结束后是静态的,可以直接统计并量化(A);激活随输入变化,必须通过校准集采样确定范围(B、C)。权重量化与激活量化可以分别设置不同比特数,D 过于绝对。