激活函数和归一化、正则化
一、激活函数
1.Sigmoid
- 提出时间:1943年(McCulloch和Pitts在⼈⼯神经元模型中⾸次使⽤)。
- 特点:输出压缩在0到1之间,具有⾮线性特性,但梯度在两端趋近于零,容易导致梯度消失问题,且输出均值不为零,可能影响训练稳定性
- 应⽤⽹络模型:早期常⽤于逻辑回归、浅层神经⽹络的分类任务,以及⽣成对抗⽹络(GANs)的输出层(⽣成概率分布)。
- 使用普遍性:在深度学习中逐渐被ReLU等替代,但在需要概率解释的任务(如⼆分类、语⾔模型)中仍有应⽤。
2.tanh
- 提出时间:1940年代(作为Sigmoid的变体被提出)。
- 特点:输出范围为-1到1,均值为零,⽐Sigmoid更易训练,但仍存在梯度消失问题。
- 应⽤⽹络模型:常⽤于循环神经⽹络(RNN)、⻓短期记忆⽹络(LSTM)的⻔控机制,以及早期深度神经⽹络的中间层。
- 使用普遍性:在现代模型中逐渐被ReLU取代,但在序列建模(如⾃然语⾔处理)和某些强化学习场景中仍有使用。
3.ReLU
- 提出时间:2012年(由Hinton团队在ImageNet竞赛中推⼴)。
- 特点:计算⾼效,缓解梯度消失问题,但存在“神经元死亡ˮ现象(输⼊负时梯度为零,导致权重⽆法更新)。
- 应⽤⽹络模型:⼴泛⽤于卷积神经⽹络(CNN)、残差⽹络(ResNet)、循环神经⽹络(RNN)等,是深度学习的主流激活函数。
- 使用普遍性:⽬前最常⽤的激活函数,适⽤于⼤多数视觉、语⾔和序列任务。
4.Leaky ReLU
- 提出时间:2013年(由Maas等⼈提出)。
- 特点:改进ReLU的“死亡ˮ问题,当输⼊为负时保留⼩梯度(如斜率0.01),保持神经元活性。
- 应⽤⽹络模型:在⽣成对抗⽹络(DCGAN)、超分辨率模型中表现良好,常⽤于替代ReLU以提升训练稳定性。
- 使用普遍性:在需要避免ReLU缺陷的场景中普遍使⽤,是ReLU的常⻅改进版本。
5.Swish
- 提出时间:2017年(由Google团队提出)。
- 特点:结合平滑性和⾃⻔控机制,⽐ReLU更灵活,适合深层⽹络。
- 应⽤⽹络模型:在Google的EfficientNet、神经架构搜索(NAS)模型中被采⽤,显著提升图像分类和⽬标检测性能。
- 使用普遍性:近年来在⼯业界和学术界的⾼性能模型中逐渐普及,尤其在需要⾼精度的视觉任务中。
以上只挑选了⼀些常⻅和常⽤的激活函数,实际上还有很多其他的激活函数,如ELU、SELU、GELU等,它们在不同的场景和任务中也有各自的优缺点和适用性。选择合适的激活函数对于模型性能和训练稳定性至关重要。
PyTorch中的⾮线性激活函数
二、归⼀化
归⼀化也是⼀种带有参数的归⼀化计算公式。但主要⽬的是为了稳定训练过程,加速模型收敛并减少过拟合。
- BatchNorm
BatchNorm 即批量归⼀化(Batch Normalization),是由 Sergey Ioffe 和 Christian Szegedy在 2015 年提出的⼀种在深度学习中⼴泛应⽤的技术,⽤于对神经⽹络中的数据进⾏归⼀化处理。以下从原理、作⽤、使⽤⽅式、局限性等⽅⾯为你详细介绍: - 原理
在神经⽹络训练过程中,每⼀层的输⼊数据分布会随着前⾯各层参数的更新⽽发⽣变化,这⼀现象被称为内部协变量偏移(Internal Covariate Shift)。BatchNorm 的核⼼思想是:对每⼀批次(mini - batch)的数据进⾏归⼀化操作,使其均值为 0,⽅差为 1,以减少内部协变量偏移。
具体步骤如下:
计算均值:对于输入的一批数据 x 1 , x 2 , ⋯ , x m x_1, x_2, \cdots, x_m x1,x2,⋯,xm( m m m 为批次大小),计算其均值 μ B \mu_B μB:
μ B = 1 m ∑ i = 1 m x i \mu_B = \frac{1}{m} \sum_{i=1}^m x_i μB=m1i=1∑mxi
计算方差:计算这批数据的方差 σ B 2 \sigma_B^2 σB2:
σ B 2 = 1 m ∑ i = 1 m ( x i − μ B ) 2 \sigma_B^2 = \frac{1}{m} \sum_{i=1}^m (x_i - \mu_B)^2 σB2=m1i=1∑m(xi−μB)2
归一化:对每个数据点 x i x_i xi 进行归一化处理,得到 x ^ i \hat{x}_i x^i:
x ^ i = x i − μ B σ B 2 + ϵ \hat{x}_i = \frac{x_i - \mu_B}{\sqrt{\sigma_B^2 + \epsilon}} x^i=σB2+ϵxi−μB
其中, ϵ \epsilon ϵ 是一个很小的常数(如 10 − 5 10^{-5} 10−5),用于避免分母为 0 的情况。
缩放和平移:为了让网络能够学习到合适的分布,引入两个可学习的参数 γ \gamma γ 和 β \beta β,对归一化后的数据进行缩放和平移:
y i = γ x ^ i + β y_i = \gamma \hat{x}_i + \beta yi=γx^i+β
- 作⽤
- 加速训练收敛:通过减少内部协变量偏移,使得每⼀层的输⼊数据分布更加稳定,从⽽可以使⽤更⼤的学习率,加快模型的收敛速度。
- 提⾼模型泛化能⼒:BatchNorm 具有⼀定的正则化效果,能够减少模型对特定训练数据的依赖,降低过拟合的⻛险。
- 缓解梯度消失和梯度爆炸:在深层神经⽹络中,归⼀化操作使得梯度在反向传播过程中更加稳定,避免了梯度在传播过程中变得过⼤或过⼩。
- PyTorch实现BatchNorm 的简单⽰例:
import torch
import torch.nn as nn
# 定义⼀个简单的全连接⽹络,包含 BatchNorm 层
class SimpleNet(nn.Module):def __init__(self):super(SimpleNet, self).__init__()self.fc1 = nn.Linear(10, 20)# 在第⼀个全连接层后添加 BatchNorm 层# 这里的 20 是第⼀个全连接层输出的特征维度# 也就是 BatchNorm 层的输入维度self.bn1 = nn.BatchNorm1d(20)self.relu = nn.ReLU()self.fc2 = nn.Linear(20, 1)def forward(self, x):x = self.fc1(x)x = self.bn1(x)x = self.relu(x)x = self.fc2(x)return x
# 创建模型实例
model = SimpleNet()
在 PyTorch 中,BatchNorm1d
里的“1d”指的是一维特征归一化,即对每个样本的每个特征通道做归一化,常用于全连接层(如MLP)或一维序列数据。
BatchNorm1d
适用于输入形状为(batch_size, num_features)
或(batch_size, num_features, length)
的数据。- “1d”不是指输入是一维向量,而是指对每个特征通道做归一化,适合处理一维特征或序列。
常见归一化层对比如下:
层名 | 适用数据类型 | 典型输入形状 |
---|---|---|
BatchNorm1d | 一维特征/序列 | (batch, features) 或 (batch, features, length) |
BatchNorm2d | 二维图像(如CNN) | (batch, channels, height, width) |
BatchNorm3d | 三维体数据(如视频) | (batch, channels, D, H, W) |
简言之:
BatchNorm1d 的“1d”表示对一维特征通道归一化,常用于全连接层或一维序列数据。
-
其它归⼀化⽅法
除 BatchNorm 外,还有以下归⼀化操作运算- LayerNorm:适合⻓序列数据(如 NLP),或批量较⼩的任务。
- GroupNorm:平衡 BN 和 LN,适合中等批量场景。
- SwitchableNorm:⾃适应选择归⼀化⽅式,适合动态批量场景。
-
概括⼩结
归⼀化是全连接神经⽹络的重要组件,通过稳定分布、加速收敛和提升泛化性,显著优化模型训练效果。实验和论⽂均证实其有效性,实际应⽤中需根据任务特性选择合适的归⼀化⽅法。
pytorch中的归⼀化层实现
三、正则化
正则化是⼀种数据筛选⽅法,作⽤是抑制过拟合,提升模型泛化能⼒
•拟合:描述模型在训练数据上的表现。
•泛化:描述模型在新数据上的表现。
•欠拟合:模型过于简单,无法有效学习数据模式。
•过拟合:模型过于复杂,过度记住训练数据,导致新数据表现不佳。
-
Dropout
Dropout 是由 Geoffrey Hinton 等人在 2012 年提出的一种正则化技术,用于缓解神经网络的过拟合问题。 -
原理
Dropout 的核心思想是在训练过程中随机"关闭"(置零)神经网络中的部分神经元,使得网络无法过度依赖某些特定特征。具体步骤如下:
-
随机失活
对于每一层神经元,以概率 p p p(称为 dropout rate)随机选择部分神经元并将其输出置零。 -
缩放补偿
为了保持网络的输出范围稳定:- 在测试时将保留的神经元输出乘以 1 / ( 1 − p ) 1/(1-p) 1/(1−p)
- 或在训练时将保留的神经元输出乘以 p p p
- 作用
- 减少过拟合:通过随机失活神经元,Dropout 迫使⽹络学习更鲁棒的特征,避免对特定神经元的过度依赖。
- 近似模型集成:每次训练时随机失活神经元相当于训练不同的⼦⽹络,测试时将这些⼦⽹络的预测结果平均,类似于集成学习的效果。
- 计算效率:Dropout 的计算成本较低,⽆需存储额外参数,且易于在现有⽹络中实现。
- PyTorch实现Dropout 的简单⽰例
import torch
import torch.nn as nn
class DropoutNet(nn.Module):def __init__(self):super(DropoutNet, self).__init__() #表示继承nn.Module类self.fc1 = nn.Linear(10, 20) # 第⼀个全连接层self.dropout = nn.Dropout(p=0.5) # 随机失活50%的神经元self.relu = nn.ReLU()self.fc2 = nn.Linear(20, 1) # 第⼆个全连接层def forward(self, x):x = self.fc1(x)x = self.dropout(x)x = self.relu(x)x = self.fc2(x)return x
model = DropoutNet()
pytorch中的dropout层
模型结构和⽅法
Pytorch中模型的基本组成是 nn.Module
。之所以称为 Module ⽽不是 Model,这之间还是有结构化
设计组合的考虑的。
代码中,我们通过继承 nn.Module
可以实现⾃定义的模型。但仔细观察可以发现,全连接神经⽹络中的基本组成 nn.Linear
也是继承⾃ nn.Module
。
从功能设计上讲,这种设计实现并不影响代码的执⾏。巧妙地⽅在于,所有继承⾃ nn.Module
的模块可以通过排列,组合等⽅式,实现各种复杂的模型结构。其本质上可以通过拼接创建更⼤更复杂的计算图。通过统⼀实现的调⽤接⼝,达成了简单且不失灵活的模型构建任务。
Module ⽅法
- train() :将模块设置为训练模式 (注意!该⽅法会使模型中的 Dropout 、 BatchNorm 等层的功能⽣效)
- eval() :将模块设置为评估模式 (注意!该⽅法会使模型中的 Dropout 、 BatchNorm 等层的功能失效)
- forward() :定义前向传播过程
- zero_grad() :重置所有模型参数的梯度。和 optimizer.zero_grad() 作⽤相同