【深度学习】实验 — 动手实现 GPT【三】:LLM架构、LayerNorm、GELU激活函数

【深度学习】实验 — 动手实现 GPT【三】:LLM架构、LayerNorm、GELU激活函数

  • 模型定义
    • 编码一个大型语言模型(LLM)架构
  • 使用层归一化对激活值进行归一化
    • LayerNorm代码实现
    • scale和shift
  • 实现带有 GELU 激活的前馈网络
    • 测试

模型定义

编码一个大型语言模型(LLM)架构

  • 像 GPT 和 Llama 这样的模型是基于原始 Transformer 架构的解码器部分,按顺序生成词。
  • 因此,这些 LLM 通常被称为“类似解码器”的 LLM。
  • 与传统的深度学习模型相比,LLM 更大,主要原因在于其庞大的参数数量,而非代码量。
  • 我们会看到,在 LLM 架构中许多元素是重复的。

请添加图片描述

  • 我们考虑的嵌入和模型大小类似于小型 GPT-2 模型。

  • 我们将具体实现最小的 GPT-2 模型(1.24 亿参数)的架构,参考 Radford 等人发表的 Language Models are Unsupervised Multitask Learners(注意,最初报告中列出该模型参数量为 1.17 亿,但模型权重库后来更正为 1.24 亿)。

  • 后续部分将展示如何将预训练权重加载到我们的实现中,以支持 3.45 亿、7.62 亿和 15.42 亿参数的模型大小。

  • 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" 表示词汇表大小为 50,257,由 BPE 分词器支持。
  • "context_length" 表示模型的最大输入词元数量,由位置嵌入实现。
  • "emb_dim" 是输入词元的嵌入维度,将每个输入词元转换为 768 维向量。
  • "n_heads" 是多头注意力机制中的注意力头数。
  • "n_layers" 是模型中的 Transformer 块数量。
  • "drop_rate" 是 dropout 机制的强度,在第 3 章中讨论过;0.1 表示在训练过程中丢弃 10% 的隐藏单元,以减轻过拟合。
  • "qkv_bias" 决定多头注意力机制中的 Linear 层在计算查询(Q)、键(K)和值(V)张量时是否包含偏置向量;我们将禁用此选项,这是现代 LLM 的标准做法。

使用层归一化对激活值进行归一化

  • 层归一化(LayerNorm),也称为层归一化,Ba 等人,2016 提出,旨在将神经网络层的激活值中心化为 0 均值,并将其方差归一化为 1。
  • 这有助于稳定训练过程,并加快有效权重的收敛速度。
  • 层归一化在 Transformer 块内的多头注意力模块之前和之后应用,稍后我们会实现;此外,它也应用在最终输出层之前。
    请添加图片描述
  • 让我们通过一个简单的神经网络层传递一个小的输入样本,来看看层归一化的工作原理:
# create 2 training examples with 5 dimensions (features) each
batch_example = torch.randn(2, 5)layer = nn.Sequential(nn.Linear(5, 6), nn.ReLU())
out = layer(batch_example)
print(out)

输出

tensor([[0.0000, 0.0000, 0.1504, 0.2049, 0.0694, 0.0000],[0.0000, 0.0000, 0.1146, 0.3098, 0.0939, 0.5742]],grad_fn=<ReluBackward0>)
  • 让我们计算上面2个输入中每一个的均值和方差:
mean = out.mean(dim=-1, keepdim=True)
var = out.var(dim=-1, keepdim=True)print("Mean:\n", mean)
print("Variance:\n", var)
Mean:tensor([[0.3448],[0.2182]], grad_fn=<MeanBackward1>)
Variance:tensor([[0.0791],[0.2072]], grad_fn=<VarBackward0>)
  • 归一化独立应用于每个输入(行);使用 dim=-1 会在最后一个维度(此处为特征维度)上执行计算,而不是在行维度上执行。

请添加图片描述

  • 减去均值并除以方差(标准差)的平方根,使输入在列(特征)维度上具有 0 的均值和 1 的方差:
out_norm = (out - mean) / torch.sqrt(var)
print("Normalized layer outputs:\n", out_norm)mean = out_norm.mean(dim=-1, keepdim=True)
var = out_norm.var(dim=-1, keepdim=True)
print("Mean:\n", mean)
print("Variance:\n", var)

输出

Normalized layer outputs:tensor([[ 1.9920, -0.1307, -0.3069, -0.7573, -0.2769, -0.5201],[-0.4793, -0.4793, -0.4793, -0.1003,  2.0176, -0.4793]],grad_fn=<DivBackward0>)
Mean:tensor([[-9.9341e-09],[ 4.5945e-08]], grad_fn=<MeanBackward1>)
Variance:tensor([[1.0000],[1.0000]], grad_fn=<VarBackward0>)
  • 每个输入都以 0 为中心,方差为 1;为了提高可读性,我们可以禁用 PyTorch 的科学计数法:
torch.set_printoptions(sci_mode=False)
print("Mean:\n", mean)
print("Variance:\n", var)

输出

Mean:tensor([[    -0.0000],[     0.0000]], grad_fn=<MeanBackward1>)
Variance:tensor([[1.0000],[1.0000]], grad_fn=<VarBackward0>)
  • 上面我们对每个输入的特征进行了归一化。
  • 现在,基于相同的思想,我们可以实现一个 LayerNorm 类:

LayerNorm代码实现

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):"""args:x: torch.TensorThe input tensorreturns:norm_x: torch.TensorThe normalized tensorStep:1. Compute the mean and variance separately2. Normalize the tensor3. Scale and shift the tensor4. Return the normalized tensor"""# complete this section (3/10)# 1. 计算每个特征的均值和方差mean = x.mean(dim=-1,keepdim=True)variance = x.var(dim=-1,keepdim=True,unbiased=False)# 2. 对张量进行归一化处理x_normalized = (x - mean) / torch.sqrt(variance + self.eps)# 3. 缩放并平移张量norm_x = self.scale * x_normalized + self.shift# 4. 返回归一化后的张量return norm_x

scale和shift

  • 注意,除了通过减去均值并除以方差来执行归一化外,我们还添加了两个可训练的参数:scaleshift
  • 初始的 scale(乘以 1)和 shift(加 0)值不会产生任何效果;但是,scaleshift 是可训练的参数,LLM 会在训练期间自动调整它们,以提高模型在训练任务中的表现。
  • 这使得模型可以学习适合其处理数据的适当缩放和偏移。
  • 另外,在计算方差的平方根之前我们添加了一个较小的值(eps),以避免方差为 0 时的除零错误。

有偏方差

  • 在上述方差计算中,设置 unbiased=False 意味着使用公式 ∑ i ( x i − x ˉ ) 2 n \cfrac{\sum_i (x_i - \bar{x})^2}{n} ni(xixˉ)2 计算方差,其中 n 为样本大小(在这里为特征或列数);此公式不包含贝塞尔校正(其分母为 n-1),因此提供了方差的有偏估计。

  • 对于嵌入维度 n 很大的 LLM,使用 n 和 n-1 之间的差异可以忽略不计。

  • 然而,GPT-2 的归一化层是在有偏方差下训练的,因此为了与我们将在后续章节加载的预训练权重兼容,我们也采用了这种设置。

  • 现在让我们实际尝试 LayerNorm

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)

输出

Mean:tensor([[    -0.0000],[    -0.0000]], grad_fn=<MeanBackward1>)
Variance:tensor([[0.9999],[1.0000]], grad_fn=<VarBackward0>)

实现带有 GELU 激活的前馈网络

  • GELU(Hendrycks 和 Gimpel, 2016)可以通过多种方式实现;其精确版本定义为 GELU ( x ) = x ⋅ Φ ( x ) \text{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 ⋅ x 3 ) ] ) \text{GELU}(x) \approx 0.5 \cdot x \cdot \left(1 + \tanh\left[\sqrt{\frac{2}{\pi}} \cdot \left(x + 0.044715 \cdot x^3\right)\right]\right) GELU(x)0.5x(1+tanh[π2 (x+0.044715x3)])(原始的 GPT-2 模型也是在这种近似下训练的)。
class GELU(nn.Module):def __init__(self):super().__init__()def forward(self, x):"""args:x: torch.TensorThe input tensorreturns:torch.TensorThe output tensor"""# Complete this section (4/10)# Approximate GELU using the tanh-based formulareturn 0.5 * x * (1 + torch.tanh((torch.sqrt(torch.tensor(2 / 3.1415)) * (x + 0.044715 * torch.pow(x, 3)))))
import matplotlib.pyplot as pltgelu, relu = GELU(), nn.ReLU()# Some sample data
x = torch.linspace(-3, 3, 100)
y_gelu, y_relu = gelu(x), relu(x)plt.figure(figsize=(8, 3))
for i, (y, label) in enumerate(zip([y_gelu, y_relu], ["GELU", "ReLU"]), 1):plt.subplot(1, 2, i)plt.plot(x, y)plt.title(f"{label} activation function")plt.xlabel("x")plt.ylabel(f"{label}(x)")plt.grid(True)plt.tight_layout()
plt.show()

输出请添加图片描述

  • 接下来,让我们实现一个小型神经网络模块 FeedForward,稍后将在 LLM 的 Transformer 块中使用:
class FeedForward(nn.Module):def __init__(self, cfg):super().__init__()"""implement self.layers as a Sequential model with:1. Linear layer with input dimension cfg["emb_dim"] and output dimension 4*cfg["emb_dim"]2. GELU activation function3. Linear layer with input dimension 4*cfg["emb_dim"] and output dimension cfg["emb_dim"]"""# complete this section (5/10)self.layers = nn.Sequential(nn.Linear(cfg["emb_dim"], 4 * cfg["emb_dim"]),  # 1. 线性层,输入维度 cfg["emb_dim"],输出 4*cfg["emb_dim"]GELU(),                                          # 2. 使用 GELU 激活函数nn.Linear(4 * cfg["emb_dim"], cfg["emb_dim"])    # 3. 线性层,输入维度 4*cfg["emb_dim"],输出 cfg["emb_dim"])def forward(self, x):return self.layers(x)
print(GPT_CONFIG_124M["emb_dim"])

输出

768

请添加图片描述

测试

ffn = FeedForward(GPT_CONFIG_124M)# input shape: [batch_size, num_token, emb_size]
x = torch.rand(2, 3, 768)
out = ffn(x)
print(out.shape)

输出

torch.Size([2, 3, 768])

请添加图片描述

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

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

相关文章

基于vue框架的的考研网上辅导系统ao9z7(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;学生,公告信息,课程分类,考研资料,考研视频,课程信息,院校建议,教师 开题报告内容 基于Vue框架的考研网上辅导系统开题报告 一、研究背景与意义 随着高等教育的普及和就业竞争的加剧&#xff0c;考研已成为众多大学生提升学历、增强就…

GPU 学习笔记二:GPU单机多卡组网和拓扑结构分析(基于A100的单机多卡拓扑结构分析)

文章目录 一、物理拓扑结构A100讲解1.1 单机多卡拓扑结构 二、术语和基础技术介绍2.1 带宽单位2.2 PCIe及PCIe Switch2.3 NVLink2.4 网卡2.5 带宽瓶颈分析2.6 HBM2.7 CPU/GPU 三、其他典型物理拓扑3.1 H100/H800拓扑分析 防止遗忘和后续翻找的麻烦&#xff0c;记录下平时学到和…

Webserver(2.6)有名管道

目录 有名管道有名管道使用有名管道的注意事项读写特性有名管道实现简单版聊天功能拓展&#xff1a;如何解决聊天过程的阻塞 有名管道 可以用在没有关系的进程之间&#xff0c;进行通信 有名管道使用 通过命令创建有名管道 mkfifo 名字 通过函数创建有名管道 int mkfifo …

超分子水凝胶与细胞的互动:现状、难题与未来蓝图

大家好&#xff01;今天来了解超分子水凝胶文章——《Using Chemistry To Recreate the Complexity of the Extracellular Matrix: Guidelines for Supramolecular Hydrogel–Cell Interactions》发表于《Journal of the American Chemical Society》。在再生医学的舞台上&…

逗号运算符应用举例

在main.cpp里输入程序如下&#xff1a; #include <iostream> //使能cin(),cout(); #include <iomanip> //使能setbase(),setfill(),setw(),setprecision(),setiosflags()和resetiosflags(); //setbase( char x )是设置输出数字的基数,如输出进制数则用set…

分类算法——决策树 详解

决策树的底层原理 决策树是一种常用的分类和回归算法&#xff0c;其基本原理是通过一系列的简单决策&#xff0c;将数据集划分为多个子集&#xff0c;从而实现分类。决策树的核心思想是通过树形结构表示决策过程&#xff0c;节点代表特征&#xff0c;边代表决策&#xff0c;叶子…

openGauss开源数据库实战十二

文章目录 任务十二 openGauss逻辑结构:表管理任务目标实施步骤一、准备工作二、创建表1.新建表默认保存在public模式中2.在一个数据库的不同模式下创建表3.创建表的时候定义约束4.创建表时使用自增数据类型5.使用现有的表创建新表 三、查看表的信息1.在gsql中查看表的定义2.查看…

一文详解精细化工行业持续增长的策略与路径解析

随着全球经济的快速发展和科技的不断进步&#xff0c;精细化工行业正面临着前所未有的挑战和机遇。在这个过程中&#xff0c;数字化转型已成为推动行业持续增长的关键因素。精细化工行业&#xff0c;作为化学工业的一个重要分支&#xff0c;其产品广泛应用于医药、农药、涂料、…

医疗器械设备语音ic芯片方案-选型大全

在医疗设备领域&#xff0c;深圳唯创知音提供了多款适用的语音IC产品&#xff0c;以下是其中几款较为常见的推荐&#xff1a; 一、WT588F02X-8S 特点&#xff1a; 1&#xff1a;低成本人机交互语音方案&#xff0c;仅需嵌入在产品中&#xff0c;提升医疗设备智能化水平。 2&…

微服务实战系列之玩转Docker(十七)

导览 前言Q&#xff1a;如何实现etcd数据的可视化管理一、创建etcd集群1. 节点定义2. 集群成员2.1 docker ps2.2 docker exec2.3 etcdctl member list 二、发布数据1. 添加数据2. 数据共享 三、可视化管理1. ETCD Keeper入门1.1 简介1.2 安装1.2.1 定义compose.yml1.2.2 启动ke…

Spring Cloud +UniApp智慧工地源码,智慧工地综合解决方案,建筑工程云平台源码

Spring Cloud UniApp智慧工地源码&#xff0c;智慧工地全套源代码包含&#xff1a;PC端大屏端移动端 智慧工地解决方案以工程建设现场管理需求为主线&#xff0c;以AI、物联网、BIM技术为手段&#xff0c;对施工现场进行立体化、全方位、全时段管理&#xff0c;实现规范施工管…

Python 从入门到实战43(Pandas数据结构)

我们的目标是&#xff1a;通过这一套资料学习下来&#xff0c;可以熟练掌握python基础&#xff0c;然后结合经典实例、实践相结合&#xff0c;使我们完全掌握python&#xff0c;并做到独立完成项目开发的能力。 上篇文章我们学习了NumPy数组操作的相关基础知识。今天学习一下pa…

数字信号处理Python示例(1)使用Python生成正弦信号

文章目录 前言一、连续时间周期信号二、正弦波三、使用Python生成正弦信号的步骤内置库说明 四、完整的python代码与运行结果1.完整的python代码2、运行结果 五、总结 前言 介绍如何使用python生成正弦信号&#xff0c;给出详细步骤和完整的python代码和运行结果。 一、连续时…

树叶分类竞赛(Baseline)以及kaggle的GPU使用

树叶分类竞赛(Baseline)-kaggle的GPU使用 文章目录 树叶分类竞赛(Baseline)-kaggle的GPU使用竞赛的步骤代码实现创建自定义dataset定义data_loader模型定义超参数训练模型预测和保存结果 kaggle使用 竞赛的步骤 本文来自于Neko Kiku提供的Baseline&#xff0c;感谢大佬提供代码…

四足机器人实战篇之二十二:四足机器人支撑腿反作用力规划之反馈控制及线性约束条件优化方法

系列文章目录 提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 TODO:写完再整理 文章目录 系列文章目录前言一、先使用反馈+前馈的控制方式,根据躯干期望的位置速度,计算出当前身体姿态的虚拟反作用力(实现躯体平衡控制器)二、再建立线性约束的凸优化问…

企业物流管理数据仓库建设的全面指南

文章目录 一、物流管理目标二、总体要求三、数据分层和数据构成&#xff08;1&#xff09;数据分层&#xff08;2&#xff09;数据构成 四、数据存储五、数据建模和数据模型&#xff08;1&#xff09;数据建模&#xff08;2&#xff09;数据模型 六、总结 在企业物流管理中&…

设计模式基础概念(行为模式):责任链模式(Chain Of Responsibility)

概述 责任链模式是一种行为设计模式&#xff0c; 允许你将请求沿着处理者链进行发送。 收到请求后&#xff0c; 每个处理者均可对请求进行处理&#xff0c; 或将其传递给链上的下个处理者。 该模式建议你将这些处理者连成一条链。 链上的每个处理者都有一个成员变量来保存对于…

centos7 安装python3.9.4,解决import ssl异常

本篇文章介绍如何在centos7中安装python3.9.4(下文简称python3)&#xff0c;解决python3安装后import ssl模块失败问题&#xff0c;为什么我要在centos7中安装python呢&#xff0c;因为我需要在服务器中跑python数据处理脚本。 安装python3同时解决import ssl模块失败问题总共包…

【分布式技术】分布式序列算法Snowflake深入解读

文章目录 概述Snowflake算法的构成&#xff1a;Snowflake算法的特点&#xff1a;Snowflake算法存在的问题&#xff1a; &#x1f50d; 雪片算法在分布式系统中是如何保证ID的唯一性和有序性的&#xff1f;唯一性&#xff08;Uniqueness&#xff09;有序性&#xff08;Orderline…

纯CSS实现UI设计中常见的丝带效果(5)

原文传送门&#xff1a;纯CSS实现UI设计中常见的丝带效果 网页中的丝带效果在设计中扮演着多重角色&#xff0c;其作用可以归纳为以下几个方面&#xff1a; 视觉吸引与装饰 增强视觉吸引力&#xff1a;丝带效果以其独特的形态和色彩&#xff0c;能够迅速吸引用户的注意力&…