9.8 KiB
9.8 KiB
actpred 多帧注意力架构改造测试报告
| 项目 | 值 |
|---|---|
| 日期 | 2026-08-09 |
| 模块 | actpred |
| 测试人 | qing |
| 环境 | Intel Xeon E3-1200 v2 (Ivy Bridge), 4 核, Linux 24.04, Python 3.x, PyTorch (CPU-only) |
| 关联文件 | config.py, model.py, dataset.py, train.py, pretrain_mt.py, predict.py, export_onnx.py, test_actpred.py |
| 前置报告 | actpred_pretrain_test_20260808.md |
一、改造背景与目标
原架构为"单帧 CNN + 历史动作 MLP/GRU + concat 融合",仅支持单帧图像输入。 本次改造目标:
- 引入注意力机制,支持多帧图像 + 历史动作序列联合建模,预测下一时间步动作
- 保持 checkpoint 格式(
model_state_dict+config)、CLI 工作流与 ONNX 导出链路不变 - 保持除 batch 维外全静态 shape,面向树莓派 AI 扩展板(NPU)部署友好
- 直接替换旧架构(用户决策):删除 MLP/GRU 编码器与 concat 路径,旧 checkpoint 作废
二、新架构
F 帧图像 (F×3×64×64) ─► 共享 CNN 编码器 ─► F 个 token ─► proj → d_model ┐
├─► [img×F, act×H, PRED] + 位置编码
动作历史 (H×D) ─► Linear proj → d_model ─► H 个 token ──────────┤ │
可学习 [PRED] token ─────────────────────────────────────────────────┘ ▼
TransformerEncoder (pre-LN, 2 层, 4 头, d_model=128)
│
取 PRED 位置输出 ─► MLP 头 ─► 预测动作 (action_dim)
| 设计点 | 取值/说明 |
|---|---|
| token 序列 | [img×F, act×H, PRED],长度固定 F+H+1(默认 3+5+1=9) |
| 帧序约定 | 旧→新,末帧为当前帧;冷启动可重复传同一帧 |
| 注意力 | nn.TransformerEncoder,pre-LN(norm_first),dim_feedforward=2×d_model |
| 位置编码 | 可学习 pos_embed (1, F+H+1, d),trunc_normal 初始化 |
| 输出 | 取末位 PRED token 过 MLP 头(d → 128 → 64 → action_dim) |
| 静态性 | forward 中 reshape 仅 batch 维动态,其余编译期固定 |
| 参数量 | 409,042(旧架构 142,034,约 2.9 倍) |
新增配置参数
| 参数 | 默认值 | 校验范围 |
|---|---|---|
--frame-len |
3 | [1, 1024] |
--attn-dim |
128 | [1, 4096],且须能被 attn-heads 整除 |
--attn-heads |
4 | [1, 64] |
--attn-layers |
2 | [1, 64] |
删除参数:--history-encoder、--action-hidden-dim。
旧 checkpoint 因 config 含未知键(history_encoder/action_hidden_dim)在加载时被
parse_checkpoint_config 以明确 ValueError 拒载,符合"作废"预期(有专项测试覆盖)。
三、单元测试
$ python test_actpred.py
Ran 56 tests in 5.959s
OK
56 项测试全部通过(安装 onnxscript/onnxruntime 后无跳过项)。本次新增/改写用例:
| 用例 | 验证点 |
|---|---|
test_forward_multi_frame |
(2,3,3,64,64) + (2,5,18) → (2,18) |
test_forward_single_frame_degenerate |
frame_len=1 退化单帧仍正常前向 |
test_forward_dynamic_batch |
batch 1/4/8 动态(frame_len=2) |
test_custom_attn_config |
attn_dim=64/heads=2/layers=1 可构建前向 |
test_attn_dim_not_divisible_by_heads_raises |
130 % 4 ≠ 0 → ValueError |
test_dataset_loading |
多帧样本 shape (3,3,32,32),batch key 改为 images |
test_frame_len_gt_history_shifts_start |
采样起点 max(history_len, frame_len-1) 正确 |
test_legacy_checkpoint_config_rejected |
旧架构 checkpoint 拒载 |
test_wrong_frame_count_raises |
推理帧数不符 → ValueError |
test_end_to_end_predict 等推理用例 |
多帧输入端到端、归一化等价性、确定性 |
四、预训练测试
4.1 训练配置
| 参数 | 值 |
|---|---|
| 数据来源 | ../bot4cj/scripts/*.mt(13 文件) |
| train/val 划分 | 文件级(11 训练文件 / 2 验证文件,杜绝滑动窗口泄漏) |
| 输入 | 全零多帧图像 (B, 3, 3, 64, 64) + action_history (B, 5, 18) |
| 优化器/调度 | AdamW (lr=0.001, wd=1e-4) + CosineAnnealingLR |
| 数据增强 | Gaussian noise (std=1.0) |
| batch_size / epochs / patience | 8 / 200 / 30 |
| 随机种子 | 42 |
4.2 训练结果
| 指标 | 值 |
|---|---|
| 最终轮数 | 65(早停,patience=30) |
| 最优 val_loss | 2476.75 |
| 产出 | checkpoints/pretrain_best.pt(含 optimizer)、checkpoints/pretrain_best_inference.pt |
关于 val_loss 数值的说明:本次 2476.75 与前次报告的 190.58 不可直接对比—— 前次数值系样本级滑动窗口划分导致的数据泄漏虚低值(已在 0808 审计中定性); 本次为文件级划分(验证集是训练中完全未见过的动作脚本),且模型更大(409K vs 142K) 而数据仅 13 个脚本,属"诚实的困难任务"数值。注意力架构的真实收益需在真实图像数据 微调后评估。
五、推理链路验证
5.1 CLI 全链路
$ bash _run.sh --model checkpoints/pretrain_best_inference.pt \
--images /tmp/f0.jpg /tmp/f1.jpg /tmp/f2.jpg \
--action-history "45,0,...(5 步 × 18 值)"
18.3430 10.1614 17.3654 ... (18 维输出,数值有限)
✅ 3 帧 + 5 步历史全链路输出正常。
5.2 错误场景
$ ... --images /tmp/f0.jpg ...
--images 需传入 3 个路径(旧→新),实际为 1 个。冷启动时可重复传同一帧路径。
✅ 帧数不符时报错信息明确,含冷启动指引。
六、ONNX 导出验证
$ python export_onnx.py --model checkpoints/pretrain_best_inference.pt --output /tmp/actpred_attn.onnx
ONNX model exported to: /tmp/actpred_attn.onnx
ONNX 一致性验证通过(最大差异: 7.629395e-06)
| 项目 | 结果 |
|---|---|
| 导出 | ✅ 成功(opset 17,输入 images (batch,3,3,64,64) + action_history (batch,5,18)) |
| onnxruntime 一致性 | ✅ 最大差异 7.63e-06(< 1e-4 阈值) |
| 动态维 | 仅 batch,NPU 编译友好 |
注:本次为环境补装了 onnxscript 与 onnxruntime(torch ≥ 2.12 ONNX 导出依赖)。
七、CPU 推理性能基准
测试方法:warmup 20 次后测 200 次取平均,输入随机 3 帧 (64,64,3) uint8 + (5,18) float32。
| 环节 | 本次(注意力,3 帧) | 前次(concat,单帧) |
|---|---|---|
| 参数量 | 409,042 | 142,034 |
| 端到端推理(含预处理) | 4.25 ms (235 FPS) | 1.61 ms (622 FPS) |
| 纯前向 | 2.77 ms (360 FPS) | 1.09 ms (916 FPS) |
| image_encoder 占比 | 1.30 ms(47%,3 帧) | 0.82 ms(75%,1 帧) |
评估:
- 235 FPS 对 bot4cj 30 FPS 控制循环仍有 7.8 倍余量,实时性满足
- 延迟增长主因:CNN 由 1 帧变 3 帧(约 3×0.43ms)+ Transformer 编码器(约 1.5ms)
- image_encoder 占比由 75% 降至 47%,注意力部分成为新的次要热点; 部署到树莓派 AI 扩展板后两者均可被 NPU 加速(静态 shape 已保证)
八、结论与下一步
8.1 测试结论
| 测试项 | 结果 |
|---|---|
| 多帧注意力模型前向 | ✅ 通过(多帧/单帧退化/动态 batch/自定义 attn 配置) |
| 配置校验 | ✅ 通过(frame_len/attn_* 值域 + 整除校验 + 旧 checkpoint 拒载) |
| 多帧数据集采样 | ✅ 通过(采样起点与样本数断言) |
| 单元测试 | ✅ 56/56 通过 |
| 预训练 | ✅ 通过(65 epoch 早停,文件级划分无泄漏) |
| 推理 CLI | ✅ 通过(正常 + 错误场景) |
| ONNX 导出 | ✅ 通过(一致性 7.63e-06) |
| CPU 性能 | ✅ 通过(235 FPS,7.8 倍实时余量) |
8.2 已知局限
- 预训练图像分支未习得:全零多帧占位下 image_encoder 与图像 token 的注意力权重 无有效梯度信号,真实收益依赖后续真实图像微调
- 数据量极少:13 个 .mt 脚本对 409K 参数模型明显不足,val_loss 绝对值偏高属预期
- 旧 checkpoint 全部作废:已删除并重训预训练 checkpoint;如有外部持有旧
best_inference.pt需同步告知重训
8.3 下一步建议
- 采集真实多帧数据:用
DataRecorder录制 bot4cj 摄像头 episode,以本次预训练 checkpoint 为起点微调(勿开--normalize-actions) - 树莓派 AI 扩展板部署验证:将 ONNX 模型走扩展板厂商工具链编译,实测 NPU 延迟
- 帧数消融:真实数据到位后对比 frame_len=1/3/5 的验证误差,确认多帧收益
- 扩充 .mt 脚本:增加动作脚本数量,缓解预训练数据不足
附录:文件变更清单
| 文件 | 类型 | 说明 |
|---|---|---|
actpred/config.py |
修改 | 新增 frame_len/attn_*;删除 history_encoder/action_hidden_dim;整除校验 |
actpred/model.py |
重写 | 多帧 Transformer 注意力架构;删除 MLP/GRU 编码器与 concat 融合 |
actpred/dataset.py |
修改 | 多帧窗口采样;batch key image → images |
actpred/train.py |
修改 | 多帧适配(frame_len 透传、batch key) |
actpred/pretrain_mt.py |
修改 | 全零多帧占位;打印信息更新 |
actpred/predict.py |
修改 | predict(images, history) 多帧 API;CLI --image → --images |
actpred/export_onnx.py |
修改 | 多帧 dummy 输入;input_names 更新 |
actpred/test_actpred.py |
修改 | 56 项用例(新增多帧/校验/拒载/帧数错误等) |
actpred/README.md |
修改 | 架构图、CLI 示例、配置表、API 文档同步 |
actpred/checkpoints/pretrain_best*.pt |
重新生成 | 旧架构 checkpoint 已删除并重训 |