NeotericLab

Naive × Claude Code:一次 char count 直接 GRPO 实验

记录 Naive 在 Claude Code 中辅助完成的训练:Qwen3-1.7B,不做 SFT,单卡 GRPO,验证准确率 21.3% → 54.4%(+33.1 个百分点)。

Naive 是研发助手,Claude Code 是运行工具,Qwen3-1.7B 是被训练的模型。会话记录中的助手型号为 naive-n0.5-flash,不据此推断底层供应商。本仓库公开训练代码、实际数据、指标与过程;不包含模型权重。

训练曲线

实验概况

项目 本次设置
日期 2026-11-01(UTC)
模型 Qwen/Qwen3-1.7B,关闭 thinking,全参数训练
硬件 单张 RTX 4090 48GB,约 64GB 系统内存
框架 verl + vLLM,FSDP2,参数与 optimizer CPU offload
数据 随机合成字符串,字符以 - 分隔,长度 5–20;train 9000 / val 1000
算法 GRPO;无 SFT;KL loss 与 reward KL 均关闭
更新 lr=1e-6;128 prompts × 8 rollouts;mini-batch=16;micro-batch=8
长度 prompt / response 上限均为 128 tokens
训练 2 epochs,140 步,每 5 步验证,含训练前基线
用时 训练进度条 1:49:50;含启动约 1h51m
判分 历史容错判分,详见 src/reward_tolerant.py

这是单次实验和固定验证集的结果,不是多 seed 平均,也不是独立盲测。数据生成器未强制去重,核对发现训练/验证间有 62 个相同的唯一问题,详见来源说明。容错判分可能把末尾无关数字计为正确,因此不等同于严格格式准确率,不能直接与官方 recipe 的结果横比。

先看过程

只核对数据和画图(无需 GPU)

需要 Python 3.12。以下命令都从仓库根目录执行:

python3 -m venv .venv
.venv/bin/pip install -r requirements-analysis.txt
.venv/bin/python -m unittest discover -s tests -v
.venv/bin/python scripts/extract_metrics.py archive/training.sanitized.log /tmp/char-count-metrics.csv
.venv/bin/python scripts/plot_metrics.py

测试检查全部 10,000 道题的真实字符计数、从日志重建全部 141 行指标与来源行号,以及判分的格式优先级和已知宽松行为。source_line 按 Python splitlines() 计算,包括日志中的 CR 进度更新。

复跑训练

在 Linux + NVIDIA GPU 环境中执行,需要 Git、Python 3.12、uv,以及兼容 CUDA 13 的驱动/系统依赖。本次配置以 48GB 显存、64GB RAM 的机器为参考,并未验证普通 24GB 4090。

训练依赖锁定在 verl commit 1876b06:torch 2.11.0、vLLM 0.24.0,完整依赖见 archive/uv.lock。准备脚本会核对 commit、lock 与 pyproject,而后同步 vllm/fsdp 环境并补装历史使用的 MLflow 3.17.2。安装体积较大。

bash scripts/setup.sh
mkdir -p models
.cache_verl/.venv/bin/hf download Qwen/Qwen3-1.7B --local-dir models/Qwen3-1.7B
bash scripts/train.sh

setup.sh 默认创建 .cache_verl。如系统缺少 CUDA 编译环境或 FlashAttention 系统依赖,可在这个固定版本的 verl 所提供的 docker/Dockerfile.uv.cu130 环境中执行;原实验的本地镜像已删除,仓库不提供可拉取的历史镜像。仓库路径请避免空格,以兼容上游 Hydra/uv 启动方式。

默认使用已保存的原实验 parquet 数据。模型下载未锁定历史 Hugging Face revision,因为记录中无法确认它;重新下载同名模型不保证字节相同。若已有本地模型和 verl 环境:

MODEL_PATH=/absolute/path/to/Qwen3-1.7B VERL_DIR=/absolute/path/to/verl bash scripts/train.sh

默认只输出 console,不要求访问原实验内网 MLflow。需要记录到自己的 MLflow 时:

MLFLOW_TRACKING_URI=http://localhost:5000 LOGGER='["console","mlflow"]' bash scripts/train.sh

历史设置为 save_freq=-1。如果希望保存新实验的权重,显式覆盖参数;这属于新实验配置:

bash scripts/train.sh trainer.save_freq=20

其他 Hydra 参数可追加在命令末尾。scripts/train.sh 保留原训练超参数,仅调整路径和日志服务配置;archive/launch_char_count.original.sanitized.sh 用于审计原配置,不作为可移植入口。

生成一份新数据

.venv/bin/python scripts/create_dataset.py --seed 42 --data_path /tmp/new-char-count
TRAIN_FILE=/tmp/new-char-count/rl/train.parquet TEST_FILE=/tmp/new-char-count/rl/test.parquet bash scripts/train.sh

历史生成器没有固定 Python random seed,因此此命令生成的是新数据,无法重建历史数据的相同字节。公开版增加 seed 并去掉生成器对 verl 的依赖,原生成器另存于 archive/。SFT 格式数据是生成器兼容输出,本次没有用来训练。

验证范围与许可证

发布整理已执行 CPU 侧的数据、指标、判分测试和 shell 参数检查;没有重新执行整轮 GPU 训练,也没有重建历史容器。训练完成附近的日志含 DataLoader worker 被 kill 的异常,详见过程说明。

代码与本仓库原创文档按 Apache-2.0 开源;第三方代码保留其版权与许可证,见 NOTICE。不分发 Qwen 权重,其使用条件由模型原仓库决定。