马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
4 Implementing a GPT model from Scratch To Generate Text
- 本章节包罗
- 编写一个雷同于GPT的大型语言模子(LLM),这个模子可以被训练来天生雷同人类的文本。
- Normalizing layer activations to stabilize neural network training
- 在深度神经网络中添加shortcut connections,以更有用地训练模子
- 实现 Transformer 模块以创建差别规模的 GPT 模子
- 盘算 GPT 模子的参数数目及其存储需求
在上一章中,学习了多头注意力机制并对其举行了编码,它是LLMs的焦点组件之一。在本章中,将编写 LLM 的其他构建块,并将它们组装成雷同 GPT 的模子
4.1 Coding an LLM architecture
- 诸如GPT和Llama等模子,基于原始Transformer架构中的decoder部分,因此,这些LLM通常被称为"decoder-like" LLMs,与传统的深度学习模子相比,LLM规模更大,这紧张归因于它们巨大的参数数目,而非代码量。由于它的很多组件都是重复的,下图提供了雷同 GPT LLM 的自上而下视图

本章将具体构建一个最小规模的GPT-2模子(1.24亿参数),并展示怎样加载预训练权重以兼容更大规模的模子。
- 1.24亿参数GPT-2模子的设置细节包罗:
- GPT_CONFIG_124M = {
- "vocab_size": 50257, # Vocabulary size
- "context_length": 1024, # Context length
- "emb_dim": 768, # Embedding dimension
- "n_heads": 12, # Number of attention heads
- "n_layers": 12, # Number of layers
- "drop_rate": 0.1, # Dropout rate
- "qkv_bias": False # Query-Key-Value bias
- }
复制代码 我们使用简短的变量名以克制后续代码行过长
- "vocab_size" 词汇表巨细,由 BPE tokenizer 支持,值为 50,257。
- "context_length" 模子的最大输入标记数目,通过 positional embeddings 实现。
- "emb_dim" token输入的嵌入巨细,将每个token转换为 768 维向量。
- "n_heads" 多头注意力机制中的注意力头数目。
- "n_layers" 是模子中 transformer 块的数目
- "drop_rate" 是 dropout 机制的强度,第 3 章讨论过;0.1 表现在训练期间抛弃 10% 的潜伏单位以缓解过拟合
- "qkv_bias" 决定多头注意力机制(第 3 章)中的 Linear 层在盘算查询(Q)、键(K)和值(V)张量时是否包罗偏置向量;我们将禁用此选项,这是当代 LLMs 的标准做法;然而,我们将在第 5 章将 OpenAI 的预训练 GPT-2 权重加载到我们的重新实现时重新讨论这一点。
- 下图中的方框展示了我们为实现终极 GPT 架构所需处理处罚的各个概念的序次。我们将从第一步开始,即一个我们称为 DummyGPTModel 的 GPT 骨架占位符:

- import torch
- import torch.nn as nn
- class DummyGPTModel(nn.Module):
- def __init__(self, cfg):
- super().__init__()
- self.tok_emb = nn.Embedding(cfg["vocab_size"], cfg["emb_dim"])
- self.pos_emb = nn.Embedding(cfg["context_length"], cfg["emb_dim"])
- self.drop_emb = nn.Dropout(cfg["drop_rate"])
-
- # Use a placeholder for TransformerBlock
- self.trf_blocks = nn.Sequential(
- *[DummyTransformerBlock(cfg) for _ in range(cfg["n_layers"])])
-
- # Use a placeholder for LayerNorm
- self.final_norm = DummyLayerNorm(cfg["emb_dim"])
- self.out_head = nn.Linear(
- cfg["emb_dim"], cfg["vocab_size"], bias=False
- )
- def forward(self, in_idx):
- batch_size, seq_len = in_idx.shape
- tok_embeds = self.tok_emb(in_idx)
- pos_embeds = self.pos_emb(torch.arange(seq_len, device=in_idx.device))
- x = tok_embeds + pos_embeds
- x = self.drop_emb(x)
- x = self.trf_blocks(x)
- x = self.final_norm(x)
- logits = self.out_head(x)
- return logits
- class DummyTransformerBlock(nn.Module):
- def __init__(self, cfg):
- super().__init__()
- # A simple placeholder
- def forward(self, x):
- # This block does nothing and just returns its input.
- return x
- class DummyLayerNorm(nn.Module):
- def __init__(self, normalized_shape, eps=1e-5):
- super().__init__()
- # The parameters here are just to mimic the LayerNorm interface.
- def forward(self, x):
- # This layer does nothing and just returns its input.
- return x
复制代码
- DummyGPTModel:简化版的 GPT 类模子,使用 PyTorch 的 nn.Module 实现。
- 模子组件:包罗标记嵌入、位置嵌入、抛弃层、变更器块、层归一化和线性输出层。
- 设置字典:设置通过 Python 字典传入,如 GPT_CONFIG_124M,用于通报模子设置。
- forward 方法:形貌数据从输入到输出的完备流程。盘算嵌入 → 应用 dropout → 通过 transformer blocks 处理处罚 → 应用归一化 → 天生 logits。
- 占位符:DummyLayerNorm 和 DummyTransformerBlock 是待实现的组件。
- 数据运动:下图提供了 GPT 模子中数据运动的高条理概述。
使用 tiktoken 分词器对由 GPT 模子的两个文本输入构成的批次举行分词:
- import tiktoken
- tokenizer = tiktoken.get_encoding("gpt2")
- batch = []
- txt1 = "Every effort moves you"
- txt2 = "Every day holds a"
- batch.append(torch.tensor(tokenizer.encode(txt1)))
- batch.append(torch.tensor(tokenizer.encode(txt2)))
- batch = torch.stack(batch, dim=0)
- print(batch)
- """输出"""
- tensor([[6109, 3626, 6100, 345],
- [6109, 1110, 6622, 257]]
- )
复制代码 接下来,我们初始化一个包罗 1.24 亿参数的 DummyGPTModel 实例,并将 tokenized batch 输入此中。
- torch.manual_seed(123)
- model = DummyGPTModel(GPT_CONFIG_124M)
- logits = model(batch)
- print("Output shape:", logits.shape)
- print(logits)
- """输出"""
- Output shape: torch.Size([2, 4, 50257])
- tensor([[[-0.9289, 0.2748, -0.7557, ..., -1.6070, 0.2702, -0.5888],
- [-0.4476, 0.1726, 0.5354, ..., -0.3932, 1.5285, 0.8557],
- [ 0.5680, 1.6053, -0.2155, ..., 1.1624, 0.1380, 0.7425],
- [ 0.0447, 2.4787, -0.8843, ..., 1.3219, -0.0864, -0.5856]],
- [[-1.5474, -0.0542, -1.0571, ..., -1.8061, -0.4494, -0.6747],
- [-0.8422, 0.8243, -0.1098, ..., -0.1434, 0.2079, 1.2046],
- [ 0.1355, 1.1858, -0.1453, ..., 0.0869, -0.1590, 0.1552],
- [ 0.1666, -0.8138, 0.2307, ..., 2.5035, -0.3055, -0.3083]]],
- grad_fn=<UnsafeViewBackward0>)
复制代码
- 输出张量:输出张量有两行,分别对应两个文本样本。每个文本样本由 4 个标记构成;每个标记是一个 50,257 维的向量,这与标记器的词汇表巨细划一。
- 嵌入维度:50,257 维对应词汇表中的唯一标记,后处理处罚阶段将其转换回 token IDs 并解码为单词。
|