{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": "# 03 ACT 在 ROCm 上的迁移与 DAgger 诊断\n\n        这一节用 ACT 说明：训练 loss 下降不等于闭环 rollout 成功。先看诊断曲线，再把数据回放、open-loop、closed-loop、失败视频和 DAgger 串成一条排障链路。\n"
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": "from pathlib import Path\nimport json\nimport os\nimport shutil\nimport subprocess\nimport sys\n\n\ndef find_topic_root():\n    cwd = Path.cwd().resolve()\n    for candidate in [cwd, *cwd.parents]:\n        if (candidate / \"assets\" / \"metrics_snapshot.json\").exists():\n            return candidate\n    raise RuntimeError(\"请从 AMD ROCm 专题目录或 notebooks 子目录启动 Jupyter。\")\n\n\nTOPIC_ROOT = find_topic_root()\nASSET_DIR = TOPIC_ROOT / \"assets\"\nNOTEBOOK_DIR = TOPIC_ROOT / \"notebooks\"\nPROJECT_ROOT = Path(os.environ.get(\"PROJECT_ROOT\", \"/path/to/every-embodied/mujoco_pnp\"))\nDATA_ROOT = Path(os.environ.get(\"DATA_ROOT\", \"/path/to/datasets/every_embodied\"))\nOUTPUT_ROOT = Path(os.environ.get(\"OUTPUT_ROOT\", TOPIC_ROOT / \"outputs\"))\nMODEL_ROOT = Path(os.environ.get(\"MODEL_ROOT\", PROJECT_ROOT / \"ckpt\"))\n\nprint(\"TOPIC_ROOT =\", TOPIC_ROOT)\nprint(\"PROJECT_ROOT =\", PROJECT_ROOT)\nprint(\"DATA_ROOT =\", DATA_ROOT)\nprint(\"OUTPUT_ROOT =\", OUTPUT_ROOT)\nprint(\"MODEL_ROOT =\", MODEL_ROOT)\n"
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": "try:\n    from IPython.display import Image, Markdown, display\nexcept Exception:\n    class Markdown(str):\n        pass\n\n    def display(obj):\n        print(obj)\n\n    def Image(filename=None, width=None):\n        return f\"[image] {filename}\"\n\n\ndef show_asset(filename, width=960):\n    path = ASSET_DIR / filename\n    if path.exists():\n        display(Image(filename=str(path), width=width))\n    else:\n        print(f\"缺少素材：{path}\")\n\n\ndef md_table(headers, rows):\n    lines = [\"| \" + \" | \".join(headers) + \" |\", \"| \" + \" | \".join([\"---\"] * len(headers)) + \" |\"]\n    for row in rows:\n        lines.append(\"| \" + \" | \".join(str(x) for x in row) + \" |\")\n    display(Markdown(\"\\n\".join(lines)))\n"
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": "## Checkpoint 1：查看 ACT 诊断曲线\n"
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": "snapshot = json.loads((ASSET_DIR / \"metrics_snapshot.json\").read_text(encoding=\"utf-8\"))\nrows = []\nfor item in snapshot[\"act_progress\"]:\n    rows.append((item[\"label\"], f'{item[\"success\"]}/{item[\"total\"]}', f'{item[\"rate\"]:.1%}'))\nmd_table([\"阶段\", \"physical_success\", \"成功率\"], rows)\nshow_asset(\"act_dagger_progress_curve.png\", width=960)\n"
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": "这条曲线不是为了证明 ACT 已经完美泛化，而是为了展示排障方向：先确认数据和闭环状态，再决定是否需要 DAgger。\n"
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": "## Checkpoint 2：ACT 严格评估命令模板\n"
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": "act_policy = MODEL_ROOT / \"act_best\" / \"step_5000\"\ncmd = f\"\"\"\ncd \"$PROJECT_ROOT\"\nexport PYTHONPATH=\"$PWD:${{PYTHONPATH:-}}\"\n./.venv/bin/python eval_policy_success.py \\\\\n  --policy act \\\\\n  --act-policy-path \"{act_policy}\" \\\\\n  --physical-success \\\\\n  --seed-start 1000 \\\\\n  --episodes 10 \\\\\n  --max-action-steps 1200 \\\\\n  --output-jsonl \"$OUTPUT_ROOT/act_seen_1000_1009.jsonl\"\n\"\"\"\nprint(cmd)\n"
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": "正式训练或批量评估更适合在终端或后台脚本里跑。Notebook 这里负责保存命令模板、解释参数含义和读取结果。\n"
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": "## Checkpoint 3：成功与失败视频对照\n"
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": "show_asset(\"act_success_sequence.jpg\", width=1100)\nshow_asset(\"act_failure_sequence.jpg\", width=1100)\n"
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": "ACT 的失败常常不是完全不动，而是接近、夹取、搬运或释放中的某一段出问题。复核视频时要写出失败发生在哪个阶段。\n"
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": "## Checkpoint 4：记录 DAgger 实验\n"
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": "rows = [\n    (\"prefix 长度\", \"例如 40 个 control tick\"),\n    (\"oracle 类型\", \"scripted policy / human correction\"),\n    (\"timestamp offset\", \"例如 correction episode 使用 2.0\"),\n    (\"采样权重\", \"例如 correction episode weight=0.25\"),\n    (\"评估 seed\", \"seen / mixed / heldout 分开写\"),\n    (\"替换基线条件\", \"必须同一 physical_success 口径超过旧基线\"),\n]\nmd_table([\"记录项\", \"示例\"], rows)\n"
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3 (ipykernel)",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}
