从零训练一个小模型-nanoGPT 模型训练 (二)参数配置内容
上次我们分析了数据准备(数据预处理)在大模型中如何实现的,也就是encoding的过程,这次我们继续讲解一下第二个文件夹,config/中配置了哪些参数,都代表什么含义。
有关配置的内容在项目中有两个,它们都属于训练工程配置,不是模型算法本身,分别是configurator文件和config/文件夹,我们来分别理解一下。
一、configurator.py-参数的读取和覆盖规则
它本身不配置“训练参数内容”,而是配置了参数如何被读取和覆盖的规则。
核心做了两件事:
1. 读取配置文件
如果命令行参数里有一个不带 = 的字符串,当你运行:
python train.py config/train_shakespeare_char.py
程序会发现第二个参数 config/train_shakespeare_char.py 不是像 --lr=0.001 这种带 = 的“参数赋值”,于是把它当作一个 Python 配置文件去执行。执行后,配置文件里定义的变量会覆盖主程序中的默认变量。关于这个文件涉及以下几个知识点,是理解它的前提:
(1)sys.argv
Python命令行参数 sys.argv 是 Python 用来拿“命令行输入内容”的列表。它本质上就是一个列表(List),里面装着你在命令行里输入的所有内容。
-
sys: 是一个 Python 内置的模块,提供了与 Python 解释器交互的功能。 -
argv: 是sys模块里的一个属性,全称是 "argument vector"(参数向量),你可以理解为“装着所有参数的列表”。
sys.argv 的作用就是:
-
接收外部指令:让你在运行脚本时,可以从外部给它传递信息(比如文件名、用户名、配置选项等)。
-
以列表形式存储:所有信息(包括脚本名)都被放进一个列表里,方便你通过索引(
sys.argv[0],sys.argv[1]...)来取用。 -
实现脚本灵活性:同一个脚本,因为接收到的参数不同,可以执行不同的操作,变得非常灵活。
运行命令
python train.py config/train_shakespeare_char.py --batch_size=64
那么:
sys.argv[0] # train.py
sys.argv[1] # config/train_shakespeare_char.py
sys.argv[2] # --batch_size=64
也就是说,程序就是靠 sys.argv 知道你在命令行里传了什么。
(2)配置管理
配置管理:把训练参数单独放到配置文件里,而不是全写死在代码里。
比如这些都属于配置:
batch_size
learning_rate
dropout
n_layer
好处是:不同实验可以用不同配置文件,不用每次改主代码,更方便复现实验。
所以 config/train_shakespeare_char.py 本质上就是一个“配置文件”。
(3)exec、globals()
可以把它想成变量仓库,globals() 就像一个仓库:
变量名是标签,比如 "batch_size"
变量值是仓库里的东西,比如 32
你做:globals()["batch_size"] = 64
就是把仓库里 "batch_size" 对应的值,从 32 换成 64。
globals() 本质上就是:当前文件全局变量名 -> 变量值 的映射表(字典)
所以配置文件执行时,只要它在这个全局表里运行,就能改掉主程序原来的默认变量。
exec(..., globals()) 连起来看
比如:
batch_size = 32
code ="batch_size = 64"
exec(code, globals())
print(batch_size)
输出:64
意思是:code 里面有一段代码 "batch_size = 64",exec(..., globals()) 让这段代码在“当前全局变量表”里执行,所以把原来的 batch_size = 32 改成了 64。
(4)读取命令行覆盖项
如果命令行里有:--batch_size=32
它就把这个参数解析成:key: batch_size、value: 32,然后覆盖当前变量。
这属于的知识类:CLI 参数解析,配置优先级设计
串起来看,比如命令行输入:python train.py config.py --batch_size=32 --dropout=0.2
程序大概会这样做:先读默认值,再执行 config.py,覆盖默认值,再解析 --batch_size=32
用字符串处理拆出:
key: batch_size
value: "32"
再用 literal_eval("32") 变成整数 32,最后把当前配置里的 batch_size 改成 32
所以连起来就是:
CLI 参数解析:从命令行读参数
字符串处理:把 --batch_size=32 拆成 key/value
literal_eval:把 "32" 变成整数 32
配置优先级设计:让命令行参数覆盖配置文件和默认值
(5)防呆设计、配置校验、工程可维护性
此外,还做了简单校验,它还检查:参数名是否存在、类型是否匹配,这种防呆设计,提前防止用户犯错,或者让错误尽早暴露。
比如命令行里写:--batc_size=32
你本来想写 batch_size,结果拼错了。如果程序完全不检查,这个参数可能根本没生效,但你自己还不知道,后面训练结果就不对了。
所以程序会做防呆:检查这个参数名存不存在、不存在就直接报错、不让错误悄悄混过去
再比如:
--batch_size=abc
batch_size 应该是整数,不应该是字符串 abc,这时也应该马上报错。
所以“防呆设计”本质上就是:通过限制、检查、报错,减少低级误操作。
“配置校验”就是:检查你传进来的配置是不是合法。
比如校验两类东西:参数名是否存在
例如程序只允许这些参数:
batch_size
learning_rate
dropout
如果你传:--hello=123,那就是非法参数,因为程序根本没有这个配置项。
类型是否匹配,比如:
batch_size 应该是 int
learning_rate 应该是 float
compile 应该是 bool
如果你传:--batch_size="abc",或者:--compile=[1,2,3],这就类型不对。
所以“配置校验”就是:确保配置项名字对、值的类型对、必要时范围也对。
更完整一点还可以检查:数值范围,比如 dropout 必须在 0~1,是否为空,参数组合是否冲突
“工程可维护性”就是:代码以后好不好改、好不好查问题、好不好让别人接手。
为什么前面的校验会提升可维护性?因为如果没有校验,可能出现这种情况:--batc_size=32
程序没报错,但其实没生效,还是用默认值在训练。几天后你发现结果不对,就很难排查: 到底是模型问题、数据问题,还是参数根本没传进去?如果有校验,程序一开始就报:Unknown config key: batc_size,那问题立刻就清楚了。所以这些检查会让工程更容易维护,因为它们能:更早发现问题,报错更明确,减少隐蔽 bug。让后来的人更容易理解系统行为。
总的来说:
防呆设计:防止用户乱传参数、拼错参数、传错类型
配置校验:具体去检查参数名和参数值是否合法
工程可维护性:通过这些检查,让程序更稳定、更容易排查和维护
二、config/ 文件夹里的配置
config/ 里的每个 .py 文件,都是一套实验场景参数模板。它们不是功能代码,不负责“实现训练逻辑”,它们负责的是:告诉 train.py:这次训练/评估应该用哪套参数。所以你可以把它理解成:train.py:总控程序,config/*.py:不同场景下的训练方案内容,每个配置文件适用什么场景。
1. config/train_shakespeare_char.py
适用场景:新手入门,字符级语言模型,小模型训练,调试训练流程,普通机器上先跑通项目,现在学shakespeare_char 时应该用它。因为它对应的数据集就是:dataset= 'shakespeare_char'
也就是说,它和你前面看的 data/shakespeare_char/prepare.py 是一套。
相关知识类型:字符级 tokenization、从零训练(scratch training)、小型 Transformer、训练参数入门
2. config/finetune_shakespeare.py
适用场景:学习“微调”概念、从预训练 GPT-2 出发,继续适配 Shakespeare 数据、想对比“从零训练”和“微调”的区别,它对应的数据集是:
dataset= 'shakespeare'
init_from= 'gpt2-xl'
这里不是 shakespeare_char,而是 shakespeare。这份数据是用 GPT-2 的 BPE tokenizer 做的,不是字符级。
相关知识类型:微调(finetuning)、预训练模型迁移
3. config/train_gpt2.py
适用场景:大规模训练、复现 GPT-2 风格训练、OpenWebText 数据集、多 GPU/高算力环境
这个不适合刚入门时直接学,因为:模型大、数据大、参数复杂、工程难度高
相关知识类型:大模型预训练、、OpenWebText、分布式训练 DDP、大批量训练
4. 设置baseline,不同模型的loss对比
config/eval_gpt2.py
config/eval_gpt2_medium.py
config/eval_gpt2_large.py
config/eval_gpt2_xl.py
这几个文件的适用场景:不训练,只评估,看不同 GPT-2 预训练模型在数据集上的 loss,做 baseline 对比,它们不是拿来“学训练流程”的第一选择,更像是: “拿现成模型来测效果”,相关知识类型:模型评估、baseline、loss 对比、不同模型规模比较,拿 4 个已经存在的 GPT-2 预训练版本,分别测一下 loss,当参照物,4 个现成选手,先下场跑一遍,给你一条成绩参考线。因为一般来说,模型越大,表示能力越强,所以在同样任务上更容易把预测做对,loss 就更低。在同类模型、训练得也比较充分的前提下,通常越大的模型 loss 越低。
因为“大模型”通常意味着它有更多参数,也就是更大的表达能力。比如它通常会有:更多层、更宽的隐藏维度、更多注意力头、更多总参数量这带来的结果是:它能学到更复杂的规律。
可以拿它们做基线比较,看小模型和大模型在同一数据上的表现差多少,帮你判断自己训练/微调出来的结果到底算不算好,baseline 把它理解成:参考线。为什么要有 baseline,因为你训练完一个模型,哪怕得到一个数字,比如:val loss = 2.90
你也不知道这到底算:好、一般、还是很差,单独一个数字没有意义。
所以必须找个“参照物”来比较,这个参照物就是 baseline。
举个最简单的例子假设你自己训练了一个模型,在验证集上:
val loss = 2.90
然后你拿现成的 gpt2 来测同一个验证集,发现:gpt2 val loss = 3.12,那就说明:你的模型比这个 baseline 更好。但如果拿 gpt2-medium 来测,结果是:gpt2-medium val loss = 2.84,那就说明:你的模型还不如这个更强的 baseline。所以 baseline 的作用就是:帮你判断结果到底处在什么水平。
为什么 nanoGPT 里有 4 个 baseline,因为作者想比较 4 个现成模型:gpt2、gpt2-medium、gpt2-large、gpt2-xl,它们都先在同一个数据集上测一遍。
这样你就知道:小模型大概什么水平、中模型什么水平、大模型什么水平、最大模型什么水平,这几条线都可以当 baseline。在这个项目里 baseline 主要回答从零训练了一个模型,或者微调了一个模型,比现成 GPT-2 差多少?比小一点的 GPT-2 好还是差?我这次改动到底有没有提升?这个结果值不值得继续做?这些都靠 baseline 来判断。
5. config/train_shakespeare_char.py 内的参数讲解
(1)训练流程与实验管理参数
out_dir
eval_interval
eval_iters
log_interval
always_save_checkpoint
它们在配置什么:
输出目录放哪里
多久评估一次
每次评估测多少个 batch
多久打印一次训练日志
保存 checkpoint 的策略
属于哪类知识:训练流程、验证集评估
(2)日志与实验跟踪
参数:
wandb_log
wandb_project
wandb_run_name
它们在配置什么:
是否启用 WandB
实验项目名
本次运行名字
属于哪类知识:
实验记录
可视化监控
训练追踪
主要在哪用到:train.py
按需补充知识点:WandB 是什么、为什么训练实验要记录超参数和 loss 曲线
(3)数据与输入形式
参数:
dataset
gradient_accumulation_steps
batch_size
block_size
它们在配置什么:
用哪份数据
一次更新前累积几次梯度
每次并行喂多少条样本
每条样本长度多长
属于哪类知识:
数据加载
mini-batch 训练
上下文窗口
梯度累计
主要在哪用到:train.py 的 get_batch()、train.py 的训练循环、block_size 还会传到 model.py
(4)模型结构
参数:
n_layer
n_head
n_embd
dropout
它们在配置什么:
n_layer:Transformer 堆多少层
n_head:每层注意力有多少个头
n_embd:每个 token 的向量维度
dropout:训练时做多强的随机丢弃
属于哪类知识:
Transformer 结构
多头注意力
embedding
正则化 / 防过拟合
主要在哪用到:train.py 先收集这些参数、model.py 真正根据它们搭模型
(5)优化与训练稳定性
参数:
learning_rate
max_iters
beta2
它们在配置什么:
学习率多大
训练总共多少步
AdamW 优化器内部平滑参数之一
属于哪类知识:
优化器
梯度下降
AdamW
训练稳定性
主要在哪用到:train.py、model.py 的 configure_optimizers(...)
按需补充的知识点:学习率是什么、Adam / AdamW 是什么、为什么学习率太大或太小都不行、iter 是什么,和 epoch 有什么区别
(6)学习率调度
参数:
lr_decay_iters
min_lr
warmup_iters
它们在配置什么:
学习率衰减持续多久
最低降到多少
前多少步做 warmup
属于哪类知识:
学习率调度
warmup
cosine decay
收敛控制
主要在哪用到:
train.py 的 get_lr()
按需补充知识点:为什么学习率不是固定不变、warmup 为什么常见、学习率衰减为什么有助于后期稳定训练
(7)运行环境
注释里给了可选项:
device
compile
它们在配置什么:
用 CPU 还是 GPU
是否启用 torch.compile
属于哪类知识:
PyTorch 运行设备
性能优化
平台兼容性
主要在哪用到:
train.py
按需补充知识点:cpu / cuda 区别、torch.compile 是什么、为什么 Windows / CPU 场景常要关掉部分优化
总结配置内容
这份 config/train_shakespeare_char.py 本质上在配置 3 件大事:
数据怎么喂:dataset、batch_size、block_size
模型长什么样:n_layer、n_head、n_embd、dropout
模型怎么学(训练流程和验证):learning_rate、max_iters、warmup_iters、lr_decay_iters、eval_interval、loss、checkpoint
如果这三块需要慢慢吃透,后面看 train.py 就不会乱。
config/train_shakespeare_char.py 配置的是一套小型字符级 GPT 训练方案,核心覆盖了:
数据输入、模型结构、优化训练、学习率调度、评估与保存、运行环境
打基础,最优先补的是:Transformer 结构(n_layer/n_head/n_embd) 和 优化训练(learning_rate/max_iters)。
这次我们了解了配置内容,接下来可以按需补充需要学习的知识点,或者从实践中去看下参数的变化,会给模型训练结果带来什么不一样的结果。下篇会讲一下并记录一下简单的训练结果。
更多推荐


所有评论(0)