python batch normalization_Batch Normalization原理与python实现

为了保证深度神经网络训练过程的稳定性,经常需要细心的选择初始化方式,并且选择较小的学习率数值,这无疑增加了任务的复杂性。为此,Google团队提出了Batch Normalization【1】方法(简称BN)用于帮助网络更好的训练。

1、理论分析

BN计算的第一步是对每一层进行独立的归一化:

其中k表示第k维特征,E表示求期望,Var表示求方差。这种归一化操作可能会改变这层的表示,所以作者提出了“identity transform”如下:

其中r(k)和B(k)是两个需要通过网络训练学习的参数,这两个参数随着迭代进行动态的更新,当下述情况时:

此时输出和输入就是完全相同的,都是x(k)。注释:identity transform,个人理解其目的是使得输出和输入相同,即不改变层的表示

综上,实现BN需要求的:均值、方差、参数beta、参数gamma。对应的算法流程如下,需要注意的是,Normalization的计算是对“每个特征”分别进行的:

2、python实现

2.1 数据和各个变量的含义

在使用类似pytorch的框架时发现,由于每个mini-batch中的数据是不同的,所以需要统计整个数据集中的均值和方差需要动态的追踪各个mini-batch(进行实现的时候参考了pytorch的BN文档【7】,其源码很多部分已经迁移到了C++所以分析起来比较困难),动态统计方式如下:

这里的“x”不是论文中的“x”,这里表示running_mean和runnning_var的更新权重。首先定义将要使用的数据:

data = np.array([[1, 2],

[1, 3],

[1, 4]]).astype(np.float32)

然后采用pytorch提供的BatchNorm1d模块进行测试,确保自己代码获得的结果能够和pytorch一致:

bn_torch = nn.BatchNorm1d(num_features=2)

data_torch = torch.from_numpy(data)

bn_output_torch = bn_torch(data_torch)

print(bn_output_torch)

得到的输出如下:

tensor([[ 0.0000, -1.1526],

[ 0.0000, 0.0000],

[ 0.0000, 1.1526]], grad_fn=)

2.2 前向传播实现

因为BN计算过程中需要保存running_mean和running_var,以及更新动量momentum和防止数值计算错误的eps,所以需要设计为类,并用实例属性来保存这些值,下面是初始化方法:

class MyBN:

def __init__(self, momentum, eps, num_features):

"""初始化参数值:param momentum: 追踪样本整体均值和方差的动量:param eps: 防止数值计算错误:param num_features: 特征数量"""

# 对每个batch的mean和var进行追踪统计

self._running_mean = 0

self._running_var = 1

# 更新self._running_xxx时的动量

self._momentum = momentum

# 防止分母计算为0

self._eps = eps

# 对应论文中需要更新的beta和gamma,采用pytorch文档中的初始化值

self._beta = np.zeros(shape=(num_features, ))

self._gamma = np.ones(shape=(num_features, ))

初始化中_beta和_gamma对应于BN中需要学习的参数,分别初始化为0和1,接下来就是前向传播的实现:

def batch_norm(self, x):

"""BN向传播:param x: 数据:return: BN输出"""

x_mean = x.mean(axis=0)

x_var = x.var(axis=0)

# 对应running_mean的更新公式

self._running_mean = (1-self._momentum)*x_mean + self._momentum*self._running_mean

self._running_var = (1-self._momentum)*x_var + self._momentum*self._running_var

# 对应论文中计算BN的公式

x_hat = (x-x_mean)/np.sqrt(x_var+self._eps)

y = self._gamma*x_hat + self._beta

return y

由于pytorch中的BatchNorm中beta和gamma初始化并不是0和1,为了保证初始化值一样,将自己定义的类的beta和gamm替换为torch初始化的值,进行如下测试:

my_bn = MyBN(momentum=0.01, eps=0.001, num_features=2)

my_bn._beta = bn_torch.bias.detach().numpy()

my_bn._gamma = bn_torch.weight.detach().numpy()

bn_output = my_bn.batch_norm(data, )

print(bn_output)

得到的结果和torch的结果一致:

[[ 0. -1.1517622]

[ 0. 0. ]

[ 0. 1.1517622]]

参考:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值