摘要
AlexNet有6000万个参数和65万个神经元,由5个卷积层组成,其中某些卷积层其后紧跟最大池化层,还有3个全连接的层,最后是1000路softmax。
为了使训练更快,作者使用了非饱和神经元(ReLU激活函数)和一个非常高效的GPU实现卷积操作。
为了减少全连接层的过拟合,作者采用了论文发表时不久之前所被提出的一种称为“dropout”的正则化方法,该方法被证明非常有效。
数据集
ImageNet 由可变分辨率的图像组成,而作者设计的系统需要恒定的输入维度。
因此,作者将图像降采样到 256 × 256 的固定分辨率。给定一个矩形图像,首先重新缩放图像,使较短的边长度为 256,然后从结果图像中裁剪出中心的256×256 patch。
作者没有以任何其他方式预处理图像,除了从每个像素中减去训练集上的均值。所以作者是在像素的(居中的)原始RGB值上训练网络。
"从每个像素中减去训练集上的均值"是一种数据预处理方法,用于减少图像数据的偏差。具体来说,对于每个像素,都会减去整个训练集上对应位置像素的平均值。这个平均值是在训练阶段计算得到的,可以理解为对每个像素位置上的颜色进行了重新调整,使得整个训练数据集的像素分布更加集中和统一。
通过这种预处理方法,可以使得模型更容易学习到图像的真实特征,因为减去了数据集的平均值后,数据集的分布更接近于零均值,这有助于避免模型在训练过程中受到数据分布不均匀的影响。
网络结构
包含八个学习层——五个卷积层和三个全连接层
使用非饱和神经元激活函数ReLU(Rectified Linear Unit)
在传统的神经网络中,常用的激活函数是sigmoid函数或者tanh函数,但这些函数在一定范围内是饱和的,导致在反向传播时可能会出现梯度消失的问题。
而ReLU函数在输入大于零时是线性的,可以避免这个问题,并且计算速度更快。
AlexNet的成功证明了ReLU激活函数的有效性,后续的深度学习模型中也广泛使用了ReLU激活函数。
多 GPU 训练
Local Response Normalization
Local Response Normalization(局部响应归一化)是一种在卷积神经网络中使用的技术,目的是增强模型的泛化能力。
它的思想是对神经元的输出进行归一化处理,使得在同一层中不同卷积核输出的特征图之间产生竞争,从而增强了模型对特征的选择性。
具体来说,对于一个给定的神经元,它的输出值会被除以一个值,这个值是它周围的神经元输出的平方和的一个函数。这样做的效果类似于生物神经系统中的侧抑制现象,即一个神经元的激活会抑制周围神经元的激活。
在AlexNet中,局部响应归一化是这样实现的:对于每一个神经元的输出值,先计算出它周围 n n n 个神经元(在同一个位置,不同卷积核的输出)的输出值的平方和,然后将这个和乘以一个小的常数 α α α,加上另一个常数 k k k,最后取这个结果的 β β β 次方根作为分母,用原来的输出值除以这个分母,得到最终的归一化输出。
通过这种方式,局部响应归一化增强了模型对不同特征的敏感度,有助于提高模型的分类性能。在 AlexNet 的实验中,使用局部响应归一化可以降低错误率,提高模型的准确性。
Overlapping Pooling
Overlapping Pooling(重叠池化)是一种在卷积神经网络中常用的技术,用于减少特征图的尺寸,同时保留重要的特征信息。
通常在卷积神经网络中,使用池化层(Pooling Layer)来降低特征图的维度,这有助于减少计算量和防止过拟合。池化操作通常包括最大池化(Max Pooling)和平均池化(Average Pooling)等。在传统的池化操作中,会将输入的特征图划分为若干个不重叠的区域,然后对每个区域进行池化操作(取最大值或平均值)。
与传统池化不同,重叠池化允许池化窗口之间有重叠。也就是说,在对特征图进行划分时,相邻的池化窗口可以有部分区域是重叠的。这样做的好处是可以保留更多的空间信息,因为重叠的部分可以被多次考虑,从而避免了一些重要特征在池化过程中被丢弃。
举个简单的例子,假设有一个4x4的特征图,如果使用2x2的池化窗口,且步长(stride)为2,则不会有重叠,因为每次池化操作都是在不同的区域上进行的。但如果将步长减小到1,那么每个池化窗口之间就会有重叠的部分,这就是重叠池化。
在AlexNet中,作者使用的是重叠最大池化,即在进行最大池化时,允许池化窗口之间有重叠。这种方法在实验中被证明可以降低错误率,提高模型的性能。
模型结构图
第三层、第四层和第五层卷积层相互连接,没有任何中间池化层或归一化层。第三个卷积层有384个大小为 3 × 3 × 256 的核,这些核连接到第二个卷积层的输出(归一化,池化)。第四个卷积层有384个大小为 3 × 3 × 192 的核,第五个卷积层有 256个大小为 3 × 3 × 192 的核。完全连接的层每层有4096个神经元。
这张模型结构图展示的是AlexNet神经网络的架构,它是一个深度卷积神经网络,具有多个卷积层、池化层、归一化层和全连接层。从左到右详细解释每部分作用:
-
输入层:
- 图片大小为 224x224 像素,有 3 个颜色通道(红、绿、蓝)。
-
第一层(卷积层):
- 使用大小为 11x11 的 96 个卷积核对输入图像进行滤波,步长为 4。
- 该层的输出是多个特征图,每个特征图是由一个卷积核生成的。
-
第二层(池化/归一化层):
- 对第一层的输出进行最大池化,通常使用 3x3 大小的滤波器,步长为 2。
- 池化后,应用局部响应归一化,这有助于增强模型泛化能力。
-
第三层(卷积层):
- 使用大小为 5x5 的 256 个卷积核,这些卷积核只与前一层中相同GPU上的特征图相连。
-
第四层(池化层):
- 再次进行最大池化,使用同样的滤波器和步长。
-
第五和第六层(卷积层):
- 使用更小的 3x3 卷积核进行滤波,数量分别是 384 和 256,此时卷积核连接前一层所有特征图。
-
第七层(池化层):
- 最后一个最大池化层,再次使用相同的滤波器和步长。
-
第八至第十层(全连接层):
- 卷积和池化层后面是三个全连接层,分别有 4096、4096 和 1000 个神经元。
- 最后一个全连接层有 1000 个输出,对应于 1000 个类别的概率。
-
ReLU激活函数:
- 在每个卷积层和全连接层之后应用ReLU激活函数。
在结构图中,可以看到两个平行的流,这代表了AlexNet使用的两个GPU。其中一些卷积层分布在两个GPU上,以并行方式处理信息。最终,所有特征信息在全连接层汇聚,得到最终的分类结果。
这种深层的结构允许网络从原始像素学习到复杂的特征表示,从而能够在大规模的图像识别任务中取得突破性的性能。
-
GPU分配和连接:
-
第二、第四和第五个卷积层: 这些层中的卷积核(卷积过滤器)只与前一层中位于同一GPU上的特征图(卷积层的输出)相连。这意味着如果模型的这一部分分布在两个GPU上,那么每个GPU会处理输入数据的一部分,其输出也只会被发送到同一GPU上的下一层。这样做可以优化计算资源,同时允许模型在多个GPU上并行计算。
-
第三个卷积层: 这一层与第二层中的所有特征图相连,不管它们位于哪个GPU上。这种全连接的方式能够确保第三层捕获到前一层所有特征图中的信息。
-
-
全连接层(Dense Layers):
- 模型的全连接层中的每个神经元都与前一层中的所有神经元相连,从而能够综合考虑前一层的所有特征。
-
归一化层(Response-Normalization Layers):
- 在第一和第二卷积层后面,有归一化层。这些层执行局部响应归一化,有助于增强模型泛化能力,如前面所解释的。
-
池化层(Max-Pooling Layers):
- 根据Section 3.4的描述,池化层遵循局部响应归一化层,以及第五个卷积层。这里使用的是重叠最大池化,能够在减少特征维度的同时保留重要信息。
-
ReLU非线性激活函数:
- 在每个卷积层和全连接层的输出上应用ReLU(Rectified Linear Unit)激活函数,这种非线性函数可以加速网络的训练,并提高模型性能。
在所提供的结构图中,可以看到数据如何在网络中流动和处理,包括从输入层到多个卷积层,然后是池化层和归一化层,最终到达全连接层,并通过一个softmax层输出最终的分类结果。每个层次都进行了相应的操作来提取和转换特征,最后进行分类决策。
减少过拟合
数据增强
减少图像数据过拟合的最简单和最常用的方法是使用标签保持变换(label-preserving transformations)人为地扩大数据集。
在AlexNet论文中,作者使用了两种数据增强(Data Augmentation)的方法来提高模型的泛化能力和减少过拟合。数据增强指的是通过在原始数据上应用一系列变换来人为地扩大数据集。这里的变换通常是一些改变图像但不改变图像类别标签的操作。数据增强使得模型可以从更多样化的数据中学习,这有助于提高模型对新鲜样本的预测能力。
这两种数据增强方法分别是:
-
图像平移和水平翻转:
- 这种方法是在原始图像上随机选择一部分,比如从 224x224 像素的图像中随机裁剪出一个区域或者进行水平翻转。通过这种方式,同一张图像可以生成多个“新”的图像,它们看起来略有不同,但实际上表示同一个类别。这种方法能够极大地增加数据集的大小和多样性。在训练时使用这些转换后的图像,可以让模型学会不依赖于特定的图像位置或朝向。
-
改变RGB颜色通道的强度:
- 第二种数据增强是通过改变训练图像中RGB通道的强度来进行的。具体做法是对整个训练集的RGB像素值进行主成分分析(PCA),然后对每张图像的每个像素,通过增加或减少与主成分相对应的数值,来改变其RGB通道的强度。这个过程相当于在每个颜色通道上加入一些噪声,这种噪声与整个数据集的颜色变化相关。这样做的目的是模拟自然环境下光照条件的变化,因为在真实世界中,即使光照条件变化,对象的识别应该是不变的。
这两种数据增强方法在训练卷积神经网络时非常常见,并已证明可以有效地提升模型在各种视觉任务上的性能。通过这样的技巧,AlexNet能够更好地理解图像的本质特征,而不会对图像中的某些特定模式(比如位置、角度、照明)过度敏感。
Dropout
在传统的神经网络训练中,组合多个不同的模型(也就是训练多个网络,然后将他们的预测结果综合起来)是一种提高性能的常见手段,因为不同的模型可能会从数据中学到稍微不同的特征和模式。但是,对于大型网络而言,由于每个单独的网络都需要大量的时间来训练,组合多个这样的模型会变得计算成本极高。
Dropout 是一种高效的替代方案,它在训练过程中随机“丢弃”(即暂时移除)每个隐藏层神经元的一部分(具体来说,每个神经元有50%的概率不被使用)。
在网络的每次前向传播过程中,被丢弃的神经元不会对结果产生影响,也不会在反向传播中更新其权重。这意味着每次输入被呈现给网络时,网络都会使用一个略微不同的架构进行学习,但是所有这些架构都共享相同的权重。
这种做法的效果类似于同时训练了大量的不同的网络,并在测试时将他们的预测结果进行平均。因为 dropout 随机地在不同的训练迭代中使用了不同的神经元子集,它有效地创建了一个从数以指数级增长的不同网络“平均”的效果,但只需支付大约两倍于单个网络的训练成本。
在测试时,为了近似这种组合效果,所有神经元都会被使用,但是它们的输出会乘以0.5(因为在训练时每个神经元只有50%的概率被使用),这相当于在所有的dropout网络中取它们输出的几何平均值。
总的来说,dropout可以视为一种正则化技术,它鼓励网络学习更加稳健的特征,减少过拟合,而且计算效率较高。
作者在图 2 的前两个全连接层中使用 dropout。没有 dropout 时,AlexNet 显示出大量的过拟合。Dropout 大约使收敛所需的迭代次数增加了一倍。
学习细节
这部分内容包括了网络的初始化、学习率的设置、权重更新规则以及防止过拟合的方法。下面是该部分的具体内容解释:
-
随机梯度下降(Stochastic Gradient Descent, SGD):
训练模型时使用了随机梯度下降法,它是一种优化算法,用于最小化损失函数。具体来说,使用的是小批量(mini-batch)梯度下降,每个批量包含128个训练样本。这种方法每次只使用一个批量的数据来更新模型权重,使得训练更快并且能够在线更新模型。 -
动量(Momentum):
使用了动量值0.9。动量帮助加速SGD在相关方向上的学习,并且抑制震荡,可以看作是加权平均过去梯度的方法,给予最近的梯度更高的权重,因此能够加速学习过程。 -
权重衰减(Weight Decay):
使用了权重衰减,也就是L2正则化,其值设置为0.0005。权重衰减可以防止模型权重变得过大,有助于控制模型的复杂度和过拟合。 -
权重更新规则:
更新权重时,权重的变化包括三部分:动量项(前一次权重更新的动量)、权重衰减项和当前梯度项。这个更新规则可以简化为:新的权重 = 前一次权重 - 学习率 * (权重衰减 * 前一次权重 + 当前批量的梯度)。 -
权重和偏差的初始化:
权重初始化是从均值为0,标准差为0.01的高斯分布中随机选取的,而第二、四和五卷积层的偏差初始化为1,全连接层的偏差初始化为1(这有助于ReLU激活函数在初期有正的梯度),其他层的偏差初始化为0。 -
学习率设置:
所有层使用相同的学习率,学习率初始设为0.01,并根据验证集上的误差停止提升时减小。当验证误差不再减小时,将学习率除以10。在整个训练过程中,学习率共减小了三次。 -
训练时间和周期:
训练模型大约需要90个epoch,也就是说数据集中的每个样本平均被模型看过90次。整个训练过程在两个NVIDIA GTX 580 3GB GPU上进行,耗时5到6天。
模型代码复现
到底输入尺寸是 224 × 224 224\times 224 224×224 还是 227 × 227 227\times 227 227×227
AlexNet 论文原始中是 224 × 224 224\times 224 224×224,但是 224 × 224 224\times 224 224×224 和 227 × 227 227\times 227 227×227 都必须保证第一个卷积层输出的特征图空间尺寸为 55 × 55 55\times 55 55×55
根据下面这个
nn.Conv2d 输出的特征图尺寸计算公式
output_size
=
⌊
input_size
−
kernel_size
+
2
×
padding
stride
+
1
⌋
\text{output\_size} = \lfloor\frac{{\text{input\_size} - \text{kernel\_size} + 2 \times \text{padding}}}{{\text{stride}}} + 1\rfloor
output_size=⌊strideinput_size−kernel_size+2×padding+1⌋
如果输入尺寸是
224
×
224
224\times 224
224×224 ,那么根据上面这个公式,需要进行 padding=2
的填充
如果输入尺寸是 227 × 227 227\times 227 227×227,那么不需要进行 padding
nn.LocalResponseNorm
nn.LocalResponseNorm
是PyTorch中的一个层,用于实现局部响应归一化(Local Response Normalization, LRN)。LRN是一种在卷积神经网络中使用的归一化技术,特别是在AlexNet架构中。它旨在增强相邻特征图之间的竞争,通过对局部输入区域进行归一化来实现这一点,从而有助于增强模型的泛化能力。
签名
torch.nn.LocalResponseNorm(size, alpha=0.0001, beta=0.75, k=1.0)
参数
size
(int): 卷积核的大小,用于计算归一化窗口的尺寸。alpha
(float, optional): 乘法因子,默认值为0.0001。beta
(float, optional): 幂指数,默认值为0.75。k
(float, optional): 加法因子,默认值为1.0。
示例
假设我们有一个具有10个通道的特征图(即卷积层的输出),我们希望对这些特征图应用局部响应归一化:
import torch
import torch.nn as nn
# 创建一个具有10个通道的随机特征图
x = torch.randn(1, 10, 24, 24)
# 定义LRN层
lrn = nn.LocalResponseNorm(size=5, alpha=0.0001, beta=0.75, k=1.0)
# 应用LRN层
y = lrn(x)
print(y.size()) # 输出: torch.Size([1, 10, 24, 24])
在这个例子中,我们首先创建了一个形状为(1, 10, 24, 24)
的随机特征图x
,其中1
是批量大小,10
是通道数,24x24
是特征图的高度和宽度。然后,我们定义了一个LocalResponseNorm
层lrn
,其中size=5
意味着每个通道将与其相邻的两个通道(总共5个通道)一起进行归一化。最后,我们将lrn
应用于特征图x
,得到归一化后的输出y
,其形状与输入x
相同。
模型结构
- 第一个卷积层使用了48个卷积核,所以它将输入的RGB图像(3个通道)转换成了48个特征通道的输出。
- 第二个卷积层有128个卷积核,它接收48个通道的输入,并输出128个特征通道。
- 第三个和第四个卷积层都有192个卷积核,这两层分别接收前一层的输出作为输入,并产生192个特征通道的输出。
- 第五个卷积层有128个卷积核,接收192个通道的输入,并输出128个特征通道。
池化层(如MaxPool2d
)不改变特征通道的数量,它们仅仅减小特征图的空间维度(即高度和宽度),有助于在网络中构建位置不变性以及减少计算量和参数数量。
nn.Conv2d 输出的特征图尺寸计算公式
output_size
=
⌊
input_size
−
kernel_size
+
2
×
padding
stride
+
1
⌋
\text{output\_size} = \lfloor\frac{{\text{input\_size} - \text{kernel\_size} + 2 \times \text{padding}}}{{\text{stride}}} + 1\rfloor
output_size=⌊strideinput_size−kernel_size+2×padding+1⌋带入第一个卷积层的参数,得到其输出的特征图尺寸为
55
×
55
55\times 55
55×55
MaxPool2d输出的特征图尺寸计算公式
假设输入特征图的尺寸为
H
×
W
H \times W
H×W,MaxPool2d
层的核大小为
k
k
k, 步长为
s
s
s, 填充为
p
p
p,则输出特征图的高度
H
o
u
t
H_{out}
Hout 和宽度
W
o
u
t
W_{out}
Wout 可以通过以下公式计算:
H o u t = ⌊ H + 2 p − k s + 1 ⌋ H_{out} = \left\lfloor\frac{H + 2p - k}{s} + 1\right\rfloor Hout=⌊sH+2p−k+1⌋
W o u t = ⌊ W + 2 p − k s + 1 ⌋ W_{out} = \left\lfloor\frac{W + 2p - k}{s} + 1\right\rfloor Wout=⌊sW+2p−k+1⌋
import torch
import torch.nn as nn
class AlexNet(nn.Module):
def __init__(self, num_classes=1000):
super(AlexNet, self).__init__()
# 特征提取部分
self.features = nn.Sequential(
# 输入图像为 224x224 像素,3个颜色通道(RGB)
nn.Conv2d(3, 96, kernel_size=11, stride=4, padding=2),
# 输出特征图尺寸:55x55
nn.ReLU(inplace=True),
nn.LocalResponseNorm(size=5, alpha=0.0001, beta=0.75, k=2)
nn.MaxPool2d(kernel_size=3, stride=2),
# 输出特征图尺寸:27x27
nn.Conv2d(96, 256, kernel_size=5, padding=2),
# 输出特征图尺寸:27x27
nn.ReLU(inplace=True),
nn.LocalResponseNorm(size=5, alpha=0.0001, beta=0.75, k=2)
nn.MaxPool2d(kernel_size=3, stride=2),
# 输出特征图尺寸:13x13
nn.Conv2d(256, 384, kernel_size=3, padding=1),
# 输出特征图尺寸:13x13
nn.ReLU(inplace=True),
nn.Conv2d(384, 384, kernel_size=3, padding=1),
# 输出特征图尺寸:13x13
nn.ReLU(inplace=True),
nn.Conv2d(384, 256, kernel_size=3, padding=1),
# 输出特征图尺寸:13x13
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3, stride=2),
# 输出特征图尺寸:6x6
)
# 自适应平均池化层到固定尺寸 6x6
# self.avgpool = nn.AdaptiveAvgPool2d((6, 6))
# 分类器部分
self.classifier = nn.Sequential(
nn.Dropout(p=0.5, inplace=True), # Dropout层用于防止过拟合
nn.Linear(256 * 6 * 6, 4096), #全连接层
nn.ReLU(inplace=True),
nn.Dropout(p=0.5, inplace=True),
nn.Linear(4096, 4096), #全连接层
nn.ReLU(inplace=True),
nn.Linear(4096, num_classes), # 输出层,num_classes为类别数
)
self.init_bias()
def init_bias(self):
for layer in self.features:
if isinstance(layer, nn.Conv2d):
nn.init.normal_(layer.weight, mean=0, std=0.01)
nn.init.constant_(layer.bias, 0)
# original paper = 1 for Conv2d layers 2nd, 4th, and 5th conv layers
nn.init.constant_(self.features[4].bias, 1)
nn.init.constant_(self.features[10].bias, 1)
nn.init.constant_(self.features[12].bias, 1)
def forward(self, x):
x = self.features(x) # 应用特征提取
# x = self.avgpool(x) # 应用平均池化
# 展平特征图,准备输入到全连接层
x = x.view(x.size(0), 256 * 6 * 6)
x = self.classifier(x) # 应用分类器
return x
# 实例化模型
model = AlexNet()
# 打印模型结构
print(model)
-
模型定义:
AlexNet
类继承自nn.Module
,这是PyTorch中所有神经网络模型的基类。 -
特征提取部分 (
self.features
):这是一个由多个卷积层、ReLU激活函数、LRN层和最大池化层组成的序列(nn.Sequential
)。这些层按顺序堆叠,用于从输入图像中提取特征。每个卷积层后都紧跟着一个ReLU激活函数,而LRN层则在部分ReLU后使用。 -
LRN层:
nn.LocalResponseNorm(size=5, alpha=0.0001, beta=0.75, k=2)
是局部响应归一化层,它在原始的AlexNet论文中被提到,用于增强模型的泛化能力。 -
分类器部分 (
self.classifier
):这是一个由Dropout层、全连接层(nn.Linear
)和ReLU激活函数组成的序列。Dropout层以0.5的概率随机丢弃特征,以防止过拟合。全连接层用于将提取的特征映射到最终的类别输出。 -
权重和偏置初始化 (
self.init_bias()
):init_bias
方法用于初始化网络中的权重和偏置。对于卷积层,权重使用正态分布初始化,偏置初始化为0。对于特定的卷积层(第2、4和5层),偏置被初始化为1,这是根据原始AlexNet论文的建议。 -
前向传播 (
forward
方法):定义了模型的前向传播路径。输入x
首先通过特征提取部分,然后通过分类器部分。最终的输出是类别的预测。 -
模型实例化:使用
AlexNet()
创建模型的实例,并打印出模型的结构。
说明:
关于 nn.ReLU(inplace=True)
# 输入图像为 224x224 像素,3个颜色通道(RGB)
nn.Conv2d(3, 96, kernel_size=11, stride=4, padding=2),
# 输出特征图尺寸:55x55
nn.ReLU(inplace=True),
ReLU通常紧跟在Conv2D操作之后,ReLU(inplace=True)
是对 nn.Conv2d()
输出的特征图进行操作。inplace=True
参数的作用是让 ReLU 函数直接在原地修改特征图,而不是产生特征图的一个副本来存放结果。这样做可以减少内存消耗,因为不需要为ReLU的输出分配新的内存。
具体来说,当一个 nn.Conv2d()
层生成了一个特征图后,接下来的 nn.ReLU(inplace=True)
将会把这个特征图中所有的负值置为零,正值保持不变,从而引入非线性。如果 inplace
设置为 True
,这个操作将直接影响原始特征图,而不是创建一个修改后的副本。这通常是安全的,除非你需要保留未经 ReLU 修改的特征图用于其他计算。
关于多个全连接层
这部分代码片段中,为什么设置多个全连接层,好处是什么?
# 分类器部分
self.classifier = nn.Sequential(
nn.Dropout(p=0.5, inplace=True), # Dropout层用于防止过拟合
nn.Linear(256 * 6 * 6, 4096), #全连接层
nn.ReLU(inplace=True),
nn.Dropout(p=0.5, inplace=True),
nn.Linear(4096, 4096), #全连接层
nn.ReLU(inplace=True),
nn.Linear(4096, num_classes), # 输出层,num_classes为类别数
)
在卷积神经网络(CNN)中,全连接层(也称为稠密层)用于将学习到的特征表征映射到样本的最终分类上。设置多个全连接层可以带来以下好处:
-
表示能力:每个全连接层都可以进一步学习前一层特征的非线性组合。堆叠多层可以增强网络的表示能力,允许模型捕获更复杂的模式。
-
深度:更深的网络理论上可以表达更复杂的函数。通过增加网络的深度,可以增强模型从数据中学习的能力。
-
抽象层次:在多层神经网络中,随着层数的加深,模型可以构建更高级的特征抽象。例如,第一层可能学习到边缘,第二层可能组合这些边缘形成纹理,更深的层可以识别出对象的具体部分。
-
决策边界:多个非线性层可以帮助模型形成更复杂的决策边界,这对于分类任务尤其重要,特别是在特征空间复杂或者分类问题本身非线性分隔的情况下。
-
学习多级特征组合:通过在多个全连接层中组合来自卷积层的特征,网络能够学习更复杂的特征组合,这些组合可能对最终的分类任务更加关键。
然而,设置多个全连接层也有可能带来过拟合的风险,尤其是在有限的训练数据上。为了缓解这一点,通常会在全连接层之间添加Dropout层。Dropout层在训练期间随机“丢弃”(即,设置为零)神经元的一部分输出,这有助于防止网络对训练数据过度拟合,增加模型的泛化能力。在上面的代码中,Dropout层被用在了两个全连接层之前,这是一个常用来减少过拟合风险的策略。
关于全连接层的参数
对的,nn.Linear
线性层通常只包含两类参数:权重(weight)和偏置(bias)。权重是输入和输出之间的连接权重,偏置是每个输出的额外偏移量。这两个参数用于计算线性变换,将输入数据映射到输出数据。
nn.Linear(2048, 2048)
包含多少个可学习的参数?
全连接层 nn.Linear(2048, 2048)
包含
2048
×
2048
2048 \times 2048
2048×2048 个权重参数和 2048 个偏置参数,总计
2048
×
2048
+
2048
=
4
,
196
,
352
2048 \times 2048 + 2048 = 4,196,352
2048×2048+2048=4,196,352 个可学习的参数。
nn.Dropout() 如何操作特征图?
# 分类器部分
self.classifier = nn.Sequential(
nn.Dropout(p=0.5, inplace=True), # Dropout层用于防止过拟合
nn.Linear(256 * 6 * 6, 4096), #全连接层
nn.ReLU(inplace=True),
nn.Dropout(p=0.5, inplace=True),
nn.Linear(4096, 4096), #全连接层
nn.ReLU(inplace=True),
nn.Linear(4096, num_classes), # 输出层,num_classes为类别数
)
nn.Dropout()
层通过随机地将一些神经元的输出设置为零来工作,从而在训练过程中丢弃一部分特征。
具体来说,对于每个输入元素(在这个上下文中是经过 nn.ReLU()
激活函数处理后的特征图中的每个值),nn.Dropout()
以一定的概率(称为丢弃率)将其设置为零,并将其他的输入元素按比例放大,以保持输入的总期望值不变。
例如,假设我们有一个经过 nn.ReLU()
激活的特征图 [0.0, 1.0, 2.0, 3.0, 4.0]
,并且 nn.Dropout()
的丢弃率为 0.5。在训练时,nn.Dropout()
可能会随机将这个特征图变成 [0.0, 0.0, 2.0, 0.0, 8.0]
。注意,非零元素(2.0和8.0)被放大了,以保持输入的总期望值不变。
在测试时,nn.Dropout()
不会丢弃任何特征,但会使用与训练时相同的放大因子来缩放输入,以保持总体统计特性不变。
通过这种方式,nn.Dropout()
提供了一种正则化,可以减少模型对特定训练样本的依赖,从而提高模型的泛化能力。这种随机丢弃的效果是,网络不能依赖于任何一个特征,因为它可能在任何时候被丢弃,迫使网络学习更加健壮的特征表示。