Files
blackbird/docs/reports/actpred_attention_rewrite_test_20260809.md
T

9.8 KiB
Raw Blame History

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 融合",仅支持单帧图像输入。 本次改造目标:

  1. 引入注意力机制,支持多帧图像 + 历史动作序列联合建模,预测下一时间步动作
  2. 保持 checkpoint 格式(model_state_dict + config)、CLI 工作流与 ONNX 导出链路不变
  3. 保持除 batch 维外全静态 shape,面向树莓派 AI 扩展板(NPU)部署友好
  4. 直接替换旧架构(用户决策):删除 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 已知局限

  1. 预训练图像分支未习得:全零多帧占位下 image_encoder 与图像 token 的注意力权重 无有效梯度信号,真实收益依赖后续真实图像微调
  2. 数据量极少:13 个 .mt 脚本对 409K 参数模型明显不足,val_loss 绝对值偏高属预期
  3. 旧 checkpoint 全部作废:已删除并重训预训练 checkpoint;如有外部持有旧 best_inference.pt 需同步告知重训

8.3 下一步建议

  1. 采集真实多帧数据:用 DataRecorder 录制 bot4cj 摄像头 episode,以本次预训练 checkpoint 为起点微调(勿开 --normalize-actions)
  2. 树莓派 AI 扩展板部署验证:将 ONNX 模型走扩展板厂商工具链编译,实测 NPU 延迟
  3. 帧数消融:真实数据到位后对比 frame_len=1/3/5 的验证误差,确认多帧收益
  4. 扩充 .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 已删除并重训