fix(pybot×actpred): v3 审计 P2 清零——验收链 fixed_range + 导出断言 + overrun 节流
- v3-P2-1: _npu_test/_onnx_validate 按 normalize_mode 分支(fixed_range 免 stats, HailoPredictor 透传模式,torch 参考同口径反归一化) - v3-P2-2: export_deploy/export_onnx 一致性 diff 超 1e-4 即 sys.exit(P2-f 闭环) - v3-P2-3: run_loop overrun 告警节流(第1次+每100次),降 hz 建议仅 >10% 输出 - P2-a1: default_column_weights 扩展列(action_dim>18)默认 1.0 - P2-c: 补 predictor 异常清理路径测试(异常传播 + finally 落盘) - P2-d/P2-e: Resize 口径与 resume scheduler T_max 语义文档化 - R2-4: _set.sh 安装后断言 CPU 版 torch,误装 CUDA 即拦截 测试: pybot 89 passed (+1)、actpred 148 passed/18 skipped
This commit is contained in:
1 parent
ad3a624b4c
commit
9179281420
13 files changed
+161
-54
No files matched your search
+15
-6
@@ -308,9 +308,13 @@ class RobotStruct:
|
||||
time.sleep(remain)
|
||||
else:
|
||||
overrun += 1
|
||||
log.warning("loop overrun: step %d took %.1fms > %.1fms "
|
||||
"(推理+执行超过周期,实际频率已低于 %.1fHz)",
|
||||
step, (dt - remain) * 1000, dt * 1000, hz)
|
||||
# 告警节流:第 1 次及每 100 次汇总一次,避免持续 overrun
|
||||
# 刷屏(50% overrun @10Hz 时原实现每秒 5 条告警)
|
||||
if overrun == 1 or overrun % 100 == 0:
|
||||
log.warning("loop overrun ×%d: step %d took %.1fms > "
|
||||
"%.1fms(推理+执行超过周期)",
|
||||
overrun, step, (dt - remain) * 1000,
|
||||
dt * 1000)
|
||||
finally:
|
||||
# max_steps 正常退出与 Ctrl-C(KeyboardInterrupt)都要落盘,
|
||||
# 否则闭环录制的 actions.npy/imu.npy 全部丢失
|
||||
@@ -318,9 +322,14 @@ class RobotStruct:
|
||||
path = recorder.flush()
|
||||
log.info("episode saved: %s", path)
|
||||
if overrun:
|
||||
log.warning("closed loop overrun %d/%d steps (%.0f%%),"
|
||||
"建议降低 --hz 或检查推理后端延迟",
|
||||
overrun, step, 100.0 * overrun / max(step, 1))
|
||||
ratio = overrun / max(step, 1)
|
||||
if ratio > 0.10: # 工程约束:overrun 比例 >10% 才建议降 hz
|
||||
log.warning("closed loop overrun %d/%d steps (%.0f%%),"
|
||||
"建议降低 --hz 或检查推理后端延迟",
|
||||
overrun, step, 100.0 * ratio)
|
||||
else:
|
||||
log.info("closed loop overrun %d/%d steps (%.1f%%)",
|
||||
overrun, step, 100.0 * ratio)
|
||||
log.info("closed loop stop after %d steps", step)
|
||||
|
||||
def _loop_recent_frames(self, camera_var, F):
|
||||
|
||||
@@ -489,3 +489,27 @@ def test_robot_importable_without_numpy():
|
||||
r = subprocess.run([sys.executable, "-c", child],
|
||||
capture_output=True, text=True, cwd=repo)
|
||||
assert r.returncode == 0 and "ok" in r.stdout, r.stderr
|
||||
|
||||
|
||||
def test_predictor_exception_still_flushes_recorder(mock_i2c, tmp_path):
|
||||
"""P2-c:predictor 中途抛异常时 run_loop 的 finally 仍落盘,
|
||||
已录制 steps 不丢失且异常照常向上传播(由 with robot 清理硬件)"""
|
||||
from pybot.recorder import EpisodeRecorder
|
||||
|
||||
class RaisingPredictor(MockPredictor):
|
||||
def predict(self, images, action_history):
|
||||
if self._step >= 1:
|
||||
raise RuntimeError("backend boom")
|
||||
return super().predict(images, action_history)
|
||||
|
||||
robot = _make_robot(LOOP_MT, mock_i2c)
|
||||
robot.active()
|
||||
pred = RaisingPredictor(frame_len=3, history_len=2, action_dim=4)
|
||||
rec = EpisodeRecorder(str(tmp_path), action_dim=4)
|
||||
with pytest.raises(RuntimeError, match="backend boom"):
|
||||
robot.run_loop(pred, hz=1000.0, max_steps=5, recorder=rec)
|
||||
robot.deactive()
|
||||
|
||||
# 第 1 步已录制(第 2 步 predict 抛异常),finally flush 已落盘
|
||||
acts = np.load(tmp_path / "episode_0000" / "actions.npy")
|
||||
assert acts.shape[0] == 1
|
||||
Reference in new issue
Block a user