fix(actpred): 修复 HEF 帧归一化误判与部署图数值不等价,补齐 P3 审计项

- hailo_infer: 帧归一化判定改为量化网格 dequant(0)(旧启发式把归一化
  帧当原始像素喂入,图像路径饱和破坏;实机 max_diff 2.55→0.37,
  img 敏感性 1.44→22.26)
- export_deploy: pool kernel 由卷积真实输出尺寸探测(H//16 在 1080
  高度下静默丢弃末行);mobilenet backbone 给出明确报错
- mt_parser: @Action 为文件末位块时解析成功,不再静默丢数据
- config: checkpoint train 段未知键/非 dict 校验;init-from 兼容性
  警告助手(normalize/action_dim),train 与 pretrain 共用
- dataset: stats 文件形状校验;predict: 移除误导性 --action-dim
- dfc_compile: --frame-count 参数化(原硬编码 3 帧)
- gen_calibration: 旧模式校准图像改分块 memmap 生成(1080p 原一次性
  分配 ~600MB)
- _npu_test: torch 参考反归一化对齐后再与 HEF 比较
- 单测 81→90 全过;README 与测速报告更新为验证轮次数据
This commit is contained in:
qing committed 2026-08-13 15:22:34 +08:00
1 parent 316758d80e
commit 823e91a30e
14 files changed
+381 -62

No files matched your search

+11 -1
View File
@@ -86,6 +86,9 @@ class DeployWrapper(nn.Module):
super().__init__()
import copy
m = model
if not hasattr(m.image_encoder, "net"):
raise ValueError(
"部署版导出仅支持 backbone=simple(MobileNet 的 DFC 改造未实现)")
ref_cnn = nn.Sequential(*list(m.image_encoder.net.children())[:-1])
self.cnns = nn.ModuleList(
[copy.deepcopy(ref_cnn) for _ in range(m._frame_len)])
@@ -99,7 +102,14 @@ class DeployWrapper(nn.Module):
m.img_proj.out_features, m.img_proj.in_features, 1, 1))
self.proj_convs.append(c)
self.proj_bias = nn.Parameter(m.img_proj.bias.data.clone())
self.pool = nn.AvgPool2d((m._image_height // 16, m._image_width // 16))
# 固定 kernel AvgPool 须与训练态 AdaptiveAvgPool2d(1) 逐值等价:
# kernel 取 ref_cnn 的真实输出尺寸。H//16 只在分辨率能被 16 整除
# 时成立(1080 高度下卷积输出 68 行,按 67 取 kernel 会静默丢弃
# 末行,破坏与训练图的数值一致)
with torch.no_grad():
probe = ref_cnn(torch.zeros(
1, 3, m._image_height, m._image_width))
self.pool = nn.AvgPool2d((probe.shape[2], probe.shape[3]))
# act_proj 权重注册为常量,用显式 MatMul+Add 代替 Linear,
# 避免 DFC 对 3D Linear 的错误卷积融合
self.act_w = nn.Parameter(m.act_proj.weight.data.t().clone()) # (D, d)