pytorch 批量归一化BatchNorm1d和BatchNorm2d的用法、BN层参数 running_mean running_var变量计算 验证

前提知识

在这里插入图片描述
BN层包括mean var gamma beta四个参数,。对于图像来说(4,3,2,2),一组特征图,一个通道的特征图对应一组参数,即四个参数均为维度为通道数的一维向量,图中gamma、beta参数维度均为[1,3]

在这里插入图片描述

其中gamma、beta为可学习参数(在pytorch中分别改叫weight和bias),训练时通过反向传播更新;

而running_mean、running_var则是在前向时先由X计算出mean和var,再由mean和var以动量momentum来更新running_mean和running_var。所以在训练阶段,running_mean和running_var在每次前向时更新一次;在测试阶段,不用再计算均值方差,则通过net.eval()固定该BN层的running_mean和running_var,此时这两个值即为训练阶段最后一次前向时确定的值,并在整个测试阶段保持不变。

class torch.nn.BatchNorm1d(num_features, eps=1e-05, momentum=0.1, affine=True) 
nn.BatchNorm2d(self, num_features, eps=1e-5, momentum=0.1, affine=True, track_running_stats=True)

1d

参数:
num_features: 来自期望输入的特征数,C from an expected input of size (N,C,L) or L from input of size (N,L)
eps: 为保证数值稳定性(分母不能趋近或取0),给分母加上的值。默认为1e-5。
momentum:滑动平均的参数,用来计算running_mean和running_var。默认为0.1。
track_running_stats,是否记录训练阶段的均值和方差,即running_mean和running_var
affine: 一个布尔值,当设为true,给该层添加可学习的仿射变换参数。

输入:(N, C)或者(N, C, L)
输出:(N, C)或者(N,C,L)(输入输出相同)

在每一个小批量(mini-batch)数据中,计算输入各个维度的均值和标准差。gamma与beta是可学习的大小为C的参数向量(C为输入大小)

2d

num_features: 来自期望输入的特征数,C from an expected input of size (N,C,H,W)
eps: 为保证数值稳定性(分母不能趋近或取0),给分母加上的值。默认为1e-5。
momentum: 动态均值和动态方差所使用的动量。默认为0.1。
affine: 一个布尔值,当设为true,给该层添加可学习的仿射变换参数,表示weight和bias将被使用
输入:(N, C,H, W) 输出:(N, C, H, W)(输入输出相同)

BN层的状态包含五个参数:

weight,缩放操作的γ gamma。
bias,缩放操作的β beta。
running_mean,训练阶段统计的均值,测试阶段会用到。
running_var,训练阶段统计的方差,测试阶段会用到。
num_batches_tracked,训练阶段的batch的数目,如果没有指定momentum,则用它来计算running_mean和running_var。一般momentum默认值为0.1,所以这个属性暂时没用。
weight和bias这两个参数需要训练,而running_mean、running_val和num_batches_tracked不需要训练,它们只是训练阶段的统计值。

running_mean running_var的计算

在训练时,BN层计算每次输入的均值与方差,并进行移动平均。移动平均默认的动量值为0.1。初始值running_mean=0.running_var=1

在这里插入图片描述
参数更新是以差分的形式进行的,xt代表新一轮batch产生的数据,x^代表历史数据,这个参数越大,代表当前batch产生的统计数据的重要性越强。0.1表示当前batch统计数据占0.1.

对于此处,可表示为:
在这里插入图片描述

在推理时,训练求得的均值/方差将用于标准化验证数据。

code 验证

gamma beta 分别针对 2个【5 5】的矩阵进行计算。



import torch
import torch.nn as nn
m = nn.BatchNorm2d(2, affine=False)
m1 = nn.BatchNorm2d(2, affine=True)
input = torch.randn(1,2,5, 5)
input = torch.tensor([[[[ 0.92767,  0.56841, -1.68725, -0.01806,  1.31190],
          [-0.95227,  1.52581, -1.21351,  0.06448,  2.72040],
          [-0.67488,  0.83880, -2.02831, -0.28432, -0.43458],
          [-1.96451, -0.15065, -1.87039,  0.13661,  0.25373],
          [-0.59261,  1.09675, -0.00749, -0.63954, -1.72408]],

         [[-1.04556, -0.07648, -0.42020,  0.06401, -1.15629],
          [ 0.77445, -0.23579, -1.26846, -0.09803,  1.07262],
          [-2.15755, -0.77489,  0.50311,  0.22077,  0.93678],
          [ 0.82926, -0.04959, -0.42568,  0.58730,  1.63708],
          [ 0.92501,  1.85740,  0.96766,  0.71574, -0.62078]]]])
output = m(input)

print(input, '\n',output,'\n',output1)

print(m.weight)#None
print(m.bias) #None
print(m1.weight)   #1
print(m1.bias)     #0
print(m1.running_mean) # init_mean=0,init_var=1     
print(m1.running_var)#0.1 更新
running_mean_init=m1.running_mean
running_var_init=m1.running_var


print("输入的第一个维度:")
print(input[0][0]) #这个数据是第一个3*4的二维数据

#求第一个维度的均值和方差
firstDimenMean=torch.Tensor.mean(input[0][0])
firstDimenMean   # -0.19192
firstDimenVar=torch.Tensor.var(input[0][0],True)   #false表示贝塞尔校正不会被使用#True BN层默认的是用的贝塞尔验证 tensor(1.45355)  False:tensor(1.39540)
firstDimenVar    # 1.3954

output1 = m1(input)

print(firstDimenMean)
print(firstDimenVar)


print(m1.running_mean) # init_mean=0,init_var=1     
print(m1.running_var)#0.1 更新
# 验证更新runing-mean var的计算,每计算一次BN,就会更新一次
running_mean_update=running_mean_init.numpy() *0.9+0.1*firstDimenMean.numpy()
running_var_update =running_var_init.numpy()*0.9  + 0.1*firstDimenVar.numpy()

batchnormone=((input[0][0][0][0]-firstDimenMean)/(torch.pow(firstDimenVar,0.5)+m1.eps))*m1.weight[0]+m1.bias[0]
print(batchnormone)
print(output1[0][0][0][0]) 

上面计算方差时有一个贝塞尔校正系数,具体可以通过如下链接参考:https://www.jianshu.com/p/8dbb2535407e

从公式上理解即在计算方差时一般的计算方式如下:

在这里插入图片描述
通过贝塞尔校正的样本方差如下:
在这里插入图片描述
目的是在总体中选取样本时能够防止边缘数据不被选到。详细的理解可以参考上面的链接。

<think>嗯,用户想了解PyTorchBatch Normalization(BN)在训练推理模式下的实现区别。首先,我需要回忆一下BN的基本原理。BN通过对每个批次的数据进行归一化,减少内部协变量偏移,加速训练。在训练时,BN计算当前批次的均值方差,并用它们来归一化数据,同时更新运行均值(running_mean运行方差(running_var)。而在推理时,BN使用这些运行统计量来进行归一化,而不是当前批次的,以保证稳定输出。 接下来,用户可能想知道PyTorch中如何具体实现这两种模式。我记得在PyTorch的`nn.BatchNorm2d`(或其他BN)中,`training`属性控制模式。当调用`model.train()`时,所有模块包括BN会切换到训练模式,使用当前批次的统计量;而`model.eval()`则切换到评估模式,使用运行统计量。此外,在训练过程中,运行均值方差是通过指数移动平均更新的,具体由动量参数控制。 用户可能还关心代码面的具体实现。比如,在训练模式下,前向传播时BN计算当前批次的均值方差,并更新running_meanrunning_var。而在推理模式下,直接使用running_meanrunning_var进行归一化。需要注意,在验证或测试时,必须手动切换到eval模式,否则BN的行为可能不符合预期,影响模型性能。 另外,用户提到的引用[1]提到在评估时使用model.eval()的重要性,即使不确定模型是否有特定行为。这可能涉及到BN之外的模块,如Dropout,但BN尤其关键,因为其行为在两种模式下确实不同。如果忘记设置eval模式,BN继续使用批次统计量,可能导致输出不稳定,尤其是在批次大小较小或数据分布变化时。 可能还需要解释动量参数的作用。动量决定了在更新running_meanrunning_var时,历史信息新批次统计量的权重。例如,动量0.1意味着每次更新保留90%的历史值,加上10%的新批次统计量。这有助于平滑训练过程中的波动,使得运行统计量更稳定。 最后,用户可能需要知道如何在实际代码中应用这些知识。例如,在训练循环中,每次迭代前调用model.train(),前向传播后计算损失反向传播;在验证时调用model.eval(),并可能使用torch.no_grad()来节省内存加速计算。同时,确保在保存加载模型时,running_meanrunning_var也被正确处理,以便在推理时正确使用。 总结一下,用户的问题需要分步骤解释BN的原理、训练与推理模式的区别、PyTorch中的具体实现方式,以及实际应用中的注意事项。同时,结合用户提供的引用[1],强调正确使用train()eval()的重要性,确保BN其他可能模块的正确行为。</think>### PyTorchBatch Normalization的训练与推理模式实现差异 #### 一、核心原理与数学表达 Batch Normalization(BN)通过标准化神经网络中间的输入分布来加速训练,其核心公式为: $$ \hat{x} = \frac{x - \mu_B}{\sqrt{\sigma_B^2 + \epsilon}} \quad y = \gamma \hat{x} + \beta $$ 其中: - $x$是输入数据 - $\mu_B$是当前批次的均值 - $\sigma_B^2$是当前批次的方差 - $\gamma$$\beta$是可学习的缩放偏移参数[^1] #### 二、训练模式(training=True) 1. **统计量计算** 每次前向传播时动态计算当前批次的均值方差: $$ \mu_B = \frac{1}{m} \sum_{i=1}^{m} x_i $$ $$ \sigma_B^2 = \frac{1}{m} \sum_{i=1}^{m} (x_i - \mu_B)^2 $$ 2. **运行统计量更新** 通过指数移动平均(EMA)更新全局统计量: ```python running_mean = momentum * running_mean + (1 - momentum) * batch_mean running_var = momentum * running_var + (1 - momentum) * batch_var ``` 其中动量参数`momentum`默认为0.1 3. **梯度传播** BN参与反向传播,更新$\gamma$$\beta$参数 #### 三、推理模式(training=False) 1. **固定统计量** 使用训练阶段积累的全局统计量: $$ \hat{x} = \frac{x - running\_mean}{\sqrt{running\_var + \epsilon}} $$ 2. **参数冻结** $\gamma$$\beta$保持训练后的最终值,不更新运行统计量 #### 四、PyTorch实现示例 ```python import torch.nn as nn # 定义BN(以2D为例) bn = nn.BatchNorm2d(num_features=64, momentum=0.1) # 训练模式(默认) model.train() output = bn(input_tensor) # 使用当前批次统计量 # 推理模式 model.eval() with torch.no_grad(): output = bn(input_tensor) # 使用running_mean/running_var ``` #### 五、关键差异对比 | 特性 | 训练模式 | 推理模式 | |--------------------|------------------|------------------| | 统计量来源 | 当前批次 | 全局累计值 | | 梯度计算 | 启用 | 禁用(通常) | | 运行统计量更新 | 是 | 否 | | Dropout等行为 | 激活 | 禁用 | | 内存占用 | 较高(保存中间值)| 较低 | #### 六、注意事项 1. 使用`model.eval()`会自动设置所有BN为推理模式 2. 在验证/测试时必须显式调用`eval()`,否则会导致统计量污染 3. 分布式训练时需同步多卡的BN统计量 4. Batch Size较小时建议使用`BatchNorm1d`的`track_running_stats=False`选项
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值