当前位置: 首页 > news >正文

模型插入 NV12 预处理节点精度问题排查流程

一、引言

在近期工具链实践过程中,频繁出现 BC 模型在插入 NV12 预处理节点后精度崩溃的现象。经分析,此类问题可分为两类:其一为用户侧 BGR/RGB 转 NV12 的代码实现缺陷;其二为 BGR/RGB 与 NV12 格式转换过程中固有的不可逆误差所致。后者的根本原因在于模型训练阶段存在严重过拟合现象,导致模型泛化能力薄弱,无法容忍格式转换带来的微小数据偏差。

此类问题的传统排查流程耗时较长,且往往需要重新训练浮点模型,对用户开发进度造成显著影响。基于此,本文提供一套标准化的快速排查方案,旨在缩短问题定位周期,降低对开发节奏的干扰。

二、问题确定与现象

2.1.1 关键术语定义

  • qat_nv12.bc/quantized_nv12.bc:插入 NV12 预处理节点的伪量化 / 定点 BC 模型
  • qat_feat.bc/quantized_feat.bc:未插入 NV12 预处理节点的伪量化 / 定点 BC 模型

2.1.2 典型现象

问题通常表现为:在对插入 NV12 预处理节点的 HBM 或 qat_nv12.bc/quantized_nv12.bc 进行精度验证时,出现 quantized_feat.bc 精度正常而 quantized_nv12.bc 精度异常的特征性差异。

2.1.3 NV12 节点插入规范

在 qat.bc 中插入 NV12 预处理节点的标准代码如下:

resizer_input = ["resize"]      # 部署时数据来源于resizer的输入节点名称列表
pyramid_input = ["pym"]         # 部署时数据来源于pyramid的输入节点名称列表# 为和历史版本保持兼容,建议使用flatten_inputs将输入展开,如下代码同时兼容新旧版本模型:
for input in func.flatten_inputs[::-1]:if input.name in pyramid_input:# pyramid&resizer 只支持 NHWC 的 input layout,若原始输入layout为NHWC,则无需插入transposenode = input.insert_transpose(permutes=[0, 3, 1, 2])# 插入前处理节点,具体可参考下一节的说明node = node.insert_image_preprocess(mode=None, divisor=1, mean=[128, 128, 128], std=[128, 128, 128])node.insert_image_convert("nv12")for input in func.flatten_inputs[::-1]:if input.name in resizer_input:# pyramid&resizer 只支持 NHWC 的 input layout,若原始输入layout为NHWC,则无需插入transposenode = input.insert_transpose(permutes=[0, 3, 1, 2])# 插入前处理节点,具体可参考下一节的说明node = node.insert_image_preprocess(mode=None, divisor=1, mean=[128, 128, 128], std=[128, 128, 128])node.insert_roi_resize("nv12")

2.2 核心验证思路

通过单帧图像分别推理两类模型(含 NV12 节点与不含 NV12 节点),对比输出结果的可视化效果及数值相似度。预期异常特征为:

  • quantized_nv12.bc 与 quantized_feat.bc 推理结果差异显著
  • qat_nv12.bc 与 quantized_nv12.bc 推理结果一致性差

推理时需要注意两个问题:

  1. quantized_nv12.bc 已经插入了 NV12->bgr/rgb 和归一化节点了,所以其输入为 NV12 图像;quantized_feat.bc 的输入需要对齐浮点模型,为手动做过归一化操作的 bgr/rgb 图像;
  2. bgr/rgb->NV12 图像的方式有多种,推荐使用以下方式;
def generate_nv12(img):w,h = img.size# Convert images to YUV formatyuv_img = img.convert('YCbCr')y_data, u_data, v_data = yuv_img.split()# Convert Y, U, and V channel data to byte streamsy_data_bytes = y_data.tobytes()u_data_bytes = u_data.resize((u_data.width // 2, u_data.height // 2)).tobytes()v_data_bytes = v_data.resize((v_data.width // 2, v_data.height // 2)).tobytes()# Arrange the UV data in the form of UVUVUVUV... uvuvuv_data = bytearray()for u_byte, v_byte in zip(u_data_bytes, v_data_bytes):uvuvuv_data.extend([u_byte, v_byte])# Input for the hbir modely = np.frombuffer(y_data_bytes, dtype=np.uint8).reshape(1, h, w, 1).astype(np.uint8)# np.save("y_data.npy", y)uv = np.frombuffer(uvuvuv_data, dtype=np.uint8).reshape(1, h//2, w//2, 2).astype(np.uint8)# np.save("uv_data.npy", uv)return y, uv

三、原因验证与示例

3.1 验证原理

当确定是插入 NV12 预处理节点导致的 bc/hbm 精度下降后,且确定输入数据处理过程完全正确,为了进一步确定原因,可以通过以下方式来证明:在输入数据中加入 2-3 个像素值的随机噪声推理浮点模型。

rgb->NV12 的过程是有损的,所以我们可以在输入图像中加小幅的随机噪声(2-3 个像素值即可),然后输入到浮点模型或者原始浮点 onnx,如果加小噪声前后的模型输出相差很大(可以观察 cos 相似度、L1 等),证明确实为浮点模型过拟合导致。

3.2 参考实现代码

以下为对比输入数据加噪前后,比较浮点 onnx 推理结果的示例代码:

from hbdk4.compiler import load,compile,hbm_perf,visualize,save,convert
import numpy as np
from horizon_tc_ui.hb_runtime import HBRuntime
def cosine_similarity(vec1, vec2):"""计算两向量余弦相似度"""vec1_flat = vec1.flatten()vec2_flat = vec2.flatten() dot_product = np.dot(vec1_flat, vec2_flat)norm_vec1 = np.linalg.norm(vec1_flat)norm_vec2 = np.linalg.norm(vec2_flat)return dot_product / (norm_vec1 * norm_vec2) if (norm_vec1 * norm_vec2) != 0 else 0
def compare_noise_impact(float_model_path):"""对比加噪前后浮点模型输出差异"""input_data = np.load("data.npy")# 添加0-2像素值范围的随机噪声noise = np.random.uniform(0, 2, size=input_data.shape).astype(np.float32)input_data_noise = input_data + noisesess = HBRuntime(float_model_path)input_names = sess.input_namesoutput_names = sess.output_names# 原始输入推理input_dict = {input_names[0]: input_data}outputs_original = sess.run(output_names, input_dict)# 加噪输入推理input_dict_noise = {input_names[0]: input_data_noise}outputs_noise = sess.run(output_names, input_dict_noise)# 计算相似度return [cosine_similarity(orig, noise) for orig, noise in zip(outputs_original, outputs_noise)]# 执行验证
similarities = compare_noise_impact(float_model_path="float_model.onnx")
for i, sim in enumerate(similarities):print(f"输出{i}余弦相似度: {sim:.6f}")

一般来说,若输出余弦相似度低于 99.9%,则可判定为浮点模型过拟合。此时建议在模型训练阶段增加 BGR/RGB→NV12→YUV444 的预处理流程,使模型在训练过程中学习并适应 NV12 转换带来的固有误差,从而提升部署时的精度稳定性。

http://www.hskmm.com/?act=detail&tid=19851

相关文章:

  • 【ARM Cache与 MMU 系列文章 7 – ARMv8v9 MMU 页表配置 01 】
  • 完整教程:【开题答辩过程】以《SpringMVC在筑原平面设计定制管理信息系统的应用与实践》为例,不会开题答辩的可以进来看看
  • 接雨水
  • 非线性规划、最优控制与多目标优化
  • 记录,结构,枚举,ref,in和out 元组
  • Gitee企业版MCP Server:开启AI驱动的企业研发新时代
  • Flutter - dart 语言从入门到精通 - 教程
  • 哈夫曼编码例题
  • Deepoc具身智能模型:为传统电厂巡检机器人注入“灵魂”与“智慧” - 实践
  • Win11共享打印0x0000bc4,三步解决共享难题
  • kafka-日志收集高效的平台部署任务
  • python第三天
  • iOS Xcode16 中删除描述文件 Provisioning Profiles
  • git仓库管理memo
  • 全国主要城市温度舒适度榜:谁在天堂,谁在蒸笼
  • 电桥采集模块 24位ADC+128倍可调增益 高精度测量支持多接口输出
  • ubuntu 系统启动服务及服务依赖
  • Jira停售Data Center尘埃落定!中国企业迁移需落实的6大关键项目管理工具清单
  • 【Cursor/Vscode】SSH免密登录 - 教程
  • python 超长代码行如何换行,符合PEP 8规范?
  • Gitee崛起:中国开发者迎来本土化研发平台新纪元
  • 关键领域软件研发知识管理的范式革命:从静态文档到智能图谱的跃迁
  • 【IEEE出版、曾获中国科协认证】第六届机械工程、智能制造与自动化技术国际学术会议 (MEMAT 2025)
  • 时间同步NTP服务
  • 【WCH蓝牙系列芯片】-基于CH585开发板—IO口(GPIO)外部中断唤醒蓝牙睡眠模式
  • 【2025-09-26】奋斗逻辑
  • 【Linux基础知识系列:第一百四十篇】理解SELinux与系统安全 - 教程
  • 关于修改 linux 系统中优先使用中文结构
  • Discord桌面应用远程代码执行漏洞分析
  • DRL模型训练:原始奖励函数记录以及绘制