上次我们首次训练了自己的模型,并尝试了通过不同长度的文本进行训练(单句文本和飞鸟集)。同时在随机配置的参数中找到了一种效果比较好的,本篇文章我们将来探索如何找到最适合的训练参数。
首先我们介绍下各个参数的作用:
这些参数会影响模型的学习速度、表现和稳定性:
- batch_size(批大小)
- 含义:一次训练中并行处理的样本数量。
 - 小 batch:更新更频繁 → 学习更快,但噪声大,可能震荡。
 - 大 batch:更新更稳定 → 更平滑收敛,但需要更多显存。
 - 探索点:小数据集时 batch 不宜太大,否则容易过拟合。
 
 - block_size(上下文长度)
- 含义:模型一次能看到的序列长度。
 - 小 block:模型“视野”短,只能学习局部关系。
 - 大 block:模型能学到长程依赖,但训练时间和显存消耗显著增加。
 - 发现点:很多 GPT 论文里就是逐渐增大 block_size,观察性能提升的。
 
 - embed_size(嵌入维度 / hidden size)
- 含义:字符/词向量的维度。
 - 小 embedding:模型表达能力不足。
 - 大 embedding:表达能力更强,但参数量、训练时间都增加。
 
 - n_layers(层数)
- 含义:Transformer 堆叠层数。
 - 层数少:模型浅,学不到复杂模式。
 - 层数多:更强的建模能力,但更容易过拟合、训练变慢。
 
 - learning_rate(学习率)
- 含义:参数更新的步长。
 - 太小:收敛慢。
 - 太大:loss 震荡甚至发散。
 - 一般配合 学习率调度器,比如 warmup 或衰减。
 
 - dropout(丢弃率)
- 含义:防止过拟合的一种正则化方法。
 - 0:完全不过滤,拟合能力最强,但过拟合风险大。
 - 0.1~0.3:常用范围。
 
 
二、如何判断训练结果的好坏
- 训练/验证 Loss
- loss 越低说明模型在训练集(或验证集)上拟合得更好。
 - 但要防止过拟合(训练 loss 低、验证 loss 高)。
 
 - 生成文本质量
- 更直观。
 - 可观察生成文本:
- 连贯(句子是否自然流畅)。
 - 合理(逻辑是否自洽)。
 - 多样性(是否不是机械重复)。
 
 
 - 收敛速度
- 同样的参数下,能更快收敛到较低 loss,说明配置更高效。
 - 这也是记录每轮训练时间的价值。
 
 - 困惑度 (Perplexity, PPL)
- 语言模型的常用指标。
 - PPL = exp(loss),数值越低越好。
 - 举例:
- PPL=50 → 模型选择下一个 token 的平均不确定性比较大。
 - PPL=10 → 模型更有信心。
 
 
 
三、目标
想比较 不同参数对训练的影响,可以观察:
- loss 曲线(是否下降更快、更稳定)。
 - 训练时间(代价 vs 收益)。
 - 生成样例文本(是否更像原文)。
 
这样就能逐步建立“参数 → 训练表现”的直观映射。
基于此,我们在上次工程的基础上添加了sweep.py,用于调用train.py针对训练数据,使用不同的参数组合进行训练,并观察训练的效果。每次训练都会生成对应参数的文件夹,loss记录和曲线,对应的模型,以及最后调用模型生产的文本样例。
需要注意的是我在sweep 里做了 block_size=64 组合,而原始数据可能太短,load_dataset 里生成 xb/yb 时索引溢出。如果没有 drop_last=True 时,最后一个 batch 的长度可能小于 block_size,导致模型 forward 时用到不存在的 token,所以必须加这个配置。
由于本次训练的时间过长,最终在训练完单句话的文本后我结束了训练,先来观察在单句文本上的训练效果。
Gpt认为的最佳结果



最佳结果
- 最优实验配置:
- batch_size=8
 - embed_dim=64
 - num_layers=2
 - hidden_dim=128
 - lr=0.0001
 - dropout=0.3
 
 - final_loss = 0.000022,表现非常好。
 
参数对结果的影响
1. Dropout
- 平均表现最好的是 0.1(0.5439),其次是 0.3。
 - 0.0(无正则)和 0.2 反而略差。
➡️ 说明少量 dropout 有助于提升效果。 
2. 学习率 (lr)
- 0.0001 最好(0.5465),随着 lr 增大,效果略差:
- 0.0001 < 0.0005 < 0.0010
➡️ 更小的学习率更稳定。 
 - 0.0001 < 0.0005 < 0.0010
 
3. Batch size
- 8 和 64 较优(0.5459 左右),中间值(16, 32)反而稍差。
➡️ 小批次或大批次更合适,中间可能震荡。 
4. Embedding 维度
- 越大越好:256 最优(0.5457),其次 128。
 - 小 embedding(32, 64)效果差。
➡️ 语义表达能力随维度上升有提升。 
5. 隐藏层维度
- 128 最佳(0.5453),大维度提升有限,64 和 256 稍差。
 
6. 层数 (num_layers)
- 2 层明显最佳(0.00011),层数增加 loss 急剧上升,12 层几乎不可用。
➡️ 模型太深反而过拟合或训练不稳定。 
总结建议
- 最优配置:
batch_size=8, embed_dim=128~256, hidden_dim=128, num_layers=2, lr=0.0001, dropout=0.1~0.3 - 趋势:
- 小学习率稳定收敛。
 - 适度的 dropout 有益。
 - embedding 越大越好,但 hidden_dim 128 足够。
 - 模型浅层效果最佳,深层导致训练崩坏。
 
 
但就整个训练数据而言,这组的loss值比较优秀,但生成的文本并不是很理想。可能是数据太简单/过拟合:模型可能记住了训练集,导致训练 loss 近乎为 0。有很多组的训练结果都生成了与训练数据完全一致的结果,只是之后混杂了太多无效内容。

为什么会出现这种现象
- 数据量太小
- 训练数据只有一句话,模型的参数量却非常大(几十万甚至上百万)。
 - 结果就是模型很容易死记硬背那句话,在训练时 loss 接近 0。
 
 - 生成时重复+失控
- 在推理阶段,模型会按照概率继续生成 token。
 - 它能复现训练句子,但之后就会进入“瞎编”状态(因为没有别的训练数据可以参考)。
 - 所以开头完全一致,后面混杂无效内容。
 
 - 语言模型的本质
- LM 学到的是 下一个词的分布,不是只背诵一句话。
 - 当上下文超出给的那一句话,模型就“没学过”,只能乱采样。
 
 
如何改进
如果想让模型只生成那句话,或者能更稳定地复现内容,可以考虑几种方法:
- 微调思路
- 单句训练 ≠ 微调。你现在的结果是“过拟合到一句话”。
 - 可以加上更多类似的句子(比如几十~几百个短句),这样模型能学到更稳健的分布。
 
 - 训练方式调整
- 减少模型大小:比如用更小的 embed_dim、hidden_dim、num_layers。模型过大会导致死记硬背+胡乱生成。
 - 增加 dropout:让模型不要那么快就“背死”一句话。
 - 训练目标修改:如果你只是要复现,可以改成 seq2seq 或者直接分类任务,而不是语言建模。
 
 - 推理时控制
- 调低 temperature(比如 0.1),模型会更确定地输出你训练过的内容,不会乱发散。
 - 甚至可以设置 greedy decoding(top_k=1),这样它几乎只会复现训练数据。
 
 
总结一句:
你的模型已经“完美记住”了那句话(所以 loss 接近 0),但因为训练数据太少,没法学到自然的语言分布,所以在生成时后半段就“胡编”。
本次主要是针对原工程进行了扩展,下一次我们将用飞鸟集来进行训练,目前还有很多问题需要解决,例如训练时间过长等问题。
本次对应的版本为1.6-1.8。

发布于2025/08/24。
