在神经网络训练时,还涉及到一些tricks,如网络权重的初始化方法,优化器种类(权重更新),图片预处理等,继续填坑。

1. 神经网络初始化(Network Initialization )

  1.1 初始化原因

    我们构建好网络,开始训练前,不能默认的将所有权重系数都初始化为零,因为所有卷积核的系数都相等时,提取特征就会一样,反向传播时的梯度也会存在对称性,网络会退化会线性模型。另外网络层数较深时,初始化权重过大,会出现梯度爆炸,而过小又会出现梯度消失。一般权重初始化时需要考虑两个问题:

    (1)权重参数全部相同时,会有梯度更新对称性问题(详细见https://www.zhihu.com/question/36068411?sort=created)

        如下图中w,b系数都相同时,a1,a2,a3的值也会相同,反过来进行梯度更新时,w,b也是按相同的速率在更新。(不管是哪个神经元,它的前向传播和反向传播的算法都是一样的,如果初始值也一样的话,不管训练多久,它们最终都一样,都无法打破对称(fail to break the symmetry),那每一层就相当于只有一个神经元,最终L层神经网络就相当于一个线性的网络,如Logistic regression)

      pytorch基础学习(二)

    (2)采用饱和激活函数时,进行随机初始化时,权重分布会使神经元输出处于激活函数的梯度饱和区域。

      (详细见:https://www.jianshu.com/p/03009cfdf733)

  1.2 初始化方法

    常用初始化方法有Gaussain initialization, Xavier initialization, Kaiming(MSRA) initialization 。pytorch的torch.nn.init模块中包含了常用的初始化函数。

    Gaussian initialization:   采用高斯分布初始化权重参数

      nn.init.normal_(tensor, mean=0, std=1) 能实现不同均值和标准差的高斯分布

      nn.init.unoform_(tensor, a=0, b=1) 能实现(a, b)范围内的均匀分布   

import torch
import torch.nn as nn
w = torch.empty(3, 5)
nn.init.uniform_(w, a=0, b=1)      #初始化为(0, 1)范围内的均匀分布
nn.init.normal_(w, mean=0, std=1)  #初始化为均值为0, 标准差为1的正态分布
nn.init.constant_(w, 0.3)          # 全部初始化为常量值0.3
nn.init.eye_(w)                     # 初始化为单位矩阵(对角线为1)
print(w)

    Xavier Initialization: 均值为0, 标准差根据输入神经元和输出神经元的参数个数决定,适合采用tanh和sigmoid等激活函数的模型,详细见下面论文

        论文:Understanding the difficulty of training deep feedforward neural networks

        nn.init.xavier_uniform_(tensor, gain=1): 根据xavier,实现了(-a, a)范围内的均匀分布,其中a的计算公式如下:

pytorch基础学习(二)

                        gain:增益,可以理解为缩放倍数,

                        fan_in: in_channel*Kw*Kh   (输入channel个数, kernel的宽和高)

                        fan_out: out_channel*Kw*Kh   (输出channel个数, kernel的宽和高)

        nn.init.xavier_normal_(tensor, gain=1): 根据xavier,实现了mean=0, std=std 的高斯分布,其中std的计算公式如下:

pytorch基础学习(二)

w = torch.empty(3, 3, 5, 5)          #fan_in=75, fan_out=75
nn.init.xavier_uniform_(w, gain=1)   #初始化为(-sqrt(6/150), sqrt(6/150))范围内的均匀分布
nn.init.xavier_normal_(w, gain=1)    #初始化为mean=0, std=sqrt(2/150)的正态分布

         关于fan_in和fan_out的计算方式,pytorch的实现代码如下:

pytorch基础学习(二)
def _calculate_fan_in_and_fan_out(tensor):
    dimensions = tensor.ndimension()
    if dimensions < 2:
        raise ValueError("Fan in and fan out can not be computed for tensor with fewer than 2 dimensions")

    if dimensions == 2:  # Linear
        fan_in = tensor.size(1)
        fan_out = tensor.size(0)
    else:
        num_input_fmaps = tensor.size(1)
        num_output_fmaps = tensor.size(0)
        receptive_field_size = 1
        if tensor.dim() > 2:
            receptive_field_size = tensor[0][0].numel()
        fan_in = num_input_fmaps * receptive_field_size
        fan_out = num_output_fmaps * receptive_field_size

    return fan_in, fan_out
计算fan_in和fan_out

相关文章: