AlexNet卷积神经网络介绍及Pytorch实现

AlexNet卷积神经网络介绍及Pytorch实现

AlexNet简介

2012年,AlexNet横空出世。它首次证明了学习到的特征可以超越手工设计的特征。它一举打破了计算机视觉研究的现状。 AlexNet使用了8层卷积神经网络,并以很大的优势赢得了2012年ImageNet图像识别挑战赛。

AlexNet和LeNet的架构非常相似,如下图所示。 本文在这里提供的是一个稍微精简版本的AlexNet,去除了当年需要两个小型GPU同时运算的设计特点。
在这里插入图片描述

AlexNet和LeNet的设计理念非常相似,但也存在显著差异。

  • AlexNet比相对较小的LeNet5要深得多。AlexNet由八层组成:五个卷积层、两个全连接隐藏层和一个全连接输出层。
  • AlexNet使用ReLU而不是sigmoid作为其激活函数。

ReLU激活函数

一方面,ReLU激活函数的计算更简单,它不需要如sigmoid激活函数那般复杂的求幂运算。 另一方面,当使用不同的参数初始化方法时,ReLU激活函数使训练模型更加容易。 当sigmoid激活函数的输出非常接近于0或1时,这些区域的梯度几乎为0,因此反向传播无法继续更新一些模型参数。 相反,ReLU激活函数在正区间的梯度总是1。 因此,如果模型参数没有正确初始化,sigmoid函数可能在正区间内得到几乎为0的梯度,从而使模型无法得到有效的训练。

Pytorch实现

net = nn.Sequential(
    nn.Conv2d(1, 96, kernel_size=11, stride=4, padding=1), nn.ReLU(),
    nn.MaxPool2d(kernel_size=3, stride=2),
    nn.Conv2d(96, 256, kernel_size=5, padding=2), nn.ReLU(),
    nn.MaxPool2d(kernel_size=3, stride=2),
    nn.Conv2d(256, 384, kernel_size=3, padding=1), nn.ReLU(),
    nn.Conv2d(384, 384, kernel_size=3, padding=1), nn.ReLU(),
    nn.Conv2d(384, 256, kernel_size=3, padding=1), nn.ReLU(),
    nn.MaxPool2d(kernel_size=3, stride=2),
    nn.Flatten(),
    nn.Linear(6400, 4096), nn.ReLU(),
    nn.Dropout(p=0.5),
    nn.Linear(4096, 4096), nn.ReLU(),
    nn.Dropout(p=0.5),
    nn.Linear(4096, 10))

AlexNet识别FasionMNIST

尽管原文中AlexNet是在ImageNet上进行训练的,但本文在这里使用的是Fashion-MNIST数据集。因为即使在现代GPU上,训练ImageNet模型,同时使其收敛可能需要数小时或数天的时间。
将AlexNet直接应用于Fashion-MNIST的一个问题是,Fashion-MNIST图像的分辨率((28 \times 28)像素)低于ImageNet图像。 为了解决这个问题,本文将它们增加到(224 \times 224)(通常来讲这不是一个明智的做法,但在这里这样做是为了有效使用AlexNet架构)。

from torch.utils.data import DataLoader
import torch
import torchvision
from torch import nn
import torch.nn.functional as F
import matplotlib.pyplot as plt


n_epochs = 5
batch_size_train = 128
batch_size_test = 1000
learning_rate = 0.001
log_interval = 10


train_loader = torch.utils.data.DataLoader(
    torchvision.datasets.FashionMNIST('./data/', train=True, download=True,
                               transform=torchvision.transforms.Compose([
                                   torchvision.transforms.ToTensor(),
                                   torchvision.transforms.Resize([224, 224])
                               ])), batch_size=batch_size_train, shuffle=True)
test_loader = torch.utils.data.DataLoader(
    torchvision.datasets.FashionMNIST('./data/', train=False, download=True,
                               transform=torchvision.transforms.Compose([
                                   torchvision.transforms.ToTensor(),
                                   torchvision.transforms.Resize([224, 224])
                               ])), batch_size=batch_size_test, shuffle=True)


# AxNet
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(1, 96, kernel_size=11, stride=4, padding=1)  # 输入通道待修改
        self.conv2 = nn.Conv2d(96, 256, kernel_size=5, padding=2)
        self.conv3 = nn.Conv2d(256, 384, kernel_size=3, padding=1)
        self.conv4 = nn.Conv2d(384, 384, kernel_size=3, padding=1)
        self.conv5 = nn.Conv2d(384, 256, kernel_size=3, padding=1)
        self.fc1 = nn.Linear(6400, 4096)  # 输入通道待修改
        self.fc2 = nn.Linear(4096, 4096)
        self.fc3 = nn.Linear(4096, 10)

    def forward(self, x):
        x = F.relu(self.conv1(x))
        x = F.max_pool2d(x, 3, stride=2)
        x = F.relu(self.conv2(x))
        x = F.max_pool2d(x, 3, stride=2)
        x = F.relu(self.conv3(x))
        x = F.relu(self.conv4(x))
        x = F.relu(self.conv5(x))
        x = F.max_pool2d(x, 3, stride=2)
        x = x.view(-1, 6400)  # 待修改
        x = F.relu(self.fc1(x))
        x = F.dropout(x, 0.5)
        x = F.relu(self.fc2(x))
        x = F.dropout(x, 0.5)
        x = self.fc3(x)
        return F.log_softmax(x, dim=1)


network = Net().cuda()  # gpu加速
optimizer = torch.optim.Adam(network.parameters(), lr=learning_rate)
train_losses = []


def train(epoch):
    network.train()  # 训练模式
    for batch_idx, (data, target) in enumerate(train_loader):
        optimizer.zero_grad()  # 梯度清零
        output = network(data.cuda())
        loss = F.nll_loss(output, target.cuda())
        loss.backward()  # 反向传播
        optimizer.step()  # 参数更新
        if batch_idx % log_interval == 0:
            print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(epoch, batch_idx * len(data),
                                                                           len(train_loader.dataset),
                                                                           100. * batch_idx / len(train_loader),
                                                                           loss.item()))
            train_losses.append(loss.item())
            torch.save(network.state_dict(), './model/model_FashionMnist.pth')
            torch.save(optimizer.state_dict(), './model/optimizer_FashionMnist.pth')


def test():
    network.eval()  # 测试模式
    test_loss = 0
    correct = 0
    with torch.no_grad():
        for data, target in test_loader:
            data_cuda = data.cuda()
            target_cuda = target.cuda()
            output = network(data_cuda)
            test_loss += F.nll_loss(output, target_cuda, reduction='sum').item()
            pred = output.data.max(1, keepdim=True)[1]
            correct += pred.eq(target_cuda.data.view_as(pred)).sum()
    test_loss /= len(test_loader.dataset)
    print('\nTest set: Avg. loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
        test_loss, correct, len(test_loader.dataset),
        100. * correct / len(test_loader.dataset)))


for epoch in range(1, n_epochs + 1):
    train(epoch)
    test()

plt.plot(train_losses)
plt.show()

运行结果如下:

Test set: Avg. loss: 0.3991, Accuracy: 8553/10000 (86%)
Test set: Avg. loss: 0.3407, Accuracy: 8743/10000 (87%)
Test set: Avg. loss: 0.3119, Accuracy: 8853/10000 (89%)
Test set: Avg. loss: 0.2954, Accuracy: 8908/10000 (89%)
Test set: Avg. loss: 0.2878, Accuracy: 8999/10000 (90%)

损失函数图像:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值