{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": "# 04 SmolVLA 在 ROCm 上的迁移与采样加权\n\n        这一节用 SmolVLA 说明：语言策略不能只看总体成功率。红杯和蓝杯指令要拆开评估，再比较复制 episode 与 Weighted sampler 的效果。\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：读取红杯/蓝杯固定指令结果\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[\"smolvla_forced_instruction_n10\"]:\n    rows.append((item[\"label\"], item[\"red_text\"], item[\"blue_text\"]))\nmd_table([\"策略\", \"红杯 physical_success\", \"蓝杯 physical_success\"], rows)\nshow_asset(\"smolvla_red_blue_success.png\", width=1100)\n"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": "baseline 红杯好、蓝杯差，说明模型不是完全不会抓，而是任务条件和颜色相关分布没有学稳。\n"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": "## Checkpoint 2：复制 episode 与 Weighted sampler 的区别\n"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": "rows = [\n    (\"复制 episode\", \"直接改变数据集 episode 分布\", \"实现简单，但容易让模型偏向某个颜色\"),\n    (\"Weighted sampler\", \"不改原始 parquet，只改采样概率\", \"更容易回滚，也更适合小数据平衡\"),\n    (\"中间 checkpoint 评估\", \"不要只看 final step\", \"本示例里 step500 比 step1000 更均衡\"),\n]\nmd_table([\"方法\", \"做法\", \"为什么要注意\"], rows)\n"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": "## Checkpoint 3：重新生成图表\n"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": "cmd = [\n    sys.executable,\n    str(TOPIC_ROOT / \"code\" / \"generate_tutorial_assets.py\"),\n    \"--source-root\",\n    str(OUTPUT_ROOT),\n]\nprint(\"如果 OUTPUT_ROOT 中有本章需要的 TSV/JSONL/MP4，可以运行：\")\nprint(\" \".join(cmd))\n# subprocess.run(cmd, check=True)\n"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": "上面的单元默认不直接执行，避免输出目录还没准备好时生成指标摘要图。确认 `$OUTPUT_ROOT` 正确后，取消最后一行注释即可。\n"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": "## Checkpoint 4：蓝杯失败和修复后成功对照\n"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": "show_asset(\"smolvla_blue_failure_sequence.jpg\", width=1100)\nshow_asset(\"smolvla_blue_success_sequence.jpg\", width=1100)\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
}
