从零开始逐步指导开发者构建自己的大型语言模型(LLM)学习笔记- 第5章 GPT 的大语言模型训练

Chapter 5: Pretraining on Unlabeled Data

从模型配置和初始化,到训练、评估、优化,再到使用各种技巧控制文本生成,最后加载预训练权重,是一个使用 GPT 架构进行自然语言处理任务的典型示例,适合学习和理解深度学习和自然语言处理的实践

  • 导入必要的库和模块
    • 导入了多个常用的 Python 库,如 matplotlibnumpytiktokentorchtensorflow 等,还使用 importlib.metadata 中的 version 函数来获取这些库的版本信息。
    • 定义了一些函数,如 text_to_token_idstoken_ids_to_textcalc_loss_batchcalc_loss_loadertrain_model_simpleevaluate_modelgenerate_and_print_sampleplot_lossessoftmax_with_temperatureprint_sampled_tokensgenerateassignload_weights_into_gpt 等,用于不同的功能,包括数据处理、模型训练、评估、文本生成、损失计算和权重加载等。

功能概述

  1. 模型配置和初始化
    • GPT_CONFIG_124M 定义了 GPT 模型的配置,包括词汇表大小、上下文长度、嵌入维度、注意力头数、层数、丢弃率等。
    • 使用 GPTModel 类(可能在 previous_chapters 模块中定义)初始化一个 GPT 模型,设置 torch.manual_seed(123) 以确保可重复性,将模型设置为评估模式 model.eval() 以在推理时禁用 dropout。
    • 展示了如何使用 generate_text_simple 函数(来自 previous_chapters)生成文本,并使用 text_to_token_ids 和 token_ids_to_text 函数在文本和 token 之间进行转换。
    • 初始生成的文本质量不佳,因为模型尚未训练。
  2. 计算生成文本的损失:交叉熵和困惑度
    • 解释了如何计算交叉熵损失,通过输入和目标 token 计算 logits,将 logits 转换为概率,使用 torch.argmax 找到预测的 token,然后计算交叉熵。
    • 展示了 PyTorch 的 torch.nn.functional.cross_entropy 函数的使用,该函数内部自动完成了一些计算步骤。
    • 困惑度是交叉熵损失的指数,它可以更直观地表示模型对词汇表的不确定程度,越低表示模型预测越接近实际分布。
  3. 训练和验证集的损失计算
    • 从 GitHub 下载一个文本文件 the-verdict.txt,并将其分为训练集和验证集。
    • 使用 create_dataloader_v1(来自 previous_chapters)创建数据加载器,将文本数据转换为批次,使用 calc_loss_batch 和 calc_loss_loader 计算批次和加载器的损失。
    • 考虑了设备选择(GPU 或 CPU),将模型和数据移动到相应设备。
  4. 模型训练
    • 定义 train_model_simple 函数进行简单的训练,包括训练循环、梯度计算、更新权重、评估和打印生成的样本。
    • 调用 train_model_simple 函数训练模型,设置 num_epochs 为 10,使用 AdamW 优化器,观察训练和验证损失以及生成的文本在训练过程中的变化,显示出开始时生成无意义的字符串,后来逐渐生成语法更正确的句子,但最终会出现过拟合,因为训练集太小。
    • 最后使用 plot_losses 函数将训练和验证损失绘制成图。
  5. 解码策略以控制随机性
    • 介绍了 generate_text_simple 函数在生成文本时的确定性,然后引入了温度缩放(temperature scaling)和 top-k 采样来控制生成文本的随机性和多样性。
    • 温度缩放通过将 logits 除以一个大于 0 的数,改变 softmax 后的概率分布,温度大于 1 会使分布更均匀,小于 1 会使分布更尖锐。
    • top-k 采样通过保留 top-k 个最可能的 token 并将其余的 logits 设为负无穷,再计算 softmax 来实现。
    • 修改 generate 函数,将温度缩放和 top-k 采样结合,生成更具多样性的文本。
  6. PyTorch 中的模型权重保存和加载
    • 使用 torch.save 保存模型权重(model.state_dict()),并使用 torch.load 加载权重。
    • 对于使用自适应优化器(如 AdamW)的情况,还可以保存和加载优化器的状态。
  7. 从 OpenAI 加载预训练权重
    • 从 OpenAI 下载 GPT-2 的预训练权重,使用 TensorFlow 加载权重(因为 OpenAI 使用 TensorFlow)。
    • 定义 load_weights_into_gpt 函数将下载的权重分配给自定义的 GPTModel 实例,考虑了形状匹配和不同权重的分配。
    • 加载权重后,使用 generate 函数生成文本,验证模型是否正确加载。

关键知识点和技术

  • 自然语言处理:使用 GPT 架构进行文本生成任务,涉及文本的 token 化、生成和评估。
  • 深度学习基础:包括模型训练、损失函数(交叉熵)、优化器(如 AdamW)、评估指标(如困惑度)。
  • 深度学习技巧:使用了层归一化(LayerNorm)、dropout、残差连接等,以及如何避免过拟合。
  • 数据处理:将文本数据转换为 token 并分批处理,使用数据加载器进行训练和验证。
  • 生成策略:通过温度缩放和 top-k 采样控制文本生成的随机性和多样性。

代码示例解释

  • 计算交叉熵损失示例
# 输入和目标张量,分别表示输入和期望生成的 token ID
inputs = torch.tensor([[16833, 3626, 6100], [40, 1107, 588]])
targets = torch.tensor([[3626, 6100, 345], [1107, 588, 11311]])
# 模型前向传播得到 logits
with torch.no_grad():
    logits = model(inputs)
# 将 logits 转换为概率
probas = torch.softmax(logits, dim=-1)
# 计算交叉熵损失
logits_flat = logits.flatten(0, 1)
targets_flat = targets.flatten()
loss = torch.nn.functional.cross_entropy(logits_flat, targets_flat)

这里,首先将输入传递给模型得到 logits,然后将 logits 转换为概率分布,最后使用 PyTorch 的 cross_entropy 函数计算交叉熵损失。在使用 cross_entropy 函数前,需要将 logits 和 targets 展平以满足函数的输入要求。

  • 训练循环示例
def train_model_simple(model, train_loader, val_loader, optimizer, device, num_epochs, eval_freq, eval_iter, start_context, tokenizer):
    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(val_loss)
                track_tokens_seen.append(tokens_seen)
                print(f"Ep {epoch+1} (Step {global_step:06d}): Train loss {train_loss:.3f}, Val loss {val_loss:.3f}")
        generate_and_print_sample(model, tokenizer, device, start_context)
    return train_losses, val_losses, track_tokens_seen

在 train_model_simple 函数中,在每个 epoch 中,将模型设置为训练模式,遍历训练数据加载器,计算损失,反向传播梯度,更新权重。在一定的评估频率下评估训练和验证损失,并打印生成的样本。

  • 温度缩放示例

def softmax_with_temperature(logits, temperature):
    scaled_logits = logits / temperature
    return torch.softmax(scaled_logits, dim=0)
# 不同温度下的缩放
temperatures = [1, 0.1, 5]
scaled_probas = [softmax_with_temperature(next_token_logits, T) for T in temperatures]

softmax_with_temperature 函数将 logits 除以温度,然后进行 softmax 操作,不同的温度会导致不同的概率分布,影响后续的 token 采样。

总的来说,这段代码展示了一个完整的流程,从模型配置和初始化,到训练、评估、优化,再到使用各种技巧控制文本生成,最后加载预训练权重,是一个使用 GPT 架构进行自然语言处理任务的典型示例,适合学习和理解深度学习和自然语言处理的实践。

In [1]:

  • In this chapter, we implement the training loop and code for basic model evaluation to pretrain an LLM
  • At the end of this chapter, we also load openly available pretrained weights from OpenAI into our model
  • The topics covered in this chapter are shown below

5.1 Evaluating generative text models

  • 这段文本主要描述了关于评估生成文本模型的内容。首先提到以回顾上一章中初始化 GPT 模型的代码作为这一部分的开始。接着阐述了语言模型的基本评估指标。最后说明在这一部分中,会将这些评估指标应用于训练集和验证集。

5.1.1 Using GPT to generate text

  • We initialize a GPT model using the code from the previous chapter

In [2]:

import torch
from previous_chapters import GP
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值