大模型基础——从零实现一个Transformer(3)

news2024/11/24 15:00:31

大模型基础——从零实现一个Transformer(1)-CSDN博客


一、前言

之前两篇文章已经讲了Transformer的Embedding,Tokenizer,Attention,Position Encoding,
本文我们继续了解Transformer中剩下的其他组件.

二、归一化

2.1 Layer Normalization

layerNorm是针对序列数据提出的一种归一化方法,主要在layer维度进行归一化,即对整个序列进行归一化。

layerNorm会计算一个layer的所有activation的均值和方差,利用均值和方差进行归一化。

𝜇=∑𝑖=1𝑑𝑥𝑖

𝜎=1𝑑∑𝑖=1𝑑(𝑥𝑖−𝜇)2

归一化后的激活值如下:

𝑦=𝑥−𝜇𝜎+𝜖𝛾+𝛽

其中 𝛾 和 𝛽 是可训练的模型参数。 𝛾 是缩放参数,新分布的方差 𝛾2 ; 𝛽 是平移系数,新分布的均值为 𝛽 。 𝜖 为一个小数,添加到方差上,避免分母为0。

2.2 LayerNormalization 代码实现

import torch
import torch.nn as nn

class LayerNorm(nn.Module):
    def __init__(self,num_features,eps=1e-6):
        super().__init__()
        self.gamma = nn.Parameter(torch.ones(num_features))
        self.beta = nn.Parameter(torch.zeros(num_features))
        self.eps = eps

    def forward(self,x):
        """

            Args:
                x (Tensor): (batch_size, seq_length, d_model)

            Returns:
                Tensor: (batch_size, seq_length, d_model)
        """
        mean = x.mean(dim=-1,keepdim=True)
        std = x.std(dim=-1,keepdim=True,unbiased=False)
        normalized_x = (x - mean) / (std + self.eps)
        return self.gamma * normalized_x + self.beta

if __name__ == '__main__':
    batch_size = 2
    seqlen = 3
    hidden_dim = 4

    # 初始化一个随机tensor
    x = torch.randn(batch_size,seqlen,hidden_dim)
    print(x)

    # 初始化LayerNorm
    layer_norm  = LayerNorm(num_features=hidden_dim)
    output_tensor = layer_norm(x)
    print("output after layer norm:\n,",output_tensor)

    torch_layer_norm = torch.nn.LayerNorm(normalized_shape=hidden_dim)
    torch_output_tensor = torch_layer_norm(x)
    print("output after torch layer norm:\n",torch_output_tensor)

三、残差连接

残差连接(residual connection,skip residual,也称为残差块)其实很简单

x为网络层的输入,该网络层包含非线性激活函数,记为F(x),用公式描述的话就是:

代码简单实现

x = x + layer(x)

四、前馈神经网络

4.1 Position-wise Feed Forward

Position-wise Feed Forward(FFN),逐位置的前馈网络,其实就是一个全连接前馈网络。目的是为了增加非线性,增强模型的表示能力。

它一个简单的两层全连接神经网络,不是将整个嵌入序列处理成单个向量,而是独立地处理每个位置的嵌入。所以称为position-wise前馈网络层。也可以看为核大小为1的一维卷积。

目的是把输入投影到特定的空间,再投影回输入维度。

FFN具体的公式如下:

𝐹𝐹𝑁(𝑥)=𝑓(𝑥𝑊1+𝑏1)𝑊2+𝑏2

上述公式对应FFN中的向量变换操作,其中f为非线性激活函数。

4.2 FFN代码实现

from torch import nn,Tensor
from torch.nn import functional as F

class PositonWiseFeedForward(nn.Module):
    def __init__(self,d_model:int ,d_ff: int ,dropout: float=0.1) -> None:
        '''

        :param d_model:  dimension of embeddings
        :param d_ff: dimension of feed-forward network
        :param dropout: dropout ratio
        '''
        super().__init__()
        self.ff1 = nn.Linear(d_model,d_ff)
        self.ff2 = nn.Linear(d_ff,d_model)
        self.dropout = nn.Dropout(dropout)

    def forward(self,x: Tensor) -> Tensor:
        '''

        :param x:  (batch_size, seq_length, d_model) output from attention
        :return: (batch_size, seq_length, d_model)
        '''
        return self.ff2(self.dropout(F.relu(self.ff1(x))))

五、Transformer Encoder Block

如图所示,编码器(Encoder)由N个编码器块(Encoder Block)堆叠而成,我们依次实现。

from torch import nn,Tensor
## 之前实现的函数引入
from llm_base.attention.MultiHeadAttention1 import MultiHeadAttention
from llm_base.layer_norm.normal_layernorm import LayerNorm
from llm_base.ffn.PositionWiseFeedForward import PositonWiseFeedForward

from typing import *


class EncoderBlock(nn.Module):
    def __init__(self,
                 d_model: int,
                 n_heads: int,
                 d_ff: int,
                 dropout: float,
                 norm_first: bool = False):
        '''

        :param d_model: dimension of embeddings
        :param n_heads: number of heads
        :param d_ff: dimension of inner feed-forward network
        :param dropout:dropout ratio
        :param norm_first : if True, layer norm is done prior to attention and feedforward operations(Pre-Norm).
                Otherwise it's done after(Post-Norm). Default to False.
        '''
        super().__init__()
        self.norm_first = norm_first

        self.attention = MultiHeadAttention(d_model,n_heads,dropout)
        self.norm1 = LayerNorm(d_model)

        self.ff = PositonWiseFeedForward(d_model,d_ff,dropout)
        self.norm2 = LayerNorm(d_model)

        self.dropout1 = nn.Dropout(dropout)
        self.dropout2 = nn.Dropout(dropout)

    # self attention sub layer
    def _self_attention_sub_layer(self,x: Tensor, attn_mask: Tensor, keep_attentions: bool) -> Tensor:
        x = self.attention(x,x,x,attn_mask,keep_attentions)
        return self.dropout1(x)

    # ffn sub layer
    def _ffn_sub_layer(self,x: Tensor) -> Tensor:
        x = self.ff(x)
        return self.dropout2(x)

    def forward(self,src: Tensor,src_mask: Tensor == None,keep_attentions: bool= False) -> Tuple[Tensor,Tensor]:
        '''

        :param src: (batch_size, seq_length, d_model)
        :param src_mask: (batch_size,  1, seq_length)
        :param keep_attentions:whether keep attention weigths or not. Defaults to False.
        :return:(batch_size, seq_length, d_model) output of encoder block
        '''
        # pass througth multi-head attention
        # src (batch_size, seq_length, d_model)
        # attn_score (batch_size, n_heads, seq_length, k_length)
        x = src
        
        # post LN or pre LN
        if self.norm_first:
            # pre LN
            x = x + self._self_attention_sub_layer(self.norm1(x),src_mask,keep_attentions)
            x = x + self._ffn_sub_layer(self.norm2(x))
        
        else:
            x = self.norm1(x + self._self_attention_sub_layer(x,src_mask,keep_attentions))
            x = self.norm2(x + self._ffn_sub_layer(x))
        
        return x


5.1 Post Norm Vs Pre Norm

公式区别

Pre Norm 和 Post Norm 的式子分别如下:

在大模型的区别

Post-LN :是在 Transformer 的原始版本中使用的归一化方案。在此方案中,每个子层(例如,自注意力机制或前馈网络)的输出先通过子层自身的操作,然后再通过层归一化(Layer Normalization)

Pre-LN:是先对输入进行层归一化,然后再传递到子层操作中。这样的顺序对于训练更深的网络可能更稳定,因为归一化的输入可以帮助缓解训练过程中的梯度消失和梯度爆炸问题。

5.2为什么Pre效果弱于Post

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

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

相关文章

基于STM32移植U8g2图形库——OLED显示(HAL库)

文章目录 一、U8g2简介1、特点2、U8g2的使用步骤 二、I2C相关介绍1、I2C的基本原理2、I2C的时序协议 三、OLED屏的工作原理四、汉字点阵显示原理五、建立STM32CubeMX工程六、U8g2移植1、U8g2源码2、移植过程 七、代码编写1、参考博主实现的U82G的demo例程(1&#xf…

VMware Workerstation开启虚拟机后,产生乱码名称日志文件

问题情况 如下图所示,我的虚拟机版本是16.1.2版本,每次在启动虚拟机之后,D盘目录下都会产生一个如图下所示的乱码名称文件。同时,虚拟机文件目录也是杂乱不堪,没有按照一台虚拟机对应一个文件夹的形式存在。 问题处理…

笔记 | 软件工程06-1:软件设计-软件设计基础

1 软件设计概述 1.1 为什么要软件设计 1.2 何为软件设计 何为软件系统的解决方案? 软件设计关注与软件需求的实现问题软件设计是需求分析和软件实现间的桥梁 1.3 软件设计的质量要求 1.4 软件设计的过程 1.4.1 软件体系结构设计 1.4.2 用户界面设计 1.4.3 软件详细…

最短路径Dijkstra算法详解

目录 最短距离问题 最短路径问题 进阶--标尺增多 升级方法 例题应用 最短距离问题 Dijkstra算法的策略: 设置集合S存放已被访问的顶点,然后执行n次下面的两个步骤(n为顶点个数): (1)每次…

go-zero整合Excelize并实现Excel导入导出

go-zero整合Excelize并实现Excel导入导出 本教程基于go-zero微服务入门教程,项目工程结构同上一个教程。 本教程主要实现go-zero框架整合Excelize,并暴露接口实现Excel模板下载、Excel导入、Excel导出。 go-zero微服务入门教程:https://blo…

科技云报道:“元年”之后,生成式AI将走向何方?

科技云报道原创。 近两年,以大模型为代表的生成式AI技术,成为引爆数字原生最重要的技术奇点,人们见证了各类文生应用的进展速度。Gartner预测,到2026年,超过80%的企业将使用生成式AI的API或模型,或在生产环…

分布式光纤测温DTS与红外热成像系统的主要区别是什么?

分布式光纤测温DTS和红外热成像系统在应用领域和工作原理上存在显著的区别,两者具有明显的差异性。红外热成像系统适用于表现扩散式发热、面式场景以及环境条件较好的情况下。它主要用于检测物体表面的温度,并且受到镜头遮挡或灰尘等因素的影响会导致失效…

论文中表格跨页了做续表的正确方法

在上方加表格 粘贴即可 文章来源于论文中表格跨页了做续表的正确方法!论文人快来学习_哔哩哔哩_bilibili 小姐姐用WPS弄的,微软的不理想,我试了试,觉得在上面增加格子再粘贴表头,效果还行

Python | Leetcode Python题解之第145题二叉树的后序遍历

题目&#xff1a; 题解&#xff1a; class Solution:def postorderTraversal(self, root: TreeNode) -> List[int]:def addPath(node: TreeNode):count 0while node:count 1res.append(node.val)node node.righti, j len(res) - count, len(res) - 1while i < j:res…

使用fprintf函数实现写日志文件的功能(附源码)

输出打印日志是排查软件异常问题一个非常重要的手段,无论是业务上的异常,还是软件异常崩溃。一个成熟的软件产品,必然有一个功能完备的日志记录与打印系统。本文就来介绍一种简单易用的写日志文件的方法,给大家提供一个参考。 1、实现思路 主要使用C库中的fopen、fprintf和…

问题:设开环系统的频率特性为则其相频特性穿越-180°线时对应的频率为()。 #学习方法#微信

问题&#xff1a;设开环系统的频率特性为则其相频特性穿越-180线时对应的频率为&#xff08;&#xff09;。 ? A、10rad1s B、3rad/s C、lradIs D、√3rad/s 参考答案如图所示

AIGC简介

目录 1.概述 2.诞生背景 3.作用 4.优缺点 4.1.优点 4.2.缺点 5.应用场景 5.1.十个应用场景 5.2.社交媒体内容 6.如何使用 7.未来展望 8.总结 1.概述 AIGC 是“人工智能生成内容”&#xff08;Artificial Intelligence Generated Content&#xff09;的缩写&#x…

uniapp自定义tabbar——中间特殊按钮放大

在APP.vue里面 .uni-tabbar__item:nth-child(4) .uni-tabbar__icon {width: 50px !important;height: 50px !important;position: relative;bottom: 30rpx;}.uni-tabbar__item:nth-child(4) .uni-tabbar__label {position: relative;bottom: 25rpx;}

Stability AI发布AI音频模型Stable Audio Open,文本生成47秒高清音效

前言 Stability AI这家以开源图像生成模型 Stable Diffusion 而闻名的公司&#xff0c;在 6 月 6 日宣布开源其最新的 AI 音频模型 Stable Audio Open。这一新模型可以根据简单的文本提示生成最多 47 秒的高质量音频数据&#xff0c;为音乐制作和声音设计领域带来了新的可能性…

背景渐变动画登录页

b站视频演示效果: 效果图: 完整代码: <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>背景…

分布式安装安装LNMP_......

分布式安装安装LNMP LNMP是什么Nginx源码编译安装准备工作关闭安全防护配置上传源码包并解压安装编译源码依赖包创建运行用户 编译安装预配置安装选项编译源代码&&安装 配置优化优化路径添加 Nginx 系统服务 Mysql源码编译安装准备工作关闭安全防护配置卸载mariadb上传…

【云原生】创建harbor私有仓库及使用aliyun个人仓库

1.安装docker #删除已有dockersystemctl stop docker yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-engine #安装docker yum install -y docker-ce-20.10.1…

经济订货批量EOQ模型

一、什么是EOQ模型 EOQ是economic order quantity&#xff08;经济订货&#xff09;原理非常简单。就是把订货带来的成本&#xff0c;分为采购成本和持有成本两部分。 采购成本&#xff1a;每次订货时发生的&#xff0c;谈判、签约、物流等成本 持有成本&#xff1a;货物入仓后…

Linux kernel本地权限提升漏洞(CentOS8升级内核的解决方案)

一、CentOS8升级kernel内核的必要性 1、增强系统的安全性。 升级CentOS内核可以提供更好的安全性保障。新的内核版本通常包含了的安全补丁和漏洞修复&#xff0c;可以有效防止系统遭受恶意攻击&#xff0c;提高系统的稳定性和安全性。 2、优化硬件兼容性。 CentOS升级内核可以…

HTML静态网页成品作业(HTML+CSS)—— 小米商城首页网页(1个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有1个页面。 二、作品演示 三、代…