从零实现大语言模型:5.2 训练LLM的核心技术与实践
llms-from-scratch-cn 项目地址: https://gitcode.com/gh_mirrors/ll/llms-from-scratch-cn
引言
在构建大语言模型(LLM)的过程中,训练环节是至关重要的阶段。本节将深入探讨如何训练一个GPT模型,包括训练循环的实现、优化器的选择以及训练过程中的关键考量因素。
训练循环的基本原理
训练LLM的核心是一个典型的PyTorch神经网络训练循环,主要包含以下关键步骤:
- 数据迭代:遍历训练集中的每个批次
- 梯度计算:通过前向传播计算损失,反向传播计算梯度
- 参数更新:使用优化器更新模型权重
- 评估监控:定期评估模型在验证集上的表现
这个循环会重复多个epoch(完整的数据集遍历),直到模型收敛或达到预定的训练次数。
代码实现详解
核心训练函数
def train_model_simple(model, train_loader, val_loader, optimizer, device, num_epochs,
eval_freq, eval_iter, start_context):
train_losses, val_losses, track_tokens_seen = [], [], []
tokens_seen, global_step = 0, -1
for epoch in range(num_epochs):
model.train()
for input_batch, target_batch in train_loader:
optimizer.zero_grad()
loss = calc_loss_batch(input_batch, target_batch, model, device)
loss.backward()
optimizer.step()
tokens_seen += input_batch.numel()
global_step += 1
if global_step % eval_freq == 0:
train_loss, val_loss = evaluate_model(
model, train_loader, val_loader, device, eval_iter)
train_losses.append(train_loss)
val_losses.append(train_loss)
track_tokens_seen.append(tokens_seen)
print(f"Ep {epoch+1} (Step {global_step:06d}): "
f"Train loss {train_loss:.3f}, Val loss {val_loss:.3f}")
generate_and_print_sample(
model, train_loader.dataset.tokenizer, device, start_context)
return train_losses, val_losses, track_tokens_seen
关键组件解析
- 优化器重置:
optimizer.zero_grad()
确保每次迭代梯度从零开始计算 - 损失计算:
calc_loss_batch
计算当前批次的损失 - 反向传播:
loss.backward()
计算参数的梯度 - 参数更新:
optimizer.step()
根据梯度更新模型参数
评估与监控
def evaluate_model(model, train_loader, val_loader, device, eval_iter):
model.eval()
with torch.no_grad():
train_loss = calc_loss_loader(train_loader, model, device, num_batches=eval_iter)
val_loss = calc_loss_loader(val_loader, model, device, num_batches=eval_iter)
model.train()
return train_loss, val_loss
评估时需要注意:
- 切换模型到评估模式(
model.eval()
) - 禁用梯度计算(
torch.no_grad()
) - 计算完成后恢复训练模式(
model.train()
)
优化器选择:AdamW
在LLM训练中,我们通常使用AdamW优化器而非标准Adam,原因在于:
- 改进的权重衰减:AdamW将权重衰减与梯度更新解耦,防止权重衰减影响自适应学习率
- 更好的泛化性:实验表明AdamW在语言模型任务上表现更优
- 训练稳定性:对超参数选择更鲁棒
典型配置:
optimizer = torch.optim.AdamW(model.parameters(), lr=0.0004, weight_decay=0.1)
训练过程分析
损失曲线解读
训练过程中观察到的典型现象:
- 初期快速下降:模型迅速学习数据的基本模式
- 后期分化:训练损失持续下降而验证损失停滞,表明过拟合
- 过拟合迹象:验证损失远高于训练损失
文本生成质量演变
训练过程中模型生成能力的典型发展轨迹:
-
初始阶段:只能生成重复字符或简单模式
- 示例输出:"Every effort moves you,,,,,,,,,,,,"
-
中期阶段:开始出现简单重复
- 示例输出:"Every effort moves you, and, and, and, and,..."
-
后期阶段:能够生成语法正确的连贯文本
- 示例输出:"Every effort moves you?" "Yes--quite insensible to the irony..."
过拟合问题与解决方案
过拟合原因分析
- 数据集太小:模型容易记住训练样本
- 训练时间过长:过多epoch导致过度适应训练数据
- 模型容量过大:相对于数据量,模型参数过多
缓解策略
- 增大数据集:使用更大规模的训练数据
- 早停(Early Stopping):监控验证损失,在恶化时停止训练
- 正则化技术:增加dropout、权重衰减等
- 单epoch训练:在大数据集上通常只需一个epoch
实践建议
- 学习率选择:对于LLM,通常使用较小的学习率(如4e-4)
- 批量大小:根据GPU内存选择最大可行批量
- 评估频率:定期评估以监控训练进度
- 硬件考量:即使是小型模型,在笔记本CPU上训练也可能需要较长时间
总结
本节详细介绍了LLM训练的核心流程和关键技术点。通过实现简单的训练循环,我们能够观察到模型从随机初始化到能够生成连贯文本的完整学习过程。理解这些基本原理对于后续探索更复杂的训练技术和模型架构至关重要。在下一节中,我们将探讨如何改进文本生成策略,使模型产生更加多样化和创造性的输出。
llms-from-scratch-cn 项目地址: https://gitcode.com/gh_mirrors/ll/llms-from-scratch-cn
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考