2026-09-03 · 原文发布日
用RL训练代码模型画水彩:开源复现
作者在Hugging Face上完整复现了此前走红的水彩画项目:语言模型只能调用p5.brush库的十个方法,写出约150行JavaScript来作画,用TRL加OpenEnv做GRPO强化学习,奖励混合方案可配。数据集、RL环境、评分模型、训练脚本和训出的模型全部开源,复制两个Space、设两个环境变量后一条hf jobs命令即可开训,文中还比较了三种奖励混合的效果。
原文要点
Hugging Face工程师Sergio Paniego开源复现了Surya Narreddi走红的水彩项目:语言模型只能调用p5.brush库47个方法中的10个,写约150行JavaScript作画,用TRL加OpenEnv做GRPO强化学习。奖励四项:门槛0.05(能编译、真上色、不作弊)、长度0.05、成对评委0.60(Qwen3-VL-30B经Inference Providers,与178张人工分级参考画比较)、HPSv3偏好模型0.30。他训练并比较了judge-led、hps-led、hps-only三种奖励混合,judge-led从0.45升到0.72。每步8个rollout、约15至18分钟,110步约需一张H200跑34小时,数据集、环境、评分模型、脚本和模型全部公开。
这次做成什么
按作者公开方案在Hugging Face上复现一次水彩GRPO训练:先复制两个Space、设好奖励混合的环境变量,用短跑验证管线,再决定是否发起110步完整训练;并先用本地小样例理解十方法限制。
准备什么
- Hugging Face账号及HF_TOKEN,且能使用Jobs、Spaces和Inference Providers(多项为付费服务)
- 本地装好hf CLI并能运行hf jobs命令
- 接受作者给出的成本量级:单H200训练、一个a100-large评分Space常驻、一个cpu-upgrade环境Space
- 已复制作者的水彩环境Space和HPSv3评分Space到自己的命名空间
具体怎么做
复制两个Space
在Hub上分别Duplicate作者公布的watercolour-env(RL环境,Docker Space,cpu-upgrade档)和watercolour-hpsv3(评分模型,a100-large档)到自己账号,记下前者的Space地址。注意评分Space整个训练期间要常驻,训练结束记得暂停或设休眠,否则持续计费。
设定奖励混合环境变量
按作者做法,用两个环境变量决定成对评委与HPSv3的权重:原始judge-led混合为评委0.60、HPSv3 0.30;验证管线可先用hps-only(评委0、HPSv3 0.90),作者先用它确认管线能学习,60步即停。
本地理解十方法限制(本站设计小练习)
在发起昂贵训练前,先用下方材料中的p5.brush示例草图本地跑一遍:只用scaleBrushes、noStroke、fill、noFill、fillBleed、fillTexture、beginShape、vertex、endShape、circle这十个方法画一朵花,体会模型被限制的作画空间,便于之后读懂rollout数据集里的代码。
发起训练
运行下方材料中的hf jobs命令:把<you>替换为自己的用户名,--env-url指向复制的环境Space,主题可用--subject 'a peach hibiscus',短跑验证可把--steps改小;硬件为h200,通过--secrets HF_TOKEN注入令牌,--push-to-hub把适配器推回Hub。
监控与判读
在trackio里看分组平均奖励曲线;判读时记住作者的两个教训:奖励曲线的个别下探可能只是该步抽到了更难的参考画(成对评委每步随机抽4张),以及基础设施失败曾以0.0混入奖励(已改为返回None并剔除该rollout),看曲线要结合画廊里对应步的实际画作。
可直接复制的材料
训练启动命令(转自作者公开配方)
引自作者文章;<you>两处需替换为自己的Hub用户名,短跑验证可将--steps 110改为60(对应作者hps-only验证跑法);all-linear、5e-5、constant_with_warmup、scale-rewards none是作者解锁首个成功跑的四项关键修改。
hf jobs uv run train/watercolour_grpo.py --flavor h200 --timeout 48h --secrets HF_TOKEN -- \
--env-url https://<you>-watercolour-env.hf.space \
--model Qwen/Qwen3.5-35B-A3B --lora --all-linear --bf16 --gradient-checkpointing \
--subject 'a peach hibiscus' --references 4 \
--top-p 0.95 --top-k 20 \
--lr 5e-5 --lr-scheduler constant_with_warmup --warmup-steps 5 \
--scale-rewards none \
--steps 110 --n-episodes 240 --num-generations 8 \
--per-device-batch-size 1 --gradient-accumulation-steps 8 \
--max-completion-length 8192 \
--run-tag my-run --out <you>/watercolour-grpo --push-to-hub十方法限制内的p5.brush示例草图(本站独立编写)
本站编写的练习代码:花瓣与花心的绘制只使用十方法白名单(scaleBrushes、noStroke、fill、noFill、fillBleed、fillTexture、beginShape、vertex、endShape、circle),createCanvas/background/三角函数为 p5.js 基础画布函数;需在加载了 p5.js 与 p5.brush 的页面运行。仅作理解作画限制之用,非训练数据,也不保证能通过作者环境的反作弊门槛(门槛要求以库方法作画而非直接 p5 调用)。
function setup() {
createCanvas(600, 600);
scaleBrushes(1.2);
noStroke();
background('#f5f0e6');
}
function draw() {
// 花瓣:大片湿画法打底,内部再叠一层更浓的小花瓣
const cx = 300, cy = 300;
for (let i = 0; i < 6; i++) {
const a = (TWO_PI / 6) * i;
const px = cx + cos(a) * 90;
const py = cy + sin(a) * 90;
fill('#e86a8a', 60);
fillBleed(0.25);
fillTexture(0.4);
beginShape();
vertex(cx, cy);
vertex(px - 40, py - 40);
vertex(px, py - 60);
vertex(px + 40, py - 40);
endShape(CLOSE);
fill('#c2185b', 90);
fillBleed(0.12);
circle(px, py - 20, 46);
}
// 花心
fill('#f2b705', 120);
fillBleed(0.08);
circle(cx, cy, 40);
noLoop();
}三种奖励混合对照配置
权重数值来自作者文章;具体通过哪两个环境变量传入请以复制的Space与训练脚本README为准,本站未实测该界面。
{"judge-led":{"pairwiseJudge":0.60,"hpsv3":0.30,"gate":0.05,"length":0.05,"note":"原始混合,作者跑到110步停"},"hps-led":{"pairwiseJudge":0.30,"hpsv3":0.60,"gate":0.05,"length":0.05,"note":"中间点,110步停"},"hps-only":{"pairwiseJudge":0.00,"hpsv3":0.90,"gate":0.05,"length":0.05,"note":"管线验证用,60步停"}}输入与输出示例
本站虚构演示,未运行;作者原60步hps-only实跑为0.58升至0.71,本例数字是按20步缩短后自拟的合理示意。
输入
本站设定的缩短练习:主题'a peach hibiscus',hps-only混合,--steps 20,每步8个rollout,仅验证环境、评分与推回Hub是否走通。对应输出
示意性trackio关键行(本站虚构):step 1 平均组奖励0.52、门槛通过率0.75;step 10 平均0.61、门槛通过率0.875;step 20 平均0.66、门槛通过率1.0,Hub上出现<you>/watercolour-grpo适配器仓库。曲线抬头、坏画(总分低于0.3)从5幅降到1幅,与作者描述的『先学会不画坏画』一致。做完检查这些
- 两个Space复制成功,环境Space的渲染接口能返回一张画作而非超时
- 短跑结束后trackio里平均奖励呈上升趋势,且无整段恒为0的平线
- 每组8个rollout未出现奖励全同(GRPO梯度死亡的征兆),作者确认其实跑无此问题
- Hub上生成适配器仓库和rollouts数据集,能打开任意一幅画对应的JavaScript源码
- 训练结束后评分Space已暂停或设好休眠,不再持续计费
容易卡住的地方
- 成本不低:作者实跑110步约34小时单H200,评分Space全程常驻;作者称单步15到18分钟,其中七八成在渲染
- Qwen3.5-35B-A3B是MoE架构,LoRA必须all-linear,否则只训练到四十层中的十层(作者踩过的坑)
- 基础设施失败曾以0.0计入奖励(最差一次占5.2%),作者已改为返回None,复现旧代码时注意核对
- 成对评委每步随机抽4张参考画,单步奖励下滑可能只是抽签难,别急于中断
- 奖励含作者个人口味(178张人工分级参考池),换主题需自建参考池,工作量在人工分级
- 界面与参数以作者仓库为准,本站未实测,文中两条环境变量的具体名称需在Space设置页核对
本站借助AI整理来源事实,独立编写中文操作指南与示例。示例不代表实际运行结果;来源效果尚未由本站独立复现。付费模板与模型、服务费用分别计算。
- 原文标题
- Training a coding model to paint watercolours with TRL and OpenEnv
- 原作者
- Hugging Face / 文章署名作者
- 原始发布日期
- 2026-09-03T00:00:00+00:00
- 来源
- https://huggingface.co/blog/train-to-paint-with-code