深度学习代码|Batch Normalization批归一化的代码实现

本文详细介绍了深度学习中批量归一化层(BatchNorm)的理论背景,包括其在图像、嵌入和序列嵌入中的应用,以及如何通过PyTorch实现。着重讲解了层的初始化参数、计算流程和拉伸与偏移参数的作用。
摘要由CSDN通过智能技术生成


一、导入相关库

import torch
from torch import nn
from labml_helpers.module import Module

二、批量归一化层BatchNorm

(一)理论基础

  1. 当输入 X ∈ R B × C × H × W X\in \mathbb{R}^{B\times C\times H\times W} XRB×C×H×W是一批图像表示时: B N ( X ) = γ X − E B , H , W [ X ] V a r B , H , W [ X ] + ϵ + β BN(X)=\gamma \frac{X- \mathbb{E}_{B,H,W}[X]}{\sqrt{Var_{B,H,W}[X]+\epsilon}}+\beta BN(X)=γVarB,H,W[X]+ϵ XEB,H,W[X]+β
  2. 当输入 X ∈ R B × C X\in \mathbb{R}^{B\times C} XRB×C是一批嵌入时: B N ( X ) = γ X − E B [ X ] V a r B [ X ] + ϵ + β BN(X)=\gamma \frac{X- \mathbb{E}_{B}[X]}{\sqrt{Var_{B}[X]+\epsilon}}+\beta BN(X)=γVarB[X]+ϵ XEB[X]+β
  3. 当输入 X ∈ R B × C × L X\in \mathbb{R}^{B\times C\times L} XRB×C×L是一批序列嵌入时: B N ( X ) = γ X − E B , L [ X ] V a r B , L [ X ] + ϵ + β BN(X)=\gamma \frac{X- \mathbb{E}_{B,L}[X]}{\sqrt{Var_{B,L}[X]+\epsilon}}+\beta BN(X)=γVarB,L[X]+ϵ XEB,L[X]+β

B:批次大小,C:通道数/特征数,H:高度,W:宽度,L:顺序

(二)代码实现

  • __init__函数:
    • channels:输入中的特征数
    • eps: ϵ \epsilon ϵ, 用于数值稳定性
    • momentum:更新指数移动平均值的动量参数
    • affine:是否使用可学习的拉伸和偏移参数
    • track_running_stats:计算移动平均线还是均值和方差

动量参数控制着对当前批次计算得到的均值和方差与之前计算的指数移动平均的均值和方差之间的权衡。

  • forward 方法实现了批标准化的前向计算过程。
    • 将输入张量 x 重塑为 (batch_size, channels, -1) 的形状,以便在每个通道上计算均值和方差。
    • 计算当前批次的均值和方差,或者使用保存的指数移动平均的均值和方差。
    • 接着对输入进行标准化,并根据是否使用可学习参数来对标准化后的结果进行拉伸和偏移。
    • 最后将结果重塑回原来的形状并返回。
  • register_buffer 是 PyTorch 中 Module 类的方法之一,用于将张量缓冲区注册到模型中,以便在模型的状态中进行跟踪。这些缓冲区在模型的训练和推理过程中保持不变,可以用于存储模型的状态信息,如均值、方差等。
  • 使用 register_buffer 方法的好处是,这些缓冲区不会被包括在模型的参数列表中,因此在模型进行优化时不会更新它们的值。这使得它们适用于存储在训练过程中需要持久化的状态信息,而不会被认为是需要训练的参数。
class BatchNorm(Module):
	def __init__(self,channels:int,*,
							eps:float=1e-5,momentum:float=0.1,
							affine:bool=True,track_running_stats:bool=True):
		super().__init__()
		self.channels=channels
		self.eps=eps
		self.momentum=momentum
		self.affine=affine
		self.track_running_stats=track_running_stats
		#如果 affine=True,则创建可学习的拉伸和偏移参数 scale 和 shift
		if self.affine:
			self.scale=nn.Parameter(torch.ones(channels))
			self.shift=nn.Parameter(torch.zeros(channels))
		#如果 track_running_stats=True,则创建exp_mean 和 exp_var,用于保存指数移动平均的均值和方差
		if self.track_running_stats:
			self.register_buffer('exp_mean',torch.zeros(channels))
			self.register_buffer('exp_var',torch.ones(channels))
		
	def forward(self,x:torch.Tensor):
		#获取输入张量的形状,并确保通道数与 channels 参数相同
		x_shape=x.shape
		batch_size=x_shape[0]
		assert self.channels==x.shape[1]
		x=x.view(batch_size,self.channels,-1)
		if self.training or not self.track_running_stats:
			#计算输入张量 x 在第 0 和第 2 个维度上的均值
			mean=x.mean(dim=[0,2])
			mean_x2=(x**2).mean(dim=[0,2])
			var=mean_x2-mean**2
			#在训练过程中更新指数移动平均的均值和方差
			if self.training and self.track_running_stats:
				self.exp_mean=(1-self.momentum)*self.exp_mean+self.momentum*mean
				self.exp_var=(1-self.momentum)*self.exp_var+self.momentum*var
		else:
			mean=self.exp_mean
			var=self.exp_var
		#归一化
		x_norm=(x-mean.view(1,-1,1))/torch.sqrt(var+self.eps).view(1,-1,1)
		#拉伸和偏移
		if self.affine:
			x_norm=self.scale.view(1,-1,1)*x_norm+self.shift.view(1,-1,1)
		return x_norm.view(x_shape)

在批标准化中,拉伸(scale)和偏移(shift)是可学习的参数,它们的作用如下:

  • 拉伸(Scale):拉伸参数通常用一个可学习的缩放因子来表示,它乘以标准化后的特征值,用于调整特征的尺度。通过拉伸参数,批标准化能够在保持数据的零均值和单位方差的同时,对每个特征进行适当的缩放,从而提高网络的表达能力。如果数据在某个特征上有较大的方差,拉伸参数可以将其缩小;反之,如果数据在某个特征上有较小的方差,拉伸参数可以将其放大。
  • 偏移(Shift):偏移参数通常用一个可学习的偏移量来表示,它加到标准化后的特征值上,用于调整特征的平移。通过偏移参数,批标准化能够在保持数据的零均值和单位方差的同时,对每个特征进行适当的平移,从而使得网络能够学习到适合当前任务的特征表示。偏移参数允许网络自由地学习每个特征的偏移量,从而提高模型的灵活性。

综合来说,拉伸和偏移参数允许网络自适应地调整标准化后的特征,使得网络能够更好地适应不同的数据分布和任务需求,从而提高模型的性能和泛化能力。

参考:https://nn.labml.ai/normalization/batch_norm/index.html

  • 39
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【为什么要学习这门课程】深度学习框架如TensorFlow和Pytorch掩盖了深度学习底层实现方法,那能否能用Python代码从零实现来学习深度学习原理呢?本课程就为大家提供了这个可能,有助于深刻理解深度学习原理。左手原理、右手代码,双管齐下!本课程详细讲解深度学习原理并进行Python代码实现深度学习网络。课程内容涵盖感知机、多层感知机、卷积神经网络、循环神经网络,并使用Python 3及Numpy、Matplotlib从零实现上述神经网络。本课程还讲述了神经网络的训练方法与实践技巧,且开展了代码实践演示。课程对于核心内容讲解深入细致,如基于计算图理解反向传播算法,并用数学公式推导反向传播算法;另外还讲述了卷积加速方法im2col。【课程收获】本课程力求使学员通过深度学习原理、算法公式及Python代码的对照学习,摆脱框架而掌握深度学习底层实现原理与方法。本课程将给学员分享深度学习的Python实现代码。课程代码通过Jupyter Notebook演示,可在Windows、ubuntu等系统上运行,且不需GPU支持。【优惠说明】 课程正在优惠中!  备注:购课后可加入白勇老师课程学习交流QQ群:957519975【相关课程】学习本课程的前提是会使用Python语言以及Numpy和Matplotlib库。相关课程链接如下:《Python编程的术与道:Python语言入门》https://edu.csdn.net/course/detail/27845《玩转Numpy计算库》https://edu.csdn.net/lecturer/board/28656《玩转Matplotlib数据绘图库》https://edu.csdn.net/lecturer/board/28720【课程内容导图及特色】
以下是一个简单的归一化代码实现: ```python import numpy as np class BatchNorm: def __init__(self, input_shape, momentum=0.99, eps=1e-5): self.momentum = momentum self.eps = eps self.gamma = np.ones(input_shape) self.beta = np.zeros(input_shape) self.running_mean = np.zeros(input_shape) self.running_var = np.zeros(input_shape) def forward(self, x, train=True): if train: batch_mean = np.mean(x, axis=0) batch_var = np.var(x, axis=0) self.running_mean = self.momentum * self.running_mean + (1 - self.momentum) * batch_mean self.running_var = self.momentum * self.running_var + (1 - self.momentum) * batch_var else: batch_mean = self.running_mean batch_var = self.running_var x_norm = (x - batch_mean) / np.sqrt(batch_var + self.eps) out = self.gamma * x_norm + self.beta return out, x_norm def backward(self, dout, x, x_norm): m = x.shape[0] dx_norm = dout * self.gamma dvar = np.sum(dx_norm * (x - self.running_mean) * (-0.5) * np.power(self.running_var + self.eps, -1.5), axis=0) dmean = np.sum(dx_norm * (-1) / np.sqrt(self.running_var + self.eps), axis=0) + dvar * np.mean(-2 * (x - self.running_mean), axis=0) dx = dx_norm / np.sqrt(self.running_var + self.eps) + dvar * 2 * (x - self.running_mean) / m + dmean / m dgamma = np.sum(dout * x_norm, axis=0) dbeta = np.sum(dout, axis=0) return dx, dgamma, dbeta ``` 该代码实现了一个简单的归一化类 `BatchNorm`,包括前向传播和反向传播的实现。在前向传播中,根据输入数据和训练标志,计算出次均值和方差,并更新 `running_mean` 和 `running_var`,然后计算出归一化数据并乘以缩放因子 `gamma` 并加上偏移量 `beta`。在反向传播中,首先计算出 `dout` 对 `gamma` 和 `beta` 的导数,然后计算出 `dx_norm`, `dvar` 和 `dmean`,最后根据链式法则计算出 `dx`, `dgamma` 和 `dbeta`。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值