Code2Pixel

Code2Pixel 设计与实现方案

这份文档把目前定下的 spec、从 MiMo-V2.6 开源 RL 环境、GAGAR 和 Automating eval design and hillclimbing 里得到的启发,整理成可以照着做的方案。带”建议”的数字是初始值,试跑后再调。

1. 目标

2. 任务定义

输入:一段文字,加上赛道和档位。

输出:agent 在 /workspace 里交三样东西,路径固定,校验要严格:

/workspace/out/final.png   最终图,尺寸由题目指定(默认 1536×1024)
/workspace/src/            生成它的全部代码
/workspace/run.sh          一条命令,在干净环境里从头重跑出 final.png

赛道

赛道 允许 禁止
主赛道 任何代码、任何渲染器(SVG、Canvas、Three.js、Blender、numpy……) 联网;读现成图片、素材、模型;调用生图模型
素材赛道 另外可用环境里预置的授权素材库(照片、贴图、HDRI、3D 模型) 联网;调用生图模型
辅助赛道 给一张参考图,用代码复刻 同主赛道

harness:直接用市面上用得最多的现成 agent,目前是 Claude Code 和 Codex,以后需要再加。不自己写 agent 循环。agent 在统一镜像里以 headless 模式运行,外层脚本(harness/run.py)负责起容器、监控预算、收集产出和记录。

档位:测的是一次正常调用、一轮长程运行的效果,也就是大家平时实际的用法。harness 不强制 agent 多试几轮,题目里也不要求用满预算:差模型多试很多次也能刷分,还会白白增加测试成本。

档位 规则
不看图 禁止查看任何图片(包括自己渲染的结果)
正常运行 可以看图

token 口径:每次模型调用的”新增输入(不含缓存命中)+ 输出”累加。缓存读取不计入预算:每轮都会重读整个上下文,计进去的话预算会被轮数吃光,而且两家缓存机制不同,没法比。

3. 题库

类别:风景、街景、动物、人物、静物、多物体、指定画风(水墨、像素、动画背景等),外加一组”代码该赢”的题:

来源优先级:

  1. 人们真实让 coding agent 画图的 prompt,比如 X 上的 showcase,改写后使用,保留出处;
  2. 人手写;
  3. 以真实 prompt 为锚点的合成题。

选题规则:

规模(建议):

集合 规模 公开 细则 用途
train 5,000+ 公开 自动生成 RL 训练
dev 150 公开 人工核对 报分、调试
test 300 不公开,每季度换一部分 人写 正式报分,不进训练

4. 评分

评分分三层。第一层是门槛,不过门槛总分直接为 0。

4.1 程序化规则(门槛)

4.2 VLM 裁判

4.3 人工校准

4.3b 细则当门槛,两两比较当主分(2026-10-02 用户定)

阶段 4 实跑里逐条细则得分接近满分(60 次里 52 次满分),分不出模型。原因是细则大多只核对”有没有”。所以改成:

4.4 训练 reward 和 benchmark 分数分开算

  训练 reward benchmark 分数
比较对象 同题一组 rollout(建议 8 个),组内比较,顺序按 Williams 设计排 固定图池
组成 门槛 × 细则得分 × 组内相对名次 主分:对图池的两两比较 Elo 和胜率;门槛没过、或题目要求细则没达标的一方直接判负。质量细则得分单独报告
细则来源 自动生成 人写或人工核对

5. 评测本身要先过的检查

一个指标只有通过下面这些检查,才进入正式报分:

  1. 分数随能力上升:至少 3 个模型、各跑 2 个 effort 档,更强的模型、更高的 effort,分数要更高。
  2. 留出区分空间:最强模型开最高 effort,也要离满分很远(建议低于 70%)。试跑用的 CLIP 认对率第一轮就 12/12,就是没有区分空间的反例。
  3. 噪声小于要关心的差距:每题跑 3 个种子,用 bootstrap 算置信区间。区间半宽要小于打算据此下结论的最小差距(建议 2 分)。报分时附上置信区间。
  4. judge 稳定:同一输出判两次,结论不一致的比例要低于 5%(建议值)。
  5. 防刷分红队:准备一批对抗样本,这些样本的得分必须是 0,或者至少不能比正常样本高:
    • base64 位图;
    • 画面里写”杰作”“完美符合题意”之类的字;
    • 在画面里写 prompt injection;
    • 硬编码像素;
    • 偷偷调用模型。
  6. 过拟合信号:给使用者一条规则:dev 分数上升而 test 分数不动,说明过拟合了。我们自己的排行榜上同时显示 dev 和 test 两个分数。

6. 数据和环境格式

每条任务一行,格式参照 MiMo,可以直接接 verl 这类训练框架:

{
  "prompt": [{"role": "user", "content": "…题目文字…"}],
  "reward_model": {
    "gate": {"size": [1536, 1024], "regen": "exact", "track": "main"},
    "claims": [{"text": "画面里正好有 3 只猫", "weight": 1}],
    "program_checks": [{"type": "background_color", "value": "#ffffff"}],
    "pairwise_pool": "pool-v1/0042"
  },
  "extra_info": {"task_id": "c2p-0042", "split": "dev", "track": "main", "budget": "6rounds",
                 "category": "动物", "source": "human", "docker_image": "code2pixel/env:0.1"}
}

统一 Docker 镜像(env/Dockerfile):Python 科学计算栈、Node 加 Three.js、headless Chromium(Playwright)、Blender 4.0、rsvg、中文字体,外加 Claude Code 和 Codex 两个 CLI;自带 c2p-render,把 SVG 或 HTML(含 WebGL)渲染成 PNG。素材赛道额外挂载一个只读的素材库。

网络:agent 用订阅账号登录,必须能连模型服务。容器只接内部网络,通过出口代理(env/proxy/)上网,代理默认拒绝,只放行两家登录和模型调用的域名,并记录每个请求。

代理管不到的地方,要在 agent 配置里关掉:联网搜索、图像生成这些工具在模型服务端执行,请求不经过我们的代理。

卡住处理:模型的流式回复偶尔会挂住。对话记录和会话记录连续 10 分钟没有新内容,判定为卡住并停止;批量运行时,卡住或一个 token 都没用就结束的,自动重跑一次,并在结果里标明。

7. 实现步骤

阶段 做什么 完成标准
0 试跑(已完成) 24 张图、结论和局限都在报告里
1 环境和 harness:Docker 镜像、出口代理、harness/run.py(Claude Code、Codex);用量计数和上限强制执行;日志 3 题 × 2 个 agent 跑通各档(已完成,见 PHASE1.md)
2 门槛:输出路径校验、断网重跑比对、静态扫描、运行时检查、程序化约束 红队对抗样本全部被判 0;试跑 24 张里正常的全部通过(已完成:手写对抗样本 15/15 判不过;验收 18 次和试跑 A 赛道 12 张没有误判,B 赛道等素材规则定了再测。见 PHASE2.md)
3 题库 v0:dev 150 题,带人工核对的细则;”代码该赢”类至少 30 题 每题有来源、类别和人判的难度(已完成 v0:常规 100 + 代码该赢 50,32 题改写自 X 上的真实 prompt;每题有来源、类别、难度、5–10 条细则,能程序判的约束写成门槛检查。细则由两个模型交叉检查,分歧和 30 题抽查按用户意见改由 subagent 审,还没有人逐条核对过;精确修改题的修改框用真实修改验证过。见 PHASE3.md)
4 VLM 裁判:逐条判细则;图池两两比较,含位置平衡和 Elo;读代码的 grader judge 两次判定不一致的比例低于 5%(进行中:裁判自洽 98–100%、两个裁判逐条一致 92%;但细则得分接近满分、两两比较结论随裁判反转,等人工标注。见 PHASE4.md)
5 生图模型基线:2–3 个生图模型画 dev 全部题,放进图池 图池覆盖 dev 全部题
6 验证评测:3 个模型 × 2 个 effort × 3 个种子;读 50 个样本;人工两两比较 第 5 节检查全部通过,不过的指标改完再测
7 训练环境:自动出题和自动生成细则,得到 train 集;组内比较 reward;导出 Parquet 和镜像 能用 verl 在 train 集上跑通一次小规模 RL,看到 dev 分数变化
8 发布:HF 数据集(train、dev)、镜像、评测代码、排行榜;test 集由我们来跑 报告给出分赛道、分档的分数、置信区间和成本

8. 还没定的问题