大模型入门 ch04:实现一个GPT模型

本文是github上的大模型教程LLMs-from-scratch的学习笔记,教程地址:教程链接

LLM大模型主要是参数量大,而不是代码量大。

这是本节的具体内容

  1. 首先实现一个GPT的骨架
  2. 分别实现GPT骨架内的各个部分,包括LayerNorm,GELU,Feed forward network和Shorcut connections
  3. 将四个部分合成Transformer块
  4. 重复多次Transformer块,实现最终的GPT架构

1. GPT骨架

首先确定模型的配置,包括词汇表数量,上下文长度,embeddding维度等等。

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"表示词汇量为50257个单词,由第2章讨论的BPE分词器支持
  • "context_length"表示模型的最大输入标记数,这是由第2章中介绍的位置嵌入启用的
  • "emb_dim"是token输入的嵌入大小,将每个输入token转换为768维向量
  • "n_heads"是第3章实现的多头注意力机制中注意力头的数量
  • "n_layers"是模型中transformer块的数量,我们将在接下来的部分中实现
  • "drop_rate"是第3章中讨论的dropout机制的强度;0.1意味着在训练过程中丢弃10%的隐藏单元以缓解过拟合
  • “qkv_bias”决定多头注意力机制(来自第3章)中的“线性”层在计算查询(Q)、键(K)和值(V)张量时是否应该包含一个偏差向量。

首先我们搭好这个骨架,后续进行补充完善:

import torch
import torch.nn as nnclass 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 TransformerBlockself.trf_blocks = nn.Sequential(*[DummyTransformerBlock(cfg) for _ in range(cfg["n_layers"])])# Use a placeholder for LayerNormself.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.shapetok_embeds = self.tok_emb(in_idx)pos_embeds = self.pos_emb(torch.arange(seq_len, device=in_idx.device))x = tok_embeds + pos_embedsx = self.drop_emb(x)x = self.trf_blocks(x)x = self.final_norm(x)logits = self.out_head(x)return logitsclass DummyTransformerBlock(nn.Module):def __init__(self, cfg):super().__init__()# A simple placeholderdef forward(self, x):# This block does nothing and just returns its input.return xclass 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

2. Layer Normalization

Layer normalization将神经网络的激活值归一化到均值为0,方差为1,使得训练更加稳定和快速。在多头注意力机制的前后,我们都会加入Layernorm层。

归一化可以对不同的维度进行归一化

例如在我们这个例子中,如果对行归一化,那么就是对每一个样本进行归一化,如果是列归一化,就是对每一个特征进行归一化。通过减去平均值再除以均方根,我们可以将输入归一化成均值为0,方差为1。

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
  • 除了通过减去均值并除以方差来执行规范化之外,我们还添加了两个可训练参数,scaleshift参数
  • 初始值scale(乘以1)和shift(加0)没有任何影响;然而,scaleshift是可训练参数,如果确定这样做会提高模型在训练任务上的性能,LLM会在训练过程中自动调整
  • 这允许模型学习最适合其处理数据的适当缩放和平移
  • 在计算方差的平方根之前,我们还添加了一个较小的值(eps);这是为了避免方差为0时除零误差

3. 前馈网络

  • 在本节中,我们实现了一个小的神经网络子模块,该子模块用作LLMs中transformer模块的一部分
  • 在深度学习中,ReLU(整流线性单元)激活函数由于其简单性和在各种神经网络架构中的有效性而被广泛使用
  • 在llm中,除了传统的ReLU之外,还使用了各种其他类型的激活函数;两个值得注意的例子是GELU(高斯误差线性单元)和SwiGLU (Swish-Gated线性单元)。
  • GELU和SwiGLU是更复杂的光滑激活函数,分别包含高斯门控线性单元和sigmoid门控线性单元,为深度学习模型提供了更好的性能,不像ReLU的更简单的分段线性函数层-激活函数 (feed forward network with GELU activations)
  • GELU 可以通过多种方式实现。准确的版本被定义为GELU(x)=x⋅Φ(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):return 0.5 * x * (1 + torch.tanh(torch.sqrt(torch.tensor(2.0 / torch.pi)) * (x + 0.044715 * torch.pow(x, 3))))

在这里插入图片描述
于是我们可以组成一个FeedFroward前馈网络层:

class FeedForward(nn.Module):def __init__(self, cfg):super().__init__()self.layers = nn.Sequential(nn.Linear(cfg["emb_dim"], 4 * cfg["emb_dim"]),GELU(),nn.Linear(4 * cfg["emb_dim"], cfg["emb_dim"]),)def forward(self, x):return self.layers(x)

4. 残差连接

  • 最初,在计算机视觉深度网络(残差网络)中提出了残差连接,以缓解梯度消失问题
  • 连接为渐变在网络中的流动创建了一条更短的路径
  • 这是通过将一个层的输出添加到后面一层的输出来实现的,通常在中间跳过一个或多个层

5. 连接注意力和全连接层,构成Transform block

  • 在本节中,我们现在将前面的概念结合到的transformer块中
  • transformer模块结合了上一章中的因果多头注意力模块和线性层,即我们在上一节中实现的前馈神经网络
  • 此外,transformer block也使用dropout和shortcut连接
from previous_chapters import MultiHeadAttentionclass TransformerBlock(nn.Module):def __init__(self, cfg):super().__init__()self.att = MultiHeadAttention(d_in=cfg["emb_dim"],d_out=cfg["emb_dim"],context_length=cfg["context_length"],num_heads=cfg["n_heads"], dropout=cfg["drop_rate"],qkv_bias=cfg["qkv_bias"])self.ff = FeedForward(cfg)self.norm1 = LayerNorm(cfg["emb_dim"])self.norm2 = LayerNorm(cfg["emb_dim"])self.drop_shortcut = nn.Dropout(cfg["drop_rate"])def forward(self, x):# Shortcut connection for attention blockshortcut = xx = self.norm1(x)x = self.att(x)  # Shape [batch_size, num_tokens, emb_size]x = self.drop_shortcut(x)x = x + shortcut  # Add the original input back# Shortcut connection for feed forward blockshortcut = xx = self.norm2(x)x = self.ff(x)x = self.drop_shortcut(x)x = x + shortcut  # Add the original input backreturn x

6. 编写GPT模型

  • transformer块重复多次;在最小的124M GPT-2模型中,我们重复12次。

我们让cfg["n_layers"] = 12

class GPTModel(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"])self.trf_blocks = nn.Sequential(*[TransformerBlock(cfg) for _ in range(cfg["n_layers"])])self.final_norm = LayerNorm(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.shapetok_embeds = self.tok_emb(in_idx)pos_embeds = self.pos_emb(torch.arange(seq_len, device=in_idx.device))x = tok_embeds + pos_embeds  # Shape [batch_size, num_tokens, emb_size]x = self.drop_emb(x)x = self.trf_blocks(x)x = self.final_norm(x)logits = self.out_head(x)return logits

7. 生成文本

GPT模型一次只生成一个token

  • 下面的generate_text_simple函数实现了贪婪解码,这是一种简单快速的生成文本的方法
  • 在贪婪解码中,在每一步,模型选择具有最高概率的单词(或标记)作为它的下一个输出(最高的logit对应最高的概率,因此我们在技术上甚至不需要显式地计算softmax函数)
  • 在下一章中,我们将实现一个更高级的generate_text函数
  • 下图描述了GPT模型在给定输入上下文的情况下如何生成下一个单词标记
def generate_text_simple(model, idx, max_new_tokens, context_size):# idx is (batch, n_tokens) array of indices in the current contextfor _ in range(max_new_tokens):# Crop current context if it exceeds the supported context size# E.g., if LLM supports only 5 tokens, and the context size is 10# then only the last 5 tokens are used as contextidx_cond = idx[:, -context_size:]# Get the predictionswith torch.no_grad():logits = model(idx_cond)# Focus only on the last time step# (batch, n_tokens, vocab_size) becomes (batch, vocab_size)logits = logits[:, -1, :]  # Apply softmax to get probabilitiesprobas = torch.softmax(logits, dim=-1)  # (batch, vocab_size)# Get the idx of the vocab entry with the highest probability valueidx_next = torch.argmax(probas, dim=-1, keepdim=True)  # (batch, 1)# Append sampled index to the running sequenceidx = torch.cat((idx, idx_next), dim=1)  # (batch, n_tokens+1)return idx

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

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

相关文章

有什么好用的电容笔?2024总结apple pencil平替笔排名TOP五!

在这个信息高度发展的社会,iPad等触控设备日益普及,电容笔的市场需求也不断扩大,因为它们在一定程度上可以替代传统的笔和纸,携带它们就无需携带厚重的书本,这种环保、便捷、方便的特点吸引了越来越多的用户。但电容笔…

动态线程池(五)

动态线程池 Filter过滤器 AlarmBaseFilter NoticeBaseFilter NotifyRedisTateLimiterFilter RedisRateLimiter redis限流器 NotifierHandler DtpNotifier动态线程池通知者 Notifier通知者 关于发送Email消息的额外说明

分布式Id生成策略-美团Leaf

之前在做物流相关的项目时候,需要在分布式系统生成运单的id。 1.需求: 1.全局唯一性:不能出现重复的ID。(基本要求) 2.递增:大多数关系型数据库(如 MySQL)使用 B 树作为索引结构。…

三菱FX3U-4DA(4通道模拟量输出)使用说明

FX3U-4DA连接在FX3G/FX3GC/FX3U/FX3UC可编程控制器上,是将来自可编程控制器的4个通道的数字值转换成模拟量值(电压/电流)并输出的模拟量特殊功能模块。 1、FX3G/FX3GC/FX3U/FX3UC可编程控制器上最多可以连接8台*1(包括其它特殊功能模块的连接台数。) 2、可以对各通道…

Global Attention Decoder for Chinese Spelling Error Correction(ACL2021)

Global Attention Decoder for Chinese Spelling Error Correction(ACL2021) 一.概述 作者认为现有的纠错方法大多是基于局部上下文信息进行纠错,没有考虑句子中错词的影响。将注意力放在错误上下文信息上可能会误导并降低CSC(Chinese Spelling Correction)的整体性…

shopro前端 短信登录只显示模板不能正常切换

删掉 换成下面的代码 // 打开授权弹框 export function showAuthModal(type smsLogin) {const modal $store(modal);setTimeout(() > {modal.$patch((state) > {state.auth type;});}, 100); }

数据集 InterHand2.6M 双手交互 三维手势建模 >> DataBall

数据集 InterHand2.6M 双手交互 三维手势建模 人工智能 深度学习 >> DataBall 数据集 InterHand2.6M,双手/单手交互 ---------------------------------------------------------------------------------------------------------- Train set * Train (H):…

MybatisPlus代码生成器使用

一、前言 Mybatis逆向工程也可以生成代码,但配置太过复杂,不便于后期维护,Mybatis Plus 主动集成了代码的自动生成,用起来也很方便,两种代码自动生成我都用过,没有好坏之分,如果非要我推荐哪一…

跨游戏引擎的H5渲染解决方案(腾讯)

本文是腾讯的一篇H5 跨引擎解决方案的精炼。 介绍 本文通过实现基于精简版的HTML5(HyperText Mark Language 5)来屏蔽不同引擎,平台底层的差异。 好处: 采用H5的开发方式,可以将开发和运营分离,运营部门自…

一个安卓鸿蒙化工具

DevEco插件,为已有安卓项目鸿蒙化加速。 目前支持: 1、安卓Vector Assets转svg; 2、json转ets model; 3、kotlin model转ets model; 下载地址:andtoharplugin1.1.0 安装: deveco插件安装选硬…

傻白甜萌妹爆改成长型女主!男频番的花瓶也有高光?

“师父,师妹不是任何人的依附,也不是小琼峰的一个摆件。” 能说出这句话的男主,堪称人间清醒。 男频作品的女性塑造向来是备受瞩目的话题。“镶边”、“挂件”、“花瓶”…总有这样的标签一个个打在“她们”身上,看似暗讽&#…

seL4 Untyped(二)

链接: Untyped Untyped 这篇主要是针对seL4物理内存管理的介绍。 物理内存 在seL4系统中,除了内核占用的一小部分静态内存之外,其他的所有的物理内存都是用户一级管理的。seL4在启动时创建的对象能力,以及seL4管理的其余物理资源&#xf…

tensorflow底层架构

tensorflow底层架构 架构图 Training libraries 和 Inference libs(训练库和推理库) Training libraries:用于模型的训练过程,包括定义模型、计算梯度、更新模型权重等。这些库提供了在训练过程中所需的所有功能。Inference lib…

推荐几本值得阅读的书籍!

大家好,这里是大话硬件。 初次关注我公众号的朋友第一反应基本都是认为内容太专业! 其实不然,大话硬件公众号除了有硬件设计方面的内容,还包含书籍推荐,个人反思总结模块等内容。 今天这篇文章继上篇荐书《相见恨晚的…

学习IEC 62055付费系统标准

1.IEC 62055 国际标准 IEC 62055 是目前关于付费系统的唯一国际标准,涵盖了付费系统、CIS 用户信息系统、售电系统、传输介质、数据传输标准、预付费电能表以及接口标准等内容。 IEC 62055-21 标准化架构IEC 62055-31 1 级和 2 级有功预付费电能表IEC 62055-41 STS…

如何快速恢复误删除的文件?教你一招,不花一分钱,三步就可以搞定!

电脑文件越存越多,我们都会不定时的进行清理,但有时候,我们难免会误删除一些重要文件。当遇到类似情况的时候,不要着急,很多时候,删除的文件是有办法恢复的。 市面上有很多文件恢复软件,就可以帮…

常用工具推荐!分享7款AI论文修改软件工具网站

在当今学术研究和写作领域,AI论文修改软件工具已经成为了不可或缺的助手。这些工具不仅能够帮助研究人员提高写作效率,还能确保论文的质量和原创性。以下是七款值得推荐的AI论文修改软件工具网站,其中特别推荐千笔-AIPassPaper。 1. 千笔-AI…

YOLOv8改进 | 特征融合篇,YOLOv8添加iAFF(多尺度通道注意力模块),并与C2f结构融合,提升小目标检测能力

摘要 特征融合,即来自不同层或分支的特征的组合,是现代网络架构中无处不在的一部分。虽然它通常通过简单的操作(如求和或拼接)来实现,但这种方式可能并不是最佳选择。在这项工作中,提出了一种统一且通用的方案,即注意力特征融合(Attentional Feature Fusion),适用于…

心理辅导系统:Spring Boot技术驱动

3 系统分析 3.1可行性分析 在进行可行性分析时,我们通常根据软件工程里方法,通过四个方面来进行分析,分别是技术、经济、操作和法律可行性。因此,在基于对目标系统的基本调查和研究后,对提出的基本方案进行可行性分析。…

攻防世界---->Windows_Reverse1(补)

做题笔记。 做题回顾。 假设,我们不知道地址随机怎么办?不能动调,只能静态分析。 下载 查壳 upx脱壳。 32ida打开。 动调报错。 重新打开,静态分析。 跟进关键函数。 不明白可以反汇编和汇编一起看。 溯源。 *decode 取值等于 by…