Batch Normalization的解释

输入的标准化处理是对图片等输入信息进行标准化处理,使得所有输入的均值为0,方差为1

normalize = T.Normalize([0.485, 0.456, 0.406],[0.229, 0.224, 0.225])

 

而Batch Normalization的目的是使各隐藏层输入的均值和方差为任意值

Batch Norm经常使用在mini-batch上,这也是其名称的由来

Batch Normalization是对下面隐藏层进行激活函数操作前的输入Z[l]进行标准层处理

Z^{[l]}=W^{[l]}A^{[l-1]}+b^{[l]}

进行的操作有:

1)对输入进行归一化操作

  • m是单个mini-batch包含样本个数
  • \varepsilon 是为了防止分母为零,可取值 10^{-8}

\mu=\frac1m\sum_iz^{(i)}

\sigma^2=\frac1m\sum_i(z_i-\mu)^2

z^{(i)}_{norm}=\frac{z^{(i)}-\mu}{\sqrt{\sigma^2+\varepsilon}}

 此时的输入Z[i]变为了均值为0,方差为1的Znorm[i]

 

2)对归一化的结果进行缩放和平移

但是大部分情况下我们其实并不希望输入均值为0,方差为1,而是希望其根据训练的需要而设置为任意值

这个时候就需要进一步处理:

\tilde z^{(i)}=\gamma\cdot z^{(i)}_{norm}+\beta

\gamma 和 \beta 是可以学习的参数,类似于W和b一样,可以通过梯度下降等算法求得

当两者的值为\gamma=\sqrt{\sigma^2+\varepsilon},\ \ \beta=u,那么\tilde z^{(i)}=z^{(i)},实现恒等映射

为什么需要进行这一步的处理:

从激活函数的角度来说,如果各隐藏层的输入均值在靠近0的区域即处于激活函数的线性区域,这样不利于训练好的非线性神经网络,得到的模型效果也不会太好

 

如resnet网络中的使用:

#这个实现的是两层的残差块,用于resnet18/34
class BasicBlock(nn.Module):
    expansion = 1

    def __init__(self, inplanes, planes, stride=1, downsample=None):
        super(BasicBlock, self).__init__()
        self.conv1 = conv3x3(inplanes, planes, stride)
        self.bn1 = nn.BatchNorm2d(planes)
        self.relu = nn.ReLU(inplace=True)
        self.conv2 = conv3x3(planes, planes)
        self.bn2 = nn.BatchNorm2d(planes)
        self.downsample = downsample
        self.stride = stride

    def forward(self, x):
        identity = x

        out = self.conv1(x)
        out = self.bn1(out)
        out = self.relu(out)

        out = self.conv2(out)
        out = self.bn2(out)

        if self.downsample is not None: #当连接的维度不同时,使用1*1的卷积核将低维转成高维,然后才能进行相加
            identity = self.downsample(x)

        out += identity
        out = self.relu(out)

        return out

 

posted @ 2019-04-28 12:08  慢行厚积  阅读(1675)  评论(0编辑  收藏  举报