AlexNet模型及代码详解

本文详细介绍了AlexNet神经网络模型,该模型在2012年ImageNet图像识别大赛中夺冠,推动了CNN在图像分类领域的广泛应用。AlexNet的特点包括使用GPU加速训练,ReLU激活函数,局部响应归一化以及Dropout技术。文章还提供了模型结构及PyTorch实现代码,并展示了训练和预测流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Alex在2012年提出的alexnet网络结构模型引爆了神经网络的应用热潮,并赢得了2012届图像识别大赛的冠军,使得CNN成为在图像分类上的核心算法模型。 

 该网络的亮点在于:
(1)首次使用了GPU进行网络加速训练。
(2)使用了ReLU激活函数,而不是传统的Sigmoid激活函数以及Tanh激活函数。
(3)使用了LRN局部响应归一化。
(4)在全连接层的前两层中使用了Droupout随机失活神经元操作,以减少过拟合。

模型组成

  • 输入层
  • 5个卷积层
  • 3个全链接层

输入层: 输入大小为224 x 224的3通道图像,实际上会经过预处理变为227X227X3

第1层:卷积层(卷积、池化)

Conv1

输入:input_size = [224, 224, 3]
卷积层:
kernels = 48 * 2 = 96 组卷积核
kernel_size = 11
padding = [1, 2] (左上围加半圈0,右下围加2倍的半圈0)
stride = 4
输出:output_size = [55, 55, 96]

output=\frac{W-F+2P}{S}+1=\frac{224-11+(1+2)}{4}+1=55

Maxpool1

  • 输入:input_size = [55, 55, 96]
  • 池化层:(只改变尺寸,不改变深度channel)
    • kernel_size = 3
    • padding = 0
    • stride = 2
  • 输出:output_size = [27, 27, 96]

output=\frac{W-F+2P}{S}+1=\frac{55-3+0}{2}+1=27

Conv2

  • 输出:output_size = [27, 27, 256]

output=\frac{W-F+2P}{S}+1=\frac{27-5+(2+2))}{1}+1=27

Maxpool2

  • 输出:output_size = [13, 13, 256]

output=\frac{W-F+2P}{S}+1=\frac{27-3}{2}+1=13

Conv3

  • 输出:output_size = [13, 13, 384]

output=\frac{W-F+2P}{S}+1=\frac{13-3+(1+1))}{1}+1=13

Conv4

  • 输出:output_size = [13, 13, 384]

output=\frac{W-F+2P}{S}+1=\frac{13-3+(1+1))}{1}+1=13

Conv5

  • 输出:output_size = [13, 13, 256]

output=\frac{W-F+2P}{S}+1=\frac{13-3+(1+1))}{1}+1=13

Maxpool3

  • 输出:output_size = [6, 6, 256]

output=\frac{W-F+2P}{S}+1=\frac{13-3+0}{1}+1=6

FC1、FC2、FC3

Maxpool3 → (6*6*256) → FC1 → 4096 → FC2 → 4096 → FC3 → 1000

代码:

1. model.py

import torch.nn as nn
import torch

class AlexNet(nn.Module):
    def __init__(self, num_classes=1000, init_weights=False):
        super(AlexNet, self).__init__()
        # 用nn.Sequential()将网络打包成一个模块,精简代码
        self.features = nn.Sequential(   # 卷积层提取图像特征
            nn.Conv2d(3, 48, kernel_size=11, stride=4, padding=2),  # input[3, 224, 224]  output[48, 55, 55]
            nn.ReLU(inplace=True), 									# 直接修改覆盖原值,节省运算内存
            nn.MaxPool2d(kernel_size=3, stride=2),                  # output[48, 27, 27]
            nn.Conv2d(48, 128, kernel_size=5, padding=2),           # output[128, 27, 27]
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2),                  # output[128, 13, 13]
            nn.Conv2d(128, 192, kernel_size=3, padding=1),          # output[192, 13, 13]
            nn.ReLU(inplace=True),
            nn.Conv2d(192, 192, kernel_size=3, padding=1),          # output[192, 13, 13]
            nn.ReLU(inplace=True),
            nn.Conv2d(192, 128, kernel_size=3, padding=1),          # output[128, 13, 13]
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2),                  # output[128, 6, 6]
        )
        self.classifier = nn.Sequential(   # 全连接层对图像分类
            nn.Dropout(p=0.5),			   # Dropout 随机失活神经元,默认比例为0.5
            nn.Linear(128 * 6 * 6, 2048),
            nn.ReLU(inplace=True),
            nn.Dropout(p=0.5),
            nn.Linear(2048, 2048),
            nn.ReLU(inplace=True),
            nn.Linear(2048, num_classes),
        )
        if init_weights:
            self._initialize_weights()
            
	# 前向传播过程
    def forward(self, x):
        x = self.features(x)
        x = torch.flatten(x, start_dim=1)	# 展平后再传入全连接层
        x = self.classifier(x)
        return x
        
	# 网络权重初始化,实际上 pytorch 在构建网络时会自动初始化权重
    def _initialize_weights(self):
        for m in self.modules():
            if isinstance(m, nn.Conv2d):                            # 若是卷积层
                nn.init.kaiming_normal_(m.weight, mode='fan_out',   # 用(何)kaiming_normal_法初始化权重
                                        nonlinearity='relu')
                if m.bias is not None:
                    nn.init.constant_(m.bias, 0)                    # 初始化偏重为0
            elif isinstance(m, nn.Linear):            # 若是全连接层
                nn.init.normal_(m.weight, 0, 0.01)    # 正态分布初始化
                nn.init.constant_(m.bias, 0)          # 初始化偏重为0

2. train.py

import os
import sys
import json

import torch
import torch.nn as nn
from torchvision import transforms, datasets, utils
import matplotlib.pyplot as plt
import numpy as np
import torch.optim as optim
from tqdm import tqdm

from model import AlexNet


def main():
    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
    print("using {} device.".format(device))

    data_transform = {
        "train": transforms.Compose([transforms.RandomResizedCrop(224),
                                     transforms.RandomHorizontalFlip(),
                                     transforms.ToTensor(),
                                     transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]),
        "val": transforms.Compose([transforms.Resize((224, 224)),  # cannot 224, must (224, 224)
                                   transforms.ToTensor(),
                                   transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])}

    data_root = os.path.abspath(os.path.join(os.getcwd(), "../.."))  # get data root path
    image_path = os.path.join(data_root, "data_set", "flower_data")  # flower data set path
    assert os.path.exists(image_path), "{} path does not exist.".format(image_path)
    train_dataset = datasets.ImageFolder(root=os.path.join(image_path, "train"),
                                         transform=data_transform["train"])
    train_num = len(train_dataset)

    # {'daisy':0, 'dandelion':1, 'roses':2, 'sunflower':3, 'tulips':4}
    flower_list = train_dataset.class_to_idx
    cla_dict = dict((val, key) for key, val in flower_list.items())
    # write dict into json file
    json_str = json.dumps(cla_dict, indent=4)
    with open('class_indices.json', 'w') as json_file:
        json_file.write(json_str)

    batch_size = 32
    nw = min([os.cpu_count(), batch_size if batch_size > 1 else 0, 8])  # number of workers
    print('Using {} dataloader workers every process'.format(nw))

    train_loader = torch.utils.data.DataLoader(train_dataset,
                                               batch_size=batch_size, shuffle=True,
                                               num_workers=nw)

    validate_dataset = datasets.ImageFolder(root=os.path.join(image_path, "val"),
                                            transform=data_transform["val"])
    val_num = len(validate_dataset)
    validate_loader = torch.utils.data.DataLoader(validate_dataset,
                                                  batch_size=4, shuffle=False,
                                                  num_workers=nw)

    print("using {} images for training, {} images for validation.".format(train_num,
                                                                           val_num))
    # test_data_iter = iter(validate_loader)
    # test_image, test_label = test_data_iter.next()
    #
    # def imshow(img):
    #     img = img / 2 + 0.5  # unnormalize
    #     npimg = img.numpy()
    #     plt.imshow(np.transpose(npimg, (1, 2, 0)))
    #     plt.show()
    #
    # print(' '.join('%5s' % cla_dict[test_label[j].item()] for j in range(4)))
    # imshow(utils.make_grid(test_image))

    net = AlexNet(num_classes=5, init_weights=True)

    net.to(device)
    loss_function = nn.CrossEntropyLoss()
    # pata = list(net.parameters())
    optimizer = optim.Adam(net.parameters(), lr=0.0002)

    epochs = 10
    save_path = './AlexNet.pth'
    best_acc = 0.0
    train_steps = len(train_loader)
    for epoch in range(epochs):
        # train
        net.train()
        running_loss = 0.0
        train_bar = tqdm(train_loader, file=sys.stdout)
        for step, data in enumerate(train_bar):
            images, labels = data
            optimizer.zero_grad()
            outputs = net(images.to(device))
            loss = loss_function(outputs, labels.to(device))
            loss.backward()
            optimizer.step()

            # print statistics
            running_loss += loss.item()

            train_bar.desc = "train epoch[{}/{}] loss:{:.3f}".format(epoch + 1,
                                                                     epochs,
                                                                     loss)

        # validate
        net.eval()
        acc = 0.0  # accumulate accurate number / epoch
        with torch.no_grad():
            val_bar = tqdm(validate_loader, file=sys.stdout)
            for val_data in val_bar:
                val_images, val_labels = val_data
                outputs = net(val_images.to(device))
                predict_y = torch.max(outputs, dim=1)[1]
                acc += torch.eq(predict_y, val_labels.to(device)).sum().item()

        val_accurate = acc / val_num
        print('[epoch %d] train_loss: %.3f  val_accuracy: %.3f' %
              (epoch + 1, running_loss / train_steps, val_accurate))

        if val_accurate > best_acc:
            best_acc = val_accurate
            torch.save(net.state_dict(), save_path)

    print('Finished Training')


if __name__ == '__main__':
    main()

3. predict.py

import torch
from model import AlexNet
from PIL import Image
from torchvision import transforms
import matplotlib.pyplot as plt
import json

# 预处理
data_transform = transforms.Compose(
    [transforms.Resize((224, 224)),
     transforms.ToTensor(),
     transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])

# load image
img = Image.open("rose.jpg")
plt.imshow(img)
# [N, C, H, W]
img = data_transform(img)
# expand batch dimension
img = torch.unsqueeze(img, dim=0)

# read class_indict
try:
    json_file = open('./class_indices.json', 'r')
    class_indict = json.load(json_file)
except Exception as e:
    print(e)
    exit(-1)

# create model
model = AlexNet(num_classes=5)
# load model weights
model_weight_path = "./AlexNet.pth"
model.load_state_dict(torch.load(model_weight_path))

# 关闭 Dropout
model.eval()
with torch.no_grad():
    # predict class
    output = torch.squeeze(model(img))     # 将输出压缩,即压缩掉 batch 这个维度
    predict = torch.softmax(output, dim=0)
    predict_cla = torch.argmax(predict).numpy()
print(class_indict[str(predict_cla)], predict[predict_cla].item())
plt.show()

### AlexNet模型结构及实现 AlexNet深度学习领域中一种经典的卷积神经网络(CNN模型,由 Alex Krizhevsky 等人在 2012 年提出。该模型在 ImageNet 图像分类竞赛中取得了突破性成果,极大地推动了深度学习在计算机视觉领域的发展。以下是 AlexNet 的详细结构及其实现方法。 #### 一、AlexNet 模型结构详解 AlexNet 的网络结构包含多个卷积层、池化层和全连接层。具体结构如下: 1. **Conv1**:第一个卷积层,输入图像尺寸为 $227 \times 227 \times 3$,使用 11×11 的卷积核,步长为 4,输出特征图尺寸为 $55 \times 55 \times 96$[^3]。 2. **Maxpool1**:最大池化层,使用 3×3 的池化窗口,步长为 2,输出特征图尺寸为 $27 \times 27 \times 96$[^3]。 3. **Conv2**:第二个卷积层,使用 5×5 的卷积核,输出特征图尺寸为 $27 \times 27 \times 256$[^3]。 4. **Maxpool2**:最大池化层,使用 3×3 的池化窗口,步长为 2,输出特征图尺寸为 $13 \times 13 \times 256$[^3]。 5. **Conv3**:第三个卷积层,使用 3×3 的卷积核,输出特征图尺寸为 $13 \times 13 \times 384$。 6. **Conv4**:第四个卷积层,使用 3×3 的卷积核,输出特征图尺寸为 $13 \times 13 \times 384$[^3]。 7. **Conv5**:第五个卷积层,使用 3×3 的卷积核,输出特征图尺寸为 $13 \times 13 \times 256$[^3]。 8. **Maxpool3**:最大池化层,使用 3×3 的池化窗口,步长为 2,输出特征图尺寸为 $6 \times 6 \times 256$。 9. **Full connection1**:第一个全连接层,包含 4096 个神经元。 10. **Full connection2**:第二个全连接层,包含 4096 个神经元。 11. **Full connection3**:第三个全连接层,输出类别数(例如 ImageNet 数据集中的 1000 类别)。 #### 二、AlexNet 模型代码实现 以下是一个基于 PyTorch 的 AlexNet 模型实现示例: ```python import torch import torch.nn as nn class AlexNet(nn.Module): def __init__(self, num_classes=1000): super(AlexNet, self).__init__() self.features = nn.Sequential( nn.Conv2d(3, 96, kernel_size=11, stride=4, padding=0), nn.ReLU(inplace=True), nn.MaxPool2d(kernel_size=3, stride=2), nn.Conv2d(96, 256, kernel_size=5, padding=2), nn.ReLU(inplace=True), nn.MaxPool2d(kernel_size=3, stride=2), nn.Conv2d(256, 384, kernel_size=3, padding=1), nn.ReLU(inplace=True), nn.Conv2d(384, 384, kernel_size=3, padding=1), nn.ReLU(inplace=True), nn.Conv2d(384, 256, kernel_size=3, padding=1), nn.ReLU(inplace=True), nn.MaxPool2d(kernel_size=3, stride=2), ) self.avgpool = nn.AdaptiveAvgPool2d((6, 6)) self.classifier = nn.Sequential( nn.Dropout(), nn.Linear(256 * 6 * 6, 4096), nn.ReLU(inplace=True), nn.Dropout(), nn.Linear(4096, 4096), nn.ReLU(inplace=True), nn.Linear(4096, num_classes), ) def forward(self, x): x = self.features(x) x = self.avgpool(x) x = torch.flatten(x, 1) x = self.classifier(x) return x ``` #### 三、训练方法 训练 AlexNet 模型时需要注意以下几点: 1. **数据增强**:通过随机裁剪、水平翻转等技术增加数据多样性,减少过拟合[^1]。 2. **ReLU 激活函数**:使用 ReLU 激活函数加速收敛,并避免梯度消失问题[^2]。 3. **Dropout**:在全连接层中使用 Dropout 技术防止过拟合。 4. **GPU 并行训练**:利用 GPU 加速训练过程,提高效率[^1]。 5. **局部响应归一化**:在某些卷积层后应用局部响应归一化以增强泛化能力[^1]。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值