深度学习篇---AlexNet网络结构

在 PyTorch 中实现 AlexNet 比想象中简单,就像用乐高积木按图纸搭建一样。我们可以分步骤来实现,从网络结构到训练过程,每一步都很直观。

一、先明确 AlexNet 的核心结构(复习)

AlexNet 的经典结构可以总结为:

输入(224×224彩色图) → 5个卷积层(带ReLU+池化) → 3个全连接层(带ReLU+Dropout) → 输出(1000类)

它的关键特点是:用 ReLU 激活函数、重叠池化、Dropout 防止过拟合,以及处理 3 通道彩色图。

二、PyTorch 实现 AlexNet 的步骤

步骤 1:导入必要的库

和实现 LeNet-5 类似,先准备好 PyTorch 的工具:

import torch  # 核心库
import torch.nn as nn  # 神经网络层
import torch.optim as optim  # 优化器
from torch.utils.data import DataLoader  # 数据加载器
from torchvision import datasets, transforms  # 图像数据处理

步骤 2:定义 AlexNet 网络结构

在 PyTorch 中,我们创建一个继承nn.Module的类,重写__init__(定义层)和forward(定义数据流向)方法。

class AlexNet(nn.Module):
    def __init__(self, num_classes=1000):
        super(AlexNet, self).__init__()
        # 卷积部分:5个卷积层 + 池化层
        self.features = nn.Sequential(
            # 卷积层1:输入3通道(RGB),输出96通道,11×11卷积核,步长4
            nn.Conv2d(3, 96, kernel_size=11, stride=4, padding=2),
            nn.ReLU(inplace=True),  # ReLU激活函数
            # 池化层1:3×3重叠池化,步长2(窗口重叠1像素)
            nn.MaxPool2d(kernel_size=3, stride=2),
            
            # 卷积层2:输入96,输出256,5×5卷积核,padding=2
            nn.Conv2d(96, 256, kernel_size=5, padding=2),
            nn.ReLU(inplace=True),
            # 池化层2:3×3重叠池化,步长2
            nn.MaxPool2d(kernel_size=3, stride=2),
            
            # 卷积层3:输入256,输出384,3×3卷积核,padding=1
            nn.Conv2d(256, 384, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            
            # 卷积层4:输入384,输出384,3×3卷积核,padding=1
            nn.Conv2d(384, 384, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            
            # 卷积层5:输入384,输出256,3×3卷积核,padding=1
            nn.Conv2d(384, 256, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            # 池化层3:3×3重叠池化,步长2
            nn.MaxPool2d(kernel_size=3, stride=2),
        )
        
        # 全连接部分:3个全连接层 + Dropout
        self.classifier = nn.Sequential(
            # Dropout层:随机关闭50%神经元,防止过拟合
            nn.Dropout(p=0.5),
            # 全连接层1:输入是256×6×6(池化后的特征),输出4096
            nn.Linear(256 * 6 * 6, 4096),
            nn.ReLU(inplace=True),
            
            nn.Dropout(p=0.5),
            # 全连接层2:输入4096,输出4096
            nn.Linear(4096, 4096),
            nn.ReLU(inplace=True),
            
            # 输出层:输入4096,输出类别数(默认1000)
            nn.Linear(4096, num_classes),
        )
    
    # 定义数据流向
    def forward(self, x):
        x = self.features(x)  # 先经过卷积部分
        x = x.view(x.size(0), 256 * 6 * 6)  # 拉平特征图(batch_size, 256*6*6)
        x = self.classifier(x)  # 再经过全连接部分
        return x

简单解释

  • nn.Sequential:按顺序组合各层,数据依次流过。
  • 卷积层参数:kernel_size是卷积核大小,stride是步长,padding是边缘填充(让输出尺寸更合理)。
  • ReLU(inplace=True):直接修改输入数据,节省内存。
  • Dropout(p=0.5):训练时随机 “关掉” 50% 的神经元,防止过拟合。

步骤 3:准备数据(以 ImageNet 为例,这里用简化版 CIFAR-10 演示)

ImageNet 数据集太大(120 万张图),我们用小型的 CIFAR-10(10 类物体)来演示,流程是一样的:

# 数据预处理:转换为Tensor+标准化+数据增强
transform = transforms.Compose([
    transforms.Resize(256),  # 缩放为256×256
    transforms.RandomCrop(224),  # 随机裁剪成224×224(数据增强)
    transforms.RandomHorizontalFlip(),  # 随机水平翻转(数据增强)
    transforms.ToTensor(),  # 转为Tensor
    # 标准化(CIFAR-10的均值和标准差)
    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])

# 加载CIFAR-10数据集
train_dataset = datasets.CIFAR10(
    root='./data', train=True, download=True, transform=transform
)
test_dataset = datasets.CIFAR10(
    root='./data', train=False, download=True, transform=transform
)

# 批量加载数据
train_loader = DataLoader(train_dataset, batch_size=128, shuffle=True, num_workers=4)
test_loader = DataLoader(test_dataset, batch_size=128, shuffle=False, num_workers=4)

数据增强的作用:通过随机裁剪、翻转等操作 “造” 更多训练数据,让模型更通用。

步骤 4:初始化模型、损失函数和优化器

  • 模型:我们定义的 AlexNet(注意 CIFAR-10 是 10 类,所以输出层设为 10)。
  • 损失函数:交叉熵损失(适合分类问题)。
  • 优化器:SGD + 动量(AlexNet 原文用的优化器)。
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')  # 用GPU加速
model = AlexNet(num_classes=10).to(device)  # 初始化模型,输出10类

criterion = nn.CrossEntropyLoss()  # 交叉熵损失
# 优化器:学习率0.01,动量0.9,权重衰减0.0005(防止权重过大)
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9, weight_decay=5e-4)

步骤 5:训练模型

训练过程和 LeNet-5 类似,都是 “预测→算损失→调参数” 的循环,但 AlexNet 更大,需要训练更久:

def train(model, train_loader, criterion, optimizer, epoch):
    model.train()  # 训练模式
    for batch_idx, (data, target) in enumerate(train_loader):
        data, target = data.to(device), target.to(device)  # 数据放GPU/CPU
        
        optimizer.zero_grad()  # 清空梯度
        output = model(data)   # 模型预测
        loss = criterion(output, target)  # 计算损失
        loss.backward()        # 反向传播算梯度
        optimizer.step()       # 更新参数
        
        # 打印进度
        if batch_idx % 100 == 0:
            print(f'Epoch {epoch}, Batch {batch_idx}, Loss: {loss.item():.6f}')

步骤 6:测试模型效果

用测试集评估模型准确率:

def test(model, test_loader):
    model.eval()  # 评估模式(关闭Dropout)
    correct = 0
    total = 0
    with torch.no_grad():  # 不计算梯度,节省内存
        for data, target in test_loader:
            data, target = data.to(device), target.to(device)
            output = model(data)
            _, predicted = torch.max(output.data, 1)  # 取概率最大的类别
            total += target.size(0)
            correct += (predicted == target).sum().item()
    
    print(f'Test Accuracy: {100 * correct / total:.2f}%')

步骤 7:开始训练和测试

AlexNet 比较深,需要多训练几轮(这里示例训练 10 轮):

for epoch in range(1, 11):
    train(model, train_loader, criterion, optimizer, epoch)
    test(model, test_loader)

运行后,你会看到准确率逐渐上升,训练 10 轮后在 CIFAR-10 上通常能达到 70%-80%(完整训练更多轮次会更高)。

三、完整代码总结

把上面的步骤整合起来,就是可直接运行的 AlexNet 实现:

import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader
from torchvision import datasets, transforms

# 1. 定义AlexNet网络结构
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=2),
            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.classifier = nn.Sequential(
            nn.Dropout(p=0.5),
            nn.Linear(256 * 6 * 6, 4096),
            nn.ReLU(inplace=True),
            
            nn.Dropout(p=0.5),
            nn.Linear(4096, 4096),
            nn.ReLU(inplace=True),
            
            nn.Linear(4096, num_classes),
        )
    
    def forward(self, x):
        x = self.features(x)
        x = x.view(x.size(0), 256 * 6 * 6)  # 拉平特征图
        x = self.classifier(x)
        return x

# 2. 准备CIFAR-10数据
transform = transforms.Compose([
    transforms.Resize(256),
    transforms.RandomCrop(224),
    transforms.RandomHorizontalFlip(),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])

train_dataset = datasets.CIFAR10(
    root='./data', train=True, download=True, transform=transform
)
test_dataset = datasets.CIFAR10(
    root='./data', train=False, download=True, transform=transform
)

train_loader = DataLoader(train_dataset, batch_size=128, shuffle=True, num_workers=4)
test_loader = DataLoader(test_dataset, batch_size=128, shuffle=False, num_workers=4)

# 3. 初始化模型、损失函数和优化器
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = AlexNet(num_classes=10).to(device)  # CIFAR-10是10类
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9, weight_decay=5e-4)

# 4. 训练函数
def train(model, train_loader, criterion, optimizer, epoch):
    model.train()
    for batch_idx, (data, target) in enumerate(train_loader):
        data, target = data.to(device), target.to(device)
        
        optimizer.zero_grad()
        output = model(data)
        loss = criterion(output, target)
        loss.backward()
        optimizer.step()
        
        if batch_idx % 100 == 0:
            print(f'Epoch {epoch}, Batch {batch_idx}, Loss: {loss.item():.6f}')

# 5. 测试函数
def test(model, test_loader):
    model.eval()
    correct = 0
    total = 0
    with torch.no_grad():
        for data, target in test_loader:
            data, target = data.to(device), target.to(device)
            output = model(data)
            _, predicted = torch.max(output.data, 1)
            total += target.size(0)
            correct += (predicted == target).sum().item()
    print(f'Test Accuracy: {100 * correct / total:.2f}%')

# 6. 开始训练和测试
for epoch in range(1, 11):
    train(model, train_loader, criterion, optimizer, epoch)
    test(model, test_loader)
    

四、关键知识点回顾

  1. 网络设计:5 个卷积层负责提取从简单到复杂的特征(边缘→纹理→物体部件),3 个全连接层负责最终分类。
  2. 核心技巧:ReLU 解决梯度消失,Dropout 防止过拟合,重叠池化保留更多细节,数据增强扩充训练数据。
  3. 实现要点:注意输入尺寸(224×224)、通道数(3 通道彩色图),以及全连接层的输入维度(256×6×6)。

运行这段代码,你就能亲手实现这个 “深度学习引爆者” 模型,感受它如何从像素中学习识别物体的能力!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值