从零构建LLM(第22部分):终于,开始训练我们的LLM Giles Thomas 2025-10-31 0 浏览 0 点赞 长文 经过了21个部分的漫长铺垫,从数据准备、分词器构建到Transformer架构的实现,我们终于来到了整个“从零构建LLM”系列的高潮——启动训练过程。本文将详细分解训练循环(Training Loop)的每一个步骤,并解释其背后的原理。 ## 训练的先决条件 在开始训练之前,我们已经准备好了: 1. **一个模型实例**: 我们自定义的`GPT`模型类的实例化对象。 2. **一个优化器 (Optimizer)**: 如 `AdamW`,它负责根据计算出的梯度来更新模型的权重。 3. **数据加载器 (DataLoaders)**: 分别为训练集和验证集准备好的PyTorch `DataLoader`,它们负责按批次(batch)提供数据。 ## 核心:训练循环 (The Training Loop) 训练过程的核心是一个循环,它会迭代多个周期(Epochs)。在每个周期内,它会遍历整个训练数据集。 一个标准的PyTorch训练步骤如下: 1. **设置模式**: 调用 `model.train()`,确保模型处于训练模式。这对于包含Dropout或BatchNorm等层的模型至关重要。 2. **数据上载**: 从`train_loader`中获取一个批次的数据,并将其移动到正确的设备上(例如GPU:`inputs, targets = inputs.to(device), targets.to(device)`)。 3. **清零梯度**: 调用 `optimizer.zero_grad()`。这是一个必须的步骤,因为PyTorch默认会累积梯度,如果不清零,上一步的梯度会影响当前步的计算。 4. **前向传播 (Forward Pass)**: 调用 `outputs = model(inputs)`,让数据通过模型,得到模型的预测输出(logits)。 5. **计算损失 (Loss Calculation)**: 使用损失函数(如 `CrossEntropyLoss`)来比较模型的预测 `outputs` 和真实标签 `targets`,计算出损失值 `loss`。这个损失值衡量了模型“错得有多离谱”。 6. **反向传播 (Backward Pass)**: 调用 `loss.backward()`。这是PyTorch自动微分引擎的神奇之处。它会自动计算出损失相对于模型中每一个参数的梯度。 7. **更新权重 (Weight Update)**: 调用 `optimizer.step()`。优化器会根据上一步计算出的梯度,来更新模型的权重,使模型在下一次预测时表现得更好。 这个过程会针对训练集中的每一个批次重复进行。 ## 必不可少:评估循环 (The Evaluation Loop) 只在训练集上表现好是不够的,我们还需要确保模型具有泛化能力。因此,在每个训练周期结束后,都需要在验证集上评估模型。 评估循环与训练循环类似,但有几个关键区别: 1. **设置模式**: 调用 `model.eval()` 来切换到评估模式。 2. **禁用梯度计算**: 将整个循环包裹在 `with torch.no_grad():` 上下文管理器中。这会告诉PyTorch在此代码块内不要计算梯度,从而节省了大量内存和计算资源。 3. **没有反向传播和优化**: 因为我们只是在评估,所以不需要计算梯度或更新权重。 通过监控验证损失(Validation Loss),我们可以判断模型是否出现了过拟合(即训练损失持续下降,但验证损失开始上升)。 ## 启动与等待 最后一步就是将训练循环和评估循环放入一个大的`for`循环中,按设定的周期数(epochs)进行迭代。 这个过程是整个项目中最耗费计算资源和时间的部分。一旦启动,我们能做的就是监控损失曲线,耐心等待模型“学会”语言的模式。这个系列的下一部分将展示如何分析训练结果并使用我们训练好的模型。 阅读 Giles Thomas 原文 本文的原始来源。 #LLM #PyTorch #从零开始 #模型训练 #深度学习