本笔记大量参考该博客,进行了少量的修改,感谢作者的付出。 【面试向】Batch Normalization | 某科学のBLOG (a-kali.github.io)
定义自己的 BN 类
我们分成 2D 和 1D 数据,分别定义对应的 BatchNrom2D 和 BatchNorm2D
首先明确 BN 在训练和测试的时候区别,在定义类需要输入的参数是 momentum, in_channels。
在写前向传播时,区分好训练和测试前提下不同的操作即可
BatchNorm 2D 的代码
注意输入的数据 input 应该是 numpy () 格式的数组。
class BatchNorm2D:
def __init__(self, channels, momentum=0.1, eps=1e-5) -> None:
self.momentum = momentum
self.eps = eps
# 滑动均值和方差
self.running_mean = np.zeros(channels)# 均值初始化为 0
self.running_var = np.ones(channels) # 注意方差初始化为 1
self.training = True
self.beta = 0
self.gamma = 1
# 下面两个是更改操作模式
def eval(self):
self.traning = False
def train(self):
self.traning = True
def forward(self, input):
out = np.zeros(input.shape)
B, C, H, W = input.shape
for i in range(C):
cur = input[:, i, :, :] # 取出当前的通道
N = cur.size # 元素总数量
if self.training:
# 计算均值和方差, 并归一化
mean = cur.sum() / N
var = ((cur - mean)**2).sum() / N
cur_out = (cur - mean) / (var + self.eps) **0.5
# 计算方差的无偏估计,利用方差的无偏估计并更新滑动值
var_unbias = ((cur - mean)**2).sum() / (N - 1)
self.running_mean[i] = (1 - self.momentum) * self.running_mean[i] + self.momentum * mean
self.running_var[i] = (1 - self.momentum) * self.running_var[i] + self.momentum * var_unbias
else:
cur_out = (cur - self.running_mean[i]) / (self.running_val[i] + self.eps) **0.5
# 缩放平移
out[:, i,:,:] = self.gamma * cur_out + self.beta
return outBatchNorm 1D 的代码 与 2D 的代码类似,只不过 1D 时没有 channel 了,输入数据的维度是 [B, D]. B 是 batch size
class BatchNorm1D:
def __init__(self, momentum=0.1, eps=1e-5) -> None:
self.momentum = momentum
self.eps = eps
self.gamma = 1
self.beta = 0
self.running_var = 1
self.running_mean = 0
self.training = True
def eval(self):
self.training = False
def train(self):
self.training = True
def forward(self, input):
N = input.size
out = np.zeros(input.shape)
if self.training:
mean = input.sum() / N
var = ((input - mean) ** 2).sum() / N
out = (out - mean) / (var + self.eps) ** 0.5
var_unbiased = ((input - mean) ** 2).sum() / (N - 1)
self.running_mean = (1 - self.momentum) * self.running_mean + self.momentum * mean
self.running_var = (1 - self.momentum) * self.running_var + self.momentum * var_unbiased
else:
out = (out - self.running_mean) / (self.running_var + self.eps) ** 0.5
return self.gamma * out + self.beta主函数
if __name__ == '__main__':
# 生成2D数据并进行测试
input_data = np.random.random([2,3,5,5])
bn2d = BatchNorm2D(input_data.shape[1])
print(bn2d.forward(input_data))
print('--------')
# 生成1D数据并进行测试
input_data = np.random.random([2,3])
bn1d = BatchNorm1D()
print(bn1d.forward(input_data))