30 个实验,一个一个看
改代码的是 GPT-6 Astra,被训练的是一个小语言模型,每次都从零开始、只读英文儿童故事。每个实验它只改 train.py 里的一处,训练 3 分钟,再拿一批没见过的故事考一次:分数比之前最好的低,就留下接着改,不然撤回。点图上的点,看它每一次改了什么、为什么这么想。
分数 越低越好
分数叫 val_bpb:小模型读那批没见过的故事时,猜下一个字有多「意外」。越低,它越能猜中,写出来的东西越像话。
所以这不是 AI 在改它自己:GPT-6 Astra 自己一个参数没变,变的是小模型的训练配方,考卷和 3 分钟的规矩是 Karpathy 和我定的。最大的一刀是第 2 个。原版每一步要喂 52 万 token,是照 H100 那种大卡配的,放在我的卡上,3 分钟只够更新 40 次;它把这个数调小,分数当场少了一半。这一刀换一个懂行的人来,多半也会先砍。后面 28 个实验加起来,只再降了 0.056。
再往后就得小心了。第 17、25、26 个各自只进步了不到 0.0005,而它最后把最好那版原样重跑一遍,分数就差出 0.0015(点「放大看后半程」,浅蓝那条带子就是这个差距)。这三次「进步」很可能只是运气,它自己在总结里也提醒了:这些只跑一次得出的排名,要谨慎看待。
同一个开头,实验前后各写一段
我把第 1 个(原样)和第 26 个(最好那版)的代码各训练 3 分钟,给同一个开头,让它们往下写。两个开头,每个用 4 个随机种子各写一次,16 段全在这儿;每段最多写 110 个 token,所以常常停在半句。人名我标了出来。
中文是我照原文翻的,原文的毛病也照着翻:实验前那版常常一句话里「她」就变成了「他」,一段里冒出五六个名字;实验后那版从头到尾是同一个主角,前后接得上。
我能在自己电脑上跑吗
能,有一块 NVIDIA 显卡就行。我用的是 autoresearch 的 Windows 显卡版;Mac 和 AMD 显卡也有别人改好的版本,列在 Karpathy 原项目的说明里,我没试过。这一趟的实际花销:
- 显卡
- RTX 5070 Ti,16G 显存。30 个实验里显存最多用到 8.2 GB,最好那版 7.2 GB。
- 准备
- 装 uv 和 PyTorch,下载训练数据 TinyStories(273 万篇英文儿童故事,约 670 MB),再训练一个分词器,前后十几分钟。
- 每个实验
- 训练 3 分钟,加上启动和考试,一个 3 分 40 秒左右(第一个要 5 分半)。30 个一共 118 分钟。
- 研究员
- GPT-6 Astra,在 Codex 里跑,推理档 max。从开工到写完总结,我一次没插手。
- token
- 读了 2327 万,写了 5.9 万。按 OpenAI 的 API 标价,约合 27 美元。
钱几乎都花在「重读」上。它每看一眼训练日志,都要把前面的对话从头再读一遍,所以 2327 万里 99.4% 是缓存命中,按每百万 1 美元算就占了 23 美元;它自己写下的只有 5.9 万 token,不到 3 美元。同样这些 token 换成 GPT-6.1 Sol 的标价是 3 美元出头,不过我没拿它跑过,它要用多少 token 不好说。用 ChatGPT 账号登录 Codex 的话,这些都算在订阅的用量里;订阅比照 API 价划算多少,我之前拿 Claude 算过一笔账。
Mia 的小贴士
- 原版的 program.md 让它先跟你一起做准备,还写着「永远别停」。想放着它自己跑,就在提示词里写明:准备工作自己做,做满多少个实验或者过了多少分钟就停。我给的是 30 个或 150 分钟,它 118 分钟就做满了 30 个。
- 我把每次训练从 5 分钟改成了 3 分钟,改在 prepare.py 的
TIME_BUDGET里(研究员不许碰这个文件)。原版在家用显卡上加上考试要 6 分多钟一个,改完两小时正好 30 个。 - 在 Windows 上,Codex 跑命令用的是 PowerShell。提示词里写一句「用 Select-String 代替 grep,用 Get-Content -Tail 代替 tail」,省得它自己去试。
- 它只读过英文儿童故事,最好那版也就是能写个像样的童话,别指望它回答问题。
换成你自己的问题,打分要什么样
这个循环本身跟语言模型没关系:改一处,跑一次,看分数,留下或撤回。网上已经有人拿它调冷邮件、调电路参数。能不能搬到你的问题上,几乎全看打分。我这次的打分有这么几个特点,少一个都容易出事:
- 一个数,机器自己算。这里就是 val_bpb。要人来看、来评的,它转不起来。
- 几分钟出一次结果。3 分钟训练加不到一分钟的考试,两小时 30 次。要等几天才知道好坏的,比如发出去的邮件有没有人回,一晚上只够试一次,这个循环就没什么意义了。
- 考卷它碰不到。考试写在 prepare.py 里,规矩写明不许改,它最后还自己核对了一遍,评估代码和开头一模一样;考的故事也是训练时没见过的。考卷能改、考题见过,最省事的「进步」就是背答案,AI 排行榜上就常出这种事。
- 先量一下分数自己会晃多少。同一份代码再跑一遍差了 0.0015。比这还小的进步,要多跑几遍才知道是不是真的。
- 分数以外你在乎的,写进规矩。它只盯这一个数。原版规矩里写了显存可以涨一点但别暴涨,同样的分数代码越简单越好;换成你的问题,速度、体积、功能不能少这些,也得写进 program.md,不然它会拿它们去换分数。
还有一点:它一次只改一处,好了才留,是一步一步往下摸。要几处一起改才见效的,这么摸很容易错过。它在总结里也写了,时间多的话,想把每批大小和学习率放在一起调,再给领先的几个配置换几个随机种子多跑几遍。
我给它的那段话,和全部记录
研究员先读 Karpathy 原项目里的 program.md(它的规则手册,我没改),我另外只给了下面这段:让它自己做准备、每个实验记笔记、到上限就停。复制过去就能用,分支名和 Windows 那几句按你的情况改。
给研究员的话(英文原文和中文意思)
You are an autonomous machine-learning researcher. This folder is Karpathy's "autoresearch" setup (Windows RTX fork). Read program.md (your rulebook), README.md, prepare.py and train.py first. The human is away. Do the setup yourself without asking anything: - Create and switch to a new git branch `autoresearch/oct27` from the current HEAD. - The data and tokenizer are already prepared in the cache. Do not run prepare.py. - Create results.tsv with this header (tab-separated, 6 columns): commit val_bpb memory_gb status description finished_at (finished_at = local wall-clock time HH:MM when that experiment finished) - Create notes.md. After EVERY experiment append: `## <n>. <short title>` then 1-3 plain-English sentences: what you changed, why you expected it to help, and what happened (numbers). Then run the experiment loop exactly as program.md describes (first run = baseline, unchanged). Notes: - The time budget per run is 3 minutes of training (set in prepare.py, which you must NOT modify). Never touch prepare.py or the evaluation. - This machine is Windows. Use PowerShell equivalents (Select-String instead of grep, Get-Content -Tail instead of tail). Launch runs as `uv run train.py > run.log 2>&1`. - If a run takes longer than 8 minutes, kill it and treat it as a crash. - Do not install packages, do not touch anything outside this folder, no network access needed. Budget (hard stop, overrides "NEVER STOP" in program.md): stop after 30 experiments in total (baseline included) OR when 150 minutes have passed since you started, whichever comes first. Do not pause to ask questions before that. When you stop, make sure the branch tip is the best kept commit, and write summary.md: baseline val_bpb, best val_bpb, how many experiments (keep / discard / crash), the kept changes in order, and 3-5 sentences on what you learned and what you would try next with more time.
你是一位自主的机器学习研究员。这个文件夹是 Karpathy 的 autoresearch(Windows 显卡版)。先读 program.md(你的规则手册)、README.md、prepare.py 和 train.py。 我不在旁边。准备工作你自己做,不要问我: - 从当前提交新建并切到分支 autoresearch/oct27。 - 数据和分词器已经准备好了,不要跑 prepare.py。 - 建一个 results.tsv,表头(制表符分隔,6 列): commit val_bpb memory_gb status description finished_at (finished_at = 这个实验结束时的本地时间 HH:MM) - 建一个 notes.md。每做完一个实验,在后面加: 「## 编号. 短标题」,再写一到三句大白话:改了什么、为什么觉得会有用、结果怎样(带数字)。 然后完全照 program.md 跑实验循环(第一个跑原样的基准)。注意: - 每次训练只有 3 分钟(写在 prepare.py 里,你不能改)。不许碰 prepare.py 和评分。 - 这台机器是 Windows,用 PowerShell 的写法(Select-String 代替 grep,Get-Content -Tail 代替 tail)。用 `uv run train.py > run.log 2>&1` 启动训练。 - 一次训练超过 8 分钟就杀掉,算崩溃。 - 不装新的包,不碰这个文件夹以外的东西,不需要联网。 预算(硬上限,盖过 program.md 里的「永远别停」):一共做满 30 个实验(含基准),或者从开始算过了 150 分钟,先到哪个就停。在那之前别停下来问问题。 停下的时候,确保分支最新的提交就是留下来的最好那个,再写一份 summary.md:基准分数、最好分数、一共几个实验(留下 / 撤回 / 崩溃各几个)、按顺序列出留下的改动,再用三到五句话写你学到了什么、时间多一点的话接下来会试什么。
30 个实验全表
| # | 改了什么 | 分数 | |
|---|---|---|---|
| 1 | 原样跑一遍,当基准baseline unchanged | 1.0416 | 留下 |
| 2 | 每一步喂的数据从 52 万 token 砍到 3.3 万total batch 32768 tokens | 0.5250 | 留下 |
| 3 | 注意力换成更快的写法full causal SDPA without explicit attention masks | 0.5051 | 留下 |
| 4 | 关掉省显存的「激活检查点」disable activation checkpointing | 0.4887 | 留下 |
| 5 | 模型改小:8 层 → 6 层depth 6 width 384 | 0.4761 | 留下 |
| 6 | 再砍小:只剩 4 层depth 4 width 256 | 0.5003 | 撤回 |
| 7 | 学习率砍一半(0.04 → 0.02)matrix learning rate 0.02 | 0.4739 | 留下 |
| 8 | 训练只看短段落(512 个 token)512-token training contexts with scaled device batches | 0.5457 | 撤回 |
| 9 | 段落取中间:1024 个 token1024-token training contexts with scaled device batches | 0.4846 | 撤回 |
| 10 | 每一步的数据再减一半total batch 16384 tokens | 0.4789 | 撤回 |
| 11 | 每一步的数据加一倍total batch 65536 tokens | 0.4863 | 撤回 |
| 12 | 去掉输出那一层的「封顶」remove output logit softcap | 0.4721 | 留下 |
| 13 | 注意力头切得更细(每个头 128 → 64 维)head dimension 64 at unchanged width 384 | 0.4748 | 撤回 |
| 14 | 6 层不变,每层变窄(384 → 256)six layers with width 256 | 0.4742 | 撤回 |
| 15 | 宽度不变,层数加回 8 层eight layers at width 384 | 0.4818 | 撤回 |
| 16 | 按现在的模型重新挑每批大小architecture-specific runtime autotune cache | 0.4700 | 留下 |
| 17 | 学习率提早往下收warmdown ratio 0.8 | 0.4698 | 留下 |
| 18 | 词向量学慢一点(0.6 → 0.2)embedding learning rate 0.2 | 0.4735 | 撤回 |
| 19 | 输出层学快一倍output projection learning rate 0.008 | 0.4706 | 撤回 |
| 20 | 输出层学慢一半output projection learning rate 0.002 | 0.4736 | 撤回 |
| 21 | 去掉权重衰减matrix weight decay 0.0 | 0.4746 | 撤回 |
| 22 | 每层中间那段窄一点(4 倍 → 3 倍)MLP expansion ratio 3 instead of 4 | 0.4703 | 撤回 |
| 23 | 注意力里去掉一步归一化attention without query and key normalization | 0.4752 | 撤回 |
| 24 | 关掉额外的「值嵌入」disable auxiliary value embeddings | 0.4776 | 撤回 |
| 25 | 学习率取中间(0.03)matrix learning rate 0.03 | 0.4696 | 留下 |
| 26 | 优化器的账记得更精确float32 AdamW moment buffers for all parameters | 0.4692 | 留下 |
| 27 | 残差那几个小旋钮学慢一点residual scalar learning rate 0.1 | 0.4718 | 撤回 |
| 28 | 位置编码更看重近处RoPE base 1000 | 0.4715 | 撤回 |
| 29 | 学习率收尾换成平滑曲线cosine instead of linear cooldown | 0.4742 | 撤回 |
| 30 | 最好那版原样再跑一遍confirmation repeat of best kept configuration | 0.4707 | 撤回 |














