【Pytorch神经网络理论篇】 16 过拟合问题的优化技巧(三):批量归一化

简介: Switchable Normalization算法,它可以将多种批量归一化算法融合并赋予可以学习的权重,在使用时,通过模型训练的方法来自动学习。

同学你好!本文章于2021年末编写,获得广泛的好评


故在2022年末对本系列进行填充与更新,欢迎大家订阅最新的专栏,获取基于Pytorch1.10版本的理论代码(2023版)实现,


Pytorch深度学习·理论篇(2023版)目录地址为:


CSDN独家 | 全网首发 | Pytorch深度学习·理论篇(2023版)目录


本专栏将通过系统的深度学习实例,从可解释性的角度对深度学习的原理进行讲解与分析,通过将深度学习知识与Pytorch的高效结合,帮助各位新入门的读者理解深度学习各个模板之间的关系,这些均是在Pytorch上实现的,可以有效的结合当前各位研究生的研究方向,设计人工智能的各个领域,是经过一年时间打磨的精品专栏!

https://v9999.blog.csdn.net/article/details/127587345

欢迎大家订阅(2023版)理论篇

以下为2021版原文~~~~

f421d0cb4ee244fbaeeb7557cb582bc7.png


1 批量归一化理论


8334dfb847781a684f6e7c32f2efea58.jpg


1.1 批量归一化原理


59924afaad2a44bbba073458ce0587ca.png

36be468d394c45d0b684fd73f7d250db.png


1.2 批量归一化定义


将每一层运算出来的数据归一化成均值为0、方差为1的标准高斯分布。这样就会在保留样本的分布特征,又消除了层与层间的分布差异。


在实际应用中,批量归一化的收敛非常快,并且具有很强的泛化能力,某种情况下可以完全代替前面讲过的正则化、Dropout。


6cfef67ad16a4f6792294e897bf207cb.png


在训练过程中,会通过优化器的反向求导来优化出合适的r,β值。BN层计算每次输入的均值与方差,并进行移动平均。移动平均默认的动量值为0.1。


在验证过程中,会使用训练求得的均值和方差对验证数据做归一化处理。


1.3 批量归一化实现


  • BatchNorm1d:对二维或三维的线性数据进行批量归一化处理,输入形然是[N,D]或者[D,N,L](N代表批次数,D代表数据的个数,L代表数据的长度)。


  • BatchNorm2d:对二维的平面数据进行批量归一化处理,输入形然是以[N,C,H,W](N代表批次数,C代表通道数,H代表亮度,W代表宽度)。


  • BatchNorm3d:对三维的立体数据进行批量归一化处理,输入形状是[N,C,D,H,W](N代表批次数,C代表通道数,D代表深度,H代表高度,W代表宽度)。


2 批量归一化实操


torch.nn.BatchNormld(num_features,eps=1e-05,momentum=0.1,affine=True,trackrunning_stats=True)


其中的参数含义如下。


  • num features:待处理的输入数据的特征数,该值需要手动计算,如果输入数据的形状是[N,D](N代表批次数,D代表数据的个数),那么该值为D。如果是在BatchNorm2d中,那么该参数要填入图片的通道数。


  • s:默认值为1e-5。为保证数值稳定性(分母不取0),给分母加上值,即给式(7-11)中的σ加上eps。


  • momentum:动态均值和动态方差使用的动量,默认值为0.1。


  • affine:是否使用自适应模式。如果参数值设置为True,那么使用自适应模式,系统将自动对式(7-11)中的r、β值进行优化学习;如果参数值设置为Flase,那么不使用自适应模型,相当于将式(7-11)中的r、β去掉。


  • track_running stats:是否跟踪当前批次数据的统计特性。在训练过程中,如果参数值设置为False,那么系统只使用当前批次数据的均值和方差;如果参数值设置为True,那么系统将跟踪每批次输入的数据并实时更新整个数据集的均值和方差。(在使用过程中,该参数值一般设置为True,表示系统将使用训练时的均值和方差。)


dede2e6e800e4c98b90e7e53415e32d8.png


3 批量归一化函数的手动代码实现


3.0 使用批量归一化方法的注意事项


  • 1、批量归一化方法不能紧跟在Dropout,层后面使用若有这种情况,Dropout层的结果会改变批量归一化所计算的数据分布,导致批量归一化后的偏差更大。


  • 2、在批量归一化方法与Switch激活函数一起使用时,需要对Switch激活函数进行权值缩放(可以使用缩放参数自学习的方法),否侧则会引起更大的抖动。


  • 3、批量归一化方法对拟次依赖严重,即对于较小批次,效果并不理想。因为批量归一化侧重的是对批次样本的归一化,当输入批次较小时,个体样本将无法代替批次样本的特征,导致模型抖动,难以收敛。


  • 4、批量归一化方法适用深层网络。因为在浅层网络中,内部协变量转移问题并不明显,所以批量归一化的效果也不明显。


3.1 使用接口调用方式实现批量归一化计算


实例描述:以二维的平面数据为例,调用BN接口对一组数据执行批量归一化算法,并将该计算结果与手动方式计算的结果进行比较。


import torch
import torch.nn as nn
# 1.1 使用接口调用的方式实现批量归一化计算
data = torch.randn(2,2,2,1) # 定义一个形状为[2,2,2,1]的模拟数据,批次中的样本数为2,每个样本的通道数为2,高和宽分别为2和1。
print(data) # 输出模拟数据
# 实例化BatchNorm2d接口,并调用该实例化对象对模拟数据进行批量归一化计算。
obn = nn.BatchNorm2d(2,affine=True) # 实例化自适应BN对象
print(obn.weight) # 输出自适应参数 r
print(obn.bias) # 输出自适应参数β
print(obn.eps) # 输出BN中的eps
output = obn(data) # 计算BN
print(output,output.size()) # 输出BN结果及形状


# 两个模拟样本数据,每个样本都有两个通道
tensor([[[[-1.3640], [ 0.7662]],[[ 1.0771], [ 0.4655]]],
           [[[-1.4258], [ 1.0477]],[[-0.1646],[ 1.6063]]]])
# 自适应参数
Parameter containing:tensor([1., 1.], requires_grad=True)
Parameter containing:tensor([0., 0.], requires_grad=True)
1e-05
# 批量归一化结果及形状===》仅改变输入数据的值,没有修改输入数据的形状
tensor([[[[-0.9694],[ 0.8743]], [[ 0.4994],[-0.4232]]],
 [[[-1.0228], [ 1.1179]], [[-1.3738], [ 1.2977]]]],
grad_fn=<NativeBatchNormBackward0>) torch.Size([2, 2, 2, 1])


3.2 使用手动方式实现归一化计算


3.2.1 方差计算与贝塞尔校正


  • 方差的计算方法是先将每个值减去均值的结果后再求平方,并求它们的均值(求和后除以总数量)。


  • 贝塞尔校正(Bessel's Correction)是一个与统计学的方差和标准差相关的修正方法,是指在计算提示样本的方差和标准差时,将分母中的n替换成n-1。这种修正方法得到的方差和标准差更近似于当前样本所在的总体集合中的方差和标准差。


3.2.2 归一化实验


为了使手动计算批量归一化的步骤更加清晰,这里只对模拟数据中第一个样本中的第一个具体数据进行手动批量归一化计算,具体步骤如下:


  • (1)取出模拟数据中两个样本的第一个通道数据;


  • (2)用手动的方式计算该数据均值和方差;


  • (3)将均值和方差代入式(7-11),对模拟数据中第一个样本中的第一个具体数据进行计算,具体代码如下。


mport torch
# 1.2 使用手动方式实现批量归一化计算
print("第1通道的数据",data[:,0])
# 计算第1通道数据的平均值与方差
Mean = torch.Tensor.mean(data[:,0])
Var = torch.Tensor.var(data[:,0],False)
print("均值",Mean)
print("方差",Var)
# 计算第1通道中第一个数据的BN结果
batchnorm = ((data[0][0][0][0] - Mean)/(torch.pow(Var,0.5)+obn.eps)) * obn.weight[0]+obn.bias[0]
print("BN结果",batchnorm)


输出:
第1通道的数据 tensor([[[-1.3640],[ 0.7662]], [[-1.4258], [1.0477]]])
均值 tensor(-0.2440)
方差 tensor(1.3350)
BN结果 tensor(-0.9694, grad_fn=<AddBackward0>)


4 通过批量归一化方法改善模型的过拟合状况


修改第1篇文章中的# 2 搭建网络模型部分


# 2 搭建网络模型
# model = LogicNet(inputdim=2,hiddendim=500,outputdim=2) # 实例化模型,增加拟合能力将hiddendim赋值为500
# 修改为
class Logic_Dropout_Net(LogicNet):
    def __init__(self,inputdim,hiddendim,outputdim):
        super(Logic_Dropout_Net, self).__init__(hiddendim=hiddendim)
    def forward(self,x):
        x = self.Linear1(x)
        x = torch.tanh(x)
        x = self.BN(x)
        x = self.Linear2(x)
        return x
model = Logic_Dropout_Net(inputdim=2,hiddendim=500,outputdim=2) # 初始化模型
optimizer = torch.optim.Adam(model.parameters(),lr=0.01) # 定义优化器:反向传播过程中使用。
# 3 训练模型+训练过程loss可视化
xt = torch.from_numpy(X).type(torch.FloatTensor) # 将numpy数据转化为张量
yt = torch.from_numpy(Y).type(torch.LongTensor) # 将numpy数据转化为张量
epochs = 200 # 定义迭代次数
losses = [] # 损失值列表


4.2 批量归一化方法改善模型---代码总览


Over_fitting_Batch normalization.py


# 2 搭建网络模型
# model = LogicNet(inputdim=2,hiddendim=500,outputdim=2) # 实例化模型,增加拟合能力将hiddendim赋值为500
# 修改为
class Logic_Dropout_Net(LogicNet):
    def __init__(self,inputdim,hiddendim,outputdim): # 初始化网络结构
        super(Logic_Dropout_Net, self).__init__(inputdim,hiddendim,outputdim)
        self.BN = nn.BatchNorm1d(hiddendim) # 定义BN层
    def forward(self,x): # 搭建两个全连接层组成的网络模型
        x = self.Linear1(x) # 将输入数据传入第1层
        x = torch.tanh(x) # 对第1层的结果进行非线性变换
        x = self.BN(x) # 对第1层的数据做BN处理
        x = self.Linear2(x) # 将数据传入第2层
        return x
model = Logic_Dropout_Net(inputdim=2,hiddendim=500,outputdim=2) # 初始化模型
optimizer = torch.optim.Adam(model.parameters(),lr=0.01) # 定义优化器:反向传播过程中使用。
# 3 训练模型+训练过程loss可视化
xt = torch.from_numpy(X).type(torch.FloatTensor) # 将numpy数据转化为张量
yt = torch.from_numpy(Y).type(torch.LongTensor) # 将numpy数据转化为张量
epochs = 200 # 定义迭代次数
# 带有批量归一化处理的模型比带有Dropout处理的模型需要更少的训练次教。因为Dropout每次都会使一部分节点不参与运算,相当于减少了单次的样本处理量,所以带有Dropout处理的模型需要更多的训练次数才可以使模型收敛。
losses = [] # 损失值列表


LogicNet_fun.py


import sklearn.datasets
import torch
import numpy as np
import  matplotlib.pyplot as plt
from torch import nn
from LogicNet_fun import LogicNet,moving_average,predict,plot_decision_boundary
# 1 构建数据集
np.random.seed(0) # 设置随机数种子
X , Y =sklearn.datasets.make_moons(40,noise=0.2) # 生成两组半圆形数据
arg = np.squeeze(np.argwhere(Y==0),axis=1) # 获取第1组数据索引
arg2 = np.squeeze(np.argwhere(Y==1),axis=1) # 获取第2组数据索引
# 显示数据
plt.title("train moons data")
plt.scatter(X[arg,0],X[arg,1],s=100,c='b',marker='+',label = 'data1')
plt.scatter(X[arg2,0],X[arg2,1],s=40,c='r',marker='o',label = 'data2')
plt.legend()
plt.show()
# 2 搭建网络模型
# model = LogicNet(inputdim=2,hiddendim=500,outputdim=2) # 实例化模型,增加拟合能力将hiddendim赋值为500
# 修改为
class Logic_Dropout_Net(LogicNet):
    def __init__(self,inputdim,hiddendim,outputdim): # 初始化网络结构
        super(Logic_Dropout_Net, self).__init__(inputdim,hiddendim,outputdim)
        self.BN = nn.BatchNorm1d(hiddendim) # 定义BN层
    def forward(self,x): # 搭建两个全连接层组成的网络模型
        x = self.Linear1(x) # 将输入数据传入第1层
        x = torch.tanh(x) # 对第1层的结果进行非线性变换
        x = self.BN(x) # 对第1层的数据做BN处理
        x = self.Linear2(x) # 将数据传入第2层
        return x
model = Logic_Dropout_Net(inputdim=2,hiddendim=500,outputdim=2) # 初始化模型
optimizer = torch.optim.Adam(model.parameters(),lr=0.01) # 定义优化器:反向传播过程中使用。
# 3 训练模型+训练过程loss可视化
xt = torch.from_numpy(X).type(torch.FloatTensor) # 将numpy数据转化为张量
yt = torch.from_numpy(Y).type(torch.LongTensor) # 将numpy数据转化为张量
epochs = 200 # 定义迭代次数
# 带有批量归一化处理的模型比带有Dropout处理的模型需要更少的训练次教。因为Dropout每次都会使一部分节点不参与运算,相当于减少了单次的样本处理量,所以带有Dropout处理的模型需要更多的训练次数才可以使模型收敛。
losses = [] # 损失值列表
for i in range(epochs):
    loss = model.getloss(xt,yt)
    losses.append(loss.item()) # 保存损失值中间状态
    optimizer.zero_grad() # 清空梯度
    loss.backward() # 反向传播损失值
    optimizer.step() # 更新参数
avgloss = moving_average(losses) # 获得损失值的移动平均值
plt.figure(1)
plt.subplot(211)
plt.xlabel('step number')
plt.ylabel('Training loss')
plt.title('step number vs Training loss')
plt.show()
# 4 模型结果可视化,观察过拟合现象
plot_decision_boundary(lambda x: predict(model,x),X,Y)
from sklearn.metrics import accuracy_score
print("训练时的准确率",accuracy_score(model.predict(xt),yt))
# 重新生成两组半圆数据
Xtest,Ytest = sklearn.datasets.make_moons(80,noise=0.2)
plot_decision_boundary(lambda x: predict(model,x),Xtest,Ytest)
Xtest_t = torch.from_numpy(Xtest).type(torch.FloatTensor) # 将numpy数据转化为张量
Ytest_t = torch.from_numpy(Ytest).type(torch.LongTensor)
print("测试时准确率",accuracy_score(model.predict(Xtest_t),Ytest_t))


4.3 小结


批量归一化更擅长解决深层网络的内部协变量转移问题,在深层网路中,才会体现出更好的性能。


5 扩展:多种批量归一化算法介绍


1.在小批次样本情况下,可以使用与批次无关的renorm方法进行批量归一化;


2.在RNN模型中,可以使用Layer Normalization算法;


3.在对抗神经网络中,可以使用Instance Normalization算法


4.Switchable Normalization算法,它可以将多种批量归一化算法融合并赋予可以学习的权重,在使用时,通过模型训练的方法来自动学习。

目录
相关文章
|
1天前
|
机器学习/深度学习 算法
基于改进遗传优化的BP神经网络金融序列预测算法matlab仿真
本项目基于改进遗传优化的BP神经网络进行金融序列预测,使用MATLAB2022A实现。通过对比BP神经网络、遗传优化BP神经网络及改进遗传优化BP神经网络,展示了三者的误差和预测曲线差异。核心程序结合遗传算法(GA)与BP神经网络,利用GA优化BP网络的初始权重和阈值,提高预测精度。GA通过选择、交叉、变异操作迭代优化,防止局部收敛,增强模型对金融市场复杂性和不确定性的适应能力。
103 80
|
4天前
|
机器学习/深度学习 人工智能 PyTorch
使用PyTorch实现GPT-2直接偏好优化训练:DPO方法改进及其与监督微调的效果对比
本文将系统阐述DPO的工作原理、实现机制,以及其与传统RLHF和SFT方法的本质区别。
50 22
使用PyTorch实现GPT-2直接偏好优化训练:DPO方法改进及其与监督微调的效果对比
|
10天前
|
机器学习/深度学习 算法 PyTorch
基于图神经网络的大语言模型检索增强生成框架研究:面向知识图谱推理的优化与扩展
本文探讨了图神经网络(GNN)与大型语言模型(LLM)结合在知识图谱问答中的应用。研究首先基于G-Retriever构建了探索性模型,然后深入分析了GNN-RAG架构,通过敏感性研究和架构改进,显著提升了模型的推理能力和答案质量。实验结果表明,改进后的模型在多个评估指标上取得了显著提升,特别是在精确率和召回率方面。最后,文章提出了反思机制和教师网络的概念,进一步增强了模型的推理能力。
33 4
基于图神经网络的大语言模型检索增强生成框架研究:面向知识图谱推理的优化与扩展
|
23天前
|
机器学习/深度学习 人工智能 PyTorch
Transformer模型变长序列优化:解析PyTorch上的FlashAttention2与xFormers
本文探讨了Transformer模型中变长输入序列的优化策略,旨在解决深度学习中常见的计算效率问题。文章首先介绍了批处理变长输入的技术挑战,特别是填充方法导致的资源浪费。随后,提出了多种优化技术,包括动态填充、PyTorch NestedTensors、FlashAttention2和XFormers的memory_efficient_attention。这些技术通过减少冗余计算、优化内存管理和改进计算模式,显著提升了模型的性能。实验结果显示,使用FlashAttention2和无填充策略的组合可以将步骤时间减少至323毫秒,相比未优化版本提升了约2.5倍。
42 3
Transformer模型变长序列优化:解析PyTorch上的FlashAttention2与xFormers
|
7天前
|
机器学习/深度学习 算法 PyTorch
基于Pytorch Gemotric在昇腾上实现GraphSage图神经网络
本文详细介绍了如何在昇腾平台上使用PyTorch实现GraphSage算法,在CiteSeer数据集上进行图神经网络的分类训练。内容涵盖GraphSage的创新点、算法原理、网络架构及实战代码分析,通过采样和聚合方法高效处理大规模图数据。实验结果显示,模型在CiteSeer数据集上的分类准确率达到66.5%。
|
8天前
|
域名解析 缓存 网络协议
优化Lua-cURL:减少网络请求延迟的实用方法
优化Lua-cURL:减少网络请求延迟的实用方法
|
7天前
|
数据采集 监控 安全
公司网络监控软件:Zig 语言底层优化保障系统高性能运行
在数字化时代,Zig 语言凭借出色的底层控制能力和高性能特性,为公司网络监控软件的优化提供了有力支持。从数据采集、连接管理到数据分析,Zig 语言确保系统高效稳定运行,精准处理海量网络数据,保障企业信息安全与业务连续性。
27 4
|
25天前
|
存储 缓存 监控
Docker容器性能调优的关键技巧,涵盖CPU、内存、网络及磁盘I/O的优化策略,结合实战案例,旨在帮助读者有效提升Docker容器的性能与稳定性。
本文介绍了Docker容器性能调优的关键技巧,涵盖CPU、内存、网络及磁盘I/O的优化策略,结合实战案例,旨在帮助读者有效提升Docker容器的性能与稳定性。
64 7
|
23天前
|
机器学习/深度学习 算法 数据安全/隐私保护
基于贝叶斯优化CNN-GRU网络的数据分类识别算法matlab仿真
本项目展示了使用MATLAB2022a实现的贝叶斯优化、CNN和GRU算法优化效果。优化前后对比显著,完整代码附带中文注释及操作视频。贝叶斯优化适用于黑盒函数,CNN用于时间序列特征提取,GRU改进了RNN的长序列处理能力。
|
13天前
|
Go 数据安全/隐私保护 UED
优化Go语言中的网络连接:设置代理超时参数
优化Go语言中的网络连接:设置代理超时参数