当前位置: 首页 > news >正文

从零开始大模型之实现GPT模型

从零开始大模型之从头实现GPT模型

  • 1.大语言模型整体架构
  • 2 大语言的Transformer模块
    • 2.1 层归一化
    • 2.2 GELU激活函数
    • 2.3 前馈神经网络
    • 2.4 快捷连接
  • 3 附录
    • 3.1 anaconda+python环境搭建

在这里插入图片描述
1.数据预处理:原始数据进行词元化,以及通过,依据词汇表生成ID编号,对ID编号随机生成嵌入向量,特别注意的是嵌入向量事实上也是一个权重,通过反向传播进行更新。

2.掩码多头注意力机制:增加掩码多头注意力机制,其中增加掩码机制是为了确定序列的输出的因果关系,多头注意力机制是为了对不同路径的来源数据进行上下文联系。

3.LLM架构transform块:进行层归一化,GELU激活函数,前馈神经网络,快捷连接。

1.大语言模型整体架构

在这里插入图片描述
数据预处理,掩码多头注意力机制已经学过了,接下来进行最重要的LLM架构的transform块的学习。
#1 Transform块总体概述
整个transform块包含以下内容,层归一化,GELU激活函数,前馈神经网络,快捷连接等等。
在这里插入图片描述

2 大语言的Transformer模块

2.1 层归一化

层归一化是为了调整神经网络的输出,让其均值为0,方差为1。目的是为了神经网络更加稳定。具体做法是依据以下的数学公式,对emb_dim维度上进行μ=x−μσ\mu=\frac{x-\mu}{\sigma}μ=σxμ,最终能够对该维度嵌入向量进行归一化,最后再加上动态可训练参数缩放和平移。

#%% 层归一化
import torch #导入torch包 类似于一个目录,包含了__init__.py以及其他模块的py文件或者其他子包
import torch.nn as nn # 导入torch包中的nn模块 一个模块就是一个.py文件,一个py文件下有函数以及类
torch.manual_seed(123) #固定随机种子
batch_example = torch.randn(2,5) #随机生成两行五列的张量,然后每行是均值为0,方差为1的正态分布
print("batch_example,随机生成的输入为:",batch_example)
layer = nn.Sequential(nn.Linear(5,6),nn.ReLU()) # 容器类装有神经网络类,并通过序列连接,输入连输出,输出也是一个神经网络模块
out = layer(batch_example)
print("自定义的神经网络结构的输出为:",out)
mean = out.mean(dim=-1,keepdim=True) #按照列的方向进行求均值,同时保持维度不变
var = out.var(dim=-1,keepdim=True) #按照行的方向进行求均值,同时保持维度不变
print("未归一化的输出的均值为:",mean,"未归一化的输出的方差为:",var)
#接下来进行归一化
out_norm = (out- mean)/torch.sqrt(var)
torch.set_printoptions(sci_mode=False)
print("归一化后的均值为:",out_norm.mean(dim=-1,keepdim=True))
print("归一化后的方差为:",out_norm.var(dim=-1,keepdim=True))

在这里插入图片描述
将上述归一化代码进行整合在一个类中:

class LayerNorm(nn.Module):def __init__(self, emb_dim):super().__init__()self.eps = 1e-5self.scale = nn.Parameter(torch.ones(emb_dim))self.shift = nn.Parameter(torch.zeros(emb_dim))def forward(self, x):mean = x.mean(dim=-1, keepdim=True)var = x.var(dim=-1, keepdim=True, unbiased=False)norm_x = (x - mean) / torch.sqrt(var + self.eps)return self.scale * norm_x + self.shift

最后测试用例:

#%% 归一化测试用例
import torch #导入torch包 类似于一个目录,包含了__init__.py以及其他模块的py文件或者其他子包
import torch.nn as nn # 导入torch包中的nn模块 一个模块就是一个.py文件,一个py文件下有函数以及类
torch.manual_seed(123) #固定随机种子
batch_example = torch.randn(2,5) #随机生成两行五列的张量,然后每行是均值为0,方差为1的正态分布
print("batch_example,随机生成的输入为:",batch_example)
class LayerNorm(nn.Module):def __init__(self, emb_dim):super().__init__()self.eps = 1e-5self.scale = nn.Parameter(torch.ones(emb_dim))self.shift = nn.Parameter(torch.zeros(emb_dim))def forward(self, x):mean = x.mean(dim=-1, keepdim=True)var = x.var(dim=-1, keepdim=True, unbiased=False)norm_x = (x - mean) / torch.sqrt(var + self.eps)return self.scale * norm_x + self.shift
ln = LayerNorm(emb_dim=5)
out_ln = ln(batch_example)
mean = out_ln.mean(dim=-1, keepdim=True)
var = out_ln.var(dim=-1, unbiased=False, keepdim=True)print("Mean:\n", mean)
print("Variance:\n", var)

2.2 GELU激活函数

精确的定义GELU(x)=x⋅ϕ(x)GELU(x)=x \cdot \phi{(x)}GELU(x)=xϕ(x),其中ϕ(x)\phi{(x)}ϕ(x)是标准高斯分布的累积分布函数,但是在实际操作中,我们会使用一种计算量较小的近似实现,可通过曲线拟合的方法近似得到,GELU(x)≈0.5⋅x⋅{1+tanh⁡[π2⋅(x+0.044715⋅x3)]}GELU(x) \approx 0.5 \cdot x \cdot \{1+\tanh[\sqrt{\frac{\pi}{2}} \cdot (x+0.044715 \cdot x^{3})]\}GELU(x)0.5x{1+tanh[2π(x+0.044715x3)]}

#%% GELU激活函数的前馈神经网络
#GELU激活类
import torch
import torch.nn as nn
import matplotlib.pyplot as plt
class GELU(nn.Module):def __init__(self):# 参数初始化super().__init__()def forward(self,x): #输入与输出return 0.5*x*(1+torch.tanh((torch.sqrt(torch.tensor(2/torch.pi)))*(x+0.044715 * torch.power(x,3))))
# GELU激活类与ReLU激活类的对比
gelu,relu = GELU(),nn.ReLU() #神经网络初始化
x = torch.linspace(-3,3,100)#生成-3到3之间的100个数
y_gelu = GELU(x)#前向传播
y_relu= nn.ReLU(x)#前向传播
plt.figure(figsize=(8,3))
for i,(label,y) in enumerate(zip(["ReLU","GELU"],[y_relu,y_gelu]),1):plt.subplot(1,2,i)plt.plot(x,y)plt.title(f"{label} activation function")plt.xlabel("x")plt.ylabel("{label}(x)")plt.grid(True)
plt.tight_layout()
plt.show()

在这里插入图片描述
RELU激活函数存在两个问题,第一个问题是当x=0的梯度不存在,第二个问题,输入小于零的输出部分直接被置为0,没有后续神经元的运算。从GELU激活函数与ReLU激活函数对比图可以看出,GELU在小于零部分梯度存在,同时在输入小于0的部分,输出接近于0,并没有置零,还能参与后续的运算。

2.3 前馈神经网络

前馈神经网络先放大输入的节点数,经过GELU激活函数,然后再缩小节点数到与原来的输入的节点数相同,通过这样一个过程,相当于去粗取精。
在这里插入图片描述

#%% 前馈神经网络
import torch
import torch.nn as nn
class FeedForward(nn.Module):#通过大模型进行层数的放大,然后再将层数缩小def __init__(self,cfg):#参数初始化,以及神经网络结构的定义super().__init__()self.layers = nn.Sequential(nn.Linear(cfg['emb_dim'],4*cfg['emb_dim']),nn.GELU(),nn.Linear(4*cfg['emb_dim'],cfg['emb_dim']))#用容器来装载神经网络结构def forward(self,x):#定义输入与输出的关系return self.layers(x)

2.4 快捷连接

残差连接实际上就是建立一个输入直接连接到输出,这样的话,下一层输入就变成了上一层的输出和上一层的输入的叠加。建立残差连接能够缓解梯度消失问题。
在这里插入图片描述

#%% 残差连接 shortcut
import torch
import torch.nn as nn
class ShortCutNn(nn.Module):def __init__(self,layer_sizes,use_shortcut):#参数初始化以及网络结构的定义super().__init__()self.use_shortcut = use_shortcutself.layers = nn.ModuleList([nn.Sequential(nn.Linear(layer_sizes[0],layer_sizes[1]),nn.GELU())#定义网络列表,nn.Sequential(nn.Linear(layer_sizes[1],layer_sizes[2]),nn.GELU()),nn.Sequential(nn.Linear(layer_sizes[2],layer_sizes[3]),nn.GELU()),nn.Sequential(nn.Linear(layer_sizes[3],layer_sizes[4]),nn.GELU()),nn.Sequential(nn.Linear(layer_sizes[4],layer_sizes[5]),nn.GELU())])def forward(self,x):for layer in self.layers:layer_out = layer(x)if self.use_shortcut and x.shape == layer_out.shape:x = x + layer_outelse:x = layer_outreturn x

3 附录

3.1 anaconda+python环境搭建

接下来进行代码准备,首先下载所有的requirements.txt中的所有依赖库,本次实验是在conda+pycharm环境下,推荐大家在conda+pycharm下进行:
首先创建conda下的环境LLM

conda create --p D:/.conda/envs/LLM 

在这里插入图片描述
然后激活conda下的LLM环境:

conda activate  D:/.conda/envs/LLM 
conda install requirements.txt

在这里插入图片描述

#%% 1 初始化信息查看
from importlib.metadata import version
print("matplotlib version:", version("matplotlib"))
print("torch version:", version("torch"))
print("tiktoken version:", version("tiktoken"))
#%% 2 配置GPT模型参数配置
GPT_CONFIG_124M = {"vocab_size": 50257,    # Vocabulary size 表示会被BPE分词器使用的由50257个单词的词汇表"context_length": 1024, # Context length  能够处理最大词元token的个数"emb_dim": 768,         # Embedding dimension 嵌入向量的纬度"n_heads": 12,          # Number of attention heads 多头的头数"n_layers": 12,         # Number of layers 神经网络的层数"drop_rate": 0.1,       # Dropout rate 丢弃率,为了防止过拟合,会随机丢弃10%的隐藏单元"qkv_bias": False       # Query-Key-Value bias qkv的偏置项开启与否,默认是关闭
}
nn用法
Embedding
Dropout
Sequential
Linear

在这里插入图片描述

http://www.dtcms.com/a/334273.html

相关文章:

  • 黑板架构详解
  • Wi-Fi 7 将如何重塑互联工作场所
  • 链式二叉树的基本操作——遍历
  • 《从入门到高可用:2025最新MySQL 8.0全栈速通指南》
  • docker-compose-mysql-定时备份数据库到其他服务器脚本
  • SpringBoot 集成Ollama 本地大模型
  • mysql的group by函数怎么使用
  • Java内功修炼(1)——时光机中的并发革命:从单任务到Java多线程
  • [Linux] Linux文件系统基本管理
  • 基于STM32的精确按键时长测量系统
  • 一周学会Matplotlib3 Python 数据可视化-绘制自相关图
  • 2020/12 JLPT听力原文 问题二 2番
  • Pycaita二次开发基础代码解析:交互选择、参数化建模与球体创建的工业级实现
  • 415. 字符串相加
  • dify 调用本地的 stable diffusion api生成图片的工作流搭建
  • 分布式存储与存储阵列:从传统到现代的存储革命
  • Windows Manager:全方位优化你的Windows系统
  • PCB高频板与普通电路板的核心差异
  • JavaScript 闭包与递归深度解析:从理论到实战
  • [优选算法专题二滑动窗口——最大连续1的个数 III]
  • 【轨物方案】预防性运维:轨物科技用AI+机器人重塑光伏电站价值链
  • K8S的ingress
  • 石头科技披露半年报:营收79.03亿元,同比大增78.96%
  • vscode中用python调用matlab的函数(环境安装)
  • pdf合并代码
  • Autosar Os新手入门
  • IOMMU多级页表查找的验证
  • 从0到1掌握 Spring Security(第三篇):三种认证方式,按配置一键切换
  • Flink Stream API 源码走读 - print()
  • TDengine IDMP 高级功能(3. 概念解释)