根因:预训练全零图像占位使 BN running_var 停在初始小值,推理时 特征放大至 ±1e6,DFC 在 token merge 点按最大幅度分配共享量化 scale,pred_token/act_tokens 全部被压成 0,HEF 输出对任何输入 恒定(详见 docs/reports/actpred_hef_insensitivity_rootcause_20260813.md) - export_deploy.py:新增 check_token_ranges 导出前 token 量级检查 (|img|>100 中止导出并提示微调;act/img 比例过大警告;归一化 模型在 z 空间采样,避免零方差列爆炸) - pretrain_mt.py:新增 --random-images(ImageNet 归一化噪声占位, 恢复 BN 统计)、--init-from(微调起点,含动作空间一致性警告)、 --normalize-actions 完整支持(训练集 stats 计算与保存、验证集复用) - gen_calibration.py:归一化模型的校准集自动 z-score 动作历史 - _onnx_validate.py / _npu_test.py:归一化模型适配(torch 参考 z-score、HailoPredictor 传 stats_path) - README:预训练章节补充新参数与 NPU 部署警告 - 单测 76/76 通过;冒烟验证:1 epoch 噪声微调后 |img| 2.46e5→8, 归一化后 |act| 694→2.9
8.4 KiB
actpred × 树莓派 AI HAT 2(Hailo-10H)推理调研报告
日期:2026-08-13(同日更新:驱动升级 5.3.0 与 DFC 编译闭环踩坑,见 §5) 设备:Raspberry Pi 5 + Raspberry Pi AI HAT 2(Hailo-10H,8GB RAM,40 TOPS)
1. 目标
调研如何利用 AI HAT 2 扩展板资源对 actpred 动作预测模型做推理加速, 验证板载软件栈可用性,并给出部署路径。
2. 环境实测结果
2.1 软件栈(2026-08-13 已升级 hailort 5.3.0)
| 组件 | 版本 | 说明 |
|---|---|---|
| hailort(运行时 + PCIe 驱动) | 5.3.0 | apt 包 h10-hailort* 5.1.1 → 升级 5.3.0(含固件) |
| 固件 | 5.3.0 | hailortcli fw-control identify 确认 |
| Python API | 5.3.0 | actpred venv 内 pip 安装 hailort-5.3.0-cp313(模块名 hailo_platform) |
| DFC(Dataflow Compiler) | 5.3 | 仅 x86 Linux,运行于 venv_dfc |
注意:Python 模块名是
hailo_platform,不是hailort(import hailort会 ModuleNotFoundError)。
2.2 硬件识别与基准
hailortcli scan # Device: 0001:01:00.0(正常识别)
hailortcli benchmark /usr/share/hailo-models/resnet_v1_50_h10.hef
# → resnet_v1_50: FPS: 307.70(驱动 5.3.0 复测,温度均值 46.7°C)
2.3 预装 HEF 模型
/usr/share/hailo-models/ 下预装了 _h8l/_h10 两套 HEF。
本机为 Hailo-10H,应使用 _h10 后缀模型:
resnet_v1_50、yolov8m、yolov8m_pose、yolov8s_pose、yolov5n_seg、yolov11m 等。
3. Python 推理 API 实测(关键发现)
hailort 5.x 对 Hailo-10 设备只支持新版 infer API:
- ❌ 旧版
VDevice().configure(hef)/InferVStreams(hef, vdev)在 Hailo-10 上报HAILO_NOT_IMPLEMENTED (error 7)(实测) - ✅ 新版
VDevice().create_infer_model(hef_path)→configure()→create_bindings()→run(bindings, timeout)(实测通过)
实测打通的最小推理流程:
import numpy as np
from hailo_platform import VDevice, HEF
hef_path = "/usr/share/hailo-models/resnet_v1_50_h10.hef"
hef = HEF(hef_path)
in_info = hef.get_input_vstream_infos()[0] # (224,224,3) uint8
out_info = hef.get_output_vstream_infos()[0] # (1,1,1000) 量化 uint8
with VDevice() as vdev:
im = vdev.create_infer_model(hef_path)
with im.configure() as c:
b = c.create_bindings()
b.input(in_info.name).set_buffer(img_uint8_hwc)
b.output(out_info.name).set_buffer(
np.zeros(tuple(out_info.shape), dtype=np.uint8))
c.run([b], timeout=10000)
q = np.asarray(b.output(out_info.name).get_buffer()).astype(np.float32)
res = (q - out_info.quant_info.qp_zp) * out_info.quant_info.qp_scale
踩坑记录
bindings.input(name)/bindings.output(name)不支持下标访问;get_buffer()在未set_buffer前返回 None,需先按HEF.get_input/output_vstream_infos()的 shape/dtype 自建 numpy 缓冲区。- 输出缓冲区 dtype/大小必须匹配 HEF 边缘格式(量化 uint8),
传 float32 会报
Output buffer size ... different than expected; 需手动用quant_info.qp_zp/qp_scale反量化。 VStreamInfo无format_type属性,shape 与量化参数从get_input/output_vstream_infos()获取。- vstream 报告顺序不可信:实测 5 输入 HEF 的报告顺序为
input_layer1,5,4,3,2,按报告顺序绑定会 frame1/frame2 错位; 必须按input_layerN数字后缀排序(hailo_infer.py已修复)。 - 摄像头实时推理走
rpicam-hello/rpicam-vid --post-process-file ...(rpicam-apps-hailo-postprocess 提供)。 hailo_platform.genai提供 LLM / VLM / Speech2Text 接口—— AI HAT 2(Hailo-10H + 8GB RAM)支持本地大模型,是与 AI HAT+(Hailo-8L)相比的最大增量。
4. actpred 部署路径
Hailo 板不能直接运行 ONNX/PyTorch,必须编译为 HEF(含量化):
actpred checkpoint (pretrain_best_inference.pt, 224×224)
→ export_deploy.py(DFC 友好改造:按帧展开 CNN、手工注意力、
(1,1,S,d) 布局)→ actpred_deploy.onnx + actpred_deploy_pred_token.npy
→ gen_calibration.py --deploy(合成帧 + .mt 动作历史 + pred_token
抖动校准)→ calibration_deploy.npz
→ dfc_compile.py(parser → optimize → compiler,含输入连通性检查)
→ model.hef(拷回树莓派)
→ hailo_infer.py(HailoPredictor,--pred-token 喂学习值)
风险与注意点:
- DFC 不在树莓派本机(无 hailo/dfc 命令),需在 x86 主机安装或 使用 Hailo 云端 DFC 服务。
- actpred 是 Transformer 结构(多头自注意力),编译前需确认所用 DFC 版本对 attention 类算子的支持;遇不支持算子可拆分模型或换 op。
- actpred 仅 ~450K 参数,Pi 5 CPU(4×A76)直接 PyTorch/ONNX Runtime 推理也在可接受延迟范围;HAT 迁移的主要收益是释放 CPU 给 pybot 主控循环与图像采集。
- HEF 的输入/输出名与量化参数由 DFC 编译决定,推理封装按
get_input/output_vstream_infos()动态适配,不硬编码名称。
5. DFC 编译与实机验证踩坑(2026-08-13)
5.1 首版 HEF:输出对输入完全不敏感
首版 HEF(64×64 checkpoint 产物)在 NPU 上首跑即发现输出对全部 5 个输入均不敏感(全 0 / 全 255 / 真实数据输出完全一致,对照 resnet HEF 同 API 验证输入通道有效,排除封装问题)。
5.2 驱动升级复测:依旧不敏感
将 hailort 5.1.1 升级到 5.3.0(与编译用 SDK 5.3 对齐)后复测: 设备识别、resnet 基准(307.7 FPS)、actpred HEF 执行(6.3ms/次) 全部正常,但 4 角输入敏感性测试(真实/全零帧 × 真实/全零历史) 输出仍完全一致 → 判定为 DFC 编译侧问题(输入在编译图中被断开/ 常量化),驱动版本不是根因。
5.3 排查发现与修复(待重编译验证)
| 发现 | 证据 | 修复 |
|---|---|---|
| pred_token 常量校准量化退化 | HEF 边缘 zp=123, scale=18571.7,任何输入量化成 0 |
gen_calibration.py 改为学习值 ±30% 抖动校准;推理端喂学习值(export_deploy.py --pred-token-out + hailo_infer.py --pred-token) |
| vstream 报告顺序乱序 | 5 输入 HEF 报告顺序 1,5,4,3,2 | hailo_infer.py 按 input_layerN 排序绑定 + 乱序单测 |
| 输入断开无任何报错 | 编译全流程通过但 HEF 恒定输出 | dfc_compile.py parser/optimize 后自动检查输入层下游连通性,断开即报错 |
| 编译前无数值门槛 | deploy ONNX 数值正确性未独立验证 | _onnx_validate.py:输入敏感性 + PyTorch 一致性(本次 PASS,差异 1.5e-5) |
5.4 待办
- x86 主机重编译(
dfc_compile.py,产物含_optimized.har); - 拷回 HEF + pred_token.npy,跑
_npu_test.py4 角敏感性复验; - 若仍不敏感:检查
_optimized.har输入层下游连通性,定位 optimize 断连的具体算子。
更新(同日):上述重编译复验已完成,输出仍不敏感;根因已定位 为预训练 checkpoint 的 BN 统计退化导致图像特征 ±1e6、uint8 量化 压死全部信号(非编译侧断连)。详见 根因分析报告。
6. 结论与产出
- AI HAT 2 软件栈完整可用,新 API 推理链路实测打通(resnet50 307 FPS)。
- actpred HEF 编译链路已全流程打通(export_deploy → gen_calibration → dfc_compile),但首版 HEF 因 DFC 编译侧输入断开不可用,修复方案 已落地,待重编译复验。
- actpred HEF 推理封装:
actpred/hailo_infer.py(HailoPredictor), 接口对齐predict.ActionPredictorInference,单测含 fake hailo_platform 的 5 输入与乱序顺序用例。 - CPU 侧性能基线(224×224,Pi 5):ONNX Runtime 11.4ms / PyTorch 21ms,见 测速报告 §6。