Horizon J6m 部署 YOLOv8s INT8 精度下降排查与优化 📅 发布时间:2026/9/18 9:50:46 👁 浏览次数: 1. 问题现场Horizon J6m 上 YOLOv8s INT8 为什么突然“不认人”板子点亮那一刻我以为 Horizon J6m 部署 YOLOv8s INT8 最难的是把模型跑起来结果模型是真跑起来了mAP50 却从 PyTorch 上的 0.512 掉到 0.348小目标检测框像喝醉一样乱飘。这个记录就是我当时从怀疑校准集、怀疑算子、怀疑后处理一路查到最后把精度拉回 0.506 的全过程。如果你也在 J6m、J6 系列或者其他边缘 BPU 上部署 YOLOv8s INT8遇到“能跑但精度下降”的问题这篇排查记录应该能帮你少绕几个弯。它不聊虚的只讲我怎么把掉点拆成可测量的小问题再用工具链和板端对齐脚本逐个验证。先说结论方向YOLOv8s 这种带 DFL 检测头、C2f 结构、SiLU 激活的模型在 INT8 量化下不是不能跑而是对校准数据、预处理、混合精度配置和后处理对齐特别敏感。很多时候你以为模型量化坏了实际上是校准图用了 BGR训练时用的是 RGB你以为算子不支持实际上是 Concat 层在 INT8 下溢出你以为板端 runtime 有问题实际上是 NMS 的类别策略和验证脚本不一致。Horizon J6m、YOLOv8s、INT8、部署、精度下降这几个词放在一起真正难的不是“部署”两个字而是把每一段误差来源钉死。1.1 硬件与模型组合我的测试组合很典型主机端用 PyTorch 和 Ultralytics 训练好的 YOLOv8s输入 640x640单类或多类检测导出 ONNX 后交给 Horizon J6m 对应工具链做 INT8 量化编译最后在 J6m 板端跑推理。训练集和验证集来自同一批业务数据标注质量还行PyTorch FP32 的 mAP50 是 0.512mAP50-95 是 0.341。ONNX FP32 推理结果和 PyTorch 基本一致mAP50 0.511说明导出环节没有明显问题。问题出在 INT8 上。默认量化配置编译后板端 mAP50 只有 0.348mAP50-95 掉到 0.201。更直观的现象是大目标还能检出但置信度普遍偏低小目标和密集目标漏检严重同一张图在 PyTorch 上框得很准在板端上框位置会整体偏移几个像素个别类别几乎全丢。这个现象很像是“输入分布不对 敏感层量化误差 后处理不一致”叠加在一起而不是单一原因。注意不要一看到掉点就认定是量化算法不行。边缘部署里量化只是误差放大器前面预处理和后处理的任何小差异都会被 INT8 放大。1.2 精度下降的量化表现我把第一次量化后的指标整理成表方便后面每修一项就对比一次。这个表后来成了我的排查进度条。阶段mAP50mAP50-95现象PyTorch FP320.5120.341基线ONNX FP320.5110.340与 PyTorch 对齐J6m INT8 默认配置0.3480.201小目标漏检、置信度低修复预处理后0.4020.236大目标恢复小目标仍差修复 letterbox 后0.4310.267框偏移改善敏感层转 int16 后0.4780.312小目标明显恢复对齐 NMS 后0.5060.336达到可接受范围这张表里最值得说的是“修复预处理后 mAP 从 0.348 到 0.402”。很多人会忽略这一点觉得预处理只是读图而已。实际上 INT8 量化会根据校准数据的分布计算激活值的 scale如果校准数据本身的通道顺序、归一化方式、填充值都和训练不一致量化参数就会偏后面再怎么调混合精度都很难补回来。1.3 先别急着改模型确认可复现的误差基线排查精度下降第一步不是改量化配置而是建立一个可复现的误差基线。我做了三件事固定随机种子固定验证集固定预处理脚本。验证集不要和校准集重叠否则你看到的指标会虚高板端实际表现会打脸。每次只改一个变量改完重新编译、重新跑板端、重新算 mAP。不要一次改五个参数那样你根本不知道是哪一项起了作用。另外板端推理结果要落盘保存包括原始输出张量、解码后的框、类别、分数。只保存可视化图片不够因为肉眼很难判断一个框偏移 3 个像素是量化误差还是 letterbox 算错。把中间张量存成 npy后面和 ONNX Runtime 输出做余弦相似度、最大绝对误差定位速度会快很多。这个习惯听起来笨但真能省时间。2. 部署链路拆解从 PyTorch 到 J6m 的每一个可能失真点Horizon J6m 上跑 YOLOv8s INT8链路大致是PyTorch 训练态模型 - 导出 ONNX - 工具链做模型检查与量化校准 - 编译成板端可执行模型 - 板端 runtime 加载推理 - 后处理解码与 NMS。每一段都可能引入误差而且误差会累积。我的经验是先把链路画清楚再按“从后往前”或“从输入到输出”的顺序逐段对齐。不要跳步跳步最后一定会回来补课。J6m 的工具链版本和早期 XJ3、J5 有差异。我的环境里入口命令已经切到hb_compile这一类很多老教程还在写hb_mapper makertbin。命令名不同但配置字段的语义很像模型参数、校准参数、量化参数、编译参数。你只要抓住“输入输出要对齐、校准数据要一致、敏感层要可配”这三个核心就不容易被工具链版本绕晕。2.1 五段式链路训练态、ONNX、量化校准、编译、板端 runtime训练态模型是浮点精度YOLOv8s 的 SiLU、Concat、Resize、Slice、DFL 都在这里。导出 ONNX 后计算图会被简化、折叠常量、调整算子顺序。这个阶段最常见的问题是 opset 不匹配、动态 shape 没关掉、输出节点选错。YOLOv8 导出时建议用固定输入尺寸opset 选工具链验证过的版本。我的经验是 opset 12 或 13 比较稳具体以 J6m 工具链文档为准。量化校准阶段会读一批校准图统计每一层激活值的分布然后计算 INT8 的 scale 和 zero point。这里的关键是校准图的预处理必须和训练、验证完全一致。你训练时用了 RGB、letterbox 填充 114、像素除以 255校准图也必须这样。否则量化器看到的分布和模型训练时看到的分布不是同一个东西掉点是必然的。编译阶段会把量化后的图映射到 BPU 算子做内存分配、算子融合、指令调度。这个阶段可能出现算子回退到 CPU、算子被替换、Concat 输入顺序变化。板端 runtime 阶段则涉及输入 tensor 的 layout、颜色格式、归一化是否在模型内部完成。J6m 通常支持 NV12 输入模型内部做 mean/scale这能省带宽但也容易因为配置写错导致通道顺序问题。2.2 YOLOv8s 在 INT8 下的敏感结构YOLOv8s 不是为 INT8 专门设计的网络它的检测头里有 DFL 回归分类分支和回归分支共享部分特征。INT8 量化对以下几类结构比较敏感第一C2f 里的 Concat。多个分支特征拼接时如果某一分支的动态范围很大INT8 的 8 bit 表示范围不够就会截断。表现是拼接后的特征图余弦相似度下降检测头输出偏移。第二SiLU 激活。SiLU 是非单调函数负半轴有小值INT8 量化后负半轴信息容易丢。第三DFL 的 softmax 和加权求和。回归分支对数值精度敏感框位置会漂。第四小目标所在的高分辨率特征层。高层语义特征经过多次下采样小目标响应本来就弱量化误差一放大就没了。我的处理顺序是先保证输入输出对齐再看中间层余弦相似度。如果某一层余弦相似度低于 0.98就考虑把这层激活改成 int16。不要一上来全图 int16那样模型体积和带宽都受不了板端帧率会掉得很难看。2.3 预处理和后处理是两个“隐形杀手”预处理里最容易被忽略的是颜色通道和 letterbox。Ultralytics 训练时默认用 RGBOpenCV 读图默认是 BGR。如果你在校准脚本里直接cv2.imread然后除以 255没有cvtColor校准数据就是 BGR。模型训练时看到的是 RGB量化器看到的却是 BGR通道分布错了量化 scale 自然错。这个错误在 FP32 上可能只掉一两个点在 INT8 上可能掉十几个点。letterbox 也一样。YOLOv8 训练时用灰色填充通常填充值是 114。如果你在板端预处理时用 0 填充或者直接 resize 不保持宽高比目标框的坐标映射就会变。量化本身不会让框整体偏移但预处理会。后处理里的 DFL 解码、anchor 点生成、NMS 阈值和类别策略也必须和验证脚本一致。板端为了省 CPU有时会把 NMS 改成 class-agnostic这会抑制重叠类别的框mAP 直接掉。提示先写一个“输入张量对齐脚本”把 PyTorch、ONNX、板端三者的输入张量打印出来。如果输入都不一致后面所有精度对比都没有意义。3. 排查方法论把“掉点”拆成可测量的小问题我排查精度下降时不会直接盯着 mAP 看因为 mAP 是最终结果信息量太少。我会把误差拆成四层输入误差、中间层误差、输出张量误差、后处理误差。每一层都有对应的对齐方法。输入层比张量的均值和最大绝对误差中间层比余弦相似度和相对误差输出层比原始输出张量后处理层比解码后的框和分数。这样即使最终 mAP 掉了我也能知道是哪一层开始崩的。这套方法的好处是它不依赖你对工具链的玄学理解。你不需要猜“是不是量化算法不行”只需要看数据。哪一层开始不一致就从哪一层往前查。大多数时候问题都在输入层或后处理层真正需要动量化配置的只占一小部分。3.1 三级对齐基线怎么搭三级对齐指的是 PyTorch - ONNX - J6m 板端。先在 PyTorch 里跑一张图保存输入张量和最终输出张量再用 ONNX Runtime 跑同一张图保存输入和输出最后用 J6m 板端 runtime 跑同一张图保存输入和输出。注意板端输入要保存实际送进模型的 tensor而不是原始图片。很多板端 API 接受 NV12 或 YUV内部转换你如果不把内部 tensor 打出来就不知道颜色转换有没有错。对齐时先比输入张量。如果 PyTorch 输入和 ONNX 输入不一致检查导出时的预处理。ONNX 里如果包含了预处理板端就不要再重复做归一化如果 ONNX 里没有预处理板端就要按训练方式补上。这个边界一定要清楚重复归一化会让像素值变成 0 到 1 再除以 255分布彻底变了。再比输出张量。YOLOv8 原始输出通常是[1, 84, 8400]前 64 个通道是 DFL 回归后 80 个通道是类别分数。如果板端输出 shape 是[1, 8400, 84]需要转置但转置顺序错了也会导致解析错。输出张量对齐后再做 DFL 解码和 NMS最后算 mAP。3.2 对齐输入张量先排除颜色、layout、归一化输入张量对齐是排查的第一步也是性价比最高的一步。我通常会打印以下信息检查项PyTorch/ONNXJ6m 板端判断shape1x3x640x6401x3x640x640一致layoutNCHWNHWC 或 NCHW需确认颜色RGBBGR 或 NV12常见错误归一化/255mean/std 配置需一致填充值1140 或 114影响边缘目标缩放letterbox直接 resize框会偏如果板端输入是 NV12模型内部配置了 mean 和 scale你要确认 NV12 到 RGB 的转换矩阵、UV 顺序、亮度范围。YUV 有 full range 和 limited range 的区别转换错了整体亮度会偏量化后更明显。我的做法是拿一张纯色图或灰阶图跑一遍看板端输入 tensor 的数值是否和预期一致。灰阶图能很快暴露通道顺序问题。还有 layout。有些 runtime 要求 NHWC有些要求 NCHW。如果配置写错模型会把通道当空间维度输出完全乱掉。这个问题在 FP32 下也会存在但如果你的板端推理只是“能出框”可能会误以为是量化掉点。所以输入对齐一定要做。3.3 逐层余弦相似度与输出误差定位输入对齐后下一步是中间层对齐。J6m 工具链通常支持导出中间层数据或者在编译配置里插入输出节点。我的做法是选几个关键节点backbone 最后一个 C2f 输出、SPPF 输出、Neck 的 Concat 输出、Detect 头的分类和回归分支输入。把这些节点在 ONNX Runtime 和板端分别取出来算余弦相似度。import numpy as np def cosine_similarity(a, b): a a.ravel().astype(np.float32) b b.ravel().astype(np.float32) return float(np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b) 1e-9)) def max_abs_error(a, b): return float(np.max(np.abs(a.astype(np.float32) - b.astype(np.float32))))余弦相似度低于 0.98 的层要重点关注。低于 0.95 基本可以确定量化误差已经伤到特征。这个时候不要急着全图改 int16先看这一层前面有没有 Concat、Resize、SiLU。如果是 Concat把 Concat 的输出或输入转 int16如果是 SiLU考虑换激活近似或把相关层转 int16如果是 DFL 回归分支优先保回归分支精度。定位到具体层之后再去工具链的量化配置文件里改 node_config。改完重新编译重新跑逐层对齐。每一轮只改一层或一组相关层记录指标变化。这个过程有点像调音不能一把梭。4. 核心根因逐一验证六类高频问题排查实录我的 J6m 精度下降问题最后确认是多个原因叠加不是单一故障。下面按我当时排查的顺序写每一类都给出验证方法和处理动作。你不需要完全照搬但可以按这个顺序检查能省很多时间。4.1 校准集数量、分布与预处理最开始我用的校准集只有 64 张而且都是从验证集里随手抽的。问题有三个数量太少分布不均衡预处理不一致。64 张图无法覆盖不同光照、目标尺度、遮挡情况量化器学到的激活分布很窄。板端遇到训练分布外的图激活值超出 scale 范围直接截断。后来我把校准集扩到 500 张覆盖白天、傍晚、逆光、遮挡、小目标密集场景并且和验证集完全隔离。预处理不一致更隐蔽。我一开始用 OpenCV 读图BGR 直接除以 255没有转 RGB。而训练时 Ultralytics 用的是 RGB。校准数据通道反了量化 scale 自然偏。修复方法很简单在读图后加cv2.cvtColor(img, cv2.COLOR_BGR2RGB)再做 letterbox 和归一化。校准数据保存成 float32 的 npy 或工具链要求的二进制格式不要保存成 uint8 再让工具链自己转因为 uint8 会丢精度归一化方式也容易错。注意校准集不是越多越好但太少一定不行。我的经验是 300 到 500 张起步类别均衡场景覆盖训练集主要分布。校准集和验证集重叠会让指标虚高板端上线后原形毕露。4.2 量化配置与混合精度默认 INT8 配置下YOLOv8s 的 Concat 和 Detect 头容易出问题。我用的工具链支持 node_config可以把指定节点的激活量化改成 int16。注意不是所有权重都改权重一般还是 int8只把敏感层的激活改成 int16。这样模型体积增加有限精度提升明显。我的配置里重点关照了 Neck 的 Concat、Detect 头里 DFL 相关的 Conv、分类分支的最后一个 Conv。校准参数方面max_percentile可以设成 0.9999 或 0.99999避免极端值把 scale 拉得太大。bias_correction建议打开能修正量化偏差。per_channel对权重量化有用通常打开。如果工具链支持 KL 散度校准可以对比 default 和 KL 的结果不同数据集差异很大不要迷信某一种。model_parameters: onnx_model: ./yolov8s.onnx march: nash output_model_file_prefix: yolov8s_j6m working_dir: ./ws input_shape: 1x3x640x640 input_type_rt: nv12 input_type_train: rgb input_layout_train: NCHW norm_type: data_mean_and_scale mean_value: 0 0 0 scale_value: 0.003921568627 0.003921568627 0.003921568627 calibration_parameters: cal_data_dir: ./calib_data cal_data_type: float32 calibration_type: default max_percentile: 0.9999 per_channel: true quantization: advance: bias_correction: true node_config: /model.22/Concat_3: activation_quantization: int16 /model.22/Concat_5: activation_quantization: int16 /model.22/cv2.0/cv2.0.2/Conv: activation_quantization: int16 /model.22/cv3.0/cv3.0.2/Conv: activation_quantization: int16上面这段配置是我的实际模板节点名要根据你的 ONNX 图来改。用 Netron 打开 ONNX找到对应 Concat 和 Conv 的名字。不要直接抄节点名不同导出方式名字会变。4.3 算子支持与 YOLOv8 特有结构YOLOv8s 的算子大部分 J6m 工具链都支持但支持不等于精度无损。Resize、Slice、Concat、Softmax 这些算子在 INT8 下可能有近似实现。我遇到的一个典型问题是上采样 Resize 在 INT8 下精度差导致小目标特征图模糊。处理方式是把 Resize 前后相关层转 int16或者调整插值方式。工具链如果支持nearest和bilinear要确认和训练时一致。Ultralytics 默认是nearest如果你在板端用了 bilinear特征图会有差异。另一个是 Slice。YOLOv8 的 DFL 解码在模型内部可能被拆成 Slice 和 Softmax。如果 Slice 的量化 scale 不对回归分支会偏。这个可以通过逐层对齐发现。我的建议是先让工具链跑一遍算子支持检查看有没有算子回退到 CPU。回退到 CPU 的算子如果不在关键路径上影响可能不大如果在 Detect 头里板端速度慢且精度可能不一致。4.4 输入格式、letterbox 与颜色通道输入格式问题我前面提过这里再展开。J6m 板端为了性能经常直接用 NV12 输入模型内部做颜色转换和归一化。配置里input_type_rt和input_type_train要写对。训练时是 RGB板端输入 NV12工具链会插入转换。如果 UV 顺序写错颜色会偏。如果 limited range 和 full range 搞混亮度会偏。这些偏差在 FP32 上可能只是轻微掉点在 INT8 上会被放大。letterbox 的填充值也要统一。Ultralytics 默认填充 114我却在板端用了 0。结果图像边缘的目标框偏移特别是靠近图像边界的对象。修复后 mAP 从 0.402 提到 0.431。这个提升看起来不大但它是后面所有优化的基础。如果连坐标映射都不对混合精度调得再好也没用。4.5 后处理 DFL、NMS 与阈值YOLOv8 的后处理不是简单的 anchor 解码。它需要把[1, 84, 8400]拆成[1, 64, 8400]和[1, 80, 8400]前 64 个通道按 4 个方向、每个方向 16 个 bin 做 softmax然后用[0, 1, ..., 15]加权求和得到距离。这个解码过程如果和训练时不一致框就会偏。我见过有人把 64 个通道直接当 4 个坐标用结果框全乱。def dfl_decode(pred, reg_max16): # pred: [1, 64, 8400] b, c, n pred.shape pred pred.reshape(b, 4, reg_max, n) pred pred.softmax(axis2) proj np.arange(reg_max, dtypenp.float32).reshape(1, 1, reg_max, 1) dist (pred * proj).sum(axis2) return distNMS 的类别策略也很关键。Ultralytics 验证时默认是每类独立 NMSagnosticFalse。板端为了省时间可能改成 class-agnostic这会把不同类别的重叠框合并导致漏检。置信度阈值和 IoU 阈值也要和验证脚本一致。我最后把 NMS 改回 per-classmAP 从 0.478 回到 0.506。4.6 工具链版本、runtime 与内存对齐工具链版本和板端 runtime 版本不一致也可能导致输出顺序变化或中间层数据异常。我遇到过编译工具链升级后Concat 输入顺序变了导致通道对应错。解决办法是锁定版本训练环境、ONNX 导出环境、量化编译工具链、板端 runtime、后处理脚本全部记录版本号。不要今天用这个版本编译明天用另一个版本部署。内存对齐问题比较少见但如果板端输入 tensor 地址没对齐可能触发 runtime 的拷贝或转换影响精度。这个一般通过官方 API 传图不会遇到自己手动管理 buffer 时要注意。我的建议是能用官方接口就用官方接口不要为了省一点内存去改底层。5. 实操过程修复精度下降的完整步骤这一节按我实际操作的顺序写你可以当成一个 checklist。每一步都有目的和验证方法不要跳步。5.1 锁定环境与版本先把所有版本固定下来记录在项目 README 里组件版本记录方式PyTorch训练环境pip freezeUltralytics导出 ONNX 的版本ONNXopset 和 onnxruntime 版本工具链J6m 对应 OpenExplorer 版本板端 runtime镜像版本或库版本后处理脚本git commit版本不一致是最难查的问题之一因为现象可能随机。固定版本后每次编译产物加 hash方便回滚。5.2 重新导出 ONNX用固定输入尺寸、固定 opset、关闭 dynamic shape。我的导出命令如下from ultralytics import YOLO model YOLO(yolov8s.pt) model.export( formatonnx, imgsz640, opset12, simplifyTrue, dynamicFalse, halfFalse, int8False, )导出后用 Netron 检查输入输出。输入应该是1x3x640x640输出应该是1x84x8400或类似。确认没有多余节点没有动态维度。然后用 onnxruntime 跑一张图和 PyTorch 输出对比确保 FP32 对齐。5.3 制作校准集校准集制作流程从训练集里抽样不要用验证集。覆盖不同类别、光照、尺度、遮挡。用和训练完全一致的预处理RGB、letterbox 填充 114、除以 255。保存成 float32 的 npy 或工具链要求的二进制格式。检查校准数据的均值和方差和训练集统计对比偏差大就重新采样。我最后用了 500 张类别分布和训练集接近。校准数据不要做数据增强增强后的分布和真实推理分布不一致量化 scale 会偏。5.4 量化编译与混合精度调整先用默认配置编译一版跑板端记录逐层余弦相似度。然后根据相似度低的层在 node_config 里加 int16。每次改完重新编译重新跑对齐。我的顺序是先保输入对齐再保 Neck 的 Concat再保 Detect 头的回归分支最后保分类分支。不要一次全改否则你不知道哪一层真正有用。编译命令随工具链版本不同我用的形式类似hb_compile -c yolov8s_j6m.yaml # 部分老版本对应 # hb_mapper makertbin --config yolov8s_j6m.yaml --model-type onnx编译日志里要关注有没有算子回退到 CPU有没有警告某层量化误差大有没有节点被融合。日志里的 warning 不要忽略很多精度问题在日志里已经有提示。5.5 板端对齐与指标复核板端跑推理后先比输入张量再比输出张量再比解码后的框。对齐脚本要能保存原始输出 npy。指标复核用同一个验证集、同一个 NMS 参数、同一个置信度阈值。我的验证脚本里会输出 mAP50、mAP50-95、每类 AP、每类漏检数。如果某一类特别差回看校准集里这一类样本是否足够。最后修复后的指标是 mAP50 0.506mAP50-95 0.336。虽然没有完全回到 FP32 的 0.512但已经满足业务要求板端帧率也在可接受范围。如果业务要求更高可以考虑 QAT但 QAT 需要训练环境和更多时间通常作为最后手段。6. 常见问题速查与避坑经验6.1 精度问题速查表现象优先怀疑验证方法处理整体置信度低校准集预处理不一致比输入张量均值和通道统一 RGB、mean/std小目标漏检Concat 或高分辨率层量化溢出逐层余弦相似度敏感层转 int16框整体偏移letterbox 填充值或缩放算错画框对比原图统一填充 114、保持宽高比框位置漂移DFL 解码不一致比原始输出张量对齐 DFL softmax 和加权某类几乎全丢校准集中该类太少看每类 AP 和校准分布补充该类校准图重叠目标被抑制NMS 类别策略不同比 NMS 前后框数改回 per-class NMS颜色异常RGB/BGR 或 NV12 UV 顺序灰阶图或纯色图测试修正颜色转换板端输出顺序变化工具链或 runtime 版本不一致比输出 shape 和节点名锁定版本只在大图掉点输入 resize 方式不同比预处理后 tensor统一 letterbox量化后速度慢很多过多层转 int16看编译日志和 profile只转必要层6.2 我实际踩过的坑第一个坑是校准集用了验证集。当时觉得方便结果板端指标和验证指标差距很大。后来把校准集和验证集彻底分开指标才可信。第二个坑是 BGR/RGB 反了。这个错误在可视化时不容易发现因为颜色看起来只是稍微偏但量化 scale 已经错了。第三个坑是校准数据保存成 uint8工具链按 0 到 255 统计模型输入却是 0 到 1scale 偏了一个数量级。第四个坑是 NMS 用了 class-agnostic导致相邻类别的框互相抑制。第五个坑是工具链升级后 Concat 输入顺序变了输出通道对应错查了很久才发现是版本问题。提示每次改完预处理或量化配置都要重新跑输入对齐。不要假设“上次是对的这次也应该对”。版本、脚本、数据任何一个变了都要重新验证。6.3 上线前检查清单上线前我会过一遍这个清单校准集和验证集无重叠类别分布合理。训练、校准、板端预处理的颜色、归一化、letterbox 完全一致。ONNX 导出固定 shape、固定 opsetFP32 对齐。板端输入张量和 ONNX 输入张量数值误差在可接受范围。输出张量 shape 和通道顺序正确。DFL 解码、anchor 生成、NMS 参数和验证脚本一致。敏感层混合精度配置有记录知道为什么转 int16。工具链、runtime、后处理脚本版本锁定。板端指标在业务验证集上复测不只看单张图。保存一版 FP32 和 INT8 的对比结果方便回滚。我现在每次部署新模型都会先把“输入对齐 输出对齐 逐层相似度”这三个脚本跑通再谈量化优化。这个过程不花哨但能让你在精度下降时知道问题出在哪而不是靠猜。J6m 这类边缘芯片的 INT8 部署本质上是一场和误差的拉锯战谁把细节对齐得更死谁就能把精度守住。