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

相关推荐
NAGNIP20 小时前
一文搞懂深度学习中的通用逼近定理!
人工智能·算法·面试
冬奇Lab1 天前
一天一个开源项目(第36篇):EverMemOS - 跨 LLM 与平台的长时记忆 OS,让 Agent 会记忆更会推理
人工智能·开源·资讯
冬奇Lab1 天前
OpenClaw 源码深度解析(一):Gateway——为什么需要一个"中枢"
人工智能·开源·源码阅读
AngelPP1 天前
OpenClaw 架构深度解析:如何把 AI 助手搬到你的个人设备上
人工智能
宅小年1 天前
Claude Code 换成了Kimi K2.5后,我再也回不去了
人工智能·ai编程·claude
九狼1 天前
Flutter URL Scheme 跨平台跳转
人工智能·flutter·github
ZFSS1 天前
Kimi Chat Completion API 申请及使用
前端·人工智能
天翼云开发者社区1 天前
春节复工福利就位!天翼云息壤2500万Tokens免费送,全品类大模型一键畅玩!
人工智能·算力服务·息壤
知识浅谈1 天前
教你如何用 Gemini 将课本图片一键转为精美 PPT
人工智能
Ray Liang1 天前
被低估的量化版模型,小身材也能干大事
人工智能·ai·ai助手·mindx