深度学习③|分类任务—AlexNet

一、前言

AlexNet(2012),是深度学习发展历程中的一个里程碑,开启了深度学习的狂潮。同时,也是如今学习深度学习绕不开的经典模型。

本文旨在通过还原AlexNet的网络结构,在学习模型的同时,强化自己的参数计算能力。


二、实现步骤

2.1环境配置

复制代码
import torch.nn as nn
import torchvision.models as models
import torch

2.2与官方AlexNet结构对照

复制代码
alexnet = models.alexnet()
# 打印官方AlexNet结构,用于对照自定义的
print(alexnet)

2.3自定义AlexNet类

复制代码
# 自定义MyAlextNet类
# 定义自定义的 AlexNet 类,必须继承nn.Module
class MyAlexNet(nn.Module):
    # 定义类的初始化方法
    def __init__(self):
        # 调用父类nn.Module的初始化方法,必须写,否则无法继承nn.Module的核心功能
        super(MyAlexNet, self).__init__()
        self.relu = nn.ReLU()
        # 实例化 Dropout 层(丢弃概率 0.5)
        # AlexNet 的全连接层后通常加 Dropout 防止过拟合)
        # Dropout 会随机让 50% 的神经元输出置 0,避免模型过度依赖某部分神经元
        self.drop = nn.Dropout(0.5)
        # ❤定义第一个卷积层
        # 批量大小,C,H,W
        # ①(4, 3, 224, 224) ------------→ (4, 64, 55, 55)
        #                  ①输入通道数(厚度)②输出通道数(卷积核数量) ③卷积核大小     ④步数      ⑤padding
        self.conv1 = nn.Conv2d(in_channels=3, out_channels=64, kernel_size=11, stride=4, padding=2)
        # ❤定义一个最大池化层 MaxPool
        # ②(4, 64, 55, 55) ------------→ (4, 64, 27, 27)
        # kernel_size=3 : 池化核大小 3×3   stride=2:池化步长 2
        self.pool1 = nn.MaxPool2d(3, stride=2)
        # ❤定义第二个卷积层
        # ③(4, 64, 27, 27) ------------→ (4, 192, 27, 27)
        self.conv2 = nn.Conv2d(in_channels=64, out_channels=192, kernel_size=5, stride=1, padding=2)
        # ❤定义第二个最大池化层
        # ④(4, 192, 27, 27) ------------→ (4, 192, 13, 13)
        self.pool2 = nn.MaxPool2d(3, stride=2)
        # ❤定义第三个卷积层
        # ⑤(4, 192, 13, 13) ------------→ (4, 384, 13, 13)
        self.conv3 = nn.Conv2d(192, 384, 3, 1, 1)
        # ❤定义第四个卷积层
        # ⑤(4, 384, 13, 13) ------------→ (4, 256, 13, 13)
        self.conv4 = nn.Conv2d(384, 256, 3, 1, 1)
        # ❤定义第五个卷积层
        # ⑤(4, 256, 13, 13) ------------→ (4, 256, 13, 13)
        self.conv5 = nn.Conv2d(256, 256, 3, 1, 1)
        # ❤定义第三个最大池化层
        # ⑤(4, 256, 13, 13) ------------→ (4, 256, 6, 6)
        self.pool3 = nn.MaxPool2d(3, stride=2)
        # 定义自适应平均池化层,
        # 核心参数output_size=6:无论输入特征图尺寸是多少,输出固定为 6×6
        # ⑥ (4, 256, 6, 6) ------------→ (4, 256, 6, 6)
        self.adapool = nn.AdaptiveAvgPool2d(output_size=6)  # 行18

        # 第一个全连接层
        self.fc1 = nn.Linear(9216, 4096)
        # 第二个全连接层
        self.fc2 = nn.Linear(4096, 4096)
        # 第三个全连接层
        self.fc3 = nn.Linear(4096, 1000)
    # 前项传播
    def forward(self, x):
        # 第一个卷积
        # (4,3,224,224) → (4,64,55,55) → (4,64,27,27)
        x = self.conv1(x)
        x = self.relu(x)
        x = self.pool1(x)
        # 第二个卷积
        # (4,64,27,27) → (4,192,27,27) → (4,192,13,13)
        x = self.conv2(x)
        x = self.relu(x)
        x = self.pool2(x)
        # 第三个卷积
        # (4,192,13,13) → (4,384,13,13)
        x = self.conv3(x)
        x = self.relu(x)
        print(x.size())
        # 第四个卷积
        # (4,384,13,13) → (4,256,13,13)
        x = self.conv4(x)
        x = self.relu(x)
        print(x.size())
        # 第五个卷积
        # (4,256,13,13) → (4,256,6,6)
        x = self.conv5(x)
        x = self.relu(x)
        x = self.pool3(x)
        print(x.size())
        # 自适应平均池化,本项目中形状无变化
        x = self.adapool(x)
        # 展平特征图,二维转为一维
        # x.size()[0]:批量大小(这里是 4),保留第一维
        # -1:自动计算剩余维度的总长度(256×6×6=9216)
        x = x.view(x.size()[0], -1)

        # 三个全连接+drop操作(减少参数量,防止过拟合)
        # (4,9216) → (4,4096)
        x = self.fc1(x)
        x = self.relu(x)
        x = self.drop(x)
        # (4,4096) → (4,4096)
        x = self.fc2(x)
        x = self.relu(x)
        x = self.drop(x)
        # (4,4096) → (4,1000)
        x = self.fc3(x)
        x = self.relu(x)

        return x

2.4模型参数统计

定义一个辅助函数,在写代码的过程中,可以用于验证所计算的参数,以conv1为例

复制代码
# 统计模型总参数和可训练参数
def get_parameter_number(model):
    # 总参数数
    total_num = sum(p.numel() for p in model.parameters()) 
    # 可训练参数数       
    trainable_num = sum(p.numel() for p in model.parameters() if p.requires_grad)  
    return {'Total': total_num, 'Trainable': trainable_num}

# 初始化自定义模型
myalexnet = MyAlexNet()

# 统计conv1层参数(权重64×3×11×11=23232 + 偏置64 = 23296)
print("Conv1层参数统计:", get_parameter_number(myalexnet.conv1))

2.5输入,验证模型

复制代码
# 模拟输入:(批量大小, 通道数, 高, 宽) = (4, 3, 224, 224)
img = torch.zeros((4, 3, 224, 224))


out = myalexnet(img)

# 打印输出维度(4, 1000),对应4个样本的1000类预测
print("模型输出维度:", out.size())

三、总结

本代码通过5个卷积层和3个全连接,配合relu激活函数、最大池化以及Dropout 来简单地模拟实现AlexNet的核心结构,用于理解卷积过程计算参数量。

相关推荐
zl_vslam4 小时前
SLAM中的非线性优-3D图优化之绝对位姿SE3约束右扰动(十七)
人工智能·算法·计算机视觉·3d
光羽隹衡4 小时前
计算机视觉——Opencv(基础操作一)
人工智能·opencv·计算机视觉
玄微云4 小时前
当暖心服务遇见硬核AI:玄微子AI让孕产关怀更有温度
大数据·人工智能·科技·物联网·产康门店
Warren2Lynch4 小时前
AI赋能企业架构:TOGAF智能建模新时代
人工智能·架构
机器学习之心4 小时前
MATLAB基于近红外光谱检测的菠萝含水率预测(多种预处理+PLS)
人工智能·算法·matlab·近红外光谱检测
张心独酌4 小时前
学习Rust:实现RESTful 任务管理 API(Todo API)
学习·rust·restful
sunxunyong4 小时前
openwork实测
人工智能
isNotNullX4 小时前
什么是可信数据空间?为什么可信数据空间是数据共享的关键?
大数据·人工智能·数据安全·数据空间
星爷AG I4 小时前
9-1 视觉通路(AGI基础理论)
人工智能·agi