31. 实现 GPT 模型的生成策略#

31.1. 介绍#

上一节我们已经完整了《动手学:GPT》的前两个部分,完成了预训练数据集的准备和 GPT 模型的定义。现在我们将开始进行 GPT 模型的训练与评估。

生成解码

这一节我们先实现 GPT 模型的生成解码功能,将模型的预测转换为可读的文本。

生成解码在流水线中的位置

31.2. 环境配置#

31.2.1. 安装依赖#

!pip install --upgrade dsxllm

31.2.2. 环境版本#

from dsxllm.util import show_version

show_version()
本书愿景:
+------+--------------------------------------------------------+
| Info |                  《动手学大语言模型》                  |
+------+--------------------------------------------------------+
| 作者 |                       吾辈亦有感                       |
| 哔站 |      https://space.bilibili.com/3546632320715420       |
| 定位 | 基于'从零构建'的理念,用实战帮助程序员快速入门大模型。 |
| 愿景 | 若让你的AI学习之路走的更容易一点,我将倍感荣幸!祝好😄 |
+------+--------------------------------------------------------+
环境信息:
+-------------+--------------+------------------------+
| Python 版本 | PyTorch 版本 | PyTorch Lightning 版本 |
+-------------+--------------+------------------------+
|   3.12.12   |    2.10.0    |         2.6.1          |
+-------------+--------------+------------------------+

31.3. GPT 模型的生成解码#

大语言模型的预训练以“下一个词元预测”为目标,因此,其文本生成过程本质上也是基于此目标的迭代:每次预测并生成一个词,直至完成整个序列。

以生成 动手学大语言模型 为例,从初始输入 开始,GPT 模型在每轮迭代中预测下一个词元,并将其添加到输入上下文中以进行下一轮预测。如下图所示,第一轮迭代添加了“a”,第二轮迭代添加了 ,第二轮迭代添加了 ,逐步形成了完整的句子。

逐次生成的过程

但是,GPT 模型本身的输入并不是下一个词,而是下一个词在词表上的预测得分 logits。因此,在生成过程中,需要根据 logits 进行解码,选择得分最高的词元作为下一个词。具体过程如下:

动手学大语言模型的生成解码过程

31.4. 生成解码方法的代码实现#

import torch
from dsxllm.gpt.model import GPTModel
from dsxllm.gpt.tokenizer import token_ids_to_text


# 定义生成函数
def greedy_generate(model: GPTModel, start_ids, max_new_tokens, context_size, tokenizer):
    """
    使用贪心解码策略(每次选择得分最高的 Token)生成文本。

    Args:
        model: 语言模型(应处于 eval 模式)
        start_ids (torch.Tensor): 输入的提示 token ID 序列,形状为 (batch_size, seq_len)
        max_new_tokens (int): 要生成的最大新 token 数量
        context_size (int): 模型支持的最大上下文长度
        tokenizer: 用于将 token IDs 解码为文本的分词器

    Returns:
        str: 生成的完整文本(包含原始提示)
    """

    model.eval()
    generated_ids = start_ids.to(model.device)

    # generated_ids 是当前上下文中的 Token IDs 数组
    for _ in range(max_new_tokens):
        # 1️⃣ 如果当前序列长度超过上下文窗口,仅保留最后 context_size 个 token 作为输入
        # 例如,如果 LLM 仅支持 3 个 token,而上下文大小为 10,则仅使用最后 3 个 token 作为上下文
        input_context = generated_ids[:, -context_size:]

        # 2️⃣ 使用模型预测每个位置的下一个 Token 在词表上的预测得分,形状为 (batch, seq_len, vocab_size)
        with torch.no_grad():
            logits = model(input_context)

        # 3️⃣ 仅关注最后一个时间步,取最后一个时间步的预测得分作为下一个词的预测,(batch, context_size, vocab_size) 变为 (batch, vocab_size)
        logits = logits[:, -1, :]

        # 4️⃣ 选择概率最高的 token ID(贪心)
        # 这里使用的是贪心解码,为了提高计算效率省去了 softmax 的计算,得分最高它的概率也是最高,所以直接取分值最高的 Token ID
        idx_next = torch.argmax(logits, dim=-1, keepdim=True)  # (batch, 1)

        # 5️⃣ 将新生成的 Token ID 追加到正在生成的序列中,进行下一个迭代的生成,形状为 (batch, n_tokens+1)
        generated_ids = torch.cat((generated_ids, idx_next), dim=1)

    # 将 token IDs 转换为文本(假设 batch_size = 1)
    return token_ids_to_text(generated_ids, tokenizer)

31.5. 使用 GPT 模型进行预测生成#

import tiktoken

from dsxllm.gpt.tokenizer import text_to_token_ids, token_ids_to_text
from dsxllm.gpt.model import GPTModel
from dsxllm.util import print_red

# 定义GPT模型的配置参数(对应124M参数版本的GPT)
GPT_CONFIG_124M = {
    "vocab_size": 50257,  # 词汇表大小,即模型可以表示的不同token的数量
    "seq_len": 256,  # 上下文长度(原为1024,此处缩短为256),决定模型一次处理的最大序列长度
    "d_model": 768,  # 嵌入维度(embedding dimension),每个token被映射到的向量维度
    "n_heads": 12,  # 注意力头数量(number of attention heads),用于多头注意力机制
    "n_layers": 12,  # 层数,Transformer块的数量
    "drop_rate": 0.1,  # Dropout率,用于防止过拟合的概率值
    "qkv_bias": False,  # 查询-键-值偏置(query-key-value bias),是否在注意力计算中使用偏置项
}

# 1️⃣ 根据定义的配置创建GPT模型实例
model = GPTModel(GPT_CONFIG_124M)


# 2️⃣ 初始化 GPT-2 使用的分词器
tokenizer = tiktoken.get_encoding("gpt2")

# 3️⃣ 使用生成解方法生成文本
generated_text = greedy_generate(
    model=model,
    start_ids=text_to_token_ids("I", tokenizer),
    max_new_tokens=10,
    context_size=GPT_CONFIG_124M["seq_len"],
    tokenizer=tokenizer,
)

# 4️⃣ 打印生成的文本
print_red("生成示例:")
print(generated_text)
生成示例:
Iammad Policies ROB accredited accommodate appTYPE boosts______ sts

从生成结果可以观察到,未经训练的GPT模型尚未掌握任何语言知识,其输出仅为随机的字符序列,缺乏基本的语句连贯性。下一节将介绍如何对该模型进行训练,以使其能够生成流畅且连贯的文本。

31.6. 答疑讨论#