使用 PyTorch 构建自定义 GPT

一、介绍

       介绍大模型,首先考虑一下使用 ChatGPT、Bing Chat 或 Bard 。您是否想过拥有自己的 ChatGPT 会是什么样子?想象一下创建自己的 GPT 模型的兴奋程度。这确实是一种难以置信的感觉!

为了开始构建自定义 GPT 的旅程,让我们仔细看看 GPT 的运作方式。

二、了解 GPT

        GPT 是Generative Pre-trained Transformer的缩写,是一种充当解码器的 Transformer 模型。它已在 BookCorpus 和 WebText 等广泛数据集上进行了预训练。为了更深入地了解 GPT,有必要探索各种类型的变压器并深入研究纯解码器变压器的运行机制。

三、变形金刚解码

        Transformer 是一种深度神经网络架构,专门用于生成类似人类的文本。LLM 模型基于三种类型的变压器架构进行开发,有些模型正在其基础上进行开发。

  • 仅编码器变压器:仅编码器变压器是变压器架构的一种特殊变体,仅专注于理解和编码输入序列的任务。它们是仅使用 Transformer 模型的编码器部分的神经网络。仅编码器转换器用于各种自然语言处理任务,例如文本分类、命名实体识别和情感分析。仅编码器 Transformer 最突出的例子是BERT(来自 Transformers 的双向编码器表示)
  • 仅解码器变压器:仅解码器变压器是一种仅使用变压器模型的解码器组件的变压器架构。这些模型用于需要解码器组件的任务,例如文本生成、机器翻译和摘要。解码器组件负责从输入序列生成输出序列。仅解码器变压器最突出的例子是GPT(生成预训练变压器)
  • Encoder-Decoder Transformers(Cross-Attention):基于 Transformer 的 Encoder-Decoder 模型是一种神经网络架构,广泛应用于语言翻译、文本摘要等 NLP 任务中。这就是原来的变压器。该架构由两个主要组件组成:编码器和解码器。编码器处理输入序列并生成输入的连续表示,而解码器则根据编码器的表示生成输出序列。基于Transformer的编码器-解码器模型已在T5、Bart、Pegasus、ProphetNet、Marge等许多预训练模型中使用。

四、了解 GPT 架构:变压器块

Transformer 块具有三个目标:准备、丰富和预测。

4.1 准备阶段:

变压器模型的初始输入由一系列单词标记组成,然后将其转换为单词嵌入。这些嵌入通过位置编码来丰富以传达其位置信息。

  • 位置编码:在 Transformer 模型中,位置编码用于定义序列中实体的位置,确保每个位置都有不同的表示。变压器本身缺乏对输入序列顺序的固有理解。序列内特定位置 (p)和嵌入空间内维度 (i)位置编码是通过正弦和余弦函数的组合来实现的。

这里,“d”表示词嵌入的维度。这些函数为各个单词位置生成不同的代码。这些代码可以扩展到训练阶段未遇到的序列长度。下一步是将这个新序列输入到变压器块中,其中每个元素都被视为密集向量。

4.2 浓缩阶段:

        丰富包括多头注意力、位置前馈神经网络、残差连接和层归一化。

        多头注意力:注意力用于评估单词之间的重要性和联系。它通过合并更多上下文和逻辑来增强矢量表示。注意力依赖于三个向量:查询向量、键向量和值向量,它们源自初始层,即词嵌入向量。查询向量对应于当前标记,键向量包含序列中的所有其他标记,并且值向量包含序列中的所有标记。

        在自注意力过程中,我们首先计算查询向量和关键向量的缩放积以获得注意力分数。接下来,通过 softmax 函数处理该注意力分数,产生一组范围从0 到 1的注意力权重。然后,每个值向量按其各自的注意力权重进行缩放,最后,它们的总和产生自注意力层的输出。

        术语“多头注意力”源自其多(三个)注意力层的组成。

  • 早期注意: 在这种情况下,短程依赖涉及相邻标记之间的关系,例如词序、词性和基本句子结构,而不需要逐步方法。
  • 中间注意力:它包含输入序列的更广泛的上下文,其中可能包括语义信息、含义、短语之间的关系以及句子中不同单词的角色。
  • 后期注意力:它结合较低层以产生有凝聚力且上下文相关的结果,包括高级抽象、话语结构、情感分析和复杂的长期联系

        Position-wise Feed-Forward Neural Network:该组件的作用是获取序列中每个元素的注意力阶段收集的信息,并将其转换为更丰富的状态。它促进序列中每个元素的非线性变换,并在后续层中继续构建自身。

        残余连接:残余连接促进信息从较早的层直接流向较晚的层。它们在解决深度神经网络中经常遇到的梯度消失问题方面发挥着至关重要的作用。

        层标准化:它不是根据批次标准化输入,而是跨特征执行标准化。这有助于通过确保一致的输入分布来稳定网络的训练,这对于具有不同序列长度的任务至关重要。

4.3 预测阶段:

        在这个过程中,线性函数和softmax函数发挥了至关重要的作用。首先,我们有一系列来自最后一个转换器块的上下文感知向量。该序列中的每个向量代表一个输入标记,并受到其与所有其他标记的交互的影响。为了将向量的输出序列投影到维度为N_w的空间(其中N_w词汇表大小),我们使用线性函数。然后,我们将 softmax 函数应用于这些投影向量,以创建词汇表上的概率分布。这种分布有助于我们预测序列中的下一个标记。

五、变压器中的重要变量

5.1 输入变量

  • 词汇量:这是指模型可以识别的唯一标记的数量。
  • 嵌入/模型大小:表示词嵌入的维度,也称为隐藏大小。
  • 序列/上下文长度:这表示模型一次性可以处理的最大标记数。

5.2 内部变量

  • 注意力头计数:在多头注意力中,输入被分为特定数量的注意力头。
  • 中间层大小:前馈网络中中间层的大小通常大于嵌入大小。
  • 层数:这对应于变压器块的数量。

5.3 训练变量

  • 批量大小:它是指在训练期间一次前向传递中一起处理多少个示例。
  • 训练的令牌:它表示模型在训练期间遇到的令牌总数,通常比纪元数更频繁地报告。

六、自定义类似 GPT 的模型

使用 Pytorch,我们将构建自定义的类似 GPT 的模型。首先我们将导入所有必需的库。

# Import the necessary libraries
import torch
import torch.nn as nn
import torch.nn.functional as F
import math
import time
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

        我们将定义 DecoderBlock,它是变压器块的单层。我们将定义解码器块所需的超参数:

  • d_model:输入向量的维度。
  • num_heads:多头注意力机制中头的数量。
  • ff_hidden_​​layer:前馈隐藏层的维度。
  • 辍学率:辍学率。

前向方法需要两个输入

  • x:输入张量。
  • target_mask:防止对某些位置的关注的掩码。
# Decoder Block
class DecoderBlock(nn.Module):def __init__(self, d_model, num_heads, ff_hidden_layer, dropout):super(DecoderBlock, self).__init__()self.self_attention = nn.MultiheadAttention(d_model, num_heads, dropout=dropout)self.norm1 = nn.LayerNorm(d_model)self.dropout1 = nn.Dropout(dropout)self.linear1 = nn.Linear(d_model, ff_hidden_layer)self.linear2 = nn.Linear(ff_hidden_layer, d_model)self.norm2 = nn.LayerNorm(d_model)self.dropout2 = nn.Dropout(dropout)def forward(self, x,target_mask):attn_output, _ = self.self_attention(x, x, x, attn_mask=target_mask)x = x + self.dropout1(attn_output)x = self.norm1(x)ff_output = self.linear2(F.relu(self.linear1(x)))x = x + self.dropout2(ff_output)x = self.norm2(x)return x

        现在,让我们创建 PositionalEncoding 类,它应用唯一的位置编码来为模型提供有关序列中标记的相对或绝对位置的信息。

# Positional Encodingclass PositionalEncoding(nn.Module):def __init__(self, d_model, dropout=0.1, max_len=5000):super(PositionalEncoding, self).__init__()self.dropout = nn.Dropout(p=dropout)pe = torch.zeros(max_len, d_model)position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model))pe[:, 0::2] = torch.sin(position * div_term)pe[:, 1::2] = torch.cos(position * div_term)pe = pe.unsqueeze(0).transpose(0, 1)self.register_buffer("pe", pe)def forward(self, x):x = x + self.pe[:x.size(0), :]return self.dropout(x)

我们需要屏蔽解码器的输入,以防止关注未来的位置。

def generate_square_subsequent_mask(sz):"""Generate a mask to prevent attention to future positions."""mask = (torch.triu(torch.ones(sz, sz)) == 1).transpose(0, 1)mask = mask.float().masked_fill(mask == 0, float('-inf')).masked_fill(mask == 1, float(0.0))return maskmask = generate_square_subsequent_mask(sz=5)plt.figure(figsize=(5,5))
sns.heatmap(mask, cmap="crest", cbar=False, square=True)
plt.title("Mask for Transformer Decoder")
plt.show()

        现在,我们来描述完整的 Transformer 解码器,包括初始嵌入层、单独的 Transformer 解码器块以及最终的线性层和 Softmax 层。

        在 TransformerDecoder 中,线性层执行线性变换,映射输出维度以匹配词汇表大小。随后,应用softmax 层将输出转换为词汇表上的概率分布。整个过程被封装在转发方法中,该方法指示通过解码器的数据流。

# Transformer Decoderclass TransformerDecoder(nn.Module):def __init__(self, vocab_size, d_model, num_heads, ff_hidden_layer, dropout):super(TransformerDecoder, self).__init__()self.embedding = nn.Embedding(vocab_size, d_model)self.pos_encoder = PositionalEncoding(d_model, dropout)self.transformer_block = DecoderBlock(d_model, num_heads, ff_hidden_layer, dropout)self.linear = nn.Linear(d_model, vocab_size)self.softmax = nn.LogSoftmax(dim=-1)def forward(self, x):x = self.embedding(x)x = self.pos_encoder(x)tgt_mask = generate_square_subsequent_mask(x.size(0))x = self.transformer_block(x,tgt_mask)output = self.linear(x)output = self.softmax(output)return output

        首先,让我们建立初始解码器。为此,我们首先概述我们的超参数。接下来,我们将构造一个表示批量大小和上下文长度的张量。之后,我们将继续对模型进行前向传播。生成的输出将采用张量的形式。最后,我们将使用“argmax”函数来提取预测的单词索引。

# Define the hyperparameters
vocab_size     = 1000
d_model        = 512
num_heads      = 1
ff_hidden_layer  = 2*d_model
dropout        = 0.1
num_layers     = 10
context_length = 50
batch_size     = 1
# Initialize the model
model = TransformerDecoder(vocab_size, d_model, num_heads, ff_hidden_layer, dropout)# Create a tensor representing batch size and context length
input_tensor = torch.randint(0, vocab_size, (context_length, batch_size))# Forward pass through the model
output = model(input_tensor)print(output.shape)  # To get the predicted word indices, we can use the `argmax` function
predicted_indices = output.argmax(dim=-1)print(predicted_indices.shape)

现在,计算参数。

def count_parameters(model):return sum(p.numel() for p in model.parameters() if p.requires_grad)print(f"The model has {count_parameters(model):,} trainable parameters")

为了查看输出,我们会将对数概率转换为 概率,并将输出张量转换为 numpy 数组。

# Convert the log probabilities to probabilities
distribution = torch.exp(output[0, 0, :])# Convert the output tensor to numpy array
distribution = distribution.detach().numpy()# Plot the distribution
plt.figure(figsize=(12, 6))
plt.bar(np.arange(vocab_size), distribution)
plt.xlabel("Word Index")
plt.ylabel("Probability")
plt.title("Output Distribution over Vocabulary")
plt.show()

现在制作一个多层解码器,这将以层数作为参数。

class MultiLayerTransformerDecoder(nn.Module):def __init__(self, vocab_size, d_model, num_heads, ff_hidden_layer, dropout, num_layers):super(MultiLayerTransformerDecoder, self).__init__()self.embedding = nn.Embedding(vocab_size, d_model)self.pos_encoder = PositionalEncoding(d_model, dropout)self.transformer_blocks = nn.ModuleList([DecoderBlock(d_model, num_heads, ff_hidden_layer, dropout)for _ in range(num_layers)])self.linear = nn.Linear(d_model, vocab_size)self.softmax = nn.LogSoftmax(dim=-1)def forward(self, x):x = self.embedding(x)x = self.pos_encoder(x)for transformer_block in self.transformer_blocks:target_mask = generate_square_subsequent_mask(x.size(0))x = transformer_block(x,target_mask)output = self.linear(x)output = self.softmax(output)return output

遵循相同的过程。

# Define the hyperparameters
vocab_size     = 10000
d_model        = 2048
num_heads      = 2
ff_hidden_layer  = 8*d_model
dropout        = 0.1
num_layers     = 20
context_length = 1000
batch_size     = 1# Create our input to the model to process
input_tensor = torch.randint(0, vocab_size, (context_length, batch_size))# Initialize the model with `num_layer` layers
model = MultiLayerTransformerDecoder(vocab_size, d_model, num_heads, ff_hidden_layer, dropout, num_layers)# Print the number of trainable parameters
print(f"The model has {count_parameters(model):,} trainable parameters")# Let's use the same input_tensor from the previous example
output = model(input_tensor)# Convert the log probabilities to probabilities for the first sequence in the batch and the first position in the sequence
distribution = torch.exp(output[0, 0, :])# Convert the output tensor to numpy array
distribution = distribution.detach().numpy()# Now plot the distribution
plt.figure(figsize=(12, 6))
plt.bar(np.arange(vocab_size), distribution)
plt.xlabel("Word Index")
plt.ylabel("Probability")
plt.title("Output Distribution over Vocabulary")
plt.show()

你可以看到你的模型。

MultiLayerTransformerDecoder((embedding): Embedding(10000, 2048)(pos_encoder): PositionalEncoding((dropout): Dropout(p=0.1, inplace=False))(transformer_blocks): ModuleList((0-19): 20 x DecoderBlock((self_attention): MultiheadAttention((out_proj): NonDynamicallyQuantizableLinear(in_features=2048, out_features=2048, bias=True))(norm1): LayerNorm((2048,), eps=1e-05, elementwise_affine=True)(dropout1): Dropout(p=0.1, inplace=False)(linear1): Linear(in_features=2048, out_features=16384, bias=True)(linear2): Linear(in_features=16384, out_features=2048, bias=True)(norm2): LayerNorm((2048,), eps=1e-05, elementwise_affine=True)(dropout2): Dropout(p=0.1, inplace=False)))(linear): Linear(in_features=2048, out_features=10000, bias=True)(softmax): LogSoftmax(dim=-1)
)

        现在,您必须使用任何您想要用自己的仅解码器变压器模型进行实验的数据集,并且您将拥有自己的 GPT。玩得开心!(代码阿克里蒂·乌帕迪亚

七、结论

        创建我们自己的类似 GPT 的模型的过程包括理解架构、在代码中实现它以及使用数据集进行实验和微调。

这次旅程让我们能够释放创造力并探索令人兴奋的自然语言处理世界。

构建自定义 GPT 不仅是一项技术成就,而且还邀请您享受乐趣并探索文本生成的无限可能性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/156051.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringCloud(一) 服务架构的演变及注册RestTemplate实现服务的远程调用

目录 一, 服务架构的演变 1.1 单体架构 1.2 分布式架构 1.3 微服务 1.4 SpringCloud 二, 服务拆分和远程调用 2,1 服务拆分原则 2.2 服务拆分示例 2.3 创建相应数据库 2.4 实现远程调用示例 1, 更改需求 2, 注册RestTemplate实现远程调用 2.5 服务消费者和提供者 一…

Springboot整合Minio实现文件上传和下载

目录 1. Minio 1.1 Minio下载 2. Springboot和Minio实现文件存储 1. Minio Minio是一个灵活、高性能、开源的对象存储解决方案,适用于各种存储需求,并可以与云计算、容器化、大数据和应用程序集成。它为用户提供了自主控制和可扩展性,使其…

Go学习第十五章——Gin参数绑定bind与验证器

Go web框架——Gin(参数绑定bind与验证器) 1 bind参数绑定1.1 JSON参数1.2 Query参数1.3 Uri绑定动态参数1.4 ShouldBind自动绑定 2 验证器2.1 常用验证器2.2 gin内置验证器2.3 自定义验证的错误信息2.4 自定义验证器 1 bind参数绑定 在Gin框架中&#…

AD教程(四)排针类元件模型的创建

AD教程(四)排针类元件模型的创建 新建元件,输入排针型号作为元件命名 快捷键TC 快速创建元件 放置外框 放置管脚,排针管脚号在原理图上一般不显示,需要将管脚号隐藏,但一般不建议隐藏,如果将管…

DL Homework 5

目录 习题4-1 对于一个神经元​编辑,并使用梯度下降优化参数w时,如果输入x恒大于0,其收敛速度会比零均值化的输入更慢。 习题4-5 如果限制一个神经网络的总神经元数量(不考虑输入层)为N1,输入层大小为​编辑,输出层大…

PyQuery库写一个有趣的爬虫程序

PyQuery库是一个基于jQuery语法的Python库,它可以方便地对HTML/XML文档进行解析和操作。使用PyQuery库可以快速地获取网页中的数据,进行数据清洗和分析。PyQuery库的基本用法包括字符串初始化、打开网页、css属性、标签内容等获取、DOM基本操作等相关技巧…

基于吉萨金字塔建造算法的无人机航迹规划-附代码

基于吉萨金字塔建造算法的无人机航迹规划 文章目录 基于吉萨金字塔建造算法的无人机航迹规划1.吉萨金字塔建造搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要:本文主要介绍利用吉萨金字塔建造算法…

NLP之LSTM与BiLSTM

文章目录 代码展示代码解读双向LSTM介绍(BiLSTM) 代码展示 import pandas as pd import tensorflow as tf tf.random.set_seed(1) df pd.read_csv("../data/Clothing Reviews.csv") print(df.info())df[Review Text] df[Review Text].astyp…

思维训练 第四课 省略句

系列文章目录 文章目录 系列文章目录前言一、省略的十五种情况1.并列复合句中某些相同成分的省略2.在用when, while, if, as if, though, although, as ,until, whether等连词引导的状语从句中,如果谓语有be,而主语又跟主句的主语相同或是(从句主语是&am…

STM智能小车——OLED实现测速小车

目录 1. 测速模块 2. 测试原理和单位换算 3. 定时器和中断实现测速开发和调试代码 4. 小车速度显示在OLED屏 1. 测速模块 用途:广泛用于电机转速检测,脉冲计数,位置限位等。有遮挡,输出高电平;无遮挡,输出低电平接线…

Linux———— 运算命令

Shell与其他编程语言一样,支持多种类型的运算符,包括: 算术运算符:用于执行数学运算,例如加法、减法、乘法和除法。 关系运算符:用于比较两个值之间的关系,例如相等、大于、小于等。 布尔运算…

3 — NLP 中的标记化:分解文本数据的艺术

一、说明 这是一个系列文章的第三篇文章, 文章前半部分分别是: 1 、NLP 的文本预处理技术 2、NLP文本预处理技术:词干提取和词形还原 在本文中,我们将介绍标记化主题。在开始之前,我建议您阅读我之前介绍的关…