归一化

9 篇文章 0 订阅
4 篇文章 0 订阅

Table of Contents

 

参考:

归一化层,目前主要有这几个方法:

区别:

BatchNorm

InstanceNorm

LocalResponseNorm


参考:

BatchNormalization、LayerNormalization、InstanceNorm、GroupNorm、SwitchableNorm总结

PyTorch学习之归一化层(BatchNorm、LayerNorm、InstanceNorm、GroupNorm)

归一化层,目前主要有这几个方法:

Batch Normalization(2015年)、Layer Normalization(2016年)、Instance Normalization(2017年)、Group Normalization(2018年)、Switchable Normalization(2018年);

区别:

将输入的图像shape记为[N, C, H, W],这几个方法主要的区别就是在:

  • BatchNorm:batch方向做归一化,算NHW的均值,对小batchsize效果不好;BN主要缺点是对batchsize的大小比较敏感,由于每次计算均值和方差是在一个batch上,所以如果batchsize太小,则计算的均值、方差不足以代表整个数据分布
  • LayerNorm:channel方向做归一化,算CHW的均值,主要对RNN作用明显;
  • InstanceNorm:一个channel内做归一化,算H*W的均值,用在风格化迁移;因为在图像风格化中,生成结果主要依赖于某个图像实例,所以对整个batch归一化不适合图像风格化中,因而对HW做归一化。可以加速模型收敛,并且保持每个图像实例之间的独立。
  • GroupNorm:将channel方向分group,然后每个group内做归一化,算(C//G)HW的均值;这样与batchsize无关,不受其约束。
  • SwitchableNorm是将BN、LN、IN结合,赋予权重,让网络自己去学习归一化层应该使用什么方法。
     

 

BatchNorm

torch.nn.BatchNorm2d(num_featureseps=1e-05momentum=0.1affine=Truetrack_running_stats=True)

  • num_features: 特征图数量
  • eps: 为保证数值稳定性(分母不能趋近或取0),给分母加上的值。默认为1e-5。
  • momentum: 动态均值和动态方差所使用的动量。默认为0.1。
  • affine: 布尔值,当设为true,给该层添加可学习的仿射变换参数。
  • track_running_stats:布尔值,当设为true,记录训练过程中的均值和方差;

均值:相当于 Figure 2 中 N个长方体的对应位置元素相加除以N

InstanceNorm

torch.nn.InstanceNorm2d(num_featureseps=1e-05momentum=0.1affine=Falsetrack_running_stats=False)

相当于N=1的BatchNorm

LocalResponseNorm

torch.nn.LocalResponseNorm(sizealpha=0.0001beta=0.75k=1.0)

size:用于归一化的邻居通道数
alpha:乘积因子,Default: 0.0001
beta :指数,Default: 0.75
k:附加因子,Default: 1

 

原文链接:https://blog.csdn.net/LoseInVain/article/details/86476010

Pytorch中的BatchNorm的API主要有:

API(Application Programming Interface,应用程序编程接口)是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节

torch.nn.BatchNorm1d(num_features, 
                     eps=1e-05, 
                     momentum=0.1, 
                     affine=True, 
                     track_running_stats=True)

一般来说pytorch中的模型都是继承nn.Module类的,都有一个属性trainning指定是否是训练状态,训练状态与否将会影响到某些层的参数是否是固定的,比如BN层或者Dropout层。通常用model.train()指定当前模型model为训练状态,model.eval()指定当前模型为测试状态。
同时,BN的API中有几个参数需要比较关心的,一个是affine指定是否需要仿射,还有个是track_running_stats指定是否跟踪当前batch的统计特性。容易出现问题也正好是这三个参数:trainning,affine,track_running_stats。

如果affine=False则γ=1,β=0,并且不能学习被更新。一般都会设置成affine=True
track_running_stats=True表示跟踪整个训练过程中的batch的统计特性,得到方差和均值,而不只是仅仅依赖与当前输入的batch的统计特性。相反的,如果track_running_stats=False那么就只是计算当前输入的batch的统计特性中的均值和方差了。当在推理阶段的时候,如果track_running_stats=False,此时如果batch_size比较小,那么其统计特性就会和全局统计特性有着较大偏差,可能导致糟糕的效果。


一般来说,trainning和track_running_stats有四种组合

  1. trainning=True, track_running_stats=True。这个是期望中的训练阶段的设置,此时BN将会跟踪整个训练过程中batch的统计特性。
  2. trainning=True, track_running_stats=False。此时BN只会计算当前输入的训练batch的统计特性,可能没法很好地描述全局的数据统计特性。
  3. trainning=False, track_running_stats=True。这个是期望中的测试阶段的设置,此时BN会用之前训练好的模型中的(假设已经保存下了)running_mean和running_var并且不会对其进行更新。一般来说,只需要设置model.eval()其中model中含有BN层,即可实现这个功能。
  4. trainning=False, track_running_stats=False 效果同2,只不过是位于测试状态,这个一般不采用,这个只是用测试输入的batch的统计特性,容易造成统计特性的偏移,导致糟糕效果。
     

代码演示:

参考https://blog.csdn.net/bigFatCat_Tom/article/details/91619977

用pytorch封装好的BN运算一下

import torch
import torch.nn as nn

a = torch.randn(2,3,4,4)
print(a)

'''
输出:
tensor([[[[-0.2083, -0.0617,  1.3143,  2.6126],
          [ 0.5093, -0.5015, -1.2195,  0.9299],
          [-0.6965,  1.0784,  0.8513,  0.4423],
          [ 0.8713,  0.1331, -0.3746, -0.1559]],

         [[-2.2629,  0.0863, -2.0906, -1.5406],
          [ 0.1329, -0.0482,  1.5541,  0.9241],
          [-0.1211, -0.4665,  0.8098,  2.0917],
          [-1.2141,  0.1769, -2.0404, -0.9025]],

         [[ 0.6931, -0.3296,  0.4235,  0.2623],
          [-0.9637, -0.0713, -0.8088,  2.1761],
          [ 0.8186, -1.6996,  1.4698, -0.9832],
          [ 0.8413, -0.0220, -0.5528, -1.0645]]],


        [[[ 0.6976, -0.6083, -2.0900, -1.7487],
          [-1.0340, -1.8326, -0.4567,  0.8283],
          [-0.1331, -0.9351, -0.1814,  1.3032],
          [ 0.6202,  0.4430, -0.3147,  2.2516]],

         [[-1.0134,  0.1929, -0.4350,  1.1158],
          [ 0.7481, -1.2626, -1.0841,  2.3136],
          [ 1.3261,  0.5567, -0.6275, -1.0899],
          [-0.5978, -0.7278, -0.0906,  0.3606]],

         [[ 0.1453,  0.0271,  0.6967, -0.9279],
          [-0.2625,  0.8887,  0.4750,  1.9671],
          [-0.9255, -0.7932, -1.5779, -0.4061],
          [-1.2149, -0.7441,  0.8653, -0.5020]]]])
'''
m = nn.BatchNorm2d(3)
out_a = m(a)
print(m.weight)
print(m.bias)
print(out_a)

'''
输出
Parameter containing:
tensor([0.3354, 0.4789, 0.3222], requires_grad=True)
Parameter containing:
tensor([0., 0., 0.], requires_grad=True)
tensor([[[[-0.0880, -0.0421,  0.3883,  0.7945],
          [ 0.1365, -0.1797, -0.4043,  0.2681],
          [-0.2407,  0.3145,  0.2435,  0.1155],
          [ 0.2497,  0.0188, -0.1400, -0.0716]],

         [[-0.8787,  0.1045, -0.8066, -0.5764],
          [ 0.1240,  0.0482,  0.7187,  0.4551],
          [ 0.0177, -0.1269,  0.4072,  0.9437],
          [-0.4398,  0.1424, -0.7855, -0.3094]],

         [[ 0.2553, -0.0888,  0.1645,  0.1103],
          [-0.3021, -0.0019, -0.2500,  0.7542],
          [ 0.2975, -0.5497,  0.5166, -0.3087],
          [ 0.3051,  0.0147, -0.1639, -0.3361]]],


        [[[ 0.1954, -0.2131, -0.6766, -0.5698],
          [-0.3463, -0.5961, -0.1657,  0.2363],
          [-0.0645, -0.3153, -0.0796,  0.3849],
          [ 0.1712,  0.1158, -0.1212,  0.6815]],

         [[-0.3558,  0.1491, -0.1137,  0.5353],
          [ 0.3814, -0.4600, -0.3853,  1.0366],
          [ 0.6233,  0.3013, -0.1942, -0.3878],
          [-0.1818, -0.2362,  0.0304,  0.2193]],

         [[ 0.0710,  0.0312,  0.2565, -0.2901],
          [-0.0662,  0.3211,  0.1819,  0.6839],
          [-0.2893, -0.2448, -0.5088, -0.1146],
          [-0.3867, -0.2283,  0.3132, -0.1468]]]],
       grad_fn=<NativeBatchNormBackward>)
'''

自己计算一下,验证运算结果: 

# 针对每个通道做均值和方差,用0,1,2分别表示3个通道,此处只验证一下0通道
print(a[:, 0, :, :])
mean1 = torch.mean(a[:, 0, :, :])
var1 = torch.var(a[:, 0, :, :], False)  # false表示bias校正不会被使用
var2 = torch.var(a[:, 0, :, :])
print(mean1)
print(var1)
print(var2)
print(m)
'''
输出
tensor([[[-0.2083, -0.0617,  1.3143,  2.6126],
         [ 0.5093, -0.5015, -1.2195,  0.9299],
         [-0.6965,  1.0784,  0.8513,  0.4423],
         [ 0.8713,  0.1331, -0.3746, -0.1559]],

        [[ 0.6976, -0.6083, -2.0900, -1.7487],
         [-1.0340, -1.8326, -0.4567,  0.8283],
         [-0.1331, -0.9351, -0.1814,  1.3032],
         [ 0.6202,  0.4430, -0.3147,  2.2516]]])
tensor(0.0729)
tensor(1.1494)
tensor(1.1865)
BatchNorm2d(3, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
'''
cal_out = (a[0][0] - mean1) / (var1.pow(0.5) + m.eps) * m.weight[0] + m.bias[0]
print(cal_out)

'''
输出
tensor([[-0.0880, -0.0421,  0.3883,  0.7945],
        [ 0.1365, -0.1797, -0.4043,  0.2681],
        [-0.2407,  0.3145,  0.2435,  0.1155],
        [ 0.2497,  0.0188, -0.1400, -0.0716]], grad_fn=<AddBackward0>)
'''

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值