PyTorch - BatchNorm2d

PyTorch - BatchNorm2d

flyfish

术语问题

在《深入浅出PyTorch》这本书中翻译成归一化
在花书《深度学习》书中翻译成标准化
在《深度学习之美》书中翻译成规范化
在《动手学深度学习》书中翻译成归一化
在《深度学习卷积神经网络从入门到精通》书中翻译成归一化
归一化,因为带了一字,容易被理解成将数据映射到[0,1], 而标准化有把数据映射到一个合理的分布的意思,翻译的不统一,容易造成讨论的概念不一致,可以参考

特征缩放(Feature_scaling)
我这里采用了 标准化 的翻译
PyTorch提供了
torch.nn.BatchNorm1d
torch.nn.BatchNorm2d
torch.nn.BatchNorm3d
这里以BatchNorm2d为例说明它的计算过程是怎样的

BatchNorm2d示例1:一个通道

import torch
import torch.nn as nn
input = torch.arange(0, 16).view(1,1,4,4).float()
# # tensor([[[[ 0.,  1.,  2.,  3.],
# #           [ 4.,  5.,  6.,  7.],
# #           [ 8.,  9., 10., 11.],
# #           [12., 13., 14., 15.]]]])

# With Learnable Parameters
m = nn.BatchNorm2d(1)
# Without Learnable Parameters
m = nn.BatchNorm2d(1, affine=False)
output = m(input)
print(output)

步骤
官网给的公式是
y = x − E [ x ] V a r [ x ] + ϵ ∗ γ + β y = \frac{x - \mathrm{E}[x]}{ \sqrt{\mathrm{Var}[x] + \epsilon}} * \gamma + \beta y=Var[x]+ϵ xE[x]γ+β
我们把公式分解
I n p u t : B = { x 1 , ⋯   , x m } \mathbf{Input}: \mathcal{B}=\{x_1,\cdots,x_m\} Input:B={x1,,xm},为m个样本组成的mini-batch 。

第一步:计算mini-batch均值

μ B ← 1 m ∑ i = 1 m x i \mu_{\mathcal{B}} \leftarrow \frac{1}{m} \sum_{i=1}^m x_i μBm1i=1mxi

第二步:计算mini-batch方差

σ B 2 ← 1 m ∑ i = 1 m ( x i − μ B ) 2 \sigma_{\mathcal{B}}^2 \leftarrow \frac{1}{m} \sum_{i=1}^m (x_i - \mu_{\mathcal{B}})^2 σB2m1i=1m(xiμB)2

第三步:标准化(normalize)

x ^ i ← x i − μ B σ B 2 + ϵ \hat{x}_i \leftarrow \dfrac{x_i-\mu_{\mathcal{B}}}{\sqrt{\sigma_{\mathcal{B}}^2+\epsilon}} x^iσB2+ϵ xiμB

第四步:缩放和平移(scale and shift)

y i ← γ x ^ i + β ≡ B N γ , β ( x i ) y_i \leftarrow \gamma \hat{x}_i+\beta \equiv \mathrm{BN}_{\gamma, \beta}(x_i) yiγx^i+βBNγ,β(xi)

因为上面是一个通道所以代码可以简写如下,这里是简写,后面的三个通道的例子是真正的计算过程,计算过程需要前三步

#第一步
first_mean= input.mean()#input的所有的数计算平均值 tensor(7.5000)
#第二步
second_variance=torch.pow(input-first_mean,exponent=2).mean()#tensor(21.2500)
#第三步
result=(input-first_mean)/(torch.sqrt(second_variance+1e-05))

输出结果都是

# tensor([[[[-1.6270, -1.4100, -1.1931, -0.9762],
#           [-0.7593, -0.5423, -0.3254, -0.1085],
#           [ 0.1085,  0.3254,  0.5423,  0.7593],
#           [ 0.9762,  1.1931,  1.4100,  1.6270]]]])

关于dim和keepdim的解释

import torch
x=torch.arange(24.0).view(2,3,4)
print(x.shape)#torch.Size([2, 3, 4])

#keepdim=True 仍然保持原来的大小,dim表示哪个维度变成1
#除了输出是1维,例如一维的10个数的平均数是一个数,结果是个标量。
print(torch.mean(x,dim=0,keepdim=True).shape)#torch.Size([1, 3, 4])
print(torch.mean(x,dim=1,keepdim=True).shape)#torch.Size([2, 1, 4])
print(torch.mean(x,dim=2,keepdim=True).shape)#torch.Size([2, 3, 1])

#keepdim=False是默认值,给dim赋值的维度会去除。
print(torch.mean(x,dim=0).shape)#torch.Size([3, 4])
print(torch.mean(x,dim=1).shape)#torch.Size([2, 4])
print(torch.mean(x,dim=2).shape)#torch.Size([2, 3])

像PyTorch这种(N, C, H, W)排列的维度是很直观的
从后往前看,
H和W就是二维的单通道图片
C个(H * W)当C=3时就是RGB通道的二维图片
N个 (C * H * W)就是N张这样的图片

BatchNorm2d示例2:三个通道的例子

import torch
import torch.nn as nn
input = torch.arange(0, 48).view(4,3,2,2).float()
# With Learnable Parameters
#m = nn.BatchNorm2d(3)
# Without Learnable Parameters
m = nn.BatchNorm2d(3, affine=False)
output = m(input)
print(output)

计算过程如下
去除维度 N,H,W,只留下C

import torch
input = torch.arange(0, 48).view(4,3,2,2).float()
eps=1e-5
mean = input.mean(dim=(0, 2, 3), keepdim=True)
var = torch.pow((input - mean) ,exponent= 2).mean(dim=(0, 2, 3), keepdim=True)
result = (input - mean) / torch.sqrt(var + eps)
print(result)

结果是两者输出结果相同

完整的参数说明

nn.BatchNorm2d(num_features)

应用批归一化即对小批量(mini-batch)数据组成的输入数据进行批标准化(Batch Normalization)操作,通过减少内部协变量偏移来加速深度网络训练。
1、num_features:
来自期望输入的特征数,该期望输入的大小为batch_size × num_features × height × width
输入输出相同)
输入Shape:(N, C, H, W)
输出Shape:(N, C, H, W)
2、eps: 为保证数值稳定性(分母不能趋近或取0),给分母加上的值。默认为1e-5。
3、momentum: 用于running_mean和running_var计算的值。 可以将累积移动平均线(cumulative moving average)(即简单平均线 simple average)设置为“无”。 默认值:0.1
3、affine: 一个布尔值,当设为true,给该层有可学习的仿射参数。
4、track_running_stats:一个布尔值,当设置为True时,此模块跟踪运行平均值和方差;设置为False时,此模块不跟踪此类统计信息,并且始终在训练和评估模式下使用批处理统计信息。 默认值:True

单纯的一个实现

import torch
def pure_batch_norm(X, gamma, beta, eps = 1e-5):
    if len(X.shape) not in (2, 4):
        raise ValueError('only supports dense or 2dconv')

    # dense
    if len(X.shape) == 2:
        # mini-batch mean
        mean = torch.mean(X, axis=0)
        # mini-batch variance
        variance = torch.mean((X - mean) ** 2, axis=0)
        # normalize
        X_hat = (X - mean) * 1.0 / torch.sqrt(variance + eps)
        # scale and shift
        out = gamma * X_hat + beta

    # 2d conv
    elif len(X.shape) == 4:
        # extract the dimensions
        N, C, H, W = X.shape
        # mini-batch mean
        mean = torch.mean(X, axis=(0, 2, 3))
        # mini-batch variance
        variance = torch.mean((X - mean.reshape((1, C, 1, 1))) ** 2, axis=(0, 2, 3))
        # normalize
        X_hat = (X - mean.reshape((1, C, 1, 1))) * 1.0 / torch.sqrt(variance.reshape((1, C, 1, 1)) + eps)
        # scale and shift
        out = gamma.reshape((1, C, 1, 1)) * X_hat + beta.reshape((1, C, 1, 1))

    return out

import torch
import torch.nn as nn
input = torch.arange(0, 48).view(4,3,2,2).float()

m = nn.BatchNorm2d(3, affine=False)
output = m(input)
print(output)

result = pure_batch_norm(input,
    gamma = torch.tensor([1,1,1]), #gammar和beta维度要和channel数相同,上面是3
    beta=torch.tensor([0,0,0]))

print(result)
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

西笑生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值