CS231n笔记4-Data Preprocessing, Weights Initialization与Batch Normalization

Data Preprocessing, Weights Initialization与Batch Normalization

  • Data Preprocessing Weights Initialization与Batch Normalization

    • 数据预处理Data Preprocessing
    • 权重初始化Weights Initialization
      • 让权重初始化为0
      • 0方差1e-2标准差
      • 0方差1标准差
      • Xavier Initialization
      • 再改进
    • 批归一化Batch Normalization
    • 后言

这一节与下一节我们来介绍一下在网络学习的前期,我们可以利用的方法以及需要注意的问题,这一节我们专注于三点

  • 数据预处理:Data Preprocessing
  • 权重初始化:Weights Initialization
  • 批归一化:Batch Normalization

数据预处理:Data Preprocessing

通常我们比较常见的数据预处理是先将数据处理成零均值(zero-centered),然后再处理成单位标准差(normalized data)。

下面给出Python的代码:

def zero_centered(X):
    """X的每一行代表一个数据
    """
    return X-np.mean(X, axis=0);

def normalized(X):
    """X的每一行代表一个数据
    """
    return X/np.std(X, axis=0);

def data_preprocess(X):
    """X的每一行代表一个数据
    """
    return normalized(zero_centered(X));

还有一种常见的预处理的模式,是先将数据进行PCA转化然后再白化数据,然而在做图像处理的时候,一般都不会用这种办法,甚至都不进行标准差单位化,而是仅仅把均值置零。

这里就不给出PCA->Whitened的代码,如果有需要,我会在后期再补充上来。

权重初始化:Weights Initialization

在深度学习中,最重要的一个部分就是权重,可以这么说,几乎所有的一起技巧也好,方法也好,都是在为学习到更好的权重服务,因此,涉及到权重的方方面面,我们都需要小心。下面我们要将的是一个关键的门槛,权重的初始化。

让权重初始化为0

回想一下,我们是如何计算前向神经网络的(忘了的读者可以看我之前的CS231n笔记),当权重为0时,每一层的计算机构都是一样的,最后只会导致结果也是完全一样,后向传播时每层的梯度也都是一样的。这样一来整个网络就是一个完全对称的网络,失去了特征提取的能力,因此显然不能让权重初始化为0。

0方差,1e-2标准差

这个初始化解决了对称的问题,在小型的网络中也适用,但是会导致non-homogeneous distributions(先mark下,到时弄懂了再来补充,知道的读者也可以给我留言,非常感谢)。

接下来我们看下在tanh激活函数下,这种初始化在10层网络中每一层节点的均值与标准差的表现情况。

可以看出,一开始数据都还是有一定标准差的(注意图中的数据并非权重的数据),但是随着层数越往后,标准差逐渐消失为0,也就是说到了后面,数据约为0,导致前向传播失败。可以说,因为初始权重的取值太小了,导致计算是数据也变得很小,然后再往后乘上还是很小的权重,而导致最后全都变成了0。

思考

由于最后的值都变成了零,那么由于在BP过程中,我们需要乘于输入的步骤,因此,会导致梯度被扼杀。

0方差,1标准差

吸取上面的教训,我们这次把初始化权重的标准差放大到1来看下吧。下面是与之前一样的例子,不过此时初始权重标准差为1。

这时我们可以看到,由于初始权重太大了,而导致计算的数据也很大,从而全部处于饱和区(-1或1,别忘了我们这是在tanh激活函数下的例子,不了解的可以看我之前的cs231n笔记)。我们知道,一旦陷入了饱和区,就没有回头的余地了,因为梯度约为0,模型基本就稳定而不继续学习了。

Xavier Initialization

在试过上面的几种情况后,我们基本能看出,初始化权重的标准差不宜太大,也不宜太小,否则模型都会夭折。所以 Glorot et al.于2010年发表了一种有效的初始化方法,成为Xavier Initialization。相比之前的只靠蒙的做法,Xavier方法利用了权重的扇入度作为标准差的衡量。

下面给出Python代码

W = np.random(fan_in, fan_out)/np.sqrt(fan_in)

接下来我们看看这种初始化方法的表现

可以看出,在10层里,每一层的数值都有比较好的分布。

似乎这下我们是找到了比较好的方法了,然后我们用ReLU替换tanh看下结果如何。

由于此时ReLU并非以零为中心的,我们可以看到每一层都有大量的数据落到饱和区0处,这显然不是我们所希望看到的。

再改进!

针对上面的问题,2015年He et al.提出了在sqrt(fan_in)里的值再除以2用以改进效果,下面给出python代码

W = np.random(fan_in, fan_out)/np.sqrt(fan_in/2)

然后我们来看下在ReLU下的表现

可以到相比之前,现在每一层的均值和方差都有比较好的改进,并且数据在坐标中的分布也比较平均,不会集聚在饱和区。

批归一化:Batch Normalization

然后可能就有读者吐槽了,既然希望每一层都有一个单位高斯分布,那为何不强制把它们处理成单位高斯分布区?

好,这时候loffe和Szegedy在2015年就提出了Batch Normalization的方法,注意这个并非权值初始化,这个是对每层的输出的数值的归一化处理,小心弄混了。

Batch Normalization的步骤与我们前面说到的数据预处理很想

1.zero-centered

x^=x?E[x]

2.normalized

x^=x^Var[x]??????√

3.允许网络对分布有所调整

y=γx^+β

注意到这里多了两个参数γ与β,因此我们一般也将BN的过程作为一层网络来处理

下面给出BN的python代码

"""代码来源:github,具体是哪个用户提供的我忘了记下来了"""
def batchnorm_forward(x, gamma, beta, bn_param):
    """
    Forward pass for batch normalization.
    During training the sample mean and (uncorrected) sample variance are
    computed from minibatch statistics and used to normalize the incoming data.
    During training we also keep an exponentially decaying running mean of the mean
    and variance of each feature, and these averages are used to normalize data
    at test-time.
    At each timestep we update the running averages for mean and variance using
    an exponential decay based on the momentum parameter:
    running_mean = momentum * running_mean + (1 - momentum) * sample_mean
    running_var = momentum * running_var + (1 - momentum) * sample_var
    Note that the batch normalization paper suggests a different test-time
    behavior: they compute sample mean and variance for each feature using a
    large number of training images rather than using a running average. For
    this implementation we have chosen to use running averages instead since
    they do not require an additional estimation step; the torch7 implementation
    of batch normalization also uses running averages.
    Input:
    - x: Data of shape (N, D)
    - gamma: Scale parameter of shape (D,)
    - beta: Shift paremeter of shape (D,)
    - bn_param: Dictionary with the following keys:
      - mode: ‘train‘ or ‘test‘; required
      - eps: Constant for numeric stability
      - momentum: Constant for running mean / variance.
      - running_mean: Array of shape (D,) giving running mean of features
      - running_var Array of shape (D,) giving running variance of features
    Returns a tuple of:
    - out: of shape (N, D)
    - cache: A tuple of values needed in the backward pass
    """
    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
    if mode == ‘train‘:

        # Forward pass
        # Step 1 - shape of mu (D,)
        mu = 1 / float(N) * np.sum(x, axis=0)

        # Step 2 - shape of var (N,D)
        xmu = x - mu

        # Step 3 - shape of carre (N,D)
        carre = xmu**2

        # Step 4 - shape of var (D,)
        var = 1 / float(N) * np.sum(carre, axis=0)

        # Step 5 - Shape sqrtvar (D,)
        sqrtvar = np.sqrt(var + eps)

        # Step 6 - Shape invvar (D,)
        invvar = 1. / sqrtvar

        # Step 7 - Shape va2 (N,D)
        va2 = xmu * invvar

        # Step 8 - Shape va3 (N,D)
        va3 = gamma * va2

        # Step 9 - Shape out (N,D)
        out = va3 + beta

        running_mean = momentum * running_mean + (1.0 - momentum) * mu
        running_var = momentum * running_var + (1.0 - momentum) * var

        cache = (mu, xmu, carre, var, sqrtvar, invvar,
                 va2, va3, gamma, beta, x, bn_param)
    elif mode == ‘test‘:

        mu = running_mean
        var = running_var
        xhat = (x - mu) / np.sqrt(var + eps)
        out = gamma * xhat + beta
        cache = (mu, var, gamma, beta, bn_param)

    else:
        raise ValueError(‘Invalid forward batchnorm mode "%s"‘ % mode)

    # Store the updated running means back into bn_param
    bn_param[‘running_mean‘] = running_mean
    bn_param[‘running_var‘] = running_var

    return out, cache

def batchnorm_backward(dout, cache):
    """
    Backward pass for batch normalization.
    For this implementation, you should write out a computation graph for
    batch normalization on paper and propagate gradients backward through
    intermediate nodes.
    Inputs:
    - dout: Upstream derivatives, of shape (N, D)
    - cache: Variable of intermediates from batchnorm_forward.
    Returns a tuple of:
    - dx: Gradient with respect to inputs x, of shape (N, D)
    - dgamma: Gradient with respect to scale parameter gamma, of shape (D,)
    - dbeta: Gradient with respect to shift parameter beta, of shape (D,)
    """
    dx, dgamma, dbeta = None, None, None

    mu, xmu, carre, var, sqrtvar, invvar, va2, va3, gamma, beta, x, bn_param = cache
    eps = bn_param.get(‘eps‘, 1e-5)
    N, D = dout.shape

    # Backprop Step 9
    dva3 = dout
    dbeta = np.sum(dout, axis=0)

    # Backprop step 8
    dva2 = gamma * dva3
    dgamma = np.sum(va2 * dva3, axis=0)

    # Backprop step 7
    dxmu = invvar * dva2
    dinvvar = np.sum(xmu * dva2, axis=0)

    # Backprop step 6
    dsqrtvar = -1. / (sqrtvar**2) * dinvvar

    # Backprop step 5
    dvar = 0.5 * (var + eps)**(-0.5) * dsqrtvar

    # Backprop step 4
    dcarre = 1 / float(N) * np.ones((carre.shape)) * dvar

    # Backprop step 3
    dxmu += 2 * xmu * dcarre

    # Backprop step 2
    dx = dxmu
    dmu = - np.sum(dxmu, axis=0)

    # Basckprop step 1
    dx += 1 / float(N) * np.ones((dxmu.shape)) * dmu

    return dx, dgamma, dbeta

后言

在实践中,一般都是使用均值归零,权重初始化一般是由Xavier,然后BN方法一般都要使用,放在FC层或Conv层之后。相信看到这里,读者对权重的初始化和批归一化都有了一个比较直观的了解,下一节我们将讲下剩下的权重更新策略Weights Update的方法以及Dropout。

时间: 2024-11-02 18:24:55

CS231n笔记4-Data Preprocessing, Weights Initialization与Batch Normalization的相关文章

CS231n笔记 Lecture 9, CNN Architectures

Review: LeNet-5 1998 by LeCun, one conv layer. Case Study: AlexNet [Krizhevsky et al. 2012] It uses a lot of mordern techniques where is still limited to historical issues (seperated feature maps, norm layers). Kind of obsolete, but it is the first C

[CS231n-CNN] Training Neural Networks Part 1 : activation functions, weight initialization, gradient flow, batch normalization | babysitting the learning process, hyperparameter optimization

课程主页:http://cs231n.stanford.edu/ ? Introduction to neural networks -Training Neural Network ______________________________________________________________________________________________________________________________________________________________

Batch normalization:accelerating deep network training by reducing internal covariate shift的笔记

说实话,这篇paper看了很久,,到现在对里面的一些东西还不是很好的理解. 下面是我的理解,当同行看到的话,留言交流交流啊!!!!! 这篇文章的中心点:围绕着如何降低  internal covariate shift 进行的, 它的方法就是进行batch normalization. internal covariate shift 和 batch normalization 1. 什么是 internal covariate shift呢? 简单地理解为一个网络或system的输入的dirs

cs231n笔记:线性分类器

cs231n线性分类器学习笔记,非翻译,根据自己的学习情况总结出的内容: 线性分类 本节介绍线性分类器,该方法可以自然延伸到神经网络和卷积神经网络中,这类方法主要有两部分组成,一个是评分函数(score function):是原始数据和类别分值的映射,另一个是损失函数:它是用来衡量预测标签和真是标签的一致性程度.我们将这类问题转化为优化问题,通过修改参数来最小化损失函数. 首先定义一个评分函数,这个函数将输入样本映射为各个分类类别的得分,得分的高低代表该样本属于该类别可能性的高低.现在假设有一个

cs231n笔记 (一) 线性分类器

线性分类器用作图像分类主要有两部分组成:一个是假设函数, 它是原始图像数据到类别的映射.另一个是损失函数,该方法可转化为一个最优化问题,在最优化过程中,将通过更新假设函数的参数值来最小化损失函数值. 从图像到标签分值的参数化映射 该方法的第一部分就是定义一个评分函数,这个函数将图像的像素值映射为各个分类类别的得分,得分高低代表图像属于该类别的可能性高低.下面会利用一个具体例子来展示该方法.现在假设有一个包含很多图像的训练集 $x_i \in \mathbb{R}^D$,每个图像都有一个对应的分类

iOS Swift学习笔记 Core Data (一)Hello Core Data

正在学习swift的Core Data,做个笔记,顺便分享源码 这个实例是一个很简单的Table,通过右上角的Add按钮可以添加新的用户名.数据存储在CoreData中,这样,才不会丢失. 通过这个例子可以学会: 使用Xcode的model编辑器创建数据对象的model data. 添加新的记录到CoreData中 从CoreData中获取记录集合 显示记录到table view中 这个例子十分简单,还有很多可以改进的地方,比如,每次要操作managed class都需要访问AppDelegat

c++primer学习笔记(2)-Variables(names initialization scope declare)

Initializers: 1.被初始化的变量在create那一瞬间得到值:double price = 109.99, discount = price * 0.6; 这样的定义是合理的. Three ways of initialization: 1. int units = 0; 2. int units = {0}; 3. int units{0}; 4. int units(0); 其中第2和第3为list initialization, 该初始化有一个特点:就是该初始化不允许有可能导

ExtJS笔记 Ext.data.Model

A Model represents some object that your application manages. For example, one might define a Model for Users, Products, Cars, or any other real-world object that we want to model in the system. Models are registered via the model manager, and are us

Python学习笔记(1)(Data Types)

Data Types 1,list 2,tuple 3,sets 4,dictionary,