batch normalization

μ B = 1 m ∑ i = 1 m x ( i ) \mu _{B} = \frac{1}{m} \sum_{i=1}^{m} x^{(i)} μB=m1i=1mx(i)
σ B 2 = 1 m ∑ i = 1 m ( x ( i ) − μ B ) 2 \sigma _{B}^{2} =\frac{1}{m} \sum_{i=1}^{m} \left ( x^{(i)} - \mu _{B} \right )^{2} σB2=m1i=1m(x(i)μB)2
X ^ ( i ) = X − μ B σ B 2 + ϵ \hat{X} ^{\left(i \right )}= \frac{X - \mu _{B}}{\sqrt{\sigma _{B}^{2}+ \epsilon }} X^(i)=σB2+ϵ XμB
y ( i ) = γ ⊙ X ^ ( i ) + β y^{\left(i \right )} = \gamma \odot \hat{X} ^{\left(i \right )} + \beta y(i)=γX^(i)+β
要学习的参数就是 γ \gamma γ β \beta β ,假如 X X X是(batch,features),那 γ \gamma γ的维度是 ( 1 , f e a t u r e s ) (1,features) (1features)
如果 X X X ( b a t c h , c h a n n e l , h e i g h t , w i d t h ) (batch,channel,height,width) (batchchannelheightwidth),那\gamma的维度是(1,channel,1,1)
测试的时候,由于没有批次,就可以用历史的 μ \mu μ σ 2 \sigma ^{2} σ2 E M A EMA EMA,或者保留每个批次的 μ \mu μ σ 2 \sigma ^{2} σ2,用样本估计总体的

#!/usr/bin/env python
# _*_ coding:utf-8 _*_
import torch
from torch import nn
 
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
 
 
def batch_norm(is_training, X, gamma, beta, moving_mean, moving_var, eps, momentum):
    # 判断当前模式是训练模式还是预测模式
    if not is_training:
        # 如果是在预测模式下,直接使用传入的移动平均所得的均值和方差
        X_hat = (X - moving_mean) / torch.sqrt(moving_var + eps)
    else:
        assert len(X.shape) in (2, 4)
        if len(X.shape) == 2:
            # 使用全连接层的情况,计算特征维上的均值和方差
            mean = X.mean(dim=0)
            var = ((X - mean) ** 2).mean(dim=0)
        else:
            # 使用二维卷积层的情况,计算通道维上(axis=1)的均值和方差。这里我们需要保持
            # X的形状以便后面可以做广播运算
            mean = X.mean(dim=0, keepdim=True).mean(dim=2, keepdim=True).mean(dim=3, keepdim=True)
            var = ((X - mean) ** 2).mean(dim=0, keepdim=True).mean(dim=2, keepdim=True).mean(dim=3, keepdim=True)
        # 训练模式下用当前的均值和方差做标准化
        X_hat = (X - mean) / torch.sqrt(var + eps)
        # 更新移动平均的均值和方差
        moving_mean = momentum * moving_mean + (1.0 - momentum) * mean
        moving_var = momentum * moving_var + (1.0 - momentum) * var
    Y = gamma * X_hat + beta  # 拉伸和偏移
    return Y, moving_mean, moving_var
 
 
class BatchNorm(nn.Module):
    def __init__(self, num_features, num_dims):
        super(BatchNorm, self).__init__()
        if num_dims == 2:
            shape = (1, num_features)
        else:
            shape = (1, num_features, 1, 1)
        # 参与求梯度和迭代的拉伸和偏移参数,分别初始化成01
        self.gamma = nn.Parameter(torch.ones(shape), True)
        self.beta = nn.Parameter(torch.zeros(shape), True)
        # 不参与求梯度和迭代的变量,全在内存上初始化成0
        self.moving_mean = torch.zeros(shape)
        self.moving_var = torch.zeros(shape)
 
    def forward(self, X):
        # 如果X不在内存上,将moving_mean和moving_var复制到X所在显存上
        if self.moving_mean.device != X.device:
            self.moving_mean = self.moving_mean.to(X.device)
            self.moving_var = self.moving_var.to(X.device)
        # 保存更新过的moving_mean和moving_var, Module实例的traning属性默认为true, 调用.eval()后设成false
        Y, self.moving_mean, self.moving_var = batch_norm(self.training,
                                                          X, self.gamma, self.beta, self.moving_mean,
                                                          self.moving_var, eps=1e-5, momentum=0.9)
        return Y
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Nightmare004

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

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

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

打赏作者

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

抵扣说明:

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

余额充值