BatchNorm详解

这篇具有很好参考价值的文章主要介绍了BatchNorm详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

引言:

前几天被同事问到了一个问题:当batch_size=1时,Batch Normalization还有没有意义,没有说出个所以然,才意识到自己从来不好好读过BN的论文(Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift),寻思着看看可不可以从论文中得到答案,本文就是自己学习记录之用,有些狗屁不通的地方请谅解。

1. Introduce

主要分析了输入数据的分布不稳定的缺点,可以概括为两点:

原文:The change in the distributions of layers’ inputs presents a problem because the layers need to continuously adapt to the new distribution. When the input distribution to a learning system changes, it is said to experience covariate shift (Shimodaira, 2000). This is typically handled via domain adaptation (Jiang, 2008).

1. 在神经网络(Neutral network)中,对于一个神经元来说,分布不固定,会导致神经元每一次计算都要学习不同的分布,加大了训练难度,而且神经网络的级联关系,这种现象会被放大。

BatchNorm详解

神经网络

原文:Fixed distribution of inputs to a sub-network would have positive consequences for the layers outside the subnetwork, as well. Consider a layer with a sigmoid activation function z = g(W u + b) where u is the layer input, the weight matrix W and bias vector b are the layer parameters to be learned, and g(x) = 1+exp( 1 -x). As |x| increases, g′(x) tends to zero. This means that for all dimensions of x = W u+b except those with small absolute values, the gradient flowing down to u will vanish and the model will train slowly.

2. 如果使用了sigmoid函数作为激活函数的话,因为激活函数的导数是跟x的绝对值成反比的,如果分布不固定,x的绝对值较大,那么就会梯度消失。

论文中提到的解决方法:

  • 使用relu激活函数:大于零的部分是线性的,所以不会有sigmoid进入饱和区的问题
  • 小心的初始化(careful initialization):如果初始化效果不好可能训练中的前几个batch就进入饱和区了
  • 小的学习率:每次backpropagation时,尽可能柔和的调整参数。

2. Towards Reducing Internal Covariate Shift

本段介绍了一下什么是internal covariate shift,简单来说就是一个环节分布变化会随着网络的加深而变得越来越严重 。深度学习网络相互关联,前一层的输出就是上一层的输入,SGD的进行参数不断的更新,上一层的输出及当前层的输入的分布会不断的变化,并随着网络数据流的传播不断影响。

原文:We could consider whitening activations at every training step or at some interval, either by modifying the network directly or by changing the parameters of the optimization algorithm to depend on the network activation values (Wiesler et al., 2014; Raiko et al., 2012; Povey et al., 2014; Desjardins & Kavukcuoglu). However, if these modifications are interspersed with the optimization steps, then the gradient descent step may attempt to update the parameters in a way that requires the normalization to be updated, which reduces the effect of the gradient step. For example, consider a layer with the input u that adds the learned bias b, and normalizes the result by subtracting the mean of the activation computed over the training data: xb = x - E[x] where x = u + b, X = {x1...N } is the set of values of x over the training set, and E[x] = N1 PN i=1 xi. If a gradient descent step ignores the dependence of E[x] on b, then it will update b ← b + ∆b, where ∆b ∝ -∂ℓ/∂xb. Then u + (b + ∆b) - E[u + (b + ∆b)] = u + b - E[u + b]. Thus, the combination of the update to b and subsequent change in normalization led to no change in the output of the layer nor, consequently, the loss. As the training continues, b will grow indefinitely while the loss remains fixed. This problem can get worse if the normalization not only centers but also scales the activations. We have observed this empirically in initial experiments, where the model blows up when the normalization parameters are computed outside the gradient descent step

这一段主要说明了,如果归一化没有参与到参数优化更新过程中,会导致参数爆炸(原文中加粗部分说明超参数b的调整与x的期望无关,作者可能想表达归一化过程与参数优化过程无关吧),解决办法就是参数更新过程(偏导数计算)中要考虑到归一化(normalization)。

3. Normalization via Mini-Batch Statistics

本小节是论文中最重要的章节,主要介绍了训练/推理过程中BN的实现,推导了BN参与的反向传播的公式,BN在CNN中的应用等。

首先,LeCun et al., 1998b[1]等人提出的归一化方法如下所示:

引入超参数后的BN方法为:

自然而然的引出了下列问题:

为什么BN的最终实现中要引入超参数γ 、β?

原文:Note that simply normalizing each input of a layer may change what the layer can represent. For instance, normalizing the inputs of a sigmoid would constrain them to the linear regime of the nonlinearity. To address this, we make sure that the transformation inserted in the network can represent the identity transform(等效变换).

如果单纯的使用归一化,会影响模型的表现能力。比如说降低了模型的非线性表达能力,以sigmoid激活函数举例,BN可能将所有的输入变量限制在了sigmoid的线性区域,模型的表达能力下降。如公式(3.1)所示,加入了超参数后,我们既可以对输入尺度上变换(  ),也可以对输入进行平移变换(  )。而且只要我们将俩个超参数分别设定为标准差和均值,即  ,  代入到公式(3.1)就可以将得到与输入一致的输出值。

BatchNorm详解

sigmoid函数

2. Batch Norm反向传播梯度计算

BN前向计算公式如下所示:

设模型损失函数为:

则BN反向传播过程,各参数的偏导数(梯度)如下:

BatchNorm详解

从中可以看出超参数γ和β的更新与普通参数更新是一样的,如果优化器选择梯度下降那么超参数的更新如下:

4. Training and Inference with BatchNormalized Networks

本节主要介绍了BN训练和推理(inference)过程的具体实现。

4.1 训练过程中的BN

训练过程BN计算过程如式3.3~3.7所示。代码实现[2]如下:

def batchnorm_forward(x, gamma, beta, bn_param):
  """
  Input:
  - x: (N, D)维输入数据
  - gamma: (D,)维尺度变化参数
  - beta: (D,)维尺度变化参数
  - bn_param: Dictionary with the following keys:
    - mode: 'train' 或者 'test'
    - eps: 一般取1e-8~1e-4
    - momentum: 计算均值、方差的更新参数
    - running_mean: (D,)动态变化array存储训练集的均值
    - running_var:(D,)动态变化array存储训练集的方差

  Returns a tuple of:
  - out: 输出y_i(N,D)维
  - cache: 存储反向传播所需数据
  """
  mode = bn_param['mode']
  eps = bn_param.get('eps', 1e-5)
  momentum = bn_param.get('momentum', 0.9)

  N, D = x.shape
  # 动态变量,存储训练集的均值方差
  running_mean = bn_param.get('running_mean', np.zeros(D, dtype=x.dtype))
  running_var = bn_param.get('running_var', np.zeros(D, dtype=x.dtype))

  out, cache = None, None
  # TRAIN 对每个batch操作
  if mode == 'train':
    sample_mean = np.mean(x, axis = 0)
    sample_var = np.var(x, axis = 0)
    x_hat = (x - sample_mean) / np.sqrt(sample_var + eps)
    out = gamma * x_hat + beta
    cache = (x, gamma, beta, x_hat, sample_mean, sample_var, eps)
    running_mean = momentum * running_mean + (1 - momentum) * sample_mean
    running_var = momentum * running_var + (1 - momentum) * sample_var
  # TEST:要用整个训练集的均值、方差
  elif mode == 'test':
    x_hat = (x - running_mean) / np.sqrt(running_var + eps)
    out = gamma * x_hat + beta
  else:
    raise ValueError('Invalid forward batchnorm mode "%s"' % mode)

  bn_param['running_mean'] = running_mean
  bn_param['running_var'] = running_var

  return out, cache

4.2 推理过程中的BN

推理过程中BN实现如下:

BatchNorm详解

推理过程BN公式

此时自然会有一个疑问:

在推理做BN运算时,均值μ和方差σ时如何确定的?

这里原文中已经做了相应的回答,原文如下:

BatchNorm详解

文中的大致意思是:模型训练好后,推理时Normalization使用的时总体(population)的期望和方差,而不是mini-batch的统计量。这里总体的期望和方差是使用mini-batch的无偏估计代替。总体方差的无偏估计如下所示:

这里有看不懂的同学可以参考该博文。

这里总体方差Var和期望E并不是在推理过程中确定的,而是在训练过程中确定的,训练过程中使用移动平均法更新总体方差和总体期望,训练结束后记录最终的方差和期望,在推理过程中使用该值计算BN,这样BN就是一种线性变换的方法。上述的BN实现代码中,关于Var和E(x)的更新如下所示:

 # 动态变量,存储训练集的均值方差
  running_mean = bn_param.get('running_mean', np.zeros(D, dtype=x.dtype))
  running_var = bn_param.get('running_var', np.zeros(D, dtype=x.dtype))
elif mode == 'test':
    x_hat = (x - running_mean) / np.sqrt(running_var + eps)
    out = gamma * x_hat + beta

与论文不同的是:代码实现中依旧是以式(3.6)计算的BN。

5. Batch-Normalized Convolutional Networks

故名思意BN对卷积神经网络的应用。在使用时肯定会遇到一下的一个问题:

BN是放在激活函数后还是激活函数之前?

原文:We could have also normalized the layer inputs u, but since u is likely the output of another nonlinearity, the shape of its distribution is likely to change during training, and constraining its first and second moments would not eliminate the covariate shift. In contrast, Wu+b is more likely to have a symmetric, non-sparse distribution, that is “more Gaussian” (Hyv¨arinen & Oja, 2000); normalizing it is likely to produce activations with a stable distribution。

经过非线性函数,分布有可能打乱了,经过 Wu+b可能拥有更加对称的非稀疏分布(更高斯),其经过BN可能会得到更稳定的分布。

5.1 BN在CNN中实现细节

BatchNorm详解

原文:BN在CNN中的应用

文中说了,为了使得BN能够利用CNN的特性,该特性就是参数共享(同一个特征图不同位置的不同元素公用一个参数)。因此,在CNN中同一个特征图使用统一的方法进行normalization,每个特征图学习一对儿γ,β。此时每一个特征图中BN的输入数据集合B就是特征图中的所有像素,mini-batch=m*w*h(m=batchsize,w,h为特征图的大小),样本均值μ样本方差计算公式((3.3),(3.4))中的  就是特征图中的第i个像素值(一个特征图对应一个方差和均值),normalization亦是对每一个元素进行。BN在CNN中的C++实现如下,与论文中是一致的。

void mean_cpu(float *x, int batch, int filters, int spatial, float *mean)
{
    // scale即是均值中的分母项
    float scale = 1./(batch * spatial);
    int i,j,k;
    // 外循环次数为filters,也即mean的维度,每次循环将得到一个平均值
    for(i = 0; i < filters; ++i){
        mean[i] = 0;
        // 中间循环次数为batch,也即叠加每张输入图片对应的某一通道上的输出
        for(j = 0; j < batch; ++j){
            // 内层循环即叠加一张输出特征图的所有像素值
            for(k = 0; k < spatial; ++k){
                // 计算偏移
                int index = j*filters*spatial + i*spatial + k;
                mean[i] += x[index];
            }
        }
        mean[i] *= scale;
    }
}

/*
** 计算输入x中每个元素的方差
** 本函数的主要用处应该就是batch normalization的第二步了
** x: 包含所有数据,比如l.output,其包含的元素个数为l.batch*l.outputs
** batch: 一个batch中包含的图片张数,即l.batch
** filters: 该层神经网络的滤波器个数,也即是该网络层输出图片的通道数
** spatial: 该层神经网络每张特征图的尺寸,也即等于l.out_w*l.out_h
** mean: 求得的平均值,维度为filters,也即每个滤波器对应有一个均值(每个滤波器会处理所有图片)
*/
void variance_cpu(float *x, float *mean, int batch, int filters, int spatial, float *variance)
{
    // 这里计算方差分母要减去1的原因是无偏估计,可以看:https://www.zhihu.com/question/20983193
    // 事实上,在统计学中,往往采用的方差计算公式都会让分母减1,这时因为所有数据的方差是基于均值这个固定点来计算的,
    // 对于有n个数据的样本,在均值固定的情况下,其采样自由度为n-1(只要n-1个数据固定,第n个可以由均值推出)
    float scale = 1./(batch * spatial - 1);
    int i,j,k;
    for(i = 0; i < filters; ++i){
        variance[i] = 0;
        for(j = 0; j < batch; ++j){
            for(k = 0; k < spatial; ++k){
                int index = j*filters*spatial + i*spatial + k;
                // 每个元素减去均值求平方
                variance[i] += pow((x[index] - mean[i]), 2);
            }
        }
        variance[i] *= scale;
    }
}
void normalize_cpu(float *x, float *mean, float *variance, int batch, int filters, int spatial)
{
    int b, f, i;
    for(b = 0; b < batch; ++b){
        for(f = 0; f < filters; ++f){
            for(i = 0; i < spatial; ++i){
                int index = b*filters*spatial + f*spatial + i;
                x[index] = (x[index] - mean[f])/(sqrt(variance[f]) + .000001f);
            }
        }
    }
}
/*
** axpy 是线性代数中的一种基本操作(仿射变换)完成y= alpha*x + y操作,其中x,y为矢量,alpha为实数系数,
** 请看: https://www.jianshu.com/p/e3f386771c51
** N: X中包含的有效元素个数
** ALPHA: 系数alpha
** X: 参与运算的矢量X
** INCX: 步长(倍数步长),即x中凡是INCX倍数编号的参与运算
** Y: 参与运算的矢量,也相当于是输出
*/
void axpy_cpu(int N, float ALPHA, float *X, int INCX, float *Y, int INCY)
{
    int i;
    for(i = 0; i < N; ++i) Y[i*INCY] += ALPHA*X[i*INCX];
}

void scal_cpu(int N, float ALPHA, float *X, int INCX)
{
    int i;
    for(i = 0; i < N; ++i) X[i*INCX] *= ALPHA;
}

此时的python实现应为:

mean=np.mean(x, axis=(2, 3))
var=np.var(x, axis=(2, 3))
x_hat = (x - sample_mean) / np.sqrt(sample_var + eps)

6. 引言中的疑问解答:当batch_size=1时,Batch Normalization还有没有意义,此时是不是等价于IN(instance norm)?

答:是有意义的,且与IN等价!因为在CNN中,BN的mini-batch≠batch size,而是=batchsize * w * h。假设某CNN的输入数据x的shape=[n, c, h, w],计算μ,σ时实际上的实现是:

mean=np.mean(x, axis=(2, 3))
var=np.var(x, axis=(2, 3))

该实现与IN是一致的。

Reference:

[1]. LeCun, Y., Bottou, L., Orr, G., and Muller, K. Efficient backprop. In Orr, G. and K., Muller (eds.), Neural Networks: Tricks of the trade. Springer, 1998b.

[2]. https://cloud.tencent.com/devel文章来源地址https://www.toymoban.com/news/detail-401469.html

到了这里,关于BatchNorm详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 多人开发共用一个nacos,怎样配置可以保证各自的请求不会请求到同事的电脑里,实现请求隔离

    1.在每个服务的配置文件里,给服务加上自己的后缀 2.配置gateway里,指向对应的带后缀服务名,如果是gateway是自动配置 可忽略此项

    2024年02月14日
    浏览(54)
  • 母亲节到了,写一个简单的C++代码给老妈送上一个爱心祝福

    🍎 博客主页:🌙@披星戴月的贾维斯 🍎 欢迎关注:👍点赞🍃收藏🔥留言 🍇系列专栏:🌙 C/C++专栏 🌙请不要相信胜利就像山坡上的蒲公英一样唾手可得,但是请相信,世界上总有一些美好值得我们全力以赴,哪怕粉身碎骨!🌙 🍉一起加油,去追寻、去成为更好的自己

    2024年02月04日
    浏览(42)
  • 牛市下一个板块该轮到谁?Gamefi赛道爆发你吃到了多少?

    进入3月中旬以来,比特币在触及7.4万美元的历史峰值之后突然跳水,一度跌至6万美元,至于其他山寨更是惨不忍睹,很多人在问牛市行情结束了吗?当然没有,众所周知,牛市多急跌,每次回调都是为了向更高的位置蓄力。更何况,美元降息的预期依旧,加上比特币减半,

    2024年04月13日
    浏览(39)
  • 3DMAX同一个文件,同事电脑渲染的是正常的,我渲染的曝光高为什么?3dmax渲染曝光怎么办呐?

    同一个文件,但是不同版本,不同渲染器可能导致渲染的效果不一样也是属于一种现象。 首先根据问题解决,渲染曝光有以下几种可能: 1.对比度过高 在3dmax中按数字【8】,打开环境与效果,点击亮度和对比度 ​查看参数设置,是否对比度给的过高导致曝光,如果参数过高

    2024年02月05日
    浏览(79)
  • nn.BatchNorm讲解,nn.BatchNorm1d, nn.BatchNorm2d代码演示

            BatchNorm是深度网络中经常用到的加速神经网络训练,加速收敛速度及稳定性的算法,是深度网络训练必不可少的一部分,几乎成为标配;         BatchNorm 即批规范化,是为了 将每个batch的数据规范化为统一的分布 ,帮助网络训练, 对输入数据做规范化,称为

    2023年04月18日
    浏览(48)
  • BatchNorm原理解析

    BatchNorm 要解决的问题 我们都知道,深度学习的话尤其是在CV中,都需要对 数据进行归一化处理 ,因为深度学习网络主要就是为了学习训练数据的分布,并在测试集中得到更好的泛化效果。但是我们 每一个 batch 输入的数据都具有不同的分布 ,显然会给网络训练带来困难。此

    2024年02月13日
    浏览(46)
  • Batchnorm 和Layernorm 区别

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 BatchNorm,一般用于CV任务,是把一个 batch (N张图片)中 同一通道 的特征,将其标准化。可以理解为对Batch中的所有图的每一层像素进行标准化。 LayerNorm,一般用于NLP任务中,是把batch中的 一个样本 (

    2024年02月10日
    浏览(41)
  • Excel 冻结前几行

    Excel中有冻结首航和冻结首列的选项,但是如果想冻结前几行该怎么操作? 冻结首行或冻结首列 视图 - 冻结窗格 - 冻结首行或冻结首列 冻结前几行或前几列 视图 - 冻结窗格 - 冻结拆分窗格 具体冻结几行和几列取决于当前选中的单元格。比如,想冻结前三行,就将选中单元格

    2024年04月27日
    浏览(42)
  • 下班前几分钟,我弄懂了Nginx

    目录 Nginx 的介绍 Nginx 的产生 Nginx 的用途 关于代理 正向代理 反向代理 项目场景 负载均衡 Web 服务器对比 Nginx 是一款是由俄罗斯的程序设计师 Igor Sysoev 所开发高性能的 Web 和 反向代理 服务器,也是一个 IMAP/POP3/SMTP 代理服务器。 在高连接并发的情况下,Nginx 是 Apache 服务器

    2024年02月05日
    浏览(38)
  • Java中如何截取字符串前几位

    在Java中,我们可以使用多种方法来截取字符串的前几位。下面我将介绍两种常见的方法:使用substring()方法和使用String类的toCharArray()方法。 方法一:使用substring()方法 substring()方法是String类中的一个方法,用于截取字符串的一部分。我们可以通过指定起始索引和结束索引来截

    2024年02月02日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包