[深度学习网络从入门到入土] 深度卷积神经网络alexnet
个人导航
知乎:https://www.zhihu.com/people/byzh_rc
CSDN:https://blog.csdn.net/qq_54636039
注:本文仅对所述内容做了框架性引导,具体细节可查询其余相关资料or源码
参考文章:各方资料
文章目录
- [深度学习网络从入门到入土] 深度卷积神经网络alexnet
- 个人导航
- 参考资料
- 背景
- 架构(公式)
- 1.输入
- 2.卷积层
- 3.激活函数(ReLU)
- 4.局部响应归一化(LRN)
- 5.池化层
- 6.全连接层
- 创新点
- 1. ReLU 取代传统激活函数
- 2. GPU 并行训练
- 3. 大模型 + 大数据
- 4. 数据增强
- 5. Dropout
- 拓展 - 局部响应归一化LRN
- 代码实现
- 项目实例
参考资料
ImageNet Classification with Deep Convolutional Neural Networks
背景
AlexNet 的核心意义不在于“用了 CNN”,而在于它首次证明: 在大数据 + GPU 条件下,深层 CNN 可以显著击败传统方法
->第一个把深度学习真正跑通并跑赢传统方法的系统工程
AlexNet 作用于 ImageNet 2012:
- Top-5 error 从 ~26% 直接降到 ~15%
- 断层式领先,直接改变研究范式
架构(公式)
AlexNet 是一个8 层可学习参数网络:
- 5 个卷积层
- 3 个全连接层
整体结构可概括为:
Input → Conv → ReLU → LRN → Pool → ⋯ → FC → Softmax \text{Input} \rightarrow \text{Conv} \rightarrow \text{ReLU} \rightarrow \text{LRN} \rightarrow \text{Pool} \rightarrow \cdots \rightarrow \text{FC} \rightarrow \text{Softmax}Input→Conv→ReLU→LRN→Pool→⋯→FC→Softmax
1.输入
原论文输入尺寸:
3 × 227 × 227 3 \times 227 \times 2273×227×227
2.卷积层
标准二维卷积:
y i , j , k = ∑ c ∑ u , v w u , v , c , k ⋅ x i + u , j + v , c + b k y_{i,j,k} = \sum_{c}\sum_{u,v} w_{u,v,c,k} \cdot x_{i+u,j+v,c} + b_kyi,j,k=c∑u,v∑wu,v,c,k⋅xi+u,j+v,c+bk
AlexNet 的关键不是公式,而是规模:
- Conv1:11 × 11 11 \times 1111×11,stride=4
- Conv2:5 × 5 5 \times 55×5
- Conv3–5:3 × 3 3 \times 33×3
3.激活函数(ReLU)
首次大规模使用 ReLU:
f ( x ) = max ( 0 , x ) f(x) = \max(0, x)f(x)=max(0,x)
对比 tanh / sigmoid:
- 避免梯度饱和
- 显著加快收敛速度
4.局部响应归一化(LRN)
AlexNet 特有(后续模型基本弃用):
b x , y i = a x , y i ( k + α ∑ j = i − n / 2 i + n / 2 ( a x , y j ) 2 ) β b_{x,y}^i = \frac{a_{x,y}^i} {\left(k + \alpha \sum_{j=i-n/2}^{i+n/2}(a_{x,y}^j)^2\right)^\beta}bx,yi=(k+α∑j=i−n/2i+n/2(ax,yj)2)βax,yi
本质:
- 引入跨通道竞争
- 模拟生物神经元侧抑制
5.池化层
重叠最大池化(overlapping max pooling):
y = max ( u , v ) ∈ Ω x u , v y = \max_{(u,v)\in \Omega} x_{u,v}y=(u,v)∈Ωmaxxu,v
stride < kernel size \text{stride} < \text{kernel size}stride<kernel size: 减少过拟合,同时保留更多空间信息
6.全连接层
最后三层:
y = W x + b \mathbf{y} = \mathbf{W}\mathbf{x} + \mathbf{b}y=Wx+b
最后一层使用 Softmax:
p i = e z i ∑ j e z j p_i = \frac{e^{z_i}}{\sum_j e^{z_j}}pi=∑jezjezi
创新点
1. ReLU 取代传统激活函数
- 训练速度数量级提升
- 为更深网络铺路
2. GPU 并行训练
- 使用两张 GPU
- 网络结构被“强行拆分”到不同 GPU 上
3. 大模型 + 大数据
- 参数量 ~ 60M
- ImageNet 规模首次被充分利用
4. 数据增强
- 随机裁剪
- 水平翻转
- RGB 颜色扰动(PCA jittering)
5. Dropout
- 首次在大规模 CNN 中系统使用
- 主要用于全连接层
h ~ i = r i h i , r i ∼ Bernoulli ( p ) \tilde{h}_i = r_i h_i,\quad r_i \sim \text{Bernoulli}(p)h~i=rihi,ri∼Bernoulli(p)
拓展 - 局部响应归一化LRN
在通道维度(channel)上做“邻域竞争/抑制”
-> 某个位置上,如果某些通道响应很大,会抑制同一位置附近通道的响应,从而“强调强响应、压制弱响应”
LRN 在 AlexNet 之后逐渐不用了,主要原因是:
- 效果一般、计算开销不小
- BatchNorm/LayerNorm/GroupNorm 更稳定、训练更快、更有效
nn.LocalResponseNorm(size=5, alpha=1e-4, beta=0.75, k=2.0):
size=5: 通道邻域窗口大小 (跨通道的局部范围)5表示每个通道会参考它自己以及左右各 2 个通道的能量(平方和)alpha=1e-4: 归一化强度系数 (越大,分母里那项越大,抑制越强)beta=0.75: 指数幂 (越大,抑制的非线性越强)k=2.0: 分母的基底常数项 (防止分母太小导致数值爆炸,也控制整体缩放)
代码实现
importtorchimporttorch.nnasnnimporttorch.nn.functionalasFclassB_AlexNet_Paper(nn.Module):def__init__(self,num_classes=1000):super().__init__()# =========# 特征提取部分# =========self.conv1=nn.Conv2d(3,96,kernel_size=11,stride=4)self.relu1=nn.ReLU(inplace=True)self.lrn1=nn.LocalResponseNorm(size=5,alpha=1e-4,beta=0.75,k=2.0)self.pool1=nn.MaxPool2d(kernel_size=3,stride=2)self.conv2=nn.Conv2d(96,256,kernel_size=5,padding=2)self.relu2=nn.ReLU(inplace=True)self.lrn2=nn.LocalResponseNorm(size=5,alpha=1e-4,beta=0.75,k=2.0)self.pool2=nn.MaxPool2d(kernel_size=3,stride=2)self.conv3=nn.Conv2d(256,384,kernel_size=3,padding=1)self.relu3=nn.ReLU(inplace=True)self.conv4=nn.Conv2d(384,384,kernel_size=3,padding=1)self.relu4=nn.ReLU(inplace=True)self.conv5=nn.Conv2d(384,256,kernel_size=3,padding=1)self.relu5=nn.ReLU(inplace=True)self.pool3=nn.MaxPool2d(kernel_size=3,stride=2)# =========# 分类器部分(保持不变)# 256*6*6 对齐 227×227 输入# =========self.classifier=nn.Sequential(nn.Dropout(p=0.5),# 仅在model.train()训练时才启用nn.Linear(256*6*6,4096),nn.ReLU(inplace=True),nn.Dropout(p=0.5),# 仅在model.train()训练时才启用nn.Linear(4096,4096),nn.ReLU(inplace=True),nn.Linear(4096,num_classes),)defforward(self,x):# =========# 1) 输入尺寸对齐:224 -> 227# =========ifx.shape[-2:]==(224,224):x=F.pad(x,(1,2,1,2),mode="constant",value=0.0)# =========# 2) Conv1 -> ReLU -> LRN -> Pool# =========x=self.conv1(x)#x=self.relu1(x)x=self.lrn1(x)x=self.pool1(x)# =========# 3) Conv2 -> ReLU -> LRN -> Pool# =========x=self.conv2(x)x=self.relu2(x)x=self.lrn2(x)x=self.pool2(x)# =========# 4) Conv3 -> ReLU# =========x=self.conv3(x)x=self.relu3(x)# =========# 5) Conv4 -> ReLU# =========x=self.conv4(x)x=self.relu4(x)# =========# 6) Conv5 -> ReLU -> Pool# =========x=self.conv5(x)x=self.relu5(x)x=self.pool3(x)# =========# 7) Flatten + classifier# =========x=x.flatten(1)x=self.classifier(x)returnxif__name__=='__main__':net=B_AlexNet_Paper(num_classes=1000)a=torch.randn(50,3,224,224)result=net(a)print(result.shape)项目实例
库环境:
numpy==1.26.4 torch==2.2.2cu121 byzh-core==0.0.9.21 byzh-ai==0.0.9.50 byzh-extra==0.0.9.12 ...AlexNet训练Oxford_IIIT_Pet数据集:
importtorchfrombyzh.ai.BtrainerimportB_Classification_Trainerfrombyzh.ai.BdataimportB_Download_Oxford_IIIT_Pet,b_get_dataloader_from_tensorfrombyzh.ai.Bmodel.study_cnnimportB_AlexNet_Paperfrombyzh.ai.Butilsimportb_get_device##### data #####downloader=B_Download_Oxford_IIIT_Pet(save_dir='D:/study_cnn/datasets/Oxford_IIIT_Pet')data_dict=downloader.get_data()X_train=data_dict['X_train_standard']y_train=data_dict['y_train']X_test=data_dict['X_test_standard']y_test=data_dict['y_test']num_classes=data_dict['num_classes']train_dataloader,val_dataloader=b_get_dataloader_from_tensor(X_train,y_train,X_test,y_test)##### model #####model=B_AlexNet_Paper(num_classes=num_classes)##### else #####epochs=10lr=1e-3device=b_get_device(use_idle_gpu=True)optimizer=torch.optim.Adam(model.parameters(),lr=lr)criterion=torch.nn.CrossEntropyLoss()##### trainer #####trainer=B_Classification_Trainer(model=model,optimizer=optimizer,criterion=criterion,train_loader=train_dataloader,val_loader=val_dataloader,device=device)trainer.set_writer1('./runs/log.txt')##### run #####trainer.train_eval_s(epochs=epochs)##### calculatetrainer.draw_loss_acc('./runs/loss_acc.png',y_lim=False)trainer.save_best_checkpoint('./runs/alexnet_best.pth')trainer.calculate_model()