Files
alpamayo-qwen05b-validation/notebooks/alpamayo_0_5b_minimal_reproduction.ipynb
2026-07-12 21:41:12 +08:00

548 lines
22 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"cells": [
{
"cell_type": "markdown",
"id": "title-and-toc",
"metadata": {},
"source": [
"# alpamayo-0.5B:NVIDIA Alpamayo 最小复现\n",
"\n",
"本 Notebook 从环境安装开始,依次完成模型与数据准备、VLM–expert 连接验证、两阶段训练、结构化轨迹分支、重载评估和结果可视化。\n",
"\n",
"## 目录\n",
"\n",
"1. [论文与复现范围](#论文与复现范围)\n",
"2. [架构介绍](#架构介绍)\n",
"3. [环境安装](#环境安装)\n",
"4. [运行配置](#运行配置)\n",
"5. [权重与数据准备](#权重与数据准备)\n",
"6. [样本检查](#样本检查)\n",
"7. [连接验证](#连接验证)\n",
"8. [Stage 1:驾驶指令 VLM](#stage-1驾驶指令-vlm)\n",
"9. [结构化轨迹 token 分支](#结构化轨迹-token-分支)\n",
"10. [Stage 2:Diffusion expert](#stage-2diffusion-expert)\n",
"11. [评估与实验结果](#评估与实验结果)\n",
"12. [复现检查清单](#复现检查清单)\n"
]
},
{
"cell_type": "markdown",
"id": "paper-and-scope",
"metadata": {},
"source": [
"<a id=\"论文与复现范围\"></a>\n",
"## 1. 论文与复现范围\n",
"\n",
"- 论文:[Alpamayo-R1: Bridging Reasoning and Action Prediction for Generalizable Autonomous Driving in the Long Tail](https://arxiv.org/abs/2511.00088)\n",
"- NVIDIA 上游仓库:[NVlabs/alpamayo](https://github.com/NVlabs/alpamayo)\n",
"- NVIDIA 模型页:[nvidia/Alpamayo-R1-10B](https://huggingface.co/nvidia/Alpamayo-R1-10B)\n",
"- 本项目数据源:[nvidia/PhysicalAI-Autonomous-Vehicles](https://huggingface.co/datasets/nvidia/PhysicalAI-Autonomous-Vehicles)\n",
"\n",
"本项目复现的是 VLM、past-KV、diffusion expert 与连续轨迹解码之间的核心连接方式。它使用 Qwen2.5-0.5B 文本骨干、约 0.80B 的完整 VLM 和 105.6M diffusion expert,在一个 PAI 样本上完成可训练、可保存、可恢复、可评估的最小闭环。它不使用 Alpamayo-R1 原始权重,也不代表完整模型规模、训练数据或驾驶能力。\n"
]
},
{
"cell_type": "markdown",
"id": "architecture",
"metadata": {},
"source": [
"<a id=\"架构介绍\"></a>\n",
"## 2. 架构介绍\n",
"\n",
"```text\n",
"前视图像 ─┐\n",
"驾驶问题 ─┼─> LLaVA VLM (CLIP + Qwen2.5-0.5B) ─┬─> 驾驶指令 / 结构化轨迹 token\n",
"历史 XY ─┘ └─> 24 层 past-KV\n",
" │\n",
"noisy XY-delta + diffusion timestep ─> 105.6M Qwen2 expert <──┘\n",
" │\n",
" vector field\n",
" │\n",
" 10-step denoising\n",
" │\n",
" 16 × 2 future XY\n",
"```\n",
"\n",
"Expert 使用 24 层、hidden size 512、8 个 query heads、2 个 KV heads 和 head dimension 64。精确参数量为 105,575,170,其中 Qwen2 主体 105,425,408、action/time projection 148,736、输出层 1,026。\n"
]
},
{
"cell_type": "markdown",
"id": "environment-guide",
"metadata": {},
"source": [
"<a id=\"环境安装\"></a>\n",
"## 3. 环境安装\n",
"\n",
"推荐使用 Python 3.12。若尚未启动 Notebook,可在仓库根目录执行:\n",
"\n",
"```bash\n",
"python3.12 -m venv .venv\n",
"source .venv/bin/activate\n",
"python -m pip install --upgrade pip\n",
"python -m pip install -e '.[notebook]'\n",
"python -m jupyter lab notebooks/alpamayo_0_5b_minimal_reproduction.ipynb\n",
"```\n",
"\n",
"下面的单元格会定位仓库根目录,并在当前 kernel 尚未安装项目时执行 editable install。\n"
]
},
{
"cell_type": "code",
"id": "environment-setup",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from __future__ import annotations\n",
"\n",
"import importlib.util\n",
"import os\n",
"import platform\n",
"import subprocess\n",
"import sys\n",
"from pathlib import Path\n",
"\n",
"def find_repo_root(start: Path) -> Path:\n",
" for candidate in (start.resolve(), *start.resolve().parents):\n",
" if (candidate / 'pyproject.toml').exists() and (candidate / 'scripts').is_dir():\n",
" return candidate\n",
" raise FileNotFoundError('请从 alpamayo-0.5B 仓库内启动此 Notebook')\n",
"\n",
"ROOT = find_repo_root(Path.cwd())\n",
"os.chdir(ROOT)\n",
"if importlib.util.find_spec('alpamayo_lite') is None:\n",
" subprocess.run([sys.executable, '-m', 'pip', 'install', '-e', str(ROOT)], check=True)\n",
"\n",
"print('Repository:', ROOT)\n",
"print('Python:', sys.version.split()[0])\n",
"print('Platform:', platform.platform())\n"
]
},
{
"cell_type": "markdown",
"id": "runtime-guide",
"metadata": {},
"source": [
"<a id=\"运行配置\"></a>\n",
"## 4. 运行配置\n",
"\n",
"支持三种执行方式:\n",
"\n",
"- `reuse`:复用本地已有权重、数据和 checkpoint;当前工作区具备完整产物时自动选择。\n",
"- `full`:全新工作区默认选择,执行 80-step Stage 1、160-step structured VLM 和 1,000-step expert。\n",
"- `smoke`:每个训练阶段只运行少量步数,用于检查代码、显存和接口;不用于复现发布指标。\n",
"\n",
"可在启动 Jupyter 前设置以下环境变量导入本地资源:\n",
"\n",
"```bash\n",
"export ALPAMAYO_PROFILE=reuse # reuse | full | smoke\n",
"export ALPAMAYO_MODEL_DIR=/path/to/qwen2.5_0.5B_vl\n",
"export ALPAMAYO_MANIFEST=/path/to/overfit_manifest.jsonl\n",
"export ALPAMAYO_PAI_RAW_DIR=/path/to/pai/raw\n",
"export ALPAMAYO_STAGE1_DIR=/path/to/stage1_vlm\n",
"export ALPAMAYO_STRUCTURED_DIR=/path/to/stage1_vlm_trajectory\n",
"export ALPAMAYO_STAGE2_DIR=/path/to/stage2_expert\n",
"```\n",
"\n",
"若自动下载 PAI 数据,Hugging Face 账号必须先接受 gated dataset 许可,并通过 `hf auth login` 或 `HF_TOKEN` 提供凭据。\n"
]
},
{
"cell_type": "code",
"id": "runtime-config",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import json\n",
"import torch\n",
"import yaml\n",
"from IPython.display import display\n",
"\n",
"BASE_CONFIG = ROOT / 'configs/local_overfit.yaml'\n",
"NOTEBOOK_OUTPUT = ROOT / 'outputs/notebook'\n",
"NOTEBOOK_OUTPUT.mkdir(parents=True, exist_ok=True)\n",
"\n",
"default_stage1 = ROOT / 'outputs/stage1_vlm'\n",
"default_stage2 = ROOT / 'outputs/stage2_expert'\n",
"has_reusable_outputs = (default_stage1 / 'stage1_metrics.json').exists() and (default_stage2 / 'expert_config.json').exists()\n",
"PROFILE = os.environ.get('ALPAMAYO_PROFILE', 'reuse' if has_reusable_outputs else 'full').lower()\n",
"if PROFILE not in {'reuse', 'full', 'smoke'}:\n",
" raise ValueError('ALPAMAYO_PROFILE must be reuse, full, or smoke')\n",
"\n",
"profile_steps = {\n",
" 'reuse': {'stage1': 80, 'structured': 160, 'stage2': 1000, 'rollouts': 16},\n",
" 'full': {'stage1': 80, 'structured': 160, 'stage2': 1000, 'rollouts': 16},\n",
" 'smoke': {'stage1': 1, 'structured': 1, 'stage2': 1, 'rollouts': 2},\n",
"}[PROFILE]\n",
"\n",
"raw = yaml.safe_load(BASE_CONFIG.read_text(encoding='utf-8'))\n",
"raw['paths']['model_dir'] = os.environ.get('ALPAMAYO_MODEL_DIR', str(ROOT / 'models/qwen2.5_0.5B_vl'))\n",
"raw['paths']['pai_raw_dir'] = os.environ.get('ALPAMAYO_PAI_RAW_DIR', str(ROOT / 'data/raw/pai'))\n",
"raw['paths']['manifest'] = os.environ.get('ALPAMAYO_MANIFEST', str(ROOT / 'data/processed/overfit_manifest.jsonl'))\n",
"raw['paths']['stage1_dir'] = os.environ.get(\n",
" 'ALPAMAYO_STAGE1_DIR',\n",
" str(default_stage1 if PROFILE == 'reuse' else NOTEBOOK_OUTPUT / 'stage1_vlm'),\n",
")\n",
"raw['paths']['stage2_dir'] = os.environ.get(\n",
" 'ALPAMAYO_STAGE2_DIR',\n",
" str(default_stage2 if PROFILE == 'reuse' else NOTEBOOK_OUTPUT / 'stage2_expert'),\n",
")\n",
"raw['stage1']['steps'] = profile_steps['stage1']\n",
"raw['stage2']['steps'] = profile_steps['stage2']\n",
"RUNTIME_CONFIG = NOTEBOOK_OUTPUT / 'runtime_config.yaml'\n",
"RUNTIME_CONFIG.write_text(yaml.safe_dump(raw, sort_keys=False), encoding='utf-8')\n",
"\n",
"MODEL_DIR = Path(raw['paths']['model_dir']).expanduser().resolve()\n",
"MANIFEST = Path(raw['paths']['manifest']).expanduser().resolve()\n",
"STAGE1_DIR = Path(raw['paths']['stage1_dir']).expanduser().resolve()\n",
"STAGE2_DIR = Path(raw['paths']['stage2_dir']).expanduser().resolve()\n",
"default_structured = ROOT / 'outputs/stage1_vlm_trajectory'\n",
"STRUCTURED_DIR = Path(os.environ.get(\n",
" 'ALPAMAYO_STRUCTURED_DIR',\n",
" str(default_structured if PROFILE == 'reuse' else NOTEBOOK_OUTPUT / 'stage1_vlm_trajectory'),\n",
")).expanduser().resolve()\n",
"HANDOFF_DIR = (ROOT / 'outputs/structured_vlm_handoff') if PROFILE == 'reuse' else (NOTEBOOK_OUTPUT / 'structured_vlm_handoff')\n",
"COMPARISON_DIR = (ROOT / 'outputs/complete_comparison') if PROFILE == 'reuse' else (NOTEBOOK_OUTPUT / 'complete_comparison')\n",
"\n",
"def run_script(name: str, *args: object) -> None:\n",
" command = [sys.executable, str(ROOT / 'scripts' / name), *map(str, args)]\n",
" print('$', ' '.join(command))\n",
" subprocess.run(command, cwd=ROOT, check=True)\n",
"\n",
"device = 'cuda' if torch.cuda.is_available() else ('mps' if torch.backends.mps.is_available() else 'cpu')\n",
"print(json.dumps({\n",
" 'profile': PROFILE,\n",
" 'steps': profile_steps,\n",
" 'device': device,\n",
" 'model_dir': str(MODEL_DIR),\n",
" 'manifest': str(MANIFEST),\n",
" 'stage1_dir': str(STAGE1_DIR),\n",
" 'stage2_dir': str(STAGE2_DIR),\n",
"}, indent=2, ensure_ascii=False))\n"
]
},
{
"cell_type": "markdown",
"id": "resources-guide",
"metadata": {},
"source": [
"<a id=\"权重与数据准备\"></a>\n",
"## 5. 权重与数据准备\n",
"\n",
"模型目录存在时直接复用,否则从 `thkim0305/qwen2.5_0.5B_vl` 下载固定 revision。Manifest 存在时直接复用,否则从 gated PAI 数据集物化单个样本。\n"
]
},
{
"cell_type": "code",
"id": "prepare-resources",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"if not (MODEL_DIR / 'model.safetensors').exists():\n",
" run_script('download_model.py', '--config', RUNTIME_CONFIG)\n",
"else:\n",
" print('Reuse model:', MODEL_DIR)\n",
"\n",
"if not MANIFEST.exists():\n",
" if not (os.environ.get('HF_TOKEN') or (Path.home() / '.cache/huggingface/token').exists()):\n",
" raise RuntimeError(\n",
" 'PAI manifest 不存在。请先接受数据集许可并运行 hf auth login,'\n",
" '或设置 ALPAMAYO_MANIFEST 指向本地 manifest。'\n",
" )\n",
" run_script('materialize_pai_subset.py', '--config', RUNTIME_CONFIG)\n",
"else:\n",
" print('Reuse manifest:', MANIFEST)\n",
"\n",
"assert (MODEL_DIR / 'config.json').exists(), MODEL_DIR\n",
"assert MANIFEST.exists(), MANIFEST\n"
]
},
{
"cell_type": "markdown",
"id": "sample-guide",
"metadata": {},
"source": [
"<a id=\"样本检查\"></a>\n",
"## 6. 样本检查\n",
"\n",
"显示单样本图像、历史轨迹和未来监督轨迹,确认 manifest 中的相对路径可以从仓库根目录解析。\n"
]
},
{
"cell_type": "code",
"id": "inspect-sample",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import matplotlib.pyplot as plt\n",
"import numpy as np\n",
"from PIL import Image\n",
"\n",
"sample = json.loads(MANIFEST.read_text(encoding='utf-8').splitlines()[0])\n",
"image_path = Path(sample['image_path'])\n",
"trajectory_path = Path(sample['trajectory_path'])\n",
"image_path = image_path if image_path.is_absolute() else ROOT / image_path\n",
"trajectory_path = trajectory_path if trajectory_path.is_absolute() else ROOT / trajectory_path\n",
"trajectory = np.load(trajectory_path)\n",
"history_xy = trajectory['history_xyz'][:, :2]\n",
"future_xy = trajectory['future_xyz'][:, :2]\n",
"\n",
"fig, axes = plt.subplots(1, 2, figsize=(12, 4.5))\n",
"axes[0].imshow(Image.open(image_path).convert('RGB'))\n",
"axes[0].set_title(f\"{sample['camera']} @ {sample['t0_us']} us\")\n",
"axes[0].axis('off')\n",
"axes[1].plot(history_xy[:, 0], history_xy[:, 1], 'o-', label='history')\n",
"axes[1].plot(future_xy[:, 0], future_xy[:, 1], 'o-', label='future target')\n",
"axes[1].axis('equal')\n",
"axes[1].grid(True, alpha=0.3)\n",
"axes[1].legend()\n",
"axes[1].set_title(sample['reasoning'])\n",
"plt.show()\n"
]
},
{
"cell_type": "markdown",
"id": "connection-guide",
"metadata": {},
"source": [
"<a id=\"连接验证\"></a>\n",
"## 7. 连接验证\n",
"\n",
"该步骤加载 VLM,提取 24 层 past-KV,实例化 105.6M expert,并检查层数、KV heads、head dimension 和输出形状。\n"
]
},
{
"cell_type": "code",
"id": "verify-connection",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"run_script('verify_connection.py', '--config', RUNTIME_CONFIG)\n",
"connection = json.loads((ROOT / 'outputs/connection_test.json').read_text(encoding='utf-8'))\n",
"connection\n"
]
},
{
"cell_type": "markdown",
"id": "stage1-guide",
"metadata": {},
"source": [
"<a id=\"stage-1驾驶指令-vlm\"></a>\n",
"## 8. Stage 1:驾驶指令 VLM\n",
"\n",
"Stage 1 冻结 vision tower、multimodal projector 和 LM head,只训练最后 8 个 Qwen2 language layers 与 final norm。`reuse` 模式在 checkpoint 存在时跳过训练。\n"
]
},
{
"cell_type": "code",
"id": "train-stage1",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"stage1_metrics_path = STAGE1_DIR / 'stage1_metrics.json'\n",
"if PROFILE == 'reuse' and stage1_metrics_path.exists():\n",
" print('Reuse Stage 1:', STAGE1_DIR)\n",
"else:\n",
" run_script('train_stage1_vlm.py', '--config', RUNTIME_CONFIG, '--steps', profile_steps['stage1'])\n",
"stage1_metrics = json.loads(stage1_metrics_path.read_text(encoding='utf-8'))\n",
"stage1_metrics\n"
]
},
{
"cell_type": "markdown",
"id": "structured-guide",
"metadata": {},
"source": [
"<a id=\"结构化轨迹-token-分支\"></a>\n",
"## 9. 结构化轨迹 token 分支\n",
"\n",
"该分支从 Stage 1 checkpoint 继续训练,加入 128 个离散 action token、meta-action 和轨迹边界标记。完整配置训练 160 步并生成 32 个轨迹 token。`smoke` 模式只验证训练入口,不保证结构化输出收敛。\n"
]
},
{
"cell_type": "code",
"id": "train-structured",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"structured_metrics_path = STRUCTURED_DIR / 'trajectory_logits_metrics.json'\n",
"if PROFILE == 'smoke':\n",
" structured_metrics = None\n",
" print('Smoke profile: skip structured generation, which requires convergence before decoding.')\n",
"elif PROFILE == 'reuse' and structured_metrics_path.exists():\n",
" print('Reuse structured VLM:', STRUCTURED_DIR)\n",
"else:\n",
" run_script(\n",
" 'train_vlm_trajectory_logits.py',\n",
" '--config', RUNTIME_CONFIG,\n",
" '--output-dir', STRUCTURED_DIR,\n",
" '--steps', profile_steps['structured'],\n",
" '--trajectory-vocab-size', 128,\n",
" '--action-min', -4,\n",
" '--action-max', 4,\n",
" '--max-new-tokens', 96,\n",
" )\n",
"if PROFILE != 'smoke':\n",
" structured_metrics = json.loads(structured_metrics_path.read_text(encoding='utf-8'))\n",
"structured_metrics\n"
]
},
{
"cell_type": "markdown",
"id": "stage2-guide",
"metadata": {},
"source": [
"<a id=\"stage-2diffusion-expert\"></a>\n",
"## 10. Stage 2:Diffusion expert\n",
"\n",
"Stage 2 冻结 Stage 1 VLM,使用其 prefix cache 训练 105,575,170 参数的 expert。目标为标准化的相邻 waypoint XY delta,flow matching 输出经反标准化和累积求和还原未来轨迹。\n"
]
},
{
"cell_type": "code",
"id": "train-stage2",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"stage2_metrics_path = STAGE2_DIR / 'stage2_metrics.json'\n",
"if PROFILE == 'reuse' and stage2_metrics_path.exists():\n",
" print('Reuse Stage 2:', STAGE2_DIR)\n",
"else:\n",
" run_script('train_stage2_expert.py', '--config', RUNTIME_CONFIG, '--steps', profile_steps['stage2'])\n",
"stage2_metrics = json.loads(stage2_metrics_path.read_text(encoding='utf-8'))\n",
"expert_config = json.loads((STAGE2_DIR / 'expert_config.json').read_text(encoding='utf-8'))\n",
"print('Expert parameters:', stage2_metrics['expert_parameters'])\n",
"stage2_metrics\n"
]
},
{
"cell_type": "markdown",
"id": "evaluation-guide",
"metadata": {},
"source": [
"<a id=\"评估与实验结果\"></a>\n",
"## 11. 评估与实验结果\n",
"\n",
"完整模式执行 16 个 diffusion rollouts、structured exact-cache handoff 和 GT/VLM/diffusion 三方比较。`smoke` 模式只执行少量 rollout,并展示仓库中保存的发布结果。\n"
]
},
{
"cell_type": "code",
"id": "reload-evaluation",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"evaluation_path = NOTEBOOK_OUTPUT / 'reload_evaluation.json'\n",
"run_script(\n",
" 'evaluate_pipeline.py',\n",
" '--config', RUNTIME_CONFIG,\n",
" '--stage2-dir', STAGE2_DIR,\n",
" '--num-rollouts', profile_steps['rollouts'],\n",
" '--base-seed', 12,\n",
" '--output', evaluation_path,\n",
")\n",
"evaluation = json.loads(evaluation_path.read_text(encoding='utf-8'))\n",
"evaluation\n"
]
},
{
"cell_type": "code",
"id": "comparison-results",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"if PROFILE != 'smoke':\n",
" run_script(\n",
" 'verify_structured_vlm_handoff.py',\n",
" '--config', RUNTIME_CONFIG,\n",
" '--vlm-dir', STRUCTURED_DIR,\n",
" '--stage2-dir', STAGE2_DIR,\n",
" '--output-dir', HANDOFF_DIR,\n",
" )\n",
" run_script(\n",
" 'build_complete_comparison.py',\n",
" '--vlm-npz', STRUCTURED_DIR / 'trajectory_logits.npz',\n",
" '--vlm-metrics', STRUCTURED_DIR / 'trajectory_logits_metrics.json',\n",
" '--diffusion-npz', STAGE2_DIR / 'reload_prediction.npz',\n",
" '--diffusion-metrics', STAGE2_DIR / 'stage2_metrics.json',\n",
" '--expert-config', STAGE2_DIR / 'expert_config.json',\n",
" '--manifest', MANIFEST,\n",
" '--diffusion-seed', 12,\n",
" '--output-dir', COMPARISON_DIR,\n",
" )\n",
" result_dir = COMPARISON_DIR\n",
"else:\n",
" print('Smoke profile: display checked-in comparison artifacts.')\n",
" result_dir = ROOT / 'results/complete_comparison'\n",
"\n",
"comparison = json.loads((result_dir / 'comparison.json').read_text(encoding='utf-8'))\n",
"metrics = comparison['metrics']\n",
"print(json.dumps({\n",
" 'vlm': metrics['vlm']['computed_from_npz'],\n",
" 'diffusion': metrics['diffusion']['computed_from_npz'],\n",
" 'trajectory_token_accuracy': metrics['vlm']['trajectory_token_accuracy'],\n",
"}, indent=2))\n",
"display(Image.open(result_dir / 'trajectory_comparison.png'))\n"
]
},
{
"cell_type": "markdown",
"id": "published-results",
"metadata": {},
"source": [
"### 仓库当前发布结果\n",
"\n",
"| 输出 | Action MSE | ADE | FDE | Max error |\n",
"| --- | ---: | ---: | ---: | ---: |\n",
"| VLM trajectory tokens | 0.0003439452 | 0.026104664 m | 0.045444489 m | 0.054956669 m |\n",
"| Diffusion(seed 12) | 0.7453363983 | 1.125946622 m | 0.258275141 m | 2.925430649 m |\n",
"\n",
"VLM 的 32 个生成 token 与量化目标全部匹配;其非零误差来自 128-bin 反量化。Diffusion 结果依赖采样 seed,仓库记录的 16-seed 平均 ADE 为 1.530302633 m。\n"
]
},
{
"cell_type": "markdown",
"id": "reproduction-checklist",
"metadata": {},
"source": [
"<a id=\"复现检查清单\"></a>\n",
"## 12. 复现检查清单\n",
"\n",
"顺序执行全部单元格后,应满足:\n",
"\n",
"- 模型目录包含 `model.safetensors` 与 `download_provenance.json`。\n",
"- Manifest 可加载一张前视图像和一份包含 history/future 的 NPZ。\n",
"- `verify_connection.py` 返回 24 层 KV,并报告 105,575,170 个 expert 参数。\n",
"- Stage 1、structured VLM 与 Stage 2 均生成指标 JSON 和权重文件。\n",
"- Reload evaluation 可重复加载 checkpoint 并输出 rollout 指标。\n",
"- 完整模式生成 handoff 指标、比较 JSON、waypoint CSV 和三方轨迹图。\n",
"\n",
"模型输出和本项目不能用于真实车辆控制或安全决策。不要提交 Hugging Face token、gated PAI 数据、下载权重或训练 checkpoint。\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (alpamayo-0.5B)",
"language": "python",
"name": "python3"
},
"language_info": {
"name": "python",
"version": "3.12"
}
},
"nbformat": 4,
"nbformat_minor": 5
}