大模型原理:预训练目标-因果语言建模(CLM)-pytorch实现数据集 作者:马育民 • 2026-01-08 17:29 • 阅读:10004 需要掌握:[大模型原理:预训练目标-因果语言建模(CLM)-使用滑动窗口进行数据采样](https://www.malaoshi.top/show_1GW2YV1NBWPm.html "大模型原理:预训练目标-因果语言建模(CLM)-使用滑动窗口进行数据采样") # 介绍 为了实现高效的数据加载器,将使用PyTorch内置的Dataset类和DataLoader类。 # 安装 ``` poetry add numpy==2.2 ``` ``` poetry add torch==2.9 ``` # 实现 ### 导入模块 ``` from importlib.metadata import version import tiktoken import torch from torch.utils.data import Dataset, DataLoader print("查看 version 版本号:", version("tiktoken")) print("查看所有支持的编码:", tiktoken.list_encoding_names()) ``` ### 定义Dataset类 该类创建对象时,传入文本、分词器、窗口大小、步长,然后对文本进行编码,根据窗口大小、步长提出 `输入-目标对` ``` class GPTDatasetV1(Dataset): """ GPTDatasetV1类继承自PyTorch的Dataset类,并定义了如何从数据集中提取单行数据。 每行数据包含多个词元ID(数量由max_length参数决定),这些词元ID被分配给input_chunk张量, 而target_chunk张量包含相应的目标词元ID。 """ def __init__(self, txt, tokenizer, max_length, stride): """ 初始化 :param txt: 文本 :param tokenizer: 分词器 :param max_length: 窗口大小 :param stride: 步长 """ self.input_ids = [] self.target_ids = [] # 对全部文本进行分词 token_ids = tokenizer.encode(txt) # 使用滑动窗口将文本划分为长度为max_length的重叠序列 for i in range(0, len(token_ids) - max_length, stride): input_chunk = token_ids[i:i + max_length] target_chunk = token_ids[i + 1:i + max_length + 1] self.input_ids.append(torch.tensor(input_chunk)) self.target_ids.append(torch.tensor(target_chunk)) def __len__(self): """ 返回数据集的总行数,否则传入数据加载器报错 :return: """ return len(self.input_ids) def __getitem__(self, idx): """ 返回指定索引的数据,必须实现,否则传入数据加载器报错 :param idx: :return: """ return self.input_ids[idx], self.target_ids[idx] ``` ### 创建数据加载器函数 定义函数 `create_dataloader_v1`,实现下面功能: 1. 初始化分词器 2. 创建数据集 3. 创建、并返回数据加载器 ``` def create_dataloader_v1(txt, batch_size=4, max_length=256, stride=128, shuffle=True, drop_last=True, num_workers=0): """ 数据加载器,用于批量生成输入-目标对 :param txt: :param batch_size: :param max_length: :param stride: :param shuffle: :param drop_last: :param num_workers: :return: """ # 初始化分词器,选择对应模型的编码,不同模型编码规则不同 tokenizer = tiktoken.get_encoding("gpt2") # 创建数据集 dataset = GPTDatasetV1(txt, tokenizer, max_length, stride) # 创建数据加载器 dataloader = DataLoader( dataset, batch_size=batch_size, shuffle=shuffle, drop_last=drop_last, # 如果drop_last为True且批次大小小于指定的batch_size,则会删除最后一批,以防止在训练期间出现损失剧增 num_workers=num_workers # 用于预处理的CPU进程数 ) return dataloader ``` ### 执行 1. 读取文本 2. 调用数据加载器函数 3. 打印前几张数据 ``` # 读取文本 with open("the-verdict.txt", "r", encoding="utf-8") as f: raw_text = f.read() dataloader = create_dataloader_v1(raw_text, batch_size=1, max_length=4, stride=1, shuffle=False) data_iter = iter(dataloader) first_batch = next(data_iter) print("第1组输入目标对:", first_batch) second_batch = next(data_iter) print("第2组输入目标对:", second_batch) ``` 执行结果: ``` 查看 version 版本号: 0.12.0 查看所有支持的编码: ['gpt2', 'r50k_base', 'p50k_base', 'p50k_edit', 'cl100k_base', 'o200k_base', 'o200k_harmony'] 第1组输入目标对: [tensor([[ 40, 367, 2885, 1464]]), tensor([[ 367, 2885, 1464, 1807]])] 第2组输入目标对: [tensor([[ 367, 2885, 1464, 1807]]), tensor([[2885, 1464, 1807, 3619]])] ``` 变量 `first_batch`包含两个张量: - 第一个张量存储输入词元ID - 第二个张量存储目标词元ID 由于 `max_length` 被设置为 `4`,因此这两个张量各自包含 `4个词元ID`。 **注意:**这里是为了简单,将输入大小设置为 `4`,在实际训练大语言模型时,输入大小通常 **不小于 `256`** ### 步长的含义 详见链接: https://www.malaoshi.top/show_1GW2YXBPPimC.html ### 批次大小的含义 调用 `create_dataloader_v1()` 函数时,传值 `batch_size=2`,其他不变: ``` dataloader = create_dataloader_v1(raw_text, batch_size=2, max_length=4, stride=1, shuffle=False) data_iter = iter(dataloader) first_batch = next(data_iter) print("第1组输入目标对:", first_batch) second_batch = next(data_iter) print("第2组输入目标对:", second_batch) ``` 执行结果: ``` 查看 version 版本号: 0.12.0 查看所有支持的编码: ['gpt2', 'r50k_base', 'p50k_base', 'p50k_edit', 'cl100k_base', 'o200k_base', 'o200k_harmony'] 第1组输入目标对: [tensor([[ 40, 367, 2885, 1464], [ 367, 2885, 1464, 1807]]), tensor([[ 367, 2885, 1464, 1807], [2885, 1464, 1807, 3619]])] 第2组输入目标对: [tensor([[2885, 1464, 1807, 3619], [1464, 1807, 3619, 402]]), tensor([[1464, 1807, 3619, 402], [1807, 3619, 402, 271]])] ``` 每次读取 **两组数据** 原文出处:http://www.malaoshi.top/show_1GW2YXCJgYVE.html