qwenjev / train.md
tchbcb's picture
v0.4.4: train.md §8.3 — v3 real-games round
be65759 verified
|
Raw History Blame Contribute Delete
30.8 kB

QwenJev — 用 Qwen3.5-9B 多模态改造 NanoJev 的 ARC-AGI-3 双系统智能体

本文档是整个项目的构造蓝图:背景 → 架构 → 数据 → 训练 → 智能体接入 → Kaggle 部署 → 评测 → 路线图。 按顺序读完即可独立复现整个系统。README 按要求留空,所有内容都在本文档中。 v0.2.0 架构决策:视觉塔必保留在 System-1 每步推理路径上——隐藏关全是陌生机制, 只看 hex 文本串没法玩游戏;本仓库的 System-1 骨干直接是多模态模型,每步都"看"当前帧。


1. 项目定位

1.1 要解决的问题

ARC Prize 2026(ARC-AGI-3)要求智能体在从未见过的交互式游戏环境中探索、获取目标、构建世界模型。评分采用 RHAE(Relative Human Action Efficiency):完成度 × 效率(步数取平方惩罚),意味着瞎探索的代价极高。

原始 NanoJev(TianyuCodings/NanoJev,0.6B)是一个极合适的 System-1 决策内核:states + questions 进,完整概率分布出,零输出 token 解码。但它有两个与本赛不匹配的短板:

  1. 没有视觉塔——骨干是纯文本的 Qwen3-0.6B,只能吃文本化的网格;
  2. 没有游戏级的探索/反思机制——它是一个"打分器",不是完整智能体。

1.2 QwenJev 的改造思路

短板 改造手段 落点
无视觉塔 视觉塔直接保留在 System-1 推理路径上:骨干改为多模态模型(hf 后端 = Qwen3-VL 系列,预训练视觉塔原样保留;tiny 后端 = 自带微型视觉塔),叶子升级为 [帧图像, state, instruction, candidate],每步都看当前帧 qwenjev/vision.py + qwenjev/system1.py
小模型感知不如 9B Qwen3.5-9B 做冻结教师,吃同一帧、过自己的视觉塔,把逐层隐状态蒸馏对齐给学生(stage A) train/distill_alignment.py
缺少探索机制 9B 作为 System-2 主控:感知局面、提出候选动作假设、失败后写记忆笔记;由调度器稀有地唤醒 qwenjev/system2.py
单步决策慢/贵 NanoJev 式 System-1:单次前向输出候选动作分布,每步都跑(含视觉前向) qwenjev/system1.py
接口封闭 完整对接官方 ARC-AGI-3-Agents 开源框架,实现 Agent 两个方法即可提交比赛 agent/qwenjev_agent.py
本地无 GPU/无游戏 内置 mock 推箱游戏(多关卡、种子确定)+ tiny 微型 VLM(~1M 参数,纯 CPU),全管线零下载跑通 data/mock_env.py

一句话:视觉塔每步都在环上(System-1 骨干原生多模态);9B 出眼光(教师蒸馏 + System-2 稀有唤醒);tiny 后端让全链路在笔记本 CPU 上跑通。

1.3 与 NanoJev 原作的关系

  • 忠实保留其输入契约:每个问题 = 一个 state + 一组候选;每个候选编码为 [帧图像, state, instruction, candidate] 的多模态叶子(原作为纯文本 [state, instruction, candidate]);候选路径重复 state;问题之间独立(前向中无跨问题注意力)。
  • 忠实保留三种原语:Choice(2–255 候选,set-attention + softmax)、Boolean(sigmoid p_true)、Score(2–10 有序等级,期望值读出)。
  • 沿用其训练配方:complete-question 交叉熵,backbone lr 1e-5、decision-head lr 1e-4。
  • 差异点:① state 序列化改为版本化规范串(原作审计文档承认 str() 序列化非规范,属遗留问题);② 叶子多模态化——视觉塔每步在环;③ 增加 ACTION6(x,y) 的候选离散化;④ 外层接 ARC-AGI-3 环境与双系统调度。

2. 总体架构

                        ┌────────────────────────────────────────────┐
                        │        ARC-AGI-3-Agents 官方框架循环          │
                        │   main.py → Swarm → Agent.choose_action()   │
                        └───────────────┬────────────────────────────┘
                                        │ frames / FrameData
                                        ▼
                        ┌────────────────────────────────────────────┐
                        │            agent/qwenjev_agent.py           │
                        │   is_done(): state is WIN                   │
                        │   choose_action(): 严格解析 + 安全回退         │
                        └───────────────┬────────────────────────────┘
                                        ▼
                        ┌────────────────────────────────────────────┐
                        │              qwenjev/hybrid.py              │
                        │   调度器: novelty / reward / stall 触发       │
                        │   动作-效果记忆 + 时间预算管理                 │
                        └──────┬───────────────────────┬─────────────┘
                     唤醒(稀有) │                       │ 每步(便宜)
                               ▼                       ▼
              ┌────────────────────────┐  ┌────────────────────────────────┐
              │  System-2 主控 (慢)     │  │  System-1 决策模型 (快)          │
              │  Qwen3.5-9B 多模态      │  │  多模态骨干 + 决策头              │
              │  · 感知局面 summarize   │  │  · 视觉塔: 每步编码当前帧 ★必保留  │
              │  · 假设机制 hypothesize │  │  · Choice 头: 候选动作打分        │
              │  · 提议候选 propose     │  │    (set-attn + softmax)         │
              │  · 失败反思 reflect     │──▶  · Boolean 头: 动作-效果判真      │
              └────────────────────────┘  │  · Score 头: 局面价值分级          │
                        ▲ 训练期教师        └────────────────────────────────┘
                        │ 同一帧过双方视觉塔    叶子 = [帧图像, state, instruction,
                        └── 蒸馏对齐 (stage A) ──      candidate],同题共享帧
                         qwenjev/vision.py 负责网格→图像/张量、多模态叶子、TinyVLM

数据流要点:

  1. state_codec.encode_observation() 把每步的帧数组编码为:规范 state 串 + 差分网格(* 标记变化格,供"上一步干了什么"这一最廉价的学习信号)+ 帧哈希(新颖性检测)。
  2. candidates.build_candidates() 生成候选:简单动作(ACTION1–5、ACTION7=undo)+ ACTION6 的锚点离散化(变化格 > 稀有格 > 8×8 粗格网,上限 255)。
  3. 当前帧随每步决策进入 System-1 视觉塔(hybrid.decide() 把 grids[0] 传给 s1.choose())——这是 v0.2.0 的硬性架构约束,不许回退到纯文本。
  4. System-2 提议的候选被稳定置顶(不删除其他候选),最终仍由 System-1 打分决定——9B 可以错,打分器说了算。
  5. RESET 永远不进候选列表,只由生命周期守卫(NOT_PLAYED / GAME_OVER / 超时)触发,防止自杀式重启。

3. 核心模块详解

3.1 视觉塔 qwenjev/vision.py(v0.2.0 新增,架构核心)

为什么必须保留视觉塔:ARC-AGI-3 的智能体只能通过帧观察世界;隐藏评测关的机制全部陌生,实体形状、邻接、运动这些线索在 hex 文本串里大量丢失。System-2 每局最多唤醒 40 次,不能指望 9B 替 System-1 看路——所以视觉塔必须长在每步都跑的 System-1 上。

两种可互换后端(同一接口):

后端 骨干 用途
"hf" AutoModelForImageTextToText 加载的 Qwen3-VL 系列多模态权重(默认 Qwen/Qwen3-VL-2B-Instruct) 正式训练/提交;预训练视觉塔原样保留,可选 freeze_vision_tower
"tiny" TinyVLM:patch-embed 微型 ViT 塔(64 视觉 token)+ byte 级微型因果 LM(~1.1M 参数) 本地跑通/CI/单测;零下载、纯 CPU、毫秒级

多模态叶子 MultiModalLeaf = [图像, state 文本, instruction, candidate]:同题候选共享同一帧,encode_question() 一次构造全部叶子。关键实现细节:注意力掩码用 additive float mask(-1e9)而不是 bool 掩码——bool 掩码与 causal 组合会在 padding 行产生全 -inf → softmax NaN(开发中实际踩过并修复,单测 test_tinyvlm_all_finite_with_padding 永久看守)。

3.2 状态编码 qwenjev/state_codec.py

  • 网格 → 文本:每格一个字符,0–15 → hex(0123456789abcdef),64×64 最多 4KB,远比视觉 token 便宜且无损。
  • 差分网格:与上一帧逐格比较,变化格写 *。注意实现教训:hex 字母可以大写标记,但 0-9 是数字无法大写——所以用专用标记符(单测覆盖了这个坑)。
  • 规范 state 串:qwenjev-state-v1|h=.. w=.. l=.. s=..\n<网格>。版本号置顶 + meta 键排序,保证同一局面永远产出同一字符串(checkpoint 可复现的前提)。
  • 网格 → 图像:grid_to_image() 用 16 色稳定调色板渲染。v0.2.0 起不只是 System-2 用:System-1 视觉塔每步也吃这张图(vision.py 转张量/PIL)。

3.3 候选生成 qwenjev/candidates.py

ACTION6(x,y) 是唯一带坐标的动作,必须离散化才能进 Choice 头。锚点优先级:

  1. 变化格(上一帧的 * 位置)——游戏机制大概率藏在这里;
  2. 稀有格(非零值按局部稀有度排序 top-24)——目标物/关键机关往往颜色稀缺;
  3. 8×8 粗格网兜底(保证全图覆盖)。

上限 255 候选(TypeSafe Choice 契约上限),顺序稳定,避免候选索引漂移悄悄改变叶子输入。

3.4 System-1 qwenjev/system1.py

  • encode_question(state, candidates, instruction, grid) → N 个多模态叶子(每候选一个,state 重复,当前帧图像共享);
  • forward_choice(leaves) → 一次 backbone 前向(含视觉塔):叶子向量 → 投影 → set-attention(同题候选间)→ softmax → 概率列表;
  • choose(..., grid) → 贪心或按分布采样,返回 Decision(probs, candidates, chosen, index);
  • forward_boolean / forward_score 及其可训练孪生 forward_boolean_logits / forward_score_logits(v0.2.0 修复:旧实现返回 detach 张量,梯度根本流不进模型);
  • save() / load_heads():tiny 后端打包 backbone + 全部头;hf 后端只存头(权重留在 HF 权重目录);
  • eval() / train_mode():决策头 dropout=0,保证加载后推理确定。

3.5 System-2 qwenjev/system2.py

  • 两种后端:mode="openai"(vLLM 的 OpenAI 兼容端点,首选)或 mode="transformers"(进程内加载,重);
  • perceive(obs, grids, memory) → 结构化 PerceptionReport:局面摘要、实体清单、≤3 条机制假设、3–8 个建议动作;输入含 hex 网格文本 + 渲染 PNG(双通道喂视觉塔)+ 记忆笔记;
  • reflect(history) → GAME_OVER/停滞后的持久记忆 {learned, avoid, next_try},跨 episode 保留;
  • bias_candidates() 把 9B 的建议动作稳定置顶(保留全部候选)。

3.6 调度器 qwenjev/hybrid.py

System-2 唤醒条件(满足其一,且调用数 < system2_max_calls_per_game):

条件 含义
新帧哈希 局面没见过,需要 9B 看一眼
levels_completed 增加 进新关卡,机制可能变
连续 12 步无变化 System-1 卡死,需要外部视角

同时管理:每局时间预算(默认 900s,官方文档明确超时会直接 fail 该次运行)、动作数上限、动作-效果记忆(哪个动作改变多少格)、每局反思笔记。

任何一层失败都不能杀死运行:9B 端点挂了 → 跳过;System-1 权重缺失 → 启发式策略;输出不合法 → 正则清洗 + 安全回退(官方文档警告:一个畸形输出就会以 ValueError 终结当前游戏)。


4. 数据管线

4.1 来源:25 个公开游戏自采(已确认可用,2026-09-23 实测)

  • 游戏源码从 arcade API 自动获取:arc-agi 包 NORMAL 模式 make() 会把游戏源码(单游戏约 120KB)缓存到 environment_files/<game_id>/<version>/,之后永久离线(OFFLINE 模式约 2000 FPS、无限实例);匿名 key 自动下发,无需 Kaggle 账号、无需接受比赛规则。一键预缓存:python ops/fetch_games.py(25 游戏约 65 秒);
  • kagglehub 比赛下载(kagglehub.competition_download('arc-prize-2026-arc-agi-3'))需要 KGAT token + 官网接受规则,且与本地游戏引擎是同一套(arc-agi 包本地托管同引擎)——本仓评测链路已不依赖它;
  • 游戏清单(与 arcprize.org/tasks 一致,ops/run_eval.py --list-games 可从 API 拉实时列表):ar25 bp35 cd82 cn04 dc22 ft09 g50t ka59 lf52 lp85 ls20 m0r0 r11l re86 s5i5 sb26 sc25 sk48 sp80 su15 tn36 tr87 tu93 vc33 wa30;
  • 评测是另外 110 个从未公开的隐藏游戏(55 个 Public LB + 55 个 Private LB),所以数据管线的一切设计都服务于"可泛化的探索先验",而非背题。

4.2 采集 data/collect_selfplay.py

  • ε-greedy(默认 ε=0.25)包住当前 HybridAgent 策略;
  • 每步记录:动作、坐标、前后帧、levels_completed 变化、可用动作集、帧哈希、规范 state;
  • 输出 JSONL 分片 data/traces/<game>/ep*.jsonl + summary.json;
  • 游戏源双轨:game_id 以 mock 开头 → 内置推箱游戏(零依赖);否则走 arc-agi 离线引擎(需安装包 + 游戏文件);
  • 批量采集时 System-2 默认关闭(吞吐优先),可选开启给少量轨迹加 9B 注释。

4.3 内置 mock 游戏 data/mock_env.py(v0.2.0 新增)

多关卡推箱游戏("sokoban-lite"),实现官方环境契约的子集:reset()/step()/observe()、FrameData 兼容字段、RESET/ACTION1-7 全动作、≤64×64 网格值 0–15、种子确定(crc32)可复现。机制刻意稀疏:推箱进目标才涨关卡、超预算 GAME_OVER——正好复刻隐藏关的稀疏奖励探索难度。step_env() 适配器统一 mock(按名调用)与官方引擎(GameAction 枚举)。

4.4 构造训练样本 data/build_dataset.py

问题族 问题模板 标签来源
Choice(主任务) "哪个候选动作最可能取得进展?" + 全部候选 即时结果分级:levels_completed 增加=+2;帧变化未丢关卡=+1;无变化=0,取最优动作为 one-hot
Boolean(效果预训练) "ACTION k 会改变画面吗?" 前后帧哈希差
Score(价值塑形) "当前局面希望多大?" 2–10 级 关卡进度 + 探索覆盖率的启发式

每个样本都携带 grid 字段(v0.2.0 起):System-1 的视觉塔训练/推理都要吃图像,样本不带帧就没法训。划分逻辑:≥5 个游戏时按游戏切分 train/val(防同游戏泄漏);单游戏冒烟时退化为按行 crc32 哈希切分(保证 train 非空——单游戏场景下按游戏切会把全部样本切进 val,开发中踩过)。

4.5 增广 data/augment.py

ARC 传统增广全部可用:转置/镜像/旋转/重着色(固定 0=背景)。ACTION6 坐标必须与网格同步变换(coord_transform()),否则标签说谎。


5. 训练方案

5.1 两阶段配方

Stage A:视觉蒸馏对齐(train/distill_alignment.py)

  • 教师:冻结的多模态模型,同一帧真实过其视觉塔(hf 后端:processor 构造 pixel_values 进模型前向;tiny 后端:教师 TinyVLM 同样吃图像张量)——绝不允许出现"蒸馏时没看图"的假对齐(v0.1 的占位符实现已废弃);
  • 学生:System-1 多模态骨干,同样图像+文本前向,取逐层隐状态池化;
  • 对齐层集隐状态(默认最后 2 层),1 − cosine 损失,逐层独立投影头;
  • 产物:checkpoints/qwenjev-s1/stage_a.pt(投影头 + tiny 学生权重),Stage B 自动加载。

Stage B:决策头 SFT(train/train_system1.py)

超参 值 出处
目标函数 complete-question CE(整题 softmax,非逐叶子二分类) NanoJev hard_lr1e5
backbone lr 1e-5 同上
decision-head lr 1e-4 同上
epochs 4(三族问题混合,真实网格随样本进视觉塔) 可调
LoRA 默认关闭;hf 大骨干时建议开 r=32, α=64 可选

v0.2.0 训练修复清单(旧代码静默失效的三处):① Boolean/Score 头改用可训练 logits 孪生方法,BCE/CE 梯度真正流进模型;② Choice 批训练改用带图前向(旧行为在 torch.no_grad() 里算概率再包装,同样训不动);③ Stage A checkpoint 自动加载,蒸馏成果不白费。

5.2 显存预算(RTX Pro 6000 96GB 实测口径)

场景 占用估算
Stage A:9B 教师 4bit + Qwen3-VL-2B 学生(含双方视觉塔前向) ~12–16 GB
Stage A:9B 教师 BF16(teacher_4bit: false) ~28–32 GB
Stage B:Qwen3-VL-2B 全参数训练 ~20–26 GB;LoRA 减半以下
推理:System-1(2B)+ System-2(9B BF16)常驻 ~26 GB,96GB 富余

消费级 24GB 卡(4090/3090)建议:教师 4bit + 学生 LoRA;tiny 后端则任意机器(含无 GPU 笔记本,~1.1M 参数 fp32 ≈ 5MB)都能跑。

5.3 下载权重

python scripts/download_weights.py            # Qwen3-0.6B + Qwen3.5-9B + NanoJev 参考

6. 智能体接入(官方开源框架)

6.1 安装到 ARC-AGI-3-Agents

git clone https://github.com/arcprize/ARC-AGI-3-Agents.git
cd ARC-AGI-3-Agents
# 1) 拷贝本仓库的 agent/qwenjev_agent.py 到 agents/
# 2) 保证 qwenjev 包可导入(repo 根目录放本仓库,或 pip install -e)
# 3) 注册:
#    agents/__init__.py 中加入
#    from .qwenjev_agent import QwenJevAgent
#    AVAILABLE_AGENTS["qwenjevagent"] = QwenJevAgent
uv run main.py --agent=qwenjevagent --game=ls20     # 单游戏试跑
uv run main.py --agent=qwenjevagent                 # 全部游戏

6.2 框架接口速查(v0.9.3)

  • 基类 Agent,必须实现 is_done(frames, latest_frame) 与 choose_action(frames, latest_frame) -> GameAction;
  • FrameData 关键字段:levels_completed / win_levels(v0.9.3 由 score/win_score 改名)、available_actions(v0.9.2+)、state;
  • GameAction:RESET、ACTION1–7;action.is_simple() / action.is_complex();复杂动作 action.set_data({"x":..,"y":..});
  • 网格 ≤64×64,值 0–15,(0,0) 左上,(x,y) 顺序;
  • 游戏状态:NOT_PLAYED / NOT_FINISHED / WIN / GAME_OVER。

7. Kaggle 部署(比赛提交)

7.1 硬件与限制

项 值
专属加速器 RTX Pro 6000(g4-standard-48:1×96GB 显存、48 vCPU、180GB 内存)
运行上限 CPU/GPU Notebook 均 ≤ 9 小时
网络 禁网(权重/依赖全部走 Kaggle Dataset)
配额 RTX 并发 1/人,高峰排队可达数小时——只在完整方案上烧 Commit

7.2 打包步骤(scripts/package_kaggle.py)

python scripts/package_kaggle.py --username <你的Kaggle用户名> --accelerator rtx6000
cd kaggle_kernel && kaggle kernels push -p .

生成的 notebook 三个关键单元格:

  1. 从比赛 Data 包的 arc_agi_3_wheels/ 离线安装 arc-agi(禁网解法一);
  2. 挂载权重 Dataset(/kaggle/input/qwenjev-weights/...,公开预训练权重合规);
  3. 实例化 QwenJevAgent,接入官方 sample-submission 驱动循环,工具包自动产出 submission.parquet。

7.3 九小时时间预算(务必先算再跑)

  • 隐藏集 110 局;平均每局预算 ≈ 4.9 分钟;
  • System-1 每步毫秒级,主导耗时的是 System-2:单次调用按 3–5s 计,每局 system2_max_calls_per_game=40 → 9B 总开销 ≈ 2–3.3 分钟/局,留有余量但不富裕;
  • 调参顺序:先压 system2_max_calls_per_game,再压 stall_patience;game_time_limit_s 宁低勿高(超时=整局报废)。

8. 评测与迭代

8.1 一键评测(v0.4.2 起:ops/run_eval.py)

pip install arc-agi                        # 官方本地引擎(PyPI,纯 Python)
pip install -U "torchao>0.16"              # v0.4.3 实测坑:旧版 torchao 会令 hf 加载失败(见下)
python ops/run_eval.py --download-only     # 一次性缓存 25 公开游戏(约 3MB,匿名 key)
python ops/run_eval.py --games all25       # 全量评测:GPU→hf 后端自动拉 HF 检查点并 merge LoRA;无 GPU→tiny
python ops/run_eval.py --games ls20 --max-actions 60     # 指定游戏 + 预算
python ops/run_eval.py --backend tiny --no-checkpoint --games mock --max-actions 60   # 纯 harness 冒烟
python ops/run_eval.py --checkpoint /path/to/dir --games ...   # 本地检查点目录(qwenjev_s1.pt [+ hf_lora/])
  • 检查点解析(默认 hf:tchbcb/qwenjev@t4_assets_v2/checkpoints):自动下载 qwenjev_s1.pt + hf_lora 分片 → parts/reassemble 重组 → sha256 校验 → 后端 auto 决定 hf(fp16 基座 + LoRA merge,与训练同构)或 tiny;
  • 生命周期:WIN 结束本局;GAME_OVER 触发 brain.on_game_over + 自动重置续玩(同一动作预算内公平比较,resets 入报告);
  • 报告字段:win / final_state / best_level / resets / actions / seconds / steps_per_s,默认写 eval_report.json(--out 改路径);
  • 增量落盘(v0.4.3):每完成一个游戏即原子重写报告(.tmp → replace),Colab/隧道中途断连也保留已完成游戏的结果,报告 meta + summary.played 恒反映已落盘部分;
  • torchao 坑(v0.4.3 实测):transformers 5.16.1 加载 Qwen3-VL 时校验 torchao 版本,torchao==0.10.0 会令 build_s1 抛 "only versions above 0.16.0 are supported",run_eval 静默回退启发式策略继续跑完(不中断)——健康检查判据:steps_per_s > 100 必是启发式,真模型推理约 1 步/秒量级(T4 实测 1.15 步/秒 @ 150 步预算);pip install -U torchao(0.18.0 验证通过)后重跑即可;
  • --list-games 从 arcade API 拉实时游戏列表(静态清单兜底)。

8.2 本地 CPU 能不能跑?(2026-09-23,2 核 / 3GB 容器实测)

配置 可行性 实测/推算依据
tiny 后端 + v0.2.0 训练头(128 维) ✅ 完整评测 25 游戏全部跑通(40 步/游戏),0.5–4 步/秒(快慢取决于 ACTION6 候选数)
tiny 后端 + v2 检查点 ❌ 维度不匹配 v2 头是 2048 维(hf 隐藏维),tiny 骨干是 128 维
hf 后端(Qwen3-VL-2B fp16) ⚠️ 需 ≥8GB 内存 基座权重 ~4.4GB + 三头 254MB(fp32, 63.5M 参数)+ 激活;本 3GB 容器物理不可行;bitsandbytes 4bit 仅限 CUDA,CPU 无替代
hf 后端(GPU:T4 16GB) ✅ 已验证 fp16 基座 + merge 后 300 步 601.6s(§11.2 v2 eval)
  • CPU 评测的检查点是 checkpoints/qwenjev-s1/(v0.2.0 时代 128 维 tiny 头 + backbone,load_heads 向后兼容:escalate/温度表缺省跳过);其结论只用于 harness 验证与横向对比,不代表 v2 模型水平;

  • 4bit 量化在 CPU 上不可用(bitsandbytes 依赖 CUDA),若要在 CPU 跑真 2B 建议在 ≥16GB 内存机器用 fp16(--backend hf 会自动走 resume_adapters(merge=True));

  • 提速方向:调小候选池(build_candidates 的 ACTION6 锚点数)或调大 eval_leaf_batch。

  • 官方正式指标 RHAE = 按关卡 min(人类步数/智能体步数, 1.0)² 加权平均,人类基线本地拿不到——所以 evaluate_local.py 的绝对分数只用于横向比较不同版本的智能体,不代表排行榜;

  • 迭代循环:改 agent/my_agent.py(或 hybrid 配置)→ 本地秒级验证 → 满意后再花 Kaggle Commit;

  • 关注三条曲线:完成率(WIN 数)、平均步数、System-2 调用次数。好方向的标志是完成率升、System-2 调用降。

8.3 v3 真游戏训练轮(2026-09-23,进行中)

背景:v2 只见过 mock 推箱,zero-shot 25 公开游戏 2 局实测 0 胜 0 关(§3 基线)→ 转真游戏训练。

采集(真数据比预想廉价得多):

  • 工具:scripts/collect_chunk.py(分块断点续采,本地沙盒前台 <9 分钟/调用友好; 非空 ep 文件即视为完成——多数游戏 ε=0.35 随机探索几十步就 GAME_OVER,早死也是有效信号);
  • 配置:configs/collect_real25.yaml(25 游戏 × 8 集 × 400 步,ε=0.35,seed 13);
  • 实测吞吐:本地 2 核 ~9 步/秒(ar25 64×64 大网格),小网格 60+ 步/秒;远端 2 核 nohup 全量 24 游戏 × 10 集约 90 分钟;
  • 本地 3GB 内存注意:build_dataset.py 已瘦身(只保留 grids_before[0],丢 grids_after 与多帧, 内存降 ~70%;顺带跳过截断行)——全量 2.8GB 轨迹可在 3GB 容器构建成功。

数据:远端 37,890 步 + 本地 36,918 步 → 合并 167,635 样本 (choice 18,389 / boolean 74,338 / score 74,808 量级,train 158,290 + val 9,245),约为 v2 mock 语料 6 倍。

训练(ops/t4_real25.py,远端 nohup python3 -u -B t4_real25.py):

  • 阶段 stamp 幂等(/content/qwenjev_work_v3/done_v3/*.stamp),失败重跑自动跳过已完成阶段;
  • prep:HF 匿名拉 v2 hf_lora 分片重组(sha256 校验)→ stage_a_lora/ 起点(与 zero-shot 基线同起点,对照干净);
  • real_b:SFT 180 步(~38s/步,T4 ~2 小时;峰值 12.6GB/15GB);
  • real_c:RLCD + 校准 → 产物自动推 HF t4_assets_v3/checkpoints/;
  • 评对照:python ops/run_eval.py --games ar25 bp35 --max-actions 150 --checkpoint hf:tchbcb/qwenjev@t4_assets_v3/checkpoints --backend hf。

判据:best_level_sum > 0(v2 基线=0)即真数据生效;仍 0 → ε 提 0.45 + System-2 教师蒸馏 + 25×16×600 重采。


9. 路线图

里程碑 内容 验收标准 状态
M0 仓库骨架 + 单测 + 文档 make test 全绿 ✅
M1 本地全链路跑通:mock 游戏 → 采集 → 建库 → Stage A 蒸馏 → Stage B 训练 → 评测(视觉塔全程在环) make smoke 五环节全绿,蒸馏 loss 收敛,36 个单测通过 ✅
M2 换 hf 后端:Qwen3-VL-2B 学生 + 9B 教师,25 公开游戏真实采集 Choice 标签集 ≥ 5 万题,公开关 eval 完成率显著高于随机基线
M3 System-2 接入 + 调度调参 完成率升 & 9B 调用数下降
M4 Kaggle 打包提交 官方 LB 出分,进入迭代循环

后续方向:RLCD 后训练(NanoJev 官方 roadmap 同款)、共享前缀推理提速、把 Score 头升级为学习型局面价值模型。


10. 风险与合规清单

  1. 泛化陷阱:隐藏 110 关机制全部陌生,过拟合 25 公开关 = 白给。每轮训练都要看"未见过游戏"上的表现(val 按游戏切分就是为此)。
  2. 畸形输出即死刑:官方文档明确模型回包必须严格解析为合法动作名,否则 ValueError 终结当前游戏——qwenjev_agent.py 已内置正则提取 + 随机合法动作回退。
  3. RESET 滥用:RESET 不在候选池,仅由生命周期守卫触发。
  4. Testing Policy:官方对评测环境禁止逆向/探测/暴力破解(详见 arcprize.org 的 Testing Policy),提交前务必通读并遵守。
  5. 开源义务:获奖者不开源方案会被取消资格——本仓库 MIT 协议即为此准备。
  6. Token 安全:HF/Kaggle token 只放 .env(已 gitignore)或环境变量;任何在聊天/截图中明文出现过的 token,用完后建议立刻轮换。
  7. 成本纪律:RTX 排队以小时计且配额独占,本地 make play-local/make eval 先行,Kaggle Commit 只留给接近最终的版本。

11. 命令速查

make setup        # 环境安装(Python 3.12+)
make test         # 单测 36 个(纯 CPU,零下载)
make smoke        # 一键本地跑通:mock采集→建库→蒸馏→训练→评测(无GPU可用)
make collect      # 自博弈采轨迹(mock 游戏 / 25 公开游戏)
make build-data   # 轨迹 → Choice/Boolean/Score 训练样本(含 grid 帧字段)
make distill      # Stage A:9B 教师 → System-1 学生 视觉蒸馏对齐
make train-s1     # Stage B:决策头 SFT(NanoJev 配方,自动加载 stage A)
make eval         # 本地评测(mock 游戏默认)
make push-hf      # 推送本仓库到 HuggingFace(HF_TOKEN 从环境读)
python scripts/download_weights.py                     # 拉权重
python scripts/serve_system2.py --port 8000            # 9B 端点(transformers 兜底)
# vllm serve Qwen/Qwen3.5-9B --port 8000               # 9B 端点(首选)
python scripts/package_kaggle.py --username XXX --accelerator rtx6000

11.1 本地跑通记录(v0.2.0,2026-09)

无 GPU(4GB RAM / CPU)环境实测:make smoke 全链路通过——mock 游戏 2400 步轨迹、5267 样本(train 4927 / val 340)、Stage A 蒸馏 56 步 align_loss 0.0062→0.0012 收敛、Stage B 三头联训完成、评测 agent 完整跑 600 步决策(每步含视觉塔前向,~210ms/步)。

切换真实模型的路径:configs/train.yaml 里 system1.backend: "hf"(学生 Qwen/Qwen3-VL-2B-Instruct)+ stage_a_distill.teacher_model: "Qwen/Qwen3.5-9B",代码路径已就绪;建议先在单卡 GPU 机器上冒烟 hf 路径,再上 Kaggle。