我来帮你分析这个 ONNX 模型转换问题。先搜索一下社区中是否有类似的案例。
根据你的日志和错误信息,我定位到了两个核心问题:
问题诊断
问题 1:float division by zero 错误
根本原因:校准阶段计算 grid scale 时,input_h - 1 = 0,说明模型中存在高度为 1 的特征图,导致除零错误。
从错误堆栈看:
grid_scale_y = ha / 2 ** (interp_bit_num - 1 + s) / (input_h - 1)
ZeroDivisionError: float division by zero
问题 2:after max iteration, there are still patterns that can be matched
原因:模型中存在 BPU 无法完全优化的算子模式,通常与动态 shape 或不支持的算子组合有关。
解决方案
方案一:跳过校准(快速验证)
先不使用校准数据,用随机数据验证模型能否通过编译:
hb_compile --model ${onnx_model} --march nash-e \
--input-shape left_image 1x3x480x640 \
--input-shape right_image 1x3x480x640 \
--skip-calibration
如果这样能通过,说明问题出在校准数据或校准流程上。
方案二:修改校准配置(推荐)
根据你的 YAML 配置,需要做以下调整:
1. 修改 YAML 配置文件
calibration_parameters:
cal_data_dir: ./calibration_data_test1/left;./calibration_data_test1/right
calibration_type: fixed # 改用 fixed 模式,避免 KL 散度计算
cal_data_num: 1 # 明确指定数量
compiler_parameters:
compile_mode: latency
optimize_level: O0 # 保持 O0,减少优化带来的问题
core_num: 1
jobs: 16
input_parameters:
input_name: left_image;right_image
input_shape: 1x3x480x640;1x3x480x640
input_type_rt: featuremap;featuremap # 改用 featuremap
input_type_train: featuremap;featuremap
input_layout_train: NCHW;NCHW
norm_type: no_preprocess;no_preprocess # 不做预处理
mean_value: ''
scale_value: ''
std_value: ''
2. 校准数据格式要求
由于你的模型已经做过归一化(ImageNet normalization stripped),校准数据应该是已经预处理后的 float32 数据:
# 生成校准数据的正确方式
import numpy as np
import os
# 左图校准数据
left_dir = './calibration_data_test1/left'
os.makedirs(left_dir, exist_ok=True)
# 读取原始图片,做与模型训练时相同的预处理
from PIL import Image
import torchvision.transforms as transforms
transform = transforms.Compose([
transforms.Resize((480, 640)),
transforms.ToTensor(), # HWC->CHW, 0-255->0-1
transforms.Normalize(mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225])
])
for i, img_path in enumerate(left_image_paths[:1]): # 先用 1 张测试
img = Image.open(img_path).convert('RGB')
img_tensor = transform(img) # [3, 480, 640], float32
img_tensor = img_tensor.unsqueeze(0) # [1, 3, 480, 640]
img_tensor.numpy().tofile(f'{left_dir}/{i:04d}.feature')
# 右图同理
关键点:
- 文件后缀用
.feature(float32 数据) - 数据已经是归一化后的 float32,不要再做 scale/mean 处理
- YAML 中
norm_type: no_preprocess
方案三:排查模型中的 1x1 特征图
使用 Netron 查看模型结构,找到高度或宽度为 1 的节点:
# 安装 netron
pip install netron
# 启动查看
netron ffs_patch_no_scatternd_sim.onnx
在 Netron 中搜索:
- 形状为
[1, C, 1, W]或[1, C, H, 1]的节点 - 特别是
Resize、Interpolate、GlobalAveragePool等算子
如果找到这样的节点,可能需要:
- 修改模型结构,避免产生 1x1 的特征图
- 使用
--disable-pass跳过某些优化
方案四:多输入校准数据对齐
从社区案例 topic/34721 看,双目模型校准需要特别注意:
校准数据目录结构
calibration_data_test1/
├── left/
│ ├── 0000.feature # float32, 1×3×480×640
│ └── 0001.feature
└── right/
├── 0000.feature # float32, 1×3×480×640
└── 0001.feature
验证脚本
import numpy as np
import os
left_dir = './calibration_data_test1/left'
right_dir = './calibration_data_test1/right'
left_files = sorted([f for f in os.listdir(left_dir) if f.endswith('.feature')])
right_files = sorted([f for f in os.listdir(right_dir) if f.endswith('.feature')])
print(f"Left: {len(left_files)} files")
print(f"Right: {len(right_files)} files")
# 验证第一个文件
if left_files:
data = np.fromfile(f'{left_dir}/{left_files[0]}', dtype=np.float32)
print(f"Left data shape: {data.shape}, expected: {1*3*480*640}")
if right_files:
data = np.fromfile(f'{right_dir}/{right_files[0]}', dtype=np.float32)
print(f"Right data shape: {data.shape}, expected: {1*3*480*640}")
建议执行顺序
- 先用方案一(
--skip-calibration)验证模型能否编译通过 - 如果成功,再用方案二准备正确的校准数据
- 如果失败,用方案三排查模型结构问题
- 参考社区案例:S100 双目深度模型量化失败
额外建议
关于 ScatterND 算子
你提到已经消除了 ScatterND,但建议确认:
# 检查模型中是否还有其他不支持的算子
hb_checker --model ffs_patch_no_scatternd_sim.onnx --march nash-e
关于 --fast-perf
这个参数主要用于加速编译,不会解决算子支持问题。如果模型本身有 unsupported patterns,加这个参数也没用。
请先尝试方案一,告诉我是否能通过编译。如果还有问题,请提供:
hb_checker的输出- Netron 中找到的 1x1 特征图节点截图
- 完整的校准数据生成脚本