) {3 ]8 S* x" n$ `0 @9 [" O在最后一个卷积层后有两个全连接层,分别有4096个输出。 这两个巨大的全连接层拥有将近1GB的模型参数。 由于早期GPU显存有限,原版的AlexNet采用了双数据流设计,使得每个GPU只负责存储和计算模型的一半参数。 幸运的是,现在GPU显存相对充裕,所以我们现在很少需要跨GPU分解模型(因此,我们的AlexNet模型在这方面与原始论文稍有不同)。 / X6 b- H( A4 {+ S% P 7 e$ M! G% a9 a" x$ E+ ^1.2.2. 激活函数1 k# T0 x, u+ p9 } j |* d1 S4 Z0 t
此外,AlexNet将sigmoid激活函数改为更简单的ReLU激活函数。 一方面,ReLU激活函数的计算更简单,它不需要如sigmoid激活函数那般复杂的求幂运算。 另一方面,当使用不同的参数初始化方法时,ReLU激活函数使训练模型更加容易。 当sigmoid激活函数的输出非常接近于0或1时,这些区域的梯度几乎为0,因此反向传播无法继续更新一些模型参数。 相反,ReLU激活函数在正区间的梯度总是1。 因此,如果模型参数没有正确初始化,sigmoid函数可能在正区间内得到几乎为0的梯度,从而使模型无法得到有效的训练。 6 k$ O b! Q$ z( M; g& Z+ c- I5 S , G P' ^; j: o! d1 V1.2.3. 容量控制和预处理 # L. t7 r* E( P5 t3 m- ~: v/ z. v, ^AlexNet通过暂退法控制全连接层的模型复杂度,而LeNet只使用了权重衰减。 为了进一步扩充数据,AlexNet在训练时增加了大量的图像增强数据,如翻转、裁切和变色。 这使得模型更健壮,更大的样本量有效地减少了过拟合。 ( ~7 k: `" `1 r7 h. }" v: |. E% E1 Q' ?- h
' R. I2 ~( }+ o h / O6 y: E1 {3 y' F- z% dimport torch 9 h$ O. B/ ~! Y. W4 c0 m# nfrom torch import nn # K9 Z/ i. I1 W$ n, @2 Pfrom d2l import torch as d2l4 Z# u. c3 _6 B7 V/ j8 H" e
$ s8 k/ r7 y, u2 L6 a- V2 H+ ynet = nn.Sequential( H/ _7 u' n% l' s
# 这里,我们使用一个11*11的更大窗口来捕捉对象。9 Z1 V! w# i7 _8 y5 e
# 同时,步幅为4,以减少输出的高度和宽度。* j5 H9 t( M6 Z7 E9 @% e
# 另外,输出通道的数目远大于LeNet 4 M1 H9 ]" ^% i# j# Y$ Y4 [ nn.Conv2d(1, 96, kernel_size=11, stride=4, padding=1), nn.ReLU(),* z& r- Y. {9 g" a
nn.MaxPool2d(kernel_size=3, stride=2),& {: R6 k3 G1 |; g
# 减小卷积窗口,使用填充为2来使得输入与输出的高和宽一致,且增大输出通道数 ) S' } k$ q, x8 U h8 P nn.Conv2d(96, 256, kernel_size=5, padding=2), nn.ReLU(), ( T4 t c3 \( J1 E. b8 b! d+ y nn.MaxPool2d(kernel_size=3, stride=2),! I: h% C! R+ Z2 ^9 M6 D5 i
# 使用三个连续的卷积层和较小的卷积窗口。$ r: ]- i8 V3 v
# 除了最后的卷积层,输出通道的数量进一步增加。7 U$ k K, B8 i# E/ k5 {
# 在前两个卷积层之后,汇聚层不用于减少输入的高度和宽度6 b6 d0 h0 V9 u, o5 ?
nn.Conv2d(256, 384, kernel_size=3, padding=1), nn.ReLU(), ! o- b# B$ y( V nn.Conv2d(384, 384, kernel_size=3, padding=1), nn.ReLU(), ' i8 o- f g+ A8 N& t+ |( f! H2 K nn.Conv2d(384, 256, kernel_size=3, padding=1), nn.ReLU(), + J( Q+ ^4 H4 q" }" y+ x( q- { nn.MaxPool2d(kernel_size=3, stride=2),. [& b8 b# y0 ?/ _. c
nn.Flatten(), 9 S6 O: a2 t; Y O o4 z+ ] # 这里,全连接层的输出数量是LeNet中的好几倍。使用dropout层来减轻过拟合 8 L* [: P; ]2 n$ N4 M nn.Linear(6400, 4096), nn.ReLU(), ! d+ i! j8 {' D% \5 w( ? nn.Dropout(p=0.5),7 r2 V. W& I. I- E/ [! B& ?
nn.Linear(4096, 4096), nn.ReLU(), 5 |9 X! Z5 E' L" o nn.Dropout(p=0.5), ) }1 k# ` R' w, K6 ~9 W # 最后是输出层。由于这里使用Fashion-MNIST,所以用类别数为10,而非论文中的10003 R" [, O/ K) l4 ], e/ z
nn.Linear(4096, 10)): j5 V: k! g: b. B
1 m0 l( d# ]4 y$ a: K/ R
我们构造一个高度和宽度都为224的单通道数据,来观察每一层输出的形状。 2 l& x+ Z7 Q0 W* i o" {) P7 c' U n6 [) D& W% x( y
X = torch.randn(1, 1, 224, 224) ! o. h( Q2 z6 {for layer in net:0 i3 D, y0 V7 a0 z6 E. t
X=layer(X) 0 e7 o% o5 R2 G' }+ L print(layer.__class__.__name__,'output shape:\t',X.shape)+ g; x& ?3 G$ J% a/ z: J
Conv2d output shape: torch.Size([1, 96, 54, 54]) * H" n) n2 s* m% IReLU output shape: torch.Size([1, 96, 54, 54])! o$ D- k1 s( V' ~% Q" ^+ M3 k
MaxPool2d output shape: torch.Size([1, 96, 26, 26]) 7 ~* n! `% n( u# l) A C$ lConv2d output shape: torch.Size([1, 256, 26, 26]); z( q' A+ W/ U5 S* o* R) e
ReLU output shape: torch.Size([1, 256, 26, 26])- b+ `. T, D# x& E8 f
MaxPool2d output shape: torch.Size([1, 256, 12, 12]) 6 w% e% m1 a+ V$ O, F! U! DConv2d output shape: torch.Size([1, 384, 12, 12])) A) ?, ~% W0 G* i/ @( D0 f2 B# @
ReLU output shape: torch.Size([1, 384, 12, 12])) Y7 @' K3 B) t% H; N
Conv2d output shape: torch.Size([1, 384, 12, 12]) 6 W; E: u; ^6 a( e p2 yReLU output shape: torch.Size([1, 384, 12, 12])6 G3 Q$ q+ q! ~
Conv2d output shape: torch.Size([1, 256, 12, 12]) " f. K. c" @% P1 Y+ Z x: A: r7 v }ReLU output shape: torch.Size([1, 256, 12, 12]) % z0 c: T+ a D4 N/ u2 nMaxPool2d output shape: torch.Size([1, 256, 5, 5]) ( f" v) R9 I9 {+ `( z: ?0 IFlatten output shape: torch.Size([1, 6400]) 2 ^4 M: Z K; M$ i) r, ^" sLinear output shape: torch.Size([1, 4096])( f' X# d/ E8 w2 N- Y; I
ReLU output shape: torch.Size([1, 4096]), p# l' \ [6 P o! v2 C
Dropout output shape: torch.Size([1, 4096])& [2 {% u3 {" k/ l$ l
Linear output shape: torch.Size([1, 4096])/ I3 j8 q( O- }$ f4 K
ReLU output shape: torch.Size([1, 4096])9 y. x+ b, a6 r0 W. j' K6 s
Dropout output shape: torch.Size([1, 4096])2 {# ^7 L# K7 D. d& `$ R! [
Linear output shape: torch.Size([1, 10]) # V! Q5 ?* Q+ t0 C! F7 H4 y2 \* `/ e; U6 j' `# h5 p) ?( t6 R
1.3. 读取数据集 : e" e2 j1 V" \& d) o尽管本文中AlexNet是在ImageNet上进行训练的,但我们在这里使用的是Fashion-MNIST数据集。因为即使在现代GPU上,训练ImageNet模型,同时使其收敛可能需要数小时或数天的时间。 将AlexNet直接应用于Fashion-MNIST的一个问题是,Fashion-MNIST图像的分辨率(28×28像素)低于ImageNet图像。 为了解决这个问题,我们将它们增加到224×224(通常来讲这不是一个明智的做法,但我们在这里这样做是为了有效使用AlexNet架构)。 我们使用d2l.load_data_fashion_mnist函数中的resize参数执行此调整。6 m9 r' Y$ O1 c! M8 N
5 H- j1 u+ Y8 }& k
batch_size = 128) | H; k4 P& b/ {& }
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size, resize=224)9 X5 b0 V: C/ z7 [
1.4. 训练AlexNet 5 U' y* f! u0 W& X现在,我们可以开始训练AlexNet了。与LeNet相比,这里的主要变化是使用更小的学习速率训练,这是因为网络更深更广、图像分辨率更高,训练卷积神经网络就更昂贵。1 j, P* S' O) J* k! l0 z# _
( @: N5 N, l/ O. mlr, num_epochs = 0.01, 10 , L8 c3 w4 o4 wd2l.train_ch6(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu()) u# x2 O+ o1 T+ `loss 0.327, train acc 0.881, test acc 0.885 M% E# ]1 M9 ?- |, r; q
4149.6 examples/sec on cuda:0 9 _/ @9 @2 I# ?+ G K& C# a% P& d9 S
: o: b9 L( }* o. v! o7 w$ ]. K6 a$ o9 j% h
V+ F# u; z4 e! t
1.5. 小结 . `5 X. y+ E- o6 y# d0 z# vAlexNet的架构与LeNet相似,但使用了更多的卷积层和更多的参数来拟合大规模的ImageNet数据集。 * s7 w: ]( q) V5 a, k2 P, K' |% n ! F3 o4 Z) O, z) x今天,AlexNet已经被更有效的架构所超越,但它是从浅层网络到深层网络的关键一步。 3 N; K' ~ @+ W2 C % x) q" q2 T, d( d尽管AlexNet的代码只比LeNet多出几行,但学术界花了很多年才接受深度学习这一概念,并应用其出色的实验结果。这也是由于缺乏有效的计算工具。5 F) E& j( M0 O, S
$ i! {, D& V0 z/ i4 W
Dropout、ReLU和预处理是提升计算机视觉任务性能的其他关键步骤。) ~% k% k; u0 u B: g+ E3 ~, Q9 `
————————————————3 [1 M+ H+ b3 `4 |( L
版权声明:本文为CSDN博主「Soloy_」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 ! J: B4 \3 ]( T. ^+ n/ p原文链接:https://blog.csdn.net/sikh_0529/article/details/126805057 ) Q' W/ f m9 y% Z! u* ^ 6 v. e1 [* H5 D. a* e M! _7 \: n, Y$ O' g0 G# J- E$ }