Batch Normalization
Batch Normalization: 批标准化
- 批:一批数据,通常为mini-batch
- 标准化:0均值,1方差
优点:
1、可以用更大的学习率,加速模型的收敛
2、可以不用精心设计权值初始化
3、可以不用dropout或者较小的dropout
4、可以不用L2或者较小的weight decay
5、可以不用LRN(local response normalization)
计算方式
代码
import torch
import numpy as np
import torch.nn as nn
import sys, os
hello_pytorch_DIR = os.path.abspath(os.path.dirname(__file__)+os.path.sep+".."+os.path.sep+"..")
sys.path.append(hello_pytorch_DIR)
from tools.common_tools import set_seed
set_seed(1) # 设置随机种子
class MLP(nn.Module):
def __init__(self, neural_num, layers=100):
super(MLP, self).__init__()
self.linears = nn.ModuleList([nn.Linear(neural_num, neural_num, bias=False) for i in range(layers)])
self.bns = nn.ModuleList([nn.BatchNorm1d(neural_num) for i in range(layers)])
self.neural_num = neural_num
def forward(self, x):
for (i, linear), bn in zip(enumerate(self.linears), self.bns):
x = linear(x)
# x = bn(x)
x = torch.relu(x)
if torch.isnan(x.std()):
print("output is nan in {} layers".format(i))
break
print("layers:{}, std:{}".format(i, x.std().item()))
return x
def initialize(self):
for m in self.modules():
if isinstance(m, nn.Linear):
# method 1
nn.init.normal_(m.weight.data, std=1) # normal: mean=0, std=1
# method 2 kaiming
# nn.init.kaiming_normal_(m.weight.data)
neural_nums = 256
layer_nums = 100
batch_size = 16
net = MLP(neural_nums, layer_nums)
# net.initialize()
inputs = torch.randn((batch_size, neural_nums)) # normal: mean=0, std=1
output = net(inputs)
print(output)
不进行权值初始化的结果
我们可以看到在第99层得到的方差是非常小的,导致网络模型无法使用。梯度消失。
对权值进行初始化,采用均值为0,标准差为1的正态分布
取消net.initialize()的注释,我们可以从下图发现,标准差特别大,而且在第35层出现了nan。梯度爆炸。
采用kaiming方法进行权值初始化
此时我们的数据尺度有一个很好的分布,标准差前后相差不大。
加入BN层
效果更好。
使用BN层的同时不进行权值初始化
效果仍然很好,所以有了BN层我们可以不用精心设置权值初始化,甚至可以不进行权值初始化。
RMB二分类的BN层效果
1、原始LeNet,不进行权值初始化
2、原始LeNet,进行权值初始化
3、有BN层的LeNet,不进行权值初始化
在LeNet的每一个卷积后添加BN层。
_BatchNorm
__init__(self, num_features, eps=1e-5, momentum=0.1, affine=True, track_running_stats=True)
nn.BatchNorm1d
nn.BatchNorm2d
nn.BatchNorm3d
参数:
- num_features: 一个样本特征数量
- eps:分母修正项
- momentum: 指数加权平均估计当前mean/var
- affine: 是否需要affine transform
- track_running_stats: 是训练状态还是测试状态
主要属性:
- running_mean: 均值
- running_var: 方差
- weight: affine transform 中的gamma
- bias: affine transform 中的beta
训练:均值和方差采用指数加权平均计算
测试:当前统计值
running_mean = (1-momentum) * pre_running_mean + momentum * mean_t
running_var = (1-momentum) * pre_running_var + momentum * var_t