【深度学习】实验 — 动手实现 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.xdnf.cn/news/1720.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

信息抽取与知识图谱技术在医疗领域中的应用

​快瞳AI开放平台支持多种输入格式&#xff0c;如电子病历、临床数据和医学文献等&#xff0c;可以将这些信息快速转换为结构化数据&#xff0c;包括自动360度不同角度的旋转识别、自动校准弯曲透视、光照不均、手写叠加处理等&#xff0c;提升数据的可操作性和可检索性。通过我…

SpringCloudAlibaba实战入门之OpenFeign高级用法(十)

在上一篇中我们简单了解了OpenFeign的简单使用,本篇是承接上一篇的高级使用拓展内容。 一、@FeignClient 标签的常用属性 @FeignClient 注解是 Spring Cloud OpenFeign 中用于声明一个 Feign 客户端的核心注解。它可以用来指定服务的名称、配置类、负载均衡策略等。下面是 @…

DBeaver 数据库安装及破解个人使用 不同版本不同jdk

DBeaver DBeaver 分为 **Lite、Enterprise、Ultimate&#xff08;功能最全&#xff09;、Community&#xff0c;**其中Community免费使用&#xff0c;但是功能不言而喻&#xff0c;具体差异自行去官网对比。 安装 DBeaver 到官网下载即可 https://dbeaver.io/download/ 激活 D…

docker安装中的遇到的问题及解决方案

docker 安装中遇到的问题及解决方案 截至2024/11/1&#xff0c;我在安装docker中遇到的问题将悉数列出&#xff0c;供大家参考。 说明&#xff1a;这些解决方案在我自己的虚拟机中有用&#xff0c;可能大家的虚拟机并不适用&#xff0c;这些解决方案均转载自另外的博客&#x…

Jetson OrinNX平台CSI相机导致cpu load average升高问题调试

1. 前言 硬件: Orin NX JP: 5.1.2, R35.4.1 用v4l2-ctl --stream-mmap -d0 命令去获取相机数据时, 用top查看cpu使用情况, CPU占用率很低,但load average在1左右, 无任何程序运行时,load average 为0 用ps -aux 查看当前进程情况,发现有两个系统进程vi-output, …

AppInventor2能否用网络摄像头画面作为屏幕的背景?

// 视频是否可以作为背景&#xff1f; // 有会员提问&#xff1a;能否用网络摄像头的实时画面作为屏幕的背景&#xff1f;就跟这个一样背景全覆盖&#xff1a; 摄像头画面是一个在线的网站链接视频流。 // 原先思路 // 1、目前原生组件无法直接实现这个功能&#xff0c;屏幕…

【开源免费】基于SpringBoot+Vue.JS网上租赁系统(JAVA毕业设计)

本文项目编号 T 050 &#xff0c;文末自助获取源码 \color{red}{T050&#xff0c;文末自助获取源码} T050&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析5.4 用例设计5.4.1 用…

fmql之Linux以太网

正点原子第57章。 dts fmql-dtsi&#xff1a; 我们用的PHY芯片是RTL8211F&#xff1a; 需要添加PHY信息&#xff1a; fmql-dtsi提供的参考&#xff1a; 根据vivado工程自动生成的&#xff1a; reg <0x1>; 配置 疑问 网口通讯需要网线&#xff0c;但是目前板卡上只有PS…

基于STM32的农业监测与管理系统设计思路介绍(代码示例)

一、项目概述 在全球农业现代化进程中&#xff0c;农业监测与管理系统的研发具有重要意义。本文介绍的基于STM32的农业监测与管理系统&#xff0c;旨在通过智能小车实现对农作物的环境监测、土壤检测等功能。该系统利用手势控制技术&#xff0c;农民可以通过简单的手势指令来操…

【2024-10-31-2024-11-03】LeetCode刷题——python语法基础题

&#x1f4dd;前言说明&#xff1a; ●本专栏主要记录本人的基础算法学习以及LeetCode刷题记录&#xff0c;主要跟随B站作者灵茶山的视频进行学习&#xff0c;专栏中一篇文章为B站对应的一个视频 题目主要为B站视频内涉及的题目以及B站视频中提到的“课后作业”。 ●文章中的理…

2024年【烟花爆竹储存】考试试卷及烟花爆竹储存试题及解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 烟花爆竹储存考试试卷考前必练&#xff01;安全生产模拟考试一点通每个月更新烟花爆竹储存试题及解析题目及答案&#xff01;多做几遍&#xff0c;其实通过烟花爆竹储存作业模拟考试很简单。 1、【单选题】( )负责烟花…

Uniapp的H5以及App不支持后端传FormData类型参数的解决方案

在uniapp中不支持FormData的传参&#xff0c;这就很恶心&#xff1b;如果强行传的话会提示&#xff0c;请求失败的报错信息。 因为后端必须要FormData类型的传参&#xff0c;所以在查阅一系列方案后&#xff0c;有一种解决办法可以完美解决。 代码&#xff1a; init() {const…

JS实现漂亮的登录页面(氛围感页面)

代码&#xff1a; <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>登录</title><style…

(C#面向初学者的 .NET 的生成 AI) 第 2 部分-什么是 AI 和 ML?

从本部分开始Luis Quintanilla介绍AI和机器学习&#xff0c;需要学习的一些东西是什么是AI和ML&#xff1f;作为一名.net开发人员如何学习使用AI和ML。 1、首先什么是AI 和 ML&#xff1f; 你可以把它看作是基本相同事物的不同层次。 在顶层的是AI&#xff08;人工智能&#xf…

Spring Boot技术:校园社团信息管理的革新者

4系统概要设计 4.1概述 本系统采用B/S结构(Browser/Server,浏览器/服务器结构)和基于Web服务两种模式&#xff0c;是一个适用于Internet环境下的模型结构。只要用户能连上Internet,便可以在任何时间、任何地点使用。系统工作原理图如图4-1所示&#xff1a; 图4-1系统工作原理…

探索高效HTTP会话管理:sessionup开源项目推荐

探索高效HTTP会话管理&#xff1a;sessionup开源项目推荐 sessionup Straightforward HTTP session management 项目地址: https://gitcode.com/gh_mirrors/se/sessionup 在现代Web应用开发中&#xff0c;会话管理是确保用户身份验证和数据安全的关键环节。为了帮助开发…

(七)JavaWeb后端开发——Maven

目录 1.Maven概述 2.Maven依赖管理 2.1依赖配置 2.2依赖传递 2.3依赖范围 2.4生命周期 1.Maven概述 maven是一款管理和构建java项目的工具 Maven的作用&#xff1a; 依赖管理&#xff1a;方便快捷的管理项目依赖的资源(jar包)&#xff0c;避免版本冲突问题统一项目结构…

jenkins 构建报错 Cannot run program “sh”

原因 在 windows 操作系统 jenkins 自动化部署的时候, 由于自动化构建的命令是 shell 执行的,而默认windows 从 path 路径拿到的 shell 没有 sh.exe &#xff0c;因此报错。 解决方法 前提是已经安装过 git WINR 输入cmd 打开命令行, 然后输入where git 获取 git 的路径, …

数据结构——二叉树

♥♥♥~~~~~~欢迎光临知星小度博客空间~~~~~~♥♥♥ ♥♥♥零星地变得优秀~也能拼凑出星河~♥♥♥ ♥♥♥我们一起努力成为更好的自己~♥♥♥ ♥♥♥如果这一篇博客对你有帮助~别忘了点赞分享哦~♥♥♥ ♥♥♥如果有什么问题可以评论区留言或者私信我哦~♥♥♥ 这一篇博客我们开…

NVR批量管理软件/平台EasyNVR多个NVR同时管理支持视频投放在电视墙上

在当今智能化、数字化的时代&#xff0c;视频监控已经成为各行各业不可或缺的一部分&#xff0c;无论是公共安全、交通管理、企业监控还是智慧城市建设&#xff0c;都离不开高效、稳定的视频监控系统的支持。而在这些应用场景中&#xff0c;将监控视频实时投放到大屏幕电视墙上…