深度学习③|分类任务—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的核心结构,用于理解卷积过程计算参数量。

相关推荐
网安情报局几秒前
RSAC 2026深度解析:AI对抗AI成主流,九大安全能力全面升级
人工智能·网络安全
key_3_feng几秒前
揭秘AI的“语言积木“:Token科普之旅
人工智能·搜索引擎·token
代码丰几秒前
Zero Code Studio:LangChain4j 工具调用 + LangGraph4j 工作流双模式的 AI 网站生成系统
java·人工智能
人工智能培训1 分钟前
多模态AI模型融合难?核心问题与解决思路
人工智能·机器学习·prompt·agent·智能体
FAFU_kyp1 分钟前
AP2 (Agent Payments Protocol) 技术流程详细解析
人工智能
北京耐用通信8 分钟前
工业自动化场景下耐达讯自动化的 CC-Link IE 转 Modbus TCP 技术方案与应用实践
人工智能·科技·物联网·网络协议·自动化
百家方案10 分钟前
2026年AI+智慧景区全场景应用解决方案白皮书 - 全1648页下载
人工智能·智慧文旅·智慧景区
intcube11 分钟前
让数据说话,让决策有据——构建闭环的数据驱动运营体系
大数据·人工智能·全面预算管理·财务规划
甄心爱学习12 分钟前
【最优化】1-6章习题
人工智能·算法
code_pgf12 分钟前
基于transformer的clip和blip之间的关系、原理、方法实现和直观可视化
人工智能·深度学习·transformer