Day 42:模型量化基础 — INT8/FP16
今日目标掌握模型量化的核心原理理解对称量化与非对称量化学会PTQ和QAT的区别为端侧部署打好基础预计阅读12分钟 |动手操作40分钟一、为什么需要量化端侧AI的核心矛盾模型太大设备太小 FP32模型 (训练时): 每个参数 4字节 (32位) ResNet-50: 25M参数 × 4 100MB YOLOv8: ~10M参数 × 4 40MB INT8模型 (量化后): 每个参数 1字节 (8位) ResNet-50: 25M参数 × 1 25MB YOLOv8: ~10M参数 × 1 10MB 模型大小减少 75%速度提升 2-4倍 FP16 (半精度): 模型大小减少 50% (4字节 → 2字节) 速度提升 1.5-2倍 (GPU有Tensor Core) 精度几乎无损importtorchimporttorch.nnasnnimporttorch.nn.functionalasFimportnumpyasnp torch.manual_seed(42)二、核心知识点2.1 量化的数学本质 量化的数学本质浮点数 → 整数 FP32 → INT8 的映射 r S × (q - Z) 其中 r: 浮点数值 (real value) q: 量化后的整数值 (quantized value) S: 缩放因子 (scale) Z: 零点 (zero point) 反量化INT8 → FP32 r S × (q - Z) 两个关键参数 S 和 Z S (r_max - r_min) / (q_max - q_min) Z round(q_min - r_min / S) INT8范围[-128, 127] q_max 127, q_min -128 例子 FP32范围: [-3.0, 5.0] S (5.0 - (-3.0)) / (127 - (-128)) 8.0 / 255 ≈ 0.0314 Z round(-128 - (-3.0) / 0.0314) round(-128 95.5) -33 验证: r 0.0314 × (-33 - (-33)) 0 ← FP32的0对应INT8的-33 classQuantizer: 手动量化器演示FP32 ↔ INT8的映射过程 def__init__(self):self.scaleNoneself.zero_pointNonedefcalibrate(self,tensor): 校准计算scale和zero_point tensor: FP32张量 r_mintensor.min().item()r_maxtensor.max().item()q_min-128# INT8最小值q_max127# INT8最大值# 计算scaleself.scale(r_max-r_min)/(q_max-q_min)# 计算zero_pointself.zero_pointround(q_min-r_min/self.scale)self.zero_pointmax(q_min,min(q_max,self.zero_point))returnself.scale,self.zero_pointdefquantize(self,tensor):量化FP32 → INT8qtorch.round(tensor/self.scaleself.zero_point)qtorch.clamp(q,-128,127)returnq.to(torch.int8)defdequantize(self,q_tensor):反量化INT8 → FP32returnself.scale*(q_tensor.float()-self.zero_point)defquantization_demo():演示FP32 → INT8 → FP32的完整流程# 原始FP32数据x_fp32torch.tensor([-3.0,-1.0,0.0,2.0,5.0])qQuantizer()scale,zpq.calibrate(x_fp32)# 量化x_int8q.quantize(x_fp32)# 反量化x_deqq.dequantize(x_int8)# 量化误差error(x_fp32-x_deq).abs()print(量化演示 (FP32 → INT8 → FP32):)print(f\n 原始FP32:{x_fp32.tolist()})print(f Scale:{scale:.6f})print(f Zero Point:{zp})print(f INT8值:{x_int8.tolist()})print(f 反量化后:{[f{v:.4f}forvinx_deq.tolist()]})print(f 量化误差:{[f{v:.4f}forvinerror.tolist()]})print(f\n 观察: 量化会引入误差但通常很小)print(f 最大误差:{error.max():.4f})quantization_demo()2.2 对称量化 vs 非对称量化 对称量化 (Symmetric Quantization): r S × q zero_point 0 (强制) 优点实现简单计算快 缺点FP32范围不对称时浪费INT8范围 适用权重通常对称分布 非对称量化 (Asymmetric Quantization): r S × (q - Z) zero_point ≠ 0 优点充分利用INT8范围 缺点计算稍复杂需要处理zero_point 适用激活值通常非对称分布如ReLU后≥0 举例 FP32范围: [0, 6.0] (ReLU后的激活值) 对称量化: r ∈ [-128×S, 127×S] 需要S 6.0/127 ≈ 0.0472 INT8范围: [-128, 127] 但只用了[0, 127] 浪费了一半的INT8范围 非对称量化: r S × (q - Z) S 6.0/255 ≈ 0.0235 Z -128 INT8范围: [-128, 127] 全部用上 [-128] → 0.0, [127] → 6.0 defsymmetric_vs_asymmetric():print(对称量化 vs 非对称量化:)print()print(对称量化:)print( r S × q)print( zero_point 0)print( 优点: 实现简单计算快)print( 缺点: 范围不对称时浪费精度)print( 适用: 权重对称分布)print()print(非对称量化:)print( r S × (q - Z))print( zero_point ≠ 0)print( 优点: 充分利用INT8范围)print( 缺点: 计算稍复杂)print( 适用: 激活值非对称分布)print()print(端侧AI实践:)print( 权重: 对称量化 (per-channel))print( 激活值: 非对称量化 (per-tensor))print( 这是TensorRT的默认策略)symmetric_vs_asymmetric()2.3 Per-Tensor vs Per-Channel Per-Tensor量化: 整个张量共享一个scale和zero_point 优点: 实现简单计算快 缺点: 不同通道分布差异大时精度差 Per-Channel量化: 每个通道有自己的scale和zero_point 优点: 精度更高每个通道独立量化 缺点: 实现稍复杂 适用: 权重不同卷积核的分布差异很大 实际配置 权重: Per-Channel对称量化 激活值: Per-Tensor非对称量化 defper_tensor_vs_channel():# 模拟权重两个通道分布差异很大weightstorch.randn(2,3,3,3)weights[0]*0.1# 通道0: 小值weights[1]*10.0# 通道1: 大值print(Per-Tensor vs Per-Channel:)print(f 通道0 范围: [{weights[0].min():.3f},{weights[0].max():.3f}])print(f 通道1 范围: [{weights[1].min():.3f},{weights[1].max():.3f}])print()print( Per-Tensor: 两个通道共享一个scale)print( → 通道0的精度被通道1拖累)print( → 通道0的小值可能被量化为0)print()print( Per-Channel: 每个通道独立的scale)print( → 通道0和通道1各自最优量化)print( → 精度更高)per_tensor_vs_channel()2.4 PTQ vs QAT PTQ (Post-Training Quantization): 训练后量化 流程FP32训练 → 校准(calibration) → INT8推理 不需要重新训练 优点简单、快速 缺点精度可能下降特别是小模型或低位量化 校准数据几百张代表性图片即可 QAT (Quantization-Aware Training): 量化感知训练 流程FP32训练 → 插入伪量化节点 → 继续训练 → INT8推理 需要重新训练几个epoch 优点精度高几乎无损 缺点需要训练时间和数据 适用于精度敏感的模型 什么时候用PTQ什么时候用QAT PTQ: 大模型、精度要求不高、快速部署 QAT: 小模型、精度要求高、低位宽(INT4) 端侧AI经验 INT8 PTQ: 大多数模型精度下降 1%够用 INT8 QAT: 如果PTQ精度下降 2%则用QAT INT4: 必须用QAT defptq_vs_qat():print(PTQ vs QAT:)print()print(PTQ (训练后量化):)print( FP32训练 → 校准 → INT8推理)print( 优点: 简单快速不需要重训练)print( 缺点: 精度可能下降)print( 适用: 大模型精度要求不高)print()print(QAT (量化感知训练):)print( FP32训练 → 插入伪量化节点 → 微调 → INT8推理)print( 优点: 精度高几乎无损)print( 缺点: 需要重训练几个epoch)print( 适用: 小模型精度敏感)print()print(端侧AI决策树:)print( INT8 → PTQ优先 → 精度OK? → 完成)print( → 精度不OK → QAT)print( INT4 → 必须QAT)ptq_vs_qat()三、动手实践PyTorch手动量化defmanual_quantize_conv(): 手动量化一个卷积层演示完整流程 # 1. 创建FP32卷积层convnn.Conv2d(3,16,3,padding1)xtorch.randn(1,3,32,32)# FP32输出withtorch.no_grad():y_fp32conv(x)print(手动量化卷积层:)print(f FP32权重形状:{conv.weight.shape})print(f FP32输出:{y_fp32.shape})# 2. 量化权重 (Per-Channel对称量化)q_weightsQuantizer()weight_scales[]weight_q[]forc_outinrange(conv.weight.shape[0]):w_channelconv.weight[c_out]# (C_in, K, K)q_weights.calibrate(w_channel)weight_scales.append(q_weights.scale)weight_q.append(q_weights.quantize(w_channel))weight_qtorch.stack(weight_q).float()weight_scalestorch.tensor(weight_scales)print(f\n 权重Scale:{weight_scales[:3].tolist()}...)print(f 量化后权重类型: INT8)print(f 量化后权重大小:{weight_q.numel()/1e6:.2f}M × 1字节 {weight_q.numel()/1e6:.2f}MB)print(f FP32权重大小:{conv.weight.numel()/1e6:.2f}M × 4字节 {conv.weight.numel()*4/1e6:.2f}MB)print(f 节省: 75%)manual_quantize_conv()四、端侧AI量化实战defedge_quantization_guide(): 端侧AI量化部署指南 guide{TensorRT INT8:{精度:FP32 → INT8,加速:2-4x,步骤:校准 → build INT8 engine,适用:Jetson系列,难度:中,},ONNX Runtime INT8:{精度:FP32 → INT8,加速:1.5-3x,步骤:ONNX → 量化 → INT8推理,适用:通用平台,难度:低,},PyTorch Mobile INT8:{精度:FP32 → INT8,加速:2-3x,步骤:torch.quantization,适用:移动端,难度:低,},NCNN INT8:{精度:FP32 → INT8,加速:2-4x,步骤:ncnn2table → ncnn2int8,适用:手机/ARM,难度:中,},FP16 (TensorRT):{精度:FP32 → FP16,加速:1.5-2x,步骤:直接转换无需校准,适用:Jetson (GPU),难度:低,},}print(端侧AI量化方案:)formethod,infoinguide.items():print(f\n [{method}])fork,vininfo.items():print(f{k}:{v})edge_quantization_guide()五、常见坑点坑1量化后精度突然大跌# 量化后精度下降 5% → 排查以下问题# 1. 校准数据不够或不够代表性# 校准数据应该覆盖推理时的数据分布# 推荐500-1000张代表性图片# 2. 某些层对量化敏感# 如最后一层、softmax层# 解决方案这些层保持FP32# 3. BatchNorm需要fold# 训练时的BN → 推理时fold到卷积中# 量化前必须fold BN# 4. 激活值范围太大# 某些激活值范围异常大# 解决方案用per-channel量化或QAT坑2FP16注意精度问题# FP16的范围[-65504, 65504]# 超出范围 → 溢出为inf# ❌ 容易溢出的场景# 1. 大数值的激活值如大batch的BN# 2. exp()操作如softmax→ 可能溢出# 3. 梯度累积训练时# ✅ 解决方案# 1. 用混合精度(AMP)FP16计算 FP32存储关键值# 2. 推理时FP16通常安全推理时数值范围可控坑3量化感知训练(QAT)的伪量化# QAT时前向传播用伪量化# 反向传播用STE (Straight-Through Estimator)# 即前向量化反向当量化不存在# 伪量化 量化 反量化(模拟量化误差)# 前向: x_quantized dequantize(quantize(x))# 反向: 梯度直接通过不通过量化函数# QAT训练时loss可能震荡# 因为量化引入了噪声# 这是正常的降低学习率即可坑4不同框架的量化格式不兼容# TensorRT INT8 ≠ ONNX INT8 ≠ NCNN INT8# 每个框架的量化格式不同# 端侧部署流水线# PyTorch → ONNX → TensorRT (INT8) → Jetson# PyTorch → ONNX → NCNN (INT8) → 手机# 不能跨框架混用量化模型# 建议确定部署平台后再决定量化方案六、今日作业手写量化器实现FP32↔INT8的量化/反量化计算量化误差PTQ实验对简单CNN做PTQ观察精度变化FP16测试对比FP32和FP16的推理速度和精度打卡评论区发你的理解格式“Day 42/100 打卡模型量化已掌握”今日小结今天你学会了 ✅ 量化的本质浮点数 → 整数节省存储和计算 ✅ INT8: 模型大小减少75%速度提升2-4x ✅ FP16: 模型大小减少50%速度提升1.5-2x ✅ 量化公式: r S × (q - Z) ✅ 对称量化 vs 非对称量化 ✅ Per-Tensor vs Per-Channel量化 ✅ PTQ: 训练后量化快速简单 ✅ QAT: 量化感知训练精度高 ✅ 端侧AI量化方案TensorRT/ONNX/NCNN ✅ 4个经典坑点明日预告Day 43TensorRT实战模型转换与优化ONNX导出、TensorRT Engine构建、INT8校准、性能分析关注我每天解锁一个端侧AI技能微信公众号xxx | 小红书xxx | CSDNxxx评论区打卡一起坚持100天附小红书图文版封面标题建议模型量化 | INT8/FP16模型缩小75%的秘密P1 — 封面标题模型量化基础副标题INT8 / FP16 / PTQ / QATP2 — 量化的本质FP32: 4字节/参数INT8: 1字节/参数公式: r S × (q - Z)S: 缩放因子Z: 零点模型缩小75%速度提升2-4倍P3 — 对称 vs 非对称对称量化: r S × q, Z0适合权重对称分布非对称量化: r S × (q - Z)适合激活值ReLU后≥0充分利用INT8范围P4 — PTQ vs QATPTQ: 训练后量化FP32 → 校准 → INT8简单快速无需重训练QAT: 量化感知训练FP32 → 伪量化 → 微调 → INT8精度高需要重训练P5 — 端侧量化方案TensorRT INT8: JetsonONNX Runtime INT8: 通用NCNN INT8: 手机/ARMFP16: 最简单GPU有Tensor CoreP6 — 端侧决策树INT8 → PTQ → 精度OK? → 完成→ 不OK → QATINT4 → 必须QATFP16 → 直接转换评论区打卡 Day 42/100标签#模型量化 #INT8 #FP16 #TensorRT #端侧部署CSDN发布提示CSDN版本建议在量化公式部分放FP32→INT8→FP32的映射图在对称vs非对称部分放两种量化方案的对比图在PTQ vs QAT部分放流程图在端侧方案部分放各框架对比表。

相关新闻

AI芯片缺陷检测黑盒难题:可解释性与工程落地实践

AI芯片缺陷检测黑盒难题:可解释性与工程落地实践

1. 当AI走进芯片车间,为什么老师傅还是不敢松手前阵子跟一位在芯片行业摸爬滚打十几年的老朋友吃饭,他跟我吐槽了一件事:公司花大价钱引进了一套AI辅助的缺陷检测系统,号称能自动识别晶圆表面的微米级瑕疵,准确率标称9…

2026/10/14 9:53:33 阅读更多 →
PS5多主机外设整合方案:HID映射、音频分离与SSD扩容实战

PS5多主机外设整合方案:HID映射、音频分离与SSD扩容实战

如果你手里有两台以上的PS5,或者你经常在客厅、书房、工作室之间搬游戏机,大概率遇到过这样的场景:手柄要重新配对,键鼠转换器插上没反应,SSD拆下来换到另一台主机上不识别,音频分离器在新机型上还多了一堆…

2026/10/14 9:53:33 阅读更多 →
PrDiMP18在UAV123上的工程级跟踪性能解析

PrDiMP18在UAV123上的工程级跟踪性能解析

1. 这个标题到底在说一件什么事?“PrDiMP18(epoch90)在UAV123的测试结果”——乍一看,像一串密码,又像实验室日志里随手记下的半句话。但如果你在目标跟踪、视觉感知或无人机智能系统方向摸爬滚打过几年,这几个词组合在一起&#…

2026/10/14 9:53:33 阅读更多 →

最新新闻

从源码编译GMSSL:国密算法支持与HTTPS链接调试实战

从源码编译GMSSL:国密算法支持与HTTPS链接调试实战

1. 从源码到动态库:为什么选择自己编译GMSSL很多人第一次接触国密算法开发时,第一反应是找现成的二进制包或者系统自带的包管理器直接安装。这个思路在大多数场景下没问题,但一旦涉及国密算法,情况就完全不一样了。GMSSL作为国内广…

2026/10/15 2:46:27 阅读更多 →
SpringBoot+Vue学院管理系统开发实战

SpringBoot+Vue学院管理系统开发实战

1. 项目概述与适用场景这个基于SpringBootVue技术栈的学院个人信息管理系统,是典型的教学级全栈开发项目。我在高校信息化部门工作期间,曾主导开发过类似系统,也指导过多名学生完成此类毕业设计。这类系统之所以成为热门选题,关键…

2026/10/15 2:46:27 阅读更多 →
SpringBoot+Vue高校医务室预约管理系统设计与实践

SpringBoot+Vue高校医务室预约管理系统设计与实践

1. 项目背景与核心价值高校医务室作为校园健康保障的第一道防线,长期面临着就诊高峰期排队混乱、病历管理低效、健康数据分散等痛点。这个基于SpringBootVue的预约管理系统,正是为了解决这些实际问题而设计的数字化解决方案。我在参与某高校医疗信息化改…

2026/10/15 2:46:27 阅读更多 →
医疗陪诊小程序开发:功能架构与技术实现详解

医疗陪诊小程序开发:功能架构与技术实现详解

1. 陪诊小程序的市场需求与产品定位医疗陪诊服务正在成为城市生活中的刚需。根据我过去三年参与医疗信息化项目的经验,独居老人、术后康复患者、异地就医人群构成了核心用户群体。这类用户往往面临"挂号难""流程陌生""行动不便"三大痛…

2026/10/15 2:46:27 阅读更多 →
KingdeeERP插件开发实战:从入门到精通

KingdeeERP插件开发实战:从入门到精通

1. 项目概述KingdeeERP作为国内主流的企业管理软件,其插件开发能力为系统功能扩展提供了强大支持。作为一名在ERP领域深耕多年的开发者,我见证了从K/3到Cloud版本的技术演进过程。插件开发不仅仅是简单的功能叠加,更是对企业业务流程的深度定…

2026/10/15 2:46:27 阅读更多 →
Flutter 欢迎页实战:用 intro_slider 构建引导页并实现「只显示一次」的路由跳转(Flutter-Notebook slider_screen 示例解析)

Flutter 欢迎页实战:用 intro_slider 构建引导页并实现「只显示一次」的路由跳转(Flutter-Notebook slider_screen 示例解析)

示例工程移动开发 【免费下载链接】Flutter-Notebook FlutterDemo合集,今天你fu了吗 项目地址: https://gitcode.com/gh_mirrors/fl/Flutter-Notebook 点击查看 免费下载 本文以 Flutter-Notebook 仓库中 mecury_project/example/slider_screen 示例为核…

2026/10/15 2:45:27 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 7:53:34 阅读更多 →