- 第 1 轮安全审计修复: F-1~F-10(路径校验、预训练架构修正等) - 第 2 轮复审修复 11 项: 3 项上轮修复不完整(R01 checkpoint 键校验/ R02 fused_hidden_dim 值域/R03 pretrained=False)+ 8 项新问题 (actions.npy 形状校验、帧数警告、CLI 值域校验、stats 形状与路径、 onnxscript 依赖、归一化语义、解析去重) - 单元测试由 17 扩展至 51 用例(50 通过 + 1 环境性跳过) - 审计文档两轮合并至 actpred_CODE_AUDIT_20260808.md,更新 INDEX
27 KiB
actpred 模块代码审计报告(第 1 轮 + 第 2 轮复审)
审查日期:2026-08-08 (Asia/Shanghai) 审查人:Automated Review 审查范围:
actpred/全模块(Python,PyTorch 动作预测神经网络)文档合并说明:本文档为两轮审计的合并版——第 1 轮(16 项发现,全部修复)见 §二~§七; 第 2 轮复审(11 项发现,含 3 项上轮修复不完整,全部修复)见 §八。
一、模块概述
| 属性 | 值 |
|---|---|
| 定位 | 机器人动作预测(图像 + 历史动作 → 下一步动作回归) |
| 语言 | Python 3 |
| 框架 | PyTorch ≥ 2.0 |
| 架构 | CNN/MobileNetV2 图像编码 + MLP/GRU 动作历史编码 + 融合头 |
| 参数量 | ~140K(simple CNN)至 ~2.3M(MobileNetV2) |
| 入口 | _run.sh(train / export / predict 子命令分发) |
依赖项
| 库 | 用途 | 版本要求 |
|---|---|---|
| torch | 神经网络训练/推理 | ≥ 2.0 |
| torchvision | MobileNetV2 预训练模型、图像变换 | ≥ 0.15 |
| numpy | 动作向量运算、归一化统计 | ≥ 1.24 |
| Pillow | 图像加载 | ≥ 9.0 |
| tqdm | 训练进度条 | ≥ 4.60 |
目录结构
actpred/
├── config.py # 三组 dataclass 配置 + CLI 参数解析 + 覆盖逻辑
├── model.py # ActionPredictor 主模型(编码器 + 融合头)
├── dataset.py # ActionDataset 数据集 + DataRecorder 数据采集器
├── train.py # 训练主流程(episode 级划分、早停、余弦退火)
├── predict.py # ActionPredictorInference 推理类 + CLI
├── export_onnx.py # ONNX 导出(opset 17,动态 batch)
├── _run.sh # 运行脚本(train/export/predict 分发)
├── _set.sh # 环境安装脚本
├── requirements.txt # 依赖声明
└── README.md # 模块文档
二、审查发现
🔴 严重问题 (P0)
[ACT-S01] Episode 索引错位:split_episodes 与 __init__ 过滤条件不一致(已修复 ✅)
- 文件:
dataset.py:26vsdataset.py:77-85 - 描述:
split_episodes基于get_episode_count→_valid_episode_dirs计算有效 episode 数量(同时检查actions.npy存在且images/为目录),生成的索引范围为[0, valid_count)。但ActionDataset.__init__收集的是所有子目录(仅检查d.is_dir()),再用episode_indices索引。两处过滤条件不一致,当 data_dir 中存在无效 episode 目录(如录制中断、缺少actions.npy)时,索引指向错误的 episode。
代码注释 # 与 __init__ 的过滤条件保持一致 声明了一致性,但实际实现并不一致:
# __init__ — 仅检查 is_dir(),包含无效目录
episodes = sorted([d for d in data_path.iterdir() if d.is_dir()])
if episode_indices is not None:
episodes = [episodes[i] for i in episode_indices] # 索引可能指向无效目录
# _valid_episode_dirs — 额外检查 actions.npy 和 images/
return sorted([d for d in data_path.iterdir()
if d.is_dir() and (d / "actions.npy").exists() and (d / "images").is_dir()])
- 触发条件: data_dir 中存在不含
actions.npy或images/的子目录(如 DataRecorder 创建目录后未调用flush()即中断) - 影响: 训练集/验证集划分错位——验证集可能选中无效 episode(0 样本),有效 episode 被遗漏。模型选择基于错误的验证集,保存的"最优"模型并非真正最优
- 修复建议:
__init__改用_valid_episode_dirs收集目录:
episodes = ActionDataset._valid_episode_dirs(data_dir)
if episode_indices is not None:
episodes = [episodes[i] for i in episode_indices]
[ACT-S02] 推理归一化静默失败(已修复 ✅)
- 文件:
predict.py:34-43 - 描述:
ActionPredictorInference.__init__通过尝试加载action_stats.npy来决定是否进行归一化,但不检查 checkpoint 中config.normalize_actions的值。如果模型训练时启用了normalize_actions=True但推理时 stats 文件缺失,归一化被静默跳过,预测结果完全错误(输出仍在归一化空间中),且无任何警告。
# 当前:仅靠文件是否存在决定是否归一化,不检查 config
try:
stats = np.load(stats_path)
self._action_mean = stats[0]
self._action_std = stats[1]
except (FileNotFoundError, ValueError):
pass # 静默失败——模型训练时用了归一化,但推理时没归一化
- 影响: 部署时遗漏
action_stats.npy文件 → 预测值无意义且无报错,这是最危险的部署陷阱 - 修复建议: 检查 config 中的
normalize_actions标志,若为 True 但 stats 文件不存在则报错:
if self._data_cfg.normalize_actions:
if not os.path.exists(stats_path):
raise FileNotFoundError(
f"模型训练时启用了动作归一化,但未找到统计文件: {stats_path}")
stats = np.load(stats_path)
self._action_mean = stats[0]
self._action_std = stats[1]
🟡 中等问题 (P1)
[ACT-S03] 空训练集无校验,train_loss=0.0 误导用户(已修复 ✅)
-
文件:
train.py:82-128 -
描述: 当 data_dir 无有效 episode 或 split 后训练集为空时,
train_one_epoch循环执行 0 次,返回total_loss / max(count, 1) = 0.0 / 1 = 0.0。训练日志显示train_loss=0.000000,看似完美。且空验证集有 WARNING(第 98-100 行),但空训练集没有任何警告。未训练的模型可能被保存为best_inference.pt。 -
触发条件:
data_dir无有效 episode;或仅 1 个 episode 且val_split > 0(split 后训练集为空) -
影响: 用户误以为训练成功,部署未训练模型
-
修复建议:
if len(train_ds) == 0:
raise ValueError(f"训练集为空(0 样本)。请检查 data_dir={cfg.data.data_dir} "
f"及 episode 数据完整性。")
[ACT-S04] 图像文件名字符串排序问题(已修复 ✅)
- 文件:
dataset.py:38-39 - 描述: 图像文件按
p.name(文件名字符串)排序。对于 DataRecorder 生成的%04d.jpg格式(如 "0001.jpg")排序正确。但若用户导入的外部数据无前导零(如 "1.jpg", "2.jpg", ..., "10.jpg"),字符串排序结果为 "1.jpg" < "10.jpg" < "2.jpg",导致图像与动作序列错位。
image_files = sorted(list(images_dir.glob("*.jpg")) + list(images_dir.glob("*.png")),
key=lambda p: p.name) # 字符串排序,无前导零时乱序
- 影响: 外部数据图像-动作对齐错乱,训练学到错误的映射
- 修复建议: 使用自然排序:
import re
def natural_key(p):
return [int(t) if t.isdigit() else t for t in re.split(r'(\d+)', p.name)]
image_files = sorted(..., key=natural_key)
[ACT-S05] 空样本列表导致 np.stack 崩溃(已修复 ✅)
- 文件:
dataset.py:53 - 描述: 当
normalize_actions=True且未提供action_stats_path时,代码从self.samples计算归一化统计量。若 samples 为空(episode 过短或无有效数据),np.stack([])抛出ValueError: need at least one array to stack,无友好错误信息。
all_actions = np.stack([s[2] for s in self.samples]) # 空列表 → 崩溃
- 修复建议:
if not self.samples:
raise ValueError(f"数据集为空,无法计算归一化统计量。"
f"请检查 data_dir={data_dir} 中的 episode 数据。")
[ACT-S06] 编程 API 未校验 action_history 形状(已修复 ✅)
-
文件:
predict.py:46-56 -
描述:
ActionPredictorInference.predict()接受任意np.ndarray作为action_history,不校验形状是否为(history_len, action_dim)。形状不匹配时,错误来自 PyTorch 内部,信息不明确。 -
影响: 用户传入错误形状的历史动作,得到不明确的报错或静默错误结果
-
修复建议:
expected_shape = (self._data_cfg.history_len, self._data_cfg.action_dim)
if action_history.shape != expected_shape:
raise ValueError(
f"action_history 形状应为 {expected_shape},实际为 {action_history.shape}")
[ACT-S07] MobileNetV2 预训练权重在线下载依赖(已修复 ✅)
-
文件:
model.py:32-33 -
描述:
MobileNetEncoder使用MobileNet_V2_Weights.DEFAULT,首次使用时从 PyTorch 服务器下载预训练权重(~14MB)。在离线环境或受限网络中会失败,且无预下载机制或离线回退。 -
影响: 离线/受限网络环境无法使用 MobileNet backbone
-
修复建议: 1) 文档说明预下载方式 2) 支持
TORCH_HOME环境变量预置权重 3) 提供本地权重路径参数
[ACT-S08] 指定 action_stats_path 但文件不存在时验证集统计量独立计算(已修复 ✅)
-
文件:
dataset.py:48-55,train.py:86-91 -
描述: 当用户通过 CLI 指定
--action-stats-path但文件不存在时,dataset.py:48的os.path.exists检查会 fallback 到从当前数据集自身计算统计量。而train.py的if cfg.data.normalize_actions and not cfg.data.action_stats_path条件为 False(path 已被指定),不会触发保存-复用逻辑。结果:训练集和验证集各自独立计算归一化统计量,验证集的归一化空间与训练集不同,val loss 不可信。 -
影响: 模型选择基于不可信的 val loss,可能保存非最优模型
-
修复建议: 指定了
action_stats_path但文件不存在时应报错,而非静默 fallback:
if action_stats_path:
if not os.path.exists(action_stats_path):
raise FileNotFoundError(f"指定的 action_stats_path 不存在: {action_stats_path}")
🟢 轻微问题 (P2)
[ACT-Q01] README 推理示例格式错误(已修复 ✅)
- 文件:
README.md:28 - 描述: 推理示例的
--action-history值"45,0,45,0,45,0,45,0,45,10,45,10,45,10,45,10"未使用冒号分隔步骤,且值数量与默认action_dim=8不匹配。正确格式应为冒号分隔的多步骤,如"45,0,45,0,45,0,45,0:..."(共history_len=5步,每步action_dim=8个值)。
[ACT-Q02] predict.py 访问私有属性(已修复 ✅)
- 文件:
predict.py:83 - 描述:
main()中predictor._data_cfg.action_dim直接访问实例私有属性。应提供公共属性或方法。
[ACT-Q03] DataRecorder episode 索引 O(n) 遍历(已修复 ✅)
- 文件:
dataset.py:94-96 - 描述:
DataRecorder.__init__使用 while 循环逐个检查 episode 目录是否存在,O(n) 次 stat 调用。episode 数量大时效率低。
[ACT-Q04] requirements.txt 无版本上限(已修复 ✅)
- 文件:
requirements.txt - 描述: 所有依赖使用
>=无上界,不同环境安装不同大版本可能导致行为差异。
[ACT-Q05] 无单元测试(已修复 ✅)
- 文件: 全局
- 描述: 模块无任何测试代码。数据加载、归一化、模型前向、ONNX 导出等关键路径完全依赖手工验证。
[ACT-Q06] _set.sh 固定安装 CPU-only PyTorch(已修复 ✅)
- 文件:
_set.sh:7 - 描述:
pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu始终安装 CPU 版本,有 GPU 的环境无法利用。未在 README 说明 GPU 安装替代方案。
[ACT-Q07] CLI --normalize-actions 无法显式关闭(已修复 ✅)
- 文件:
config.py:64 - 描述:
action="store_true"+default=None设计使得该参数只能设为 True 或使用默认值,无法通过 CLI 显式设为 False。当配置文件中normalize_actions=True时,CLI 无法覆盖关闭。
[ACT-Q08] ONNX 导出无运行时验证(已修复 ✅)
- 文件:
export_onnx.py - 描述: 导出 ONNX 后仅打印路径,不验证导出模型能否正确加载和推理。建议用
onnxruntime做一致性检查。
三、统计汇总
| 等级 | 数量 | 问题 ID | 状态 |
|---|---|---|---|
| 🔴 Critical | 2 | S01, S02 | 全部修复 ✅ |
| 🟡 Medium | 6 | S03-S08 | 全部修复 ✅ |
| 🟢 Low | 8 | Q01-Q08 | 全部修复 ✅ |
| 合计 | 16 | 全部修复 ✅ |
按类别统计
| 类别 | 问题数 | 占比 |
|---|---|---|
| 数据正确性(索引错位、归一化) | 3 | 19% |
| 输入校验(形状、空集、路径) | 4 | 25% |
| 可靠性(崩溃、静默失败) | 3 | 19% |
| 环境/部署(下载依赖、CPU-only) | 2 | 12% |
| 代码质量/文档 | 4 | 25% |
四、修复优先级建议
第一阶段(紧急) ✅ 已完成
- ACT-S01: 修复 episode 索引错位——
__init__改用_valid_episode_dirs - ACT-S02: 推理归一化检查——读取
config.normalize_actions,缺失 stats 文件时报错
第二阶段(重要) ✅ 已完成
- ACT-S03: 空训练集校验——添加
len(train_ds) == 0检查并报错 - ACT-S05: 空样本列表防御——计算统计量前检查 samples 非空
- ACT-S06: 编程 API 形状校验——
predict()入口校验 action_history 形状 - ACT-S08: 指定 stats 路径不存在时报错,而非静默 fallback
第三阶段(优化) ✅ 已完成
- ACT-S04: 自然排序图像文件名
- ACT-S07: MobileNet 权重下载失败时给出明确的预下载指引
- ACT-Q01-Q08: 文档修正、代码质量优化、单元测试、版本约束等
五、亮点
| 亮点 | 说明 |
|---|---|
| Episode 级 train/val 划分 | 按完整 episode 划分而非随机样本,避免相邻帧数据泄露 |
| 归一化统计量隔离 | 训练集计算 stats → 保存 → 验证集复用,避免验证集信息泄露 |
| 安全 checkpoint 加载 | weights_only=True 防止反序列化攻击 |
| 双 checkpoint 策略 | best.pt(含 optimizer,可恢复训练)+ best_inference.pt(仅权重+config,用于部署) |
| 空验证集保底处理 | validate() 返回 inf,best_val_loss 不被更新,训练结束保底保存最终权重 |
| 梯度裁剪 + 余弦退火 | max_grad_norm + CosineAnnealingLR,训练稳定性有保障 |
| 全局可复现 | random/numpy/torch/DataLoader generator 全部设种子 |
| 懒加载 MobileNet 依赖 | import 在 __init__ 内,不强制要求 torchvision 预训练模块 |
六、修复总结
修复时间:2026-08-08 全部 16 项问题已于审查当日修复完毕,17 项单元测试全部通过。
修改文件清单
| 文件 | 修复项 | 说明 |
|---|---|---|
dataset.py |
S01, S04, S05, S08, Q03 | episode 索引一致性、自然排序、空集防御、stats 路径校验、glob 优化 |
predict.py |
S02, S06, Q02 | 归一化检查、形状校验、公共属性 |
train.py |
S03 | 空训练集校验 |
model.py |
S07 | MobileNet 下载错误提示 |
config.py |
Q07 | BooleanOptionalAction 双向开关 |
export_onnx.py |
Q08 | ONNX 一致性验证 |
requirements.txt |
Q04 | 版本上限约束 |
_set.sh |
Q06 | GPU 安装说明 |
README.md |
Q01 | 推理示例修正 |
test_actpred.py |
Q05 | 新建,17 项单元测试 |
测试结果
Ran 17 tests in 0.070s
OK
测试覆盖:自然排序、动作历史解析、模型前向传播(MLP/GRU/动态 batch)、数据录制、数据集加载(含空集/无效路径报错)、配置与 CLI 参数。
七、附录
审查工具
- 人工静态分析
- 代码路径追踪
- 边界条件推演
参考文档
审查人
- 自动化审计助手
- 审查时间:2026-08-08
本报告由自动化代码审计生成,供开发团队参考。修复建议需结合实际场景评估。
八、第 2 轮复审(2026-08-08)
前置文档:第 1 轮安全审计(10 项发现,全部标记已修复 ✅)
8.1 复审方法
本轮采用静态通读 + 动态验证:除逐文件复查全部源码外,对疑点编写了针对性复现脚本(checkpoint 畸形 config、值域校验边界、数据形状不匹配、CLI 越界参数等),所有结论均以实测输出为准,不采信审计文档的"已修复"标记。
实测环境:Intel Xeon E3-1200 v2, Linux 24.04, PyTorch CPU-only。第 1 轮审计后测试已扩展至 39 用例(38 通过 + 1 环境性跳过)。
8.2 复审结论摘要
| 类别 | 数量 | 说明 |
|---|---|---|
| A 类:上轮"已修复"标记与实现不符(修复不完整/未覆盖) | 3 | ACT-R01 ~ ACT-R03,均涉及安全审计 F-3 / F-8 的修复遗漏 |
| B 类:新发现问题 | 8 | ACT-R04 ~ ACT-R11,数据校验、CLI 校验、部署约定、文档缺口 |
| 合计 | 11 | 无 P0/P1,全部为 P3 级;安全评级维持 B+;全部已修复 ✅ |
模块仍为离线 CLI 工具(不监听端口、不联网、输入均来自本机可信路径),无远程可利用漏洞。本轮问题集中在输入健壮性、修复覆盖完整性、部署约定文档化。
8.3 A 类:上轮修复项复审(3 项)
[ACT-R01] checkpoint config 多余键仍抛裸 TypeError(F-8 声称已修复,实际未修复)🟡 P3 ✅ 已修复
- 位置:
predict.py、export_onnx.py(DataConfig(**cfg_dict["data"])/ModelConfig(**cfg_dict["model"])) - 上轮声明: 安全审计 F-8 描述为"多余键触发裸 TypeError",修复项为新增
validate_config_values(),结论"已修复 ✅" - 实测: 向 checkpoint config 的
data段注入未知键evil_extra_key,加载时抛TypeError: DataConfig.__init__() got an unexpected keyword argument 'evil_extra_key'。validate_config_values在DataConfig(**...)之后才被调用,未知键在构造阶段即崩溃,校验函数根本无法执行。 - 影响: 畸形/损坏 checkpoint(或未来 config 结构演进产生的多余键)报错信息不含文件名与上下文;上轮"已修复"结论与实现不符。
- 修复: 新增
parse_checkpoint_config(),构造前校验键集合,未知键/缺段/非 dict 抛带键名的 ValueError。
[ACT-R02] validate_config_values 遗漏 fused_hidden_dim,恶意 checkpoint 可致 OOM(F-8 修复不完整)🟡 P3 ✅ 已修复
- 位置:
config.py - 实测: 设
model.fused_hidden_dim = 10**9,validate_config_values通过;构造ActionPredictor时FusionHead分配内存抛RuntimeError ... DefaultCPUAllocator: can't allocate。另有dropout(可 <0 或 >1)也未被校验。 - 影响: 与 F-8 防护目标(恶意/损坏 checkpoint 防内存耗尽)直接冲突——攻击面同类、防护漏了
fused_hidden_dim。 - 修复: 校验表补充
fused_hidden_dim ∈ [1, 4096]、dropout ∈ [0, 1],并扩展 train 字段校验(lr/val_split/batch_size/epochs/patience/num_workers/max_grad_norm/weight_decay)。
[ACT-R03] pretrain_mt.py 未传 pretrained=False,mobilenet 离线预训练仍失败(F-3 修复不完整)🟡 P3 ✅ 已修复
- 位置:
pretrain_mt.py - 实测:
model = ActionPredictor(cfg.model, cfg.data)未传pretrained=False。--backbone mobilenet时构造即尝试下载 ImageNet 权重(~14MB):① 离线/受限网络环境下预训练直接RuntimeError;② 零图像预训练会用load_state_dict全程覆盖这些权重,下载纯属浪费。 - 影响: F-3 的修复只覆盖了"推理/导出"两个入口,遗漏了第三个模型构造入口(预训练)。当前默认 backbone=simple 未触发,属潜伏问题。
- 修复: 构造模型传
pretrained=False。
8.4 B 类:新发现问题(8 项)
[ACT-R04] ActionDataset 不校验 actions.npy 列数与 action_dim 一致性 🟡 P3 ✅ 已修复
- 位置:
dataset.py - 实测: 构造 6 列
actions.npy配action_dim=4,数据集加载成功,样本action_history形状 (3, 6);直到训练DataLoadercollate 阶段才因形状不一致报错,错误远离数据源头且信息不友好。 - 修复: 加载后校验
actions.ndim == 2 and actions.shape[1] == action_dim,否则抛带 episode 路径的 ValueError。
[ACT-R05] 图像/动作帧数不匹配时静默截断,无任何警告 🟡 P3 ✅ 已修复
- 位置:
dataset.py(n = min(n_frames, n_images)) - 实测: 12 帧动作 + 8 张图像,数据集静默按 8 帧使用,尾部 4 帧动作被丢弃且无提示。
- 修复:
n_frames != n_images时打印 WARNING(含 episode 路径与数量)。
[ACT-R06] 训练 CLI 参数无值域校验,越界值静默接受 🟡 P3 ✅ 已修复
- 位置:
config.py(apply_overrides)、train.py - 实测:
--history-len 0、--val-split 2.0、--lr -1全部静默接受并进入训练:history_len=0产生空 history 样本;val_split=2.0验证集吞掉全部 episode;lr=-1loss 发散。 - 对比:
validate_config_values()只被推理/导出路径调用,训练 CLI 完全不校验——同一份参数两套待遇。 - 修复: train.py / pretrain_mt.py 在
apply_overrides后调用validate_config_values(cfg.data, cfg.model, cfg.train)。
[ACT-R07] predict.py 加载 action_stats.npy 不校验形状 🟡 P3 ✅ 已修复
- 位置:
predict.py - 实测:
action_stats.npy形状错误(如 (2, 7) 配 action_dim=4)时加载成功,推理阶段抛难以定位的广播错误ValueError: operands could not be broadcast together with shapes (3,4) (7,)。 - 修复: 加载后校验
stats.shape == (2, action_dim),并强制转 float32(兼容 float64 stats)。
[ACT-R08] 推理端硬编码 stats 路径约定,config 中 action_stats_path 为死字段 🟡 P3 ✅ 已修复
- 位置:
predict.pyvstrain.py、config.py - 描述: 训练时
action_stats_path被写入 checkpoint config;但推理端从不读取该字段,硬编码从 checkpoint 同目录找action_stats.npy。部署约定(stats 必须与 checkpoint 同目录、同名)未在任何文档说明。 - 修复: 推理端优先解析 config 记录的
action_stats_path(相对路径按 checkpoint 目录解析),旧 checkpoint 回退同目录约定;README 新增「部署注意」章节。
[ACT-R09] README 未说明 ONNX 导出硬依赖 onnxscript,按文档执行直接失败 🟡 P3 ✅ 已修复
- 位置:
README.md、export_onnx.py、_set.sh - 实测: 当前 venv(torch 2.13)执行
bash _run.sh export抛ModuleNotFoundError: No module named 'onnxscript'——torch ≥2.12 的torch.onnx.export走 dynamo 路径,onnxscript 为硬依赖。 - 修复:
_set.sh增加 onnxscript/onnxruntime 安装;README 补充依赖说明。
[ACT-R10] 预训练-微调归一化语义不匹配(方法论)🟡 P3 ✅ 已修复
- 位置:
pretrain_mt.py(全程无归一化)vstrain.py(--normalize-actions支持) - 描述: 预训练始终在非归一化动作空间训练;若微调时开启
--normalize-actions,--init-from加载的预训练权重将在归一化空间继续训练,输入分布突变。 - 修复: README 微调示例注明「预训练权重搭配非归一化微调使用」。
[ACT-R11] MTActionDataset 命名误导 + parse_mt_directory 重复解析 3 次 🟡 P3 ✅ 已修复
- 位置:
pretrain_mt.py(n_rows = matrix.shape[1]实为列数) - 描述: ① 变量名
n_rows取自shape[1](列数),与直觉相反,易在后续维护中引入行列颠倒 bug;②main()先parse_mt_directory一次做文件级划分,train_ds / val_ds 构造时又各解析一次全部文件,同一目录共解析 3 次。 - 修复: 改名
n_cols;MTActionDataset新增files参数复用预解析结果,解析次数 3 次 → 1 次。
8.5 测试覆盖缺口(复审确认)
复审时 test_actpred.py 39 用例,以下路径无覆盖:checkpoint config 异常结构(多余键/缺段)、validate_config_values 的 model/train 字段、ActionDataset 归一化正常路径、actions.npy 列数不匹配/帧数不匹配、split_episodes 边界、train.py/pretrain_mt.py 的 main() 端到端、stats 形状错误。
8.6 修复记录(全部 ✅)
修复时间:2026-08-08(复审当日) 全部 11 项问题已修复并验证,单元测试由 39 用例扩展至 51 用例(50 通过 + 1 环境性跳过)。
| 问题 | 修复内容 | 文件 |
|---|---|---|
| ACT-R01 | 新增 parse_checkpoint_config():校验 config 键集合,未知键/缺段/非 dict 抛带键名的 ValueError |
config.py、predict.py、export_onnx.py |
| ACT-R02 | 校验表补充 fused_hidden_dim ∈ [1,4096]、dropout ∈ [0,1],并扩展 train 字段校验 |
config.py |
| ACT-R03 | pretrain_mt.py 构造模型传 pretrained=False,消除零图像预训练的无谓下载与离线失败 |
pretrain_mt.py |
| ACT-R04 | actions.npy 加载后校验 ndim==2 且 shape[1]==action_dim,否则抛带 episode 路径的 ValueError |
dataset.py |
| ACT-R05 | 帧数不匹配打印 WARNING(含 episode 路径与数量) | dataset.py |
| ACT-R06 | train.py / pretrain_mt.py 在 apply_overrides 后调用 validate_config_values(cfg.data, cfg.model, cfg.train) |
train.py、pretrain_mt.py |
| ACT-R07 | stats 加载后校验形状 (2, action_dim),并强制转 float32(兼容 float64 stats) |
predict.py |
| ACT-R08 | 推理端优先解析 checkpoint config 记录的 action_stats_path(相对路径按 checkpoint 目录解析),旧 checkpoint 回退同目录约定;README 新增「部署注意」 |
predict.py、README.md |
| ACT-R09 | _set.sh 增加 onnxscript/onnxruntime 安装;README 补充依赖说明 |
_set.sh、README.md |
| ACT-R10 | README 微调示例注明「预训练权重搭配非归一化微调使用」 | README.md |
| ACT-R11 | n_rows 改名 n_cols;MTActionDataset 新增 files 参数复用预解析结果,解析次数 3 次 → 1 次 |
pretrain_mt.py |
8.7 验证记录
- 全部 51 项单元测试通过(
Ran 51 tests ... OK (skipped=1)) - 复现脚本确认:多余键 → ValueError(含键名);fused_hidden_dim=10⁹ → 加载期拦截(不再 OOM);stats 形状错误 → ValueError(含路径与期望形状);
--lr -1→ CLI 拦截 - 预训练端到端(3 个 .mt、3 epochs)正常,空验证集保底保存路径正确
- 推理端 stats 双路径(config 相对路径 / 同目录回退)均验证通过
- 上轮声称的亮点机制(weights_only、文件级划分、stats 隔离、保底保存等)经复查均属实
本文档为两轮审计合并版:第 1 轮(§二~§七)+ 第 2 轮复审(§八),全部 27 项发现均已修复,修复项均经回归验证。