Batch Normalization、Layer Normalization代码实现

目录

  • 前言
  • 批量正则化-BN
  • 层正则化-LN

前言

BN(Batch Normalization)首次提出与论文,主要目的是为了解决训练深层神经网络慢的问题。我们可以神经网络整体可以看成一个高阶的复杂函数,通过训练优化它的参数,可以用于拟合各种复杂的数据分布。一般而言,一个网络会有多层,其中的每一层都可以看成一个子函数,用于拟合其各自的子分布。由于下一层的输入来自上一层的输出,而随着训练过程中上一层网络参数的改动,它的输出也将发生变化,那么将会导致下一层学习更加慢,同时也会使得模型的训练更加难,这个现象在原文中被称为“internal covariate shif”现象,针对这一问题,作者提出了将上一层的输出进行标准化以调整下一层输入的分布,以减弱“internal covariate shif”的影响,BN一般用在卷积层之后,激活层之前。更多的细节可以参考原文Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift。

BN涉及到跨样本间的计算,因而难免会受到batch size大小的影响;另一方面,在序列样本中(如文本、语音等),一般会进行padding对齐每条样本的长度,以便批量输入到模型中,此时在跨样本计算统计值的话,会引入噪声;为了解决以上两个问题,LN(Layer Normalization)就应运而生,单独对每条样本的特征进行正则化,详情可参考原文Layer Normalization。

类似的还有Instance Normalization、Group Normalization、Switchable Normalization,这里就不多赘述了。

以下部分将会省略很多细节,直接进入代码实现部分。

批量正则化-BN

BN是同时对所有样本的对应通道进行正则化,有多少个通道,就会有多少组均值和方差,单独对每个通道的值进行缩放,示意图如下:
在这里插入图片描述

假设数据格式为 V [ B , C , H , W ] V_[B,C,H,W_] V[B,C,H,W],分别表示 b a t c h _ s i z e batch\_size batch_size、通道数、高度、宽度,那么针对通过维度的任一个坐标 c ∈ [ 0 , C ) c\in [0, C) c[0,C),都会求出一组均值和方差

u c = 1 B ∗ H ∗ W ∑ b ∈ [ 0 , B ) h ∈ [ 0 , H ) w ∈ [ 0 , W ) V [ b , h , w ] u_c = \frac{1} {B*H*W} \sum_{b\in[0,B) h\in [0,H) w\in[0,W)} V_[b,h,w] uc=BHW1b[0,B)h[0,H)w[0,W)V[b,h,w]

θ c 2 = 1 B ∗ H ∗ W ∑ b ∈ [ 0 , B ) h ∈ [ 0 , H ) w ∈ [ 0 , W ) ( V [ b , h , w ] − u c ) 2 \theta^2_c = \frac{1} {B*H*W} \sum_{b\in[0,B) h\in [0,H) w\in[0,W)}(V_[b,h,w] - u_c)^2 θc2=BHW1b[0,B)h[0,H)w[0,W)(V[b,h,w]uc)2

接下来对该通道坐标的每一个值,进行缩放操作

$ \hat{V}{[:, c, :, :]} \leftarrow \gamma_c . \frac{V{[:,c,:,:]} - u_c } {\sqrt{\theta^2_c + \epsilon}} + \beta_c $

其中 ϵ \epsilon ϵ为一个非常小的常数,防止分母为0, γ c , β c \gamma_c,\beta_c γc,βc为该通道对应的参数。

import torch
from torch.nn import BatchNorm1d, BatchNorm2d, BatchNorm3d
import numpy as np
np.random.seed(0)

class myBatchNorm(torch.nn.Module):
    def __init__(self,
                 size, 
                 dim,
                 eps: float = 1e-6) -> None:
        super().__init__()
        self.gamma = torch.nn.Parameter(torch.ones(size))
        self.beta = torch.nn.Parameter(torch.zeros(size))
        self.eps = eps
        self.dim = dim

    def forward(self, tensor: torch.Tensor):  # pylint: disable=arguments-differ
        mean = tensor.mean(self.dim, keepdim=True)
        std = tensor.std(self.dim, unbiased=False, keepdim=True)
        return self.gamma * (tensor - mean) / (std + self.eps) + self.beta

print("-----一维BN------")
val_tensor = torch.from_numpy(np.random.randn(1, 3, 4)).float()
BN1 = BatchNorm1d(3, affine=False)(val_tensor)
print(BN1)
myBN1 = myBatchNorm((1, 3, 1), (0, 2))(val_tensor)
print(myBN1)

print("-----二维BN------")
val_tensor = torch.from_numpy(np.random.randn(1, 3, 4, 5)).float()
BN2 = BatchNorm2d(3, affine=False)(val_tensor)
print(BN2)
myBN2 = myBatchNorm((1, 3, 1, 1), (0, 2, 3))(val_tensor)
print(myBN2)

print("-----三维BN------")
val_tensor = torch.from_numpy(np.random.randn(1, 2, 3, 4, 5)).float()
BN3 = BatchNorm3d(2, affine=False)(val_tensor)
print(BN3)
myBN3 = myBatchNorm((1, 2, 1, 1, 1), (0, 2, 3, 4))(val_tensor)
print(myBN3)

输出如下:

-----一维BN------
tensor([[[ 0.5905, -1.3359, -0.5187,  1.2640],
         [ 1.3397, -1.2973,  0.4893, -0.5317],
         [-0.9773, -0.1110, -0.5604,  1.6487]]])
tensor([[[ 0.5905, -1.3359, -0.5187,  1.2640],
         [ 1.3397, -1.2973,  0.4893, -0.5317],
         [-0.9773, -0.1110, -0.5604,  1.6488]]], grad_fn=<AddBackward0>)
-----二维BN------
tensor([[[[ 0.4834, -0.1121,  0.1880,  0.0854,  1.1662],
          [-0.4165,  0.0662, -1.0209, -2.6032,  0.3834],
          [ 0.5797, -0.9166,  1.8886, -1.5800, -0.1828],
          [-0.3997,  1.2022,  1.1431, -0.0811,  0.1268]],

         [[-0.5048, -1.5601,  0.0165,  0.5033,  1.5403],
          [ 1.5133, -0.0216,  0.0605, -0.6600, -1.0187],
          [-1.2951,  2.2359, -0.1397, -0.0706, -0.8572],
          [ 1.1031, -1.2059,  0.1470, -0.5122,  0.7259]],

         [[-0.2520, -1.2639,  0.4771,  1.1667,  0.6201],
          [ 0.9766, -0.4386, -0.0283, -0.4962, -0.0235],
          [-0.7087, -2.0882,  0.7877, -0.0873, -1.9430],
          [ 1.2188, -0.8510,  0.5981,  1.6211,  0.7145]]]])
tensor([[[[ 0.4834, -0.1121,  0.1880,  0.0854,  1.1662],
          [-0.4165,  0.0662, -1.0209, -2.6032,  0.3834],
          [ 0.5797, -0.9166,  1.8886, -1.5800, -0.1828],
          [-0.3997,  1.2022,  1.1431, -0.0811,  0.1268]],

         [[-0.5048, -1.5601,  0.0165,  0.5033,  1.5403],
          [ 1.5133, -0.0216,  0.0605, -0.6600, -1.0187],
          [-1.2951,  2.2359, -0.1397, -0.0706, -0.8572],
          [ 1.1031, -1.2059,  0.1470, -0.5122,  0.7260]],

         [[-0.2520, -1.2639,  0.4771,  1.1667,  0.6201],
          [ 0.9766, -0.4386, -0.0283, -0.4962, -0.0235],
          [-0.7087, -2.0882,  0.7877, -0.0873, -1.9430],
          [ 1.2188, -0.8510,  0.5981,  1.6211,  0.7145]]]],
       grad_fn=<AddBackward0>)
-----三维BN------
tensor([[[[[ 0.8306, -1.5469,  0.0926, -0.9961, -1.1823],
           [-0.8900, -0.6223, -0.2541, -1.4771,  0.5917],
           [ 0.1560, -1.8487,  1.1800,  1.5882,  0.8701],
           [-0.4905, -1.3826,  0.7456, -0.7141,  0.9138]],

          [[-0.1018,  0.6676,  0.0465,  0.3972, -0.2998],
           [ 1.4780, -0.1832,  0.0922,  1.5754, -1.6599],
           [-1.5826,  0.6604, -1.4851,  1.6360, -0.7245],
           [-1.0588,  1.6152,  1.1722,  1.5598,  0.5970]],

          [[-1.1727,  1.6023, -0.5787,  0.4932,  0.6382],
           [-0.4656,  0.3046,  0.6131,  0.0666, -1.4112],
           [-0.0117,  1.0179, -1.0059, -0.4602, -0.7461],
           [ 1.5415,  0.3629,  0.0977, -1.0813,  0.2297]]],


         [[[-0.5496,  0.1743, -0.5101,  0.8350,  0.7327],
           [-0.0719,  0.5476, -0.9788, -1.3869,  0.5920],
           [ 0.3125,  0.7926,  2.5845,  1.1098, -0.7940],
           [ 1.2866, -1.2072, -0.3315,  0.0717,  1.8979]],

          [[-0.6218, -0.7055,  0.0407, -0.5384,  1.2965],
           [-0.9653, -1.0345, -0.3071, -0.3689,  2.1195],
           [ 1.1148,  0.2314, -1.1145,  1.0072, -0.8836],
           [-1.4418,  1.3594,  0.4665,  1.0856,  0.4684]],

          [[ 1.0199, -0.5257, -0.9185,  0.8403, -0.6819],
           [-0.5652, -0.3253,  0.1596, -0.2212, -1.2677],
           [-0.5181, -2.1374,  0.7825, -1.5005, -0.9904],
           [ 0.1951, -0.6164,  1.7233, -1.1836,  0.4154]]]]])
tensor([[[[[ 0.8306, -1.5469,  0.0926, -0.9961, -1.1823],
           [-0.8900, -0.6223, -0.2541, -1.4771,  0.5917],
           [ 0.1560, -1.8487,  1.1800,  1.5882,  0.8701],
           [-0.4905, -1.3826,  0.7456, -0.7141,  0.9138]],

          [[-0.1018,  0.6676,  0.0465,  0.3972, -0.2998],
           [ 1.4780, -0.1832,  0.0922,  1.5754, -1.6599],
           [-1.5826,  0.6604, -1.4851,  1.6360, -0.7245],
           [-1.0588,  1.6153,  1.1722,  1.5598,  0.5970]],

          [[-1.1727,  1.6024, -0.5787,  0.4932,  0.6382],
           [-0.4656,  0.3046,  0.6131,  0.0666, -1.4112],
           [-0.0117,  1.0179, -1.0059, -0.4602, -0.7461],
           [ 1.5415,  0.3629,  0.0977, -1.0813,  0.2297]]],


         [[[-0.5496,  0.1743, -0.5101,  0.8350,  0.7327],
           [-0.0719,  0.5476, -0.9788, -1.3870,  0.5920],
           [ 0.3125,  0.7926,  2.5845,  1.1098, -0.7940],
           [ 1.2866, -1.2072, -0.3315,  0.0717,  1.8979]],

          [[-0.6218, -0.7055,  0.0407, -0.5384,  1.2965],
           [-0.9653, -1.0346, -0.3071, -0.3689,  2.1195],
           [ 1.1148,  0.2314, -1.1145,  1.0072, -0.8836],
           [-1.4418,  1.3594,  0.4665,  1.0856,  0.4684]],

          [[ 1.0199, -0.5257, -0.9185,  0.8403, -0.6819],
           [-0.5652, -0.3253,  0.1596, -0.2212, -1.2677],
           [-0.5181, -2.1374,  0.7825, -1.5005, -0.9904],
           [ 0.1951, -0.6164,  1.7233, -1.1836,  0.4154]]]]],
       grad_fn=<AddBackward0>)

层正则化-LN

LN是逐个样本进行正则化,假设数据格式为 V [ B , T , C ] V_[B,T,C_] V[B,T,C],分别表示 b a t c h _ s i z e batch\_size batch_size、序列长度、特征维度,那么一般会针对每个样本的每个序列点的特征进行标准化,当然也可以对每个样本整体进行标准化,示意图如下:
在这里插入图片描述

下面以对每个样本的每个序列点进行标准化为例进行公示的演示。

u b , t = 1 C ∑ c ∈ [ 0 , C ) V [ b , t , c ] u_{b,t} = \frac{1} {C} \sum_{c\in[0,C)} V_[b,t,c] ub,t=C1c[0,C)V[b,t,c]

θ b , t 2 = 1 C ∑ c ∈ [ 0 , C ) ( V [ b , t , c ] − u b , t ) 2 \theta^2_{b,t} = \frac{1} {C} \sum_{c\in[0,C)}(V_[b,t,c] - u_{b,t})^2 θb,t2=C1c[0,C)(V[b,t,c]ub,t)2

接下来,进行对应的缩放操作

V ^ [ b , t , : ] ← γ t . V [ b , t , : ] − u b , t θ b , t 2 + ϵ + β t \hat{V}_{[b, t, :]} \leftarrow \gamma_t . \frac{V_{[b,t,:]} - u_{b,t} } {\sqrt{\theta^2_{b,t} + \epsilon}} + \beta_t V^[b,t,:]γt.θb,t2+ϵ V[b,t,:]ub,t+βt
其中 ϵ \epsilon ϵ为一个非常小的常数,防止分母为0,注意 γ t , β t \gamma_t,\beta_t γtβt为所有样本共享。

import torch
from torch.nn import LayerNorm as LN
import numpy as np
np.random.seed(0)

val = np.random.randn(2, 3, 4)
val_tensor = torch.from_numpy(val).float()
class myLayerNorm(torch.nn.Module):
    def __init__(self,
                 size,
                 dim,
                 eps: float = 1e-6) -> None:
        super().__init__()
        self.gamma = torch.nn.Parameter(torch.ones(size))
        self.beta = torch.nn.Parameter(torch.zeros(size))
        self.eps = eps
        self.dim = dim

    def forward(self, tensor: torch.Tensor):  # pylint: disable=arguments-differ
        mean = tensor.mean(self.dim, keepdim=True)
        std = tensor.std(self.dim, unbiased=False, keepdim=True)
        return self.gamma * (tensor - mean) / (std + self.eps) + self.beta

print("对整个样本进行正则化")
LN2 = LN([3, 4])(val_tensor)
myLN2 = myLayerNorm((3, 4), (1, 2))(val_tensor)
print("torchNL")
print(LV2)

print("myML")
print(myLN2)

print("对每个样本的每个序列点进行正则化")
LN1 = LN(4)(val_tensor)
print(LN1)
myLN2 = myLayerNorm((4), 2)(val_tensor)
print(myLN2)

输出如下:

对整个样本进行正则化
torchNL
tensor([[[ 1.1009, -0.3772,  0.2498,  1.6177],
         [ 1.2131, -1.8700,  0.2188, -0.9749],
         [-0.9227, -0.3659, -0.6548,  0.7652]],

        [[ 0.7022,  0.0685,  0.3878,  0.2786],
         [ 1.4288, -0.2555,  0.2582, -0.8987],
         [-2.5826,  0.5957,  0.8047, -0.7878]]],
       grad_fn=<NativeLayerNormBackward0>)
myML
tensor([[[ 1.1009, -0.3772,  0.2498,  1.6177],
         [ 1.2131, -1.8700,  0.2188, -0.9749],
         [-0.9227, -0.3659, -0.6548,  0.7652]],

        [[ 0.7022,  0.0685,  0.3878,  0.2786],
         [ 1.4288, -0.2555,  0.2582, -0.8987],
         [-2.5826,  0.5957,  0.8047, -0.7878]]], grad_fn=<AddBackward0>)
对每个样本的每个序列点进行正则化
tensor([[[ 0.5905, -1.3359, -0.5187,  1.2640],
         [ 1.3397, -1.2973,  0.4893, -0.5317],
         [-0.9773, -0.1110, -0.5604,  1.6487]],

        [[ 1.4983, -1.2706,  0.1247, -0.3525],
         [ 1.5190, -0.4557,  0.1465, -1.2098],
         [-1.5448,  0.8043,  0.9587, -0.2182]]],
       grad_fn=<NativeLayerNormBackward0>)
tensor([[[ 0.5905, -1.3359, -0.5187,  1.2640],
         [ 1.3397, -1.2973,  0.4893, -0.5317],
         [-0.9773, -0.1110, -0.5604,  1.6488]],

        [[ 1.4985, -1.2707,  0.1247, -0.3525],
         [ 1.5190, -0.4557,  0.1465, -1.2098],
         [-1.5448,  0.8043,  0.9587, -0.2182]]], grad_fn=<AddBackward0>)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[易语言]使用易语言部署yolov5-7.0的图像分类模型

【官方框架地址】 GitHub - ultralytics/yolov5: YOLOv5 &#x1f680; in PyTorch > ONNX > CoreML > TFLite 【算法介绍】 YOLO&#xff08;You Only Look Once&#xff09;系列算法是一种在计算机视觉领域广泛应用的目标检测算法&#xff0c;而YOLOv5是该系列中的…

数据结构初阶之排序

个人主页&#xff1a;点我进入主页 专栏分类&#xff1a;C语言初阶 C语言程序设计————KTV C语言小游戏 C语言进阶 C语言刷题 数据结构初阶 Linux 欢迎大家点赞&#xff0c;评论&#xff0c;收藏。 一起努力,共赴大厂。 目录 一.前言 二.选择排序 …

智能安全帽识别系统简析

在工业安全领域&#xff0c;安全帽识别系统的重要性不言而喻。这种系统利用先进的图像识别技术&#xff0c;确保工地上每位工人都佩戴安全帽&#xff0c;从而大幅提升工作场所的安全性。本文旨在探讨这一系统的工作原理、应用范围以及面临的挑战。 安全帽识别系统的工作原理 智…

GPT图解大模型是怎样构建的

❤️作者主页&#xff1a;小虚竹 ❤️作者简介&#xff1a;大家好,我是小虚竹。2022年度博客之星评选TOP 10&#x1f3c6;&#xff0c;Java领域优质创作者&#x1f3c6;&#xff0c;CSDN博客专家&#x1f3c6;&#xff0c;华为云享专家&#x1f3c6;&#xff0c;掘金年度人气作…

0基础学java-day25(JDBC 和数据库连接池)

一、JDBC概述 1 基本介绍 2 简单模拟 package com.hspedu.jdbc.myjdbc;/*** author 林然* version 1.0* 我们规定的 jdbc 接口(方法)*/ public interface JdbcInterface {//连接public Object getConnection() ;//crudpublic void crud();//关闭连接public void close(); }pac…

立白科技集团:研发安全推动数字化蜕变,日化业务再上新高度

立白科技集团成立于1994年&#xff0c;是我国日化行业的领军企业&#xff0c;致力于成为一家“品牌引领、数字经营、富有创新、富有活力”的智慧服务型企业。从2018年开始&#xff0c;立白科技集团加速数字化转型&#xff0c;打造数据和业务中台&#xff0c;并建立toB和toC平台…

小程序学习基础(首页展示)

原理通过首页展示的方式设置一个按钮&#xff0c;然后点击按钮跳转到相应的页面即可。 一 在js中定义一个需要展示页面的数组 二 在页面中使用fou循环来遍历其中的数据&#xff0c;并展示出来 页面代码 <!--index.wxml--> <navigation-bar title"牧原" …

vue3 锚点定位 点击滚动高亮

功能描述 点击导航跳到对应模块的起始位置&#xff0c;并且高亮点击的导航&#xff1b; 滚动到相应的模块时&#xff0c;对应的导航也自动高亮&#xff1b; 效果展示 注意事项 一定要明确哪个是要滚动的盒子&#xff1b;滚动的高度要减去导航栏的高度&#xff1b;当前在导航1…

Redis相关命令详解及其原理

Redis概念 Redis&#xff0c;英文全称是remote dictionary service&#xff0c;也就是远程字典服务。这是kv存储数据库。Redis&#xff0c;包括所有的数据库&#xff0c;都是请求-回应模式&#xff0c;通俗来说就是数据库不会主动地要给前台推送数据&#xff0c;只有前台发送了…

【HarmonyOS4.0】第十篇-ArkUI布局容器组件(二)

三、层叠布局容器&#xff08;Stack&#xff09; 堆叠容器组件 Stack的布局方式是把子组件按照设置的对齐方式顺序依次堆叠&#xff0c;后一个子组件覆盖在前一个子组件上边。 注意&#xff1a;Stack 组件层叠式布局&#xff0c;尺寸较小的布局会有被遮挡的风险&#xff0c; …

JS常用插件 Swiper插件 实现轮播图

Swiper介绍 Swiper 是一款免费以及轻量级的移动设备触控滑块的js框架 中文官网地址: https://www.swiper.com.cn/ 点击查看Swiper演示&#xff0c;里面的功能和样式十分丰富&#xff0c;根据自己的需求选择 中文教程中详细介绍了如何使用Swiper API文档中介绍了各个模块以及参…

计算机导论05-计算机网络

文章目录 计算机网络基础计算机网络概述计算机网络的概念计算机网络的功能计算机网络的组成 计算机网络的发展计算机网络的类型 网络体系结构网络互联模型OSI/RM结构与功能TCP/IP结构模型TCP/IP与OSI/RM的比较 网络地址与分配IP地址构成子网的划分IPv6 传输介质与网络设备网络传…

电脑桌面便签在哪设置?备忘录软件哪个好?

好记性不如烂笔头&#xff01;相信很多打工族在电脑面前办公的时候&#xff0c;都需要随时记录工作中的事项&#xff0c;有的用TXT记录&#xff0c;有的手写笔记&#xff0c;还有一些用电脑桌面便签类软件。而当我们待办事项繁多的时候&#xff0c;手写或文本记录并不能有效帮我…

图解python | 字符串及操作

1.Python元组 Python的元组与列表类似&#xff0c;不同之处在于元组的元素不能修改。 元组使用小括号&#xff0c;列表使用方括号。 元组创建很简单&#xff0c;只需要在括号中添加元素&#xff0c;并使用逗号隔开即可。 tup1 (ByteDance, ShowMeAI, 1997, 2022) tup2 (1…

老师假期有工资么

老师在享受假期的时候&#xff0c;很多人都会好奇&#xff1a;教师寒暑假会有工资吗&#xff1f; 老师也是劳动者&#xff0c;享有法律规定的各种权益。其中之一就是在规定的工作时间内获得报酬。既然老师在正常工作日上班有工资&#xff0c;那么在假期呢&#xff1f; 实际上…

数字化时代,VR全景展示如何让用户一窥全貌?

数字化时代&#xff0c;VR全景展示为各行各业提供了无限的可能性。随着VR全景技术的逐步普及&#xff0c;VR全景展示以其独特的呈现方式和新颖十足的交互体验&#xff0c;正在不断改变着人们对于展示宣传的理解。 传统的展示方式&#xff0c;通常需要将产品、图文、品牌等元素集…

【计算机组成与体系结构Ⅱ】指令调度与分支延迟(实验)

实验4&#xff1a;指令调度与分支延迟 一、实验目的 1. 加深对指令调度技术的理解。 2. 加深对分支延迟技术的理解。 3. 熟练采用指令调度技术解决流水线中的数据冲突的方法。 4. 进一步理解指令调度技术对CPU性能的改进。 5. 进一步理解延迟分支技术对CPU性能的改进。 二…

企业组网搭建有哪些?

在当今全球化的商业环境中&#xff0c;集团公司必须建立起一个无缝连接的网络&#xff0c;以确保高效的信息传输和资源共享。为实现这一目标&#xff0c;选择可靠而安全的网络组网方案至关重要。本文将介绍几种主要的集团公司网络组网方案&#xff0c;以帮助企业根据其具体需求…

人人都在用的PDF软件,也要接入ChatGPT了

随着人工智能技术的不断进步和发展&#xff0c;Chatbot技术的应用已经逐渐从娱乐和社交领域扩展到了更多的实际场景中。在办公软件领域&#xff0c;聊天机器人已经成为了提升工作效率、减少人力投入的重要工具&#xff0c;多家头部企业都在探讨将AI接入到软件及应用中的使用方案…

深入解析阻塞队列BlockingQueue及源码(超详细)

一、基础概念 1.1 BlockingQueue BlockingQueue 是 java.util.concurrent 包提供的用于解决并发生产者 - 消费者问题的最有用的类。 1.1.1 队列类型&#xff1a; 无限队列 &#xff08;unbounded queue &#xff09; - 几乎可以无限增长 有限队列 &#xff08; bounded qu…