整理 | 屠敏出品 | CSDN(ID:CSDNnews)今天,前 OpenAI 联合创始人、Eureka Labs 创始人 Andrej Karpa...
2025-10-15 0
整理 | 屠敏
出品 | CSDN(ID:CSDNnews)
今天,前 OpenAI 联合创始人、Eureka Labs 创始人 Andrej Karpathy(安德烈·卡帕西)带来了一个全新的开源项目——nanochat。
用他自己的话说,这是他写过的最“疯狂”的作品之一:
只要 4 个小时、100 美元,就能“手搓”一款属于自己的 ChatGPT。倘若花上 12 个小时来训练,其性能可超越 GPT-2。
简而言之,nanochat 可以看做是一个类似 ChatGPT 的 LLM 的全栈实现,它把训练和推理的全流程都整合进了一个干净、轻量、可修改、几乎零依赖的代码库里。
你只要启动一台云端 GPU,运行一条脚本命令,大约 4 小时后,就能在 ChatGPT 风格的网页界面中,与自己训练的 LLM 对话了。不仅如此,它还可以写诗、讲故事和回答一些简单的问题等等。
可喜的是,此项目遵循 MIT 协议开源,这意味着任何人都可以自己去尝试做一款 GPT。正因此,项目发布数小时内,便斩获了 7.1k Star,引发无数 AI 开发者热议与尝试。
话不多说,感兴趣的小伙伴可通过 GitHub 开源地址,即刻上手体验:https://github.com/karpathy/nanochat
仅有 8000 行代码的 nanochat
根据 Karpathy 介绍,nanochat 约有 8000 行代码,几乎覆盖了整个模型训练与推理流程,具体包括:
Karpathy 进一步表示,模型训练的规模可根据时间与成本灵活调整:
与此同时,Karpathy 在 GitHub 上打趣道:
“这是 100 美元能构建的最强 ChatGPT。”
而对于未来目标,Karpathy 称:
我的目标是把整个“强基线”(strong baseline)技术栈整合到一个统一、简洁、可读、可修改、便于分叉的仓库中。nanochat 将成为正在开发中的课程 LLM101n 的收官项目。
LLM101n 是 Karpathy 所创立的教育公司 Eureka Labs 面向本科生开设的一门课程,旨在带领学生从零构建属于自己的 AI 模型。其补充说,nanochat 未来有望像 nanoGPT 一样,发展成一个研究平台或基准项目。
快速上手
为了让更多的爱好者迅速上手,Karpathy 在 GitHub 上(https://github.com/karpathy/nanochat/discussions/1)详细分享了 nanochat 的教程。
nanochat 被设计为在单个 8×H100 GPU 机器上运行,此次教程中,Karpathy 使用了 Lambda GPU Cloud,每小时大约 24 美元。当然想要尝试的爱好者们也可根据个人情况自行选择,进行了尝试。
接下来看看他到底是怎么做的?
环境搭建
首先,克隆项目并进入目录:
git clone git@github.com:karpathy/nanochat.gitcd nanochat
用 100 美元训练出最强的类 ChatGPT,其背后最快体验魔力的方法是运行speedrun.sh(速通)脚本。
speedrun.sh 脚本可以在一台新机器上直接运行,从头到尾完成训练和推理。
一切的前提就是需要确保安装了新的 uv 项目管理工具。然后创建虚拟环境、安装依赖并激活它,这样在终端输入 python 时,就会使用虚拟环境里的 Python,而不是系统自带的 Python:
# 安装 uv(如果还没安装的话)command -v uv &> /dev/null || curl -LsSf https://astral.sh/uv/install.sh | sh# 创建本地虚拟环境 .venv(如果不存在的话)[ -d ".venv" ] || uv venv# 安装仓库依赖uv sync# 激活虚拟环境,这样 `python` 就会使用项目的虚拟环境source .venv/bin/activate
接下来,需要安装 Rust/Cargo来编译 nanochat 中自定义的 Rust 分词器。
Karpathy 称,引入新的分词器确实有点麻烦,但之前 Python 版本的 minbpe 太慢,而 HuggingFace 的 tokenizer 太臃肿且复杂。
所以他自己实现了一个新的 Rust 分词器来训练(经过测试效果与 Python 版本一致),但推理阶段仍会使用 OpenAI 的 tiktoken来保证效率。
编译分词器步骤如下:
# 安装 Rust / Cargocurl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -ysource "$HOME/.cargo/env"# 编译 rustbpe Tokenizeruv run maturin develop --release --manifest-path rustbpe/Cargo.toml
这样就完成了分词器的编译和环境搭建,为后续训练做准备。
训练分词器
接下来,就需要预训练数据,以便完成两个任务:
这里的预训练数据就是大量网页文本,在教程中,Karpathy 使用的是 FineWeb-EDU 数据集。
他解释道,通常大家可以直接用 HuggingFace 的 datasets.load_dataset 来加载,但这个太笨重、臃肿,而且把一些很简单的逻辑隐藏起来,所以他自己选择了重新打包了整个数据集,生成了简单、完全随机打乱的数据分片,方便高效访问。
此外,Karpathy 还把 sample-100B 版本上传成了 karpathy/fineweb-edu-100b-shuffle(https://huggingface.co/datasets/karpathy/fineweb-edu-100b-shuffle)。
每个分片是一个简单的 Parquet 文件,约 0.25M 个字符,压缩后(gzip 压缩)在磁盘占用约100MB 空间。数据集总共有1822 个分片,但训练一个depth=20的模型只需要240 个分片。
下载数据:
python -m nanochat.dataset -n 240
默认情况下,这些数据会存放在 ~/.cache/nanochat。下载完成后,就可以训练分词器了。分词器的作用是把文本在字符串和代码表符号序列之间互相转换。
同样在默认情况下,Karpathy 表示,训练的词表大小是 2¹⁶ = 65,536个 token,这个数字比较好记。其中少数 token 被保留作特殊用途(后续聊天 schema 会用到)。训练集大小约20 亿字符,训练时间仅需约 1 分钟。
训练算法与 OpenAI 的方法一致(正则分割 + byte-level BPE)。
训练完成后,可以评估分词器效果:
python -m scripts.tok_train --max_chars=2000000000python -m scripts.tok_eval
评估结果显示,分词器压缩率约为 4.8,也就是说平均 4.8 个原始字符会变成 1 个 token。同时,也可以将 nanochat 的结果与GPT-2和GPT-4分词器做对比:
有趣的是,虽然词汇量较小,但在 FineWeb 数据集上,nanochat 的分词器表现略胜 GPT-4。这是因为 nanochat 的分词器正好针对这个数据集训练,能够更好地匹配文档分布,比如在英语文本压缩上略占优势。
训练阶段
预训练
在开始预训练之前,Karpathy 建议需要下载一个名为“eval bundle”的文件。
在预训练过程中,脚本会定期评估 CORE 指标。简单来说,CORE 是一个规范化的综合指标,用于衡量模型在多个自动补全数据集上的表现。数据集包括 HellaSwag、Jeopardy、BigBench QA、Wikidata、ARC-Easy/Challenge、COPA、Commonsense QA、PIQA、Lambada、Winograd、BoolQ 等,总共 22 个数据集。
下载、解压,并将 eval bundle 放到基础目录下:~/.cache/nanochat/eval_bundle
curl -L -o eval_bundle.zip https://karpathy-public.s3.us-west-2.amazonaws.com/eval_bundle.zipunzip -q eval_bundle.ziprm eval_bundle.zipmv eval_bundle "$HOME/.cache/nanochat"
另外一个可选步骤是设置 wandb,可以在训练过程中查看漂亮的可视化曲线。虽然 uv 已经安装了 wandb,但你仍需要注册账号并登录:
wandb login
接下来,可以开始预训练了!
Karpathy 表示,这是计算量最大的一步,模型通过预测序列中的下一个 token来压缩网页文本,同时也逐渐学习世界知识。
torchrun --standalone --nproc_per_node=8 -m scripts.base_train -- --depth=20
这里 Karpathy 使用了 8 张 GPU启动训练,训练一个20 层的 Transformer。默认情况下,每张 GPU 每次前向/反向传播处理32 行 × 2048 token,也就是 524,288 ≈ 0.5M token 每步优化。
如果 wandb 已设置,可加上 --run=speedrun 记录训练日志。
训练过程中,你会看到类似信息(为了简洁起见,这里删除了一些内容):
Vocab size: 65,536num_layers: 20model_dim: 1280num_heads: 10num_kv_heads: 10Tokens / micro-batch / rank: 32 x 2048 = 65,536Tokens / micro-batch: 524,288Total batch size 524,288 => gradient accumulation steps: 1Number of parameters: 560,988,160Estimated FLOPs per token: 3.491758e+09Calculated number of iterations from target data:param ratio: 21,400Total number of training tokens: 11,219,763,200Tokens : Params ratio: 20.00Total training FLOPs estimate: 3.917670e+19Scaling the LR for the AdamW parameters ∝1/√(1280/768) = 0.774597Muon: Grouping 80 params of shape torch.Size([1280, 1280]), device cuda:0, dtype torch.float32Muon: Grouping 20 params of shape torch.Size([1280, 5120]), device cuda:0, dtype torch.float32Muon: Grouping 20 params of shape torch.Size([5120, 1280]), device cuda:0, dtype torch.float32Step 00000 | Validation bpb: 3.3013^[step 00000/21400 (0.00%) | loss: 11.090355 | lrm: 1.00 | dt: 23156.74ms | tok/sec: 22,640 | mfu: 1.00 | total time: 0.00mstep 00001/21400 (0.00%) | loss: 10.808654 | lrm: 1.00 | dt: 649.22ms | tok/sec: 807,569 | mfu: 35.64 | total time: 0.00mstep 00002/21400 (0.01%) | loss: 10.179083 | lrm: 1.00 | dt: 472.29ms | tok/sec: 1,110,094 | mfu: 48.99 | total time: 0.00mstep 00003/21400 (0.01%) | loss: 9.449214 | lrm: 1.00 | dt: 487.47ms | tok/sec: 1,075,523 | mfu: 47.47 | total time: 0.00mstep 00004/21400 (0.02%) | loss: 8.903216 | lrm: 1.00 | dt: 487.57ms | tok/sec: 1,075,308 | mfu: 47.46 | total time: 0.00mstep 00005/21400 (0.02%) | loss: 8.531662 | lrm: 1.00 | dt: 482.58ms | tok/sec: 1,086,417 | mfu: 47.95 | total time: 0.00mstep 00006/21400 (0.03%) | loss: 8.231589 | lrm: 1.00 | dt: 487.21ms | tok/sec: 1,076,113 | mfu: 47.49 | total time: 0.00mstep 00007/21400 (0.03%) | loss: 7.993080 | lrm: 1.00 | dt: 484.10ms | tok/sec: 1,083,014 | mfu: 47.80 | total time: 0.00mstep 00008/21400 (0.04%) | loss: 7.803373 | lrm: 1.00 | dt: 488.17ms | tok/sec: 1,073,989 | mfu: 47.40 | total time: 0.00mstep 00009/21400 (0.04%) | loss: 7.627318 | lrm: 1.00 | dt: 484.78ms | tok/sec: 1,081,486 | mfu: 47.73 | total time: 0.00mstep 00010/21400 (0.05%) | loss: 7.491893 | lrm: 1.00 | dt: 487.03ms | tok/sec: 1,076,511 | mfu: 47.51 | total time: 0.00mstep 00011/21400 (0.05%) | loss: 7.354157 | lrm: 1.00 | dt: 487.10ms | tok/sec: 1,076,334 | mfu: 47.50 | total time: 0.01mstep 00012/21400 (0.06%) | loss: 7.246406 | lrm: 1.00 | dt: 487.99ms | tok/sec: 1,074,383 | mfu: 47.42 | total time: 0.02mstep 00013/21400 (0.06%) | loss: 7.159368 | lrm: 1.00 | dt: 486.56ms | tok/sec: 1,077,540 | mfu: 47.55 | total time: 0.02m
可以看到,这个 Transformer 在注意力机制中有 1280 维通道,注意力头数为 10,总参数约5.6 亿。按照 Chinchilla scaling law 推荐,这里需要训练约 560M×20≈11.2B tokens。由于优化器的每一步都需要 524,288 个 tokens,这意味着总共需要约 11.2B/0.5M≈21400 次迭代。
通过将每个标记的预估 FLOP 数乘以标记总数,最终得到这个模型的性能约为 4e19 FLOP。
学习率会自动按 1/sqrt(dim) 的比例缩小,因为较大的模型更倾向于较小的学习率。
这次过程中,Karpathy 使用 Muon 优化矩阵,并使用 AdamW 优化嵌入和去嵌入。此模型中没有其他可训练参数(偏差、rmsnorm 参数等)。训练会定期报告“验证 bpb”,即验证数据集上的每字节位数。
每字节位数比典型的交叉熵损失要好得多,因为它进一步将每个标记的损失用该标记的字节数进行归一化,从而使该指标与分词器无关。
因此,无论你的分词器词汇量大小,这个数字都是可比的,这与原始交叉熵损失不同。
注意,每一步大约需要 0.5 秒,lrm 是学习率衰减乘数(在训练结束时会线性下降到 0),报告的 MFU(模型浮点运算利用率)看起来不错,几乎达到了一半左右,这意味着我们正在利用大量可用的 bfloat16 计算资源。
训练大约需要 3 小时执行完 4e19 FLOPs。在 wandb 上,你会看到 bpb 逐渐下降(模型预测下一个 token 更准确),CORE 指标逐渐上升。
训练完成后,可通过以下命令进一步评估模型:
torchrun --standalone --nproc_per_node=8 -m scripts.base_losstorchrun --standalone --nproc_per_node=8 -m scripts.base_eval
可以看到,训练集和验证集的 bpb 达到 0.81,而CORE指标上升到0.22。作为对比,eval bundle 中包含了 GPT-2 模型的 CORE 分数。其中,CORE0.22略高于 GPT-2 Large(0.21),但略低于 GPT-2 XL(也就是标准 GPT-2,0.26)。
此时的模型本质上是一个高级的自动补全工具,我们可以通过几个示例提示(prompts)来了解模型里存储了哪些知识。文件 base_loss.py会执行这些示例提示。Prompt 内容如下:
prompts = [ "The capital of France is", "The chemical symbol of gold is", "If yesterday was Friday, then tomorrow will be", "The opposite of hot is", "The planets of the solar system are:", "My favorite color is", "If 5*x + 3 = 13, then x is",]
模型完成结果如下:
The capital of France is Paris. It is the largest city in France and the second largest city in EuropeThe chemical symbol of gold is Au. The chemical symbol of silver is Ag. The chemical symbol of copper isIf yesterday was Friday, then tomorrow will be Saturday. If yesterday was Monday, then tomorrow will be Monday. If yesterday wasThe opposite of hot is cold. The opposite of hot is cold. The opposite of hot is cold.The planets of the solar system are: Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune,My favorite color is red. It is the color of the sun, the color of the sky,If 5*x + 3 = 13, then x is a positive integer.
可见模型已经掌握了地理、化学、时间逻辑、基础数学和太阳系行星等知识,但对一些简单常识(如天空颜色)仍不确定。
不过,对于一个训练成本仅 72 美元的模型来说,表现已经相当不错了。推理阶段使用自定义 Engine 类,支持KV 缓存提升效率,并实现了prefill和decode两个常用阶段。同时,Engine 还支持调用工具(如 Python 解释器),这在后续训练 GSM8K 时会非常有用。
中期训练
接下来是中期训练,主要是进一步微调模型,让它更适合 SmolTalk 对话数据。
算法上和预训练完全相同,但现在训练的数据变成了多轮对话,模型也会学习新的特殊 token,用来构建多轮对话对象。
每条对话大致如下(参考 OpenAI Harmony chat 格式):
bos|>user_start|>What is the color of the sky?user_end|>assistant_start|>Red. Wait, possibly blue. I'm not sure.assistant_end|>user_start|>loluser_end|>assistant_start|>...etcetc
其中 这样的 token 是特殊 token,遵循 OpenAI 的格式。中期训练阶段对于模型中的许多调整非常有用:
默认的中期训练数据混合如下:
train_dataset = TaskMixture([ SmolTalk(split="train"), # 460K rows of general conversations MMLU(subset="auxiliary_train", split="train"), # 100K rows of multiple choice problems drawn from ARC, MC_TEST, OBQA, RACE GSM8K(subset="main", split="train"), # 8K rows teaching simple math and (calculator) tool use]) # total: 460K + 100K + 8K = 568K rows
启动中期训练命令:
torchrun --standalone --nproc_per_node=8 -m scripts.mid_train
这一步大约只需 8 分钟,远比预训练的 3 小时短。现在模型已经成为一个完整的Chat 模型,可以充当 Assistant 回答用户问题。评估模型:
torchrun --standalone --nproc_per_node=8 -m scripts.chat_eval -- -i mid
此阶段模型的表现:
- ARC-Easy: 0.3561- ARC-Challenge: 0.2875- MMLU: 0.3111- GSM8K: 0.0250- HumanEval: 0.0671- ChatCORE metric: 0.0730
我们可以看到以下几点:
Karpathy 表示,由于没有太好的图表能展示这一步的效果,但可以看看他之前给一个更大模型做中期训练(midtraining)时的曲线图——能直观看到这些指标在微调过程中是如何上升的。
监督微调
在训练中期之后,接下来是监督微调(SFT)阶段。这是对对话数据的又一轮微调,但这里通常会精挑细选最优质的数据,同时也可以加入一些安全训练,比如训练助手学会拒绝不合适的请求。Karpathy 调侃道,“我们的模型连天空是什么颜色都不太确定,所以目前在生物安全方面应该没问题。”
SFT 阶段的一个重要改进是领域适配(domain adaptation):
运行 SFT 并重新评估模型:
torchrun --standalone --nproc_per_node=8 -m scripts.chat_sfttorchrun --standalone --nproc_per_node=8 -m scripts.chat_eval -- -i sft
这一阶段大约只需 7 分钟,你会发现各项指标都有小幅提升:
- ARC-Easy: 0.3876- ARC-Challenge: 0.2807- MMLU: 0.3151- GSM8K: 0.0455- HumanEval: 0.0854- ChatCORE metric: 0.0884
最后,我们可以真正以用户身份与模型进行对话了!虽然在中期训练后就可以聊,但现在效果会更好。可以在终端里聊天:
python -m scripts.chat_cli
或者通过网页界面聊天:
python -m scripts.chat_web
chat_web 会使用 FastAPI启动服务,记得正确访问,比如在 Lambda 上用节点的公网 IP 加端口,例如:
http://209.20.xxx.xxx:8000/
聊天界面大致会是这样的效果:
Karpathy 提醒道——由于这个 100 美元档模型只有 4e19 FLOPs 能力,聊起来就像在跟幼儿园小朋友对话。它目前还不可能赢得物理或诗歌比赛,但令人惊讶的是,我们用这么少的预算就能训练出这样一个模型,而且这个项目远未完全调优,潜力很大。
强化学习
speedrun 的最后阶段(默认情况下被注释掉)是强化学习(RL)。
通过 RLHF(基于人类反馈的强化学习)可以提升模型性能几个百分点,同时缓解采样循环带来的问题,比如幻觉生成、无限循环等。但对于自己构建的小模型来说,这些问题不是主要考虑因素。
在使用的数据集中,Karpathy 表示,GSM8K是唯一有清晰、客观奖励函数的数据集(即数学题的正确答案)。因此可以直接在答案上进行强化学习,通过一个简单的 RL 循环交替进行采样和训练:
torchrun --standalone --nproc_per_node=8 -m scripts.chat_rltorchrun --standalone --nproc_per_node=8 -m scripts.chat_eval -- -i rl -a GSM8K
在 RL 过程中,模型会遍历训练集中的所有 GSM8K 题目,先生成答案,然后根据奖励评分,再用高奖励的答案进行训练。我们使用了一个高度简化的 GRPO训练循环:
最终的效果看起来更像 REINFORCE,但保留了 GR(group relative)部分来计算奖励优势。对于这种规模和任务,这种方法效果还可以。具体细节可以查看脚本。
当前,默认情况下,RL 被注释掉,因为它还没有完全调优,也没有实现完整通用的 RLHF。Karpathy 表示,其目前只在 GSM8K 上进行 RL,因此评估也只限于 GSM8K(使用 -a 标志)。强化学习训练时间较长,因为监督信号有限,默认设置大约 1.5 小时,效果如下:
从图中可以看到:
强化学习对更大模型的提升更明显。
性能结果
值得注意的是,项目文件夹中会生成 report.md文件,它记录了训练的详细信息,并在末尾提供了一个清晰的总结表格,方便查看各项指标和模型表现。
下面就是 nanochat 在 100 美元成本下的成绩单:
总花费时间:3 小时 51 分钟。
不过,Karpathy 也提醒道,nanochat 目前还远未完成,还有很多需要调优或优化的地方,但整体框架已经足够清晰,所以现在把它上传到 GitHub,让更多人参与改进和完善。
整体来看,nanochat 不是一项颠覆性的突破,但它非常实用。它将 LLM 训练的门槛降低到了普通人也能达到的水平。你可以亲眼看到,仅用几百美元和几小时就能完成什么。
参考:
https://github.com/karpathy/nanochat
https://x.com/karpathy/status/1977755427569111362
https://github.com/karpathy/nanochat/discussions/1
https://analyticsindiamag.com/ai-news-updates/andrej-karpathy-releases-nanochat-a-minimal-chatgpt-clone/
相关文章
整理 | 屠敏出品 | CSDN(ID:CSDNnews)今天,前 OpenAI 联合创始人、Eureka Labs 创始人 Andrej Karpa...
2025-10-15 0
在中国国际进口博览会迈入第八届的重要节点,国家会展中心(上海)即将再度汇聚全球目光。作为“全勤生”,德国永恒力公司不仅连续八年扎根进博会,更以翻倍至3...
2025-10-15 0
姐妹们,坦白说,一年前我觉得Pocket 3也就那样,没啥特别心动的感觉但这次,他们背着我悄悄升级了好多!我重新测评完,真的被惊到了! 人像拍摄绝了!...
2025-10-15 0
每经记者:赵雯琪 每经编辑:张益铭全球电商的竞争与动荡,正为提供物流等基础设施服务的公司带来新的变量。10月14日,极兔速递(01519.HK,股价9...
2025-10-15 0
10月13日,2025第二届中国光谷跨境电商高质量发展大会举行。现场,湖北省跨境电商产业联盟启动,首批近100家成员单位加入,将形成资源协同共享、抱团...
2025-10-15 0
来源:环球市场播报博通公司(股票代码:AVGO)于周二推出一款新型网络芯片,该芯片可通过将数十万块数据处理芯片连接起来,助力企业搭建人工智能计算系统,...
2025-10-15 0
湖北日报讯(记者喻煜、通讯员王泱、陈丹)10月14日,东湖论坛“前沿科技论坛”在武汉光谷科技会展中心举行开幕式及圆桌交流,现场座无虚席。论坛以“创新驱...
2025-10-15 0
证券日报网讯 东方精工10月14日在互动平台回答投资者提问时表示,2025年7月21日公司与乐聚机器人签署了《战略合作协议》,就战略合作达成意向性约定...
2025-10-15 0
发表评论