什么是正则化

- 正则化的目的就是让模型在新样本上也表现稳定、防止过拟合;神经网络表示能力强,更容易把训练数据学得太死,所以尤其需要各种正则化策略
- 目前在深度学习中使用较多的策略有范数惩罚,DropOut,特殊的网络层等,接下来我们对其进行详细的介绍
Dropout正则化【掌握】
模型一深、参数一多、数据又不够时,就很容易过拟合。Dropout(随机失活)就是一种很常用的解决办法。

- 训练时怎么做:以超参数
p(丢弃率)的概率,随机让一部分神经元输出变成 0;没被丢掉的神经元要再除以1-p做缩放。这样每次训练都像是在训练一个不同的子网络,可以减轻过拟合 - p 怎么选:通常取
0.2~0.5。模型较小或任务较复杂时可以更小;网络很深时可以适当更大。实际里常把 Dropout 放在全连接层的激活函数后面 - 测试时怎么做:预测时不允许神经元失活,要让所有神经元一起工作,这样结果更稳定。测试/推理阶段使用
model.eval() - 为什么要缩放:训练时把保留下来的输出除以
1-p,是为了让训练和测试阶段的输出期望保持一致;训练阶段使用model.train()
为什么训练时允许神经元失活,预测时却不允许?
- 1- 训练时:故意打散神经元之间的依赖,减少过拟合
- 2- 预测时:让所有神经元都参与计算,结果更稳定
我们通过一段代码观察下dropout的效果:
Dropout 效果示例
import torch
if __name__ == '__main__':
# 准备输入的样本数据
inputs = torch.randint(low=1,high=10,size=(1,4),dtype=torch.float32)
print(f"输入数据内容{inputs}")
# 构建神经网络结构
hidden = torch.nn.Linear(4,5)
dropout = torch.nn.Dropout(p=0.4)
# 计算数据
result = hidden(inputs) # 隐藏层进行线性求和
result = torch.tanh(result) # 隐藏层进激活函数
print(f"激活函数后结果{result}")
result = dropout(result) # Dropout层随机失活。将Dropout当成一层神经网络层使用即可
print(f"随机失活后结果{result}")上述代码将Dropout层的丢弃概率p设置为0.4,此时经过Dropout层计算的张量中就出现了很多0, 未变为0的按照(1/(1-0.4))进行处理。
批量归一化(Batch Normalization)【了解】
在神经网络的训练过程中,流经网络的数据都是一个batch,每个batch之间的数据分布变化非常剧烈,这就使得网络参数频繁的进行大的调整以适应流经网络的不同分布的数据,给模型训练带来非常大的不稳定性,使得模型难以收敛。如果我们对每一个batch的数据进行标准化之后,数据分布就变得稳定,参数的梯度变化也变得稳定,有助于加快模型的收敛。
展开查看更多
通过标准化每一层的输入,使其均值接近0,方差接近1,从而加速训练并提高泛化能力。

深度学习中的批量归一化BN与机器学习中的标准化处理的区别是啥?
机器学习:对所有的业务数据在输入给到算法之前,统一进行一次性的标准化处理
深度学习:对输入进神经网络的每个批次的数据进行单独的标准化处理。例如:总共有100条样本,16条/批次,7批次,
这7个批次各自计算均值和标准差,然后独立进行标准化处理
先对数据标准化,再对数据重构(缩放+平移),写成公式如下所示:

λ和β是可学习的参数,它相当于对标准化后的值做了一个线性变换,λ为系数,β为偏置;
eps 通常指为 1e-5,避免分母为 0;
E(x) 表示变量的均值;
Var(x) 表示变量的方差;
批量归一化的步骤如下:
-
计算均值和方差:对于每个神经元(即每一层的输入特征),计算该特征在一个小批量(batch)上的均值 $μ_B$ 和方差 $\sigma_B^2$,它们的计算公式如下:
$$μ_B=\frac{1}{m} \sum_{i=1}^{m} x_i$$
$$σ_B^2=\frac{1}{m} \sum_{i=1}^{m} (x_i - \mu_B)^2$$其中 $x_i$ 表示小批量中的第 $i$ 个样本,$m$ 是小批量的样本数量。
-
标准化:然后,对每个样本的输入进行标准化,得到归一化的输出:
$$\hat{x}_i = \frac{x_i - \mu_B}{\sqrt{\sigma_B^2 + \epsilon}}$$其中,$ϵ$ 是一个小常数,用来避免除以零的情况。
-
缩放和平移:为了让网络能够恢复其学习能力,BN 层引入了两个可训练的参数 $γ$ 和 $β$,分别用于缩放和平移:
$$y_i = \gamma \hat{x}_i + β$$其中,$γ$ 和 $β$ 是可学习的参数,通过 γ 和 β,BN 层不再是简单的将每一层输入强行变为标准正态分布,而是允许网络学习更适合于该层的输入分布;规范化操作会丢失原始输入的一些信息,而 $γ$ 和 $β$ 可以弥补这种信息损失。
批量归一化的作用: 输入到神经网络的输入层数据,我们可以进行量纲的处理,例如:标准化、归一化
-
减少内部协方差偏移: 通过对每层的输入进行标准化,减少了输入数据分布的变化,从而加速了训练过程,并使得网络在训练过程中更加稳定。
-
加速训练:
- 在没有批量归一化的情况下,神经网络的训练通常会很慢,尤其是深度网络。因为在每层的训练过程中,输入数据的分布(特别是前几层)会不断变化,这会导致网络学习速度缓慢。
- 批量归一化通过确保每层的输入数据在训练时分布稳定,有效减少了这种变化,从而加速了训练过程。
-
起到正则化作用: 批量归一化可以视作一种正则化方法,因为它引入了对训练样本的噪声(不同批次的统计信息不同,批次较小的均值和方差估计会更加不准确),使得模型不容易依赖特定的输入特征,从而起到一定的正则化效果,减少了对其他正则化技术(如Dropout)的需求。
-
提升泛化能力: 由于其正则化效果,批量归一化能帮助网络在测试集上取得更好的性能。
批量归一化层在计算机视觉领域使用较多
Batch Normalization 的使用步骤:
- 在网络层后添加 BN 层:
- 通常,BN 层会添加在卷积层 (Conv2d) 或全连接层 (Linear) 之后,激活函数之前。
- 例如:Conv2d -> BN -> ReLU 或者 Linear -> BN -> ReLU。
- 训练时:model.train()
- BN 层会计算当前批次的均值 $μ$ 和方差 $σ²$。
- 然后,利用这两个统计量对当前批次的数据进行规范化。
- 规范化后的数据会被缩放 $γ$ 和平移 $β$。
- 同时,BN 层还会维护一个全局均值和全局方差的移动平均值,用于推理阶段。
- 推理时:model.eval()
- 推理时,不会再使用当前批次的均值和方差,而是使用训练阶段计算的全局均值和全局方差。
- 同样,规范化后的数据会被缩放 $γ$ 和平移 $β$。
Batch Normalization 示例
import torch
if __name__ == '__main__':
# 准备输入数据
"""
样本数据结构是4维的,每个位置上的参数含义解释:
1:样本中有1张图片
2:图片的颜色通道个数C
3:图片的高度H
4:图片的宽度W
"""
input_2d = torch.randn(size=(1,2,3,4))
# 批量归一化BN层
"""
BatchNorm2d中参数解释:
num_features:在处理图片的时候,输入图片的通道数有几个
eps:是一个小常数,为了防止分母为0
affine:该值通常设置为True。表示神经网络内部自动的去学习得到公式中的γ和β系数
类的作用解释:
BatchNorm1d:主要用来处理文本内容。输入数据的形状是 N,num_features
N:样本数据条数
num_features:输入样本的特征个数
BatchNorm2d:主要用来处理图片。输入数据的形状是 N,C,H,W。
N:图片的张数
C:图片的通道数。常见图片的通道数为3 RGB
H:图片的高度
W:图片的宽度
BatchNorm3d:主要用来处理视频(视频是有多张图片组成的)。输入数据的形状是 N,C,D,H,W。
N:图片的张数
C:图片的通道数。常见图片的通道数为3 RGB
D:是维度数
H:图片的高度
W:图片的宽度
"""
bn2d = torch.nn.BatchNorm2d(num_features=2,eps=1e-5,momentum=0.1,affine=True)
output = bn2d(input_2d)
print("公式中的γ",bn2d.weight)
print("公式中的β",bn2d.bias)