5.6--AlexNET


Alexnet简介

例如:由于数据和硬件的发展,2012年Alexnet深度卷积神经网络横空出世,其相比于之前LeNet的特点有网络模型更宽更深,也就是网络的参数量增加,此外将sigmoid激活函数改成ReLU激活函数,并且使用dropout方法,防止模型过拟合的问题。


一、查看相关库和硬件资源

使用的是python3.8

import time
import torch
from torch import nn, optim
import torchvision

import sys
sys.path.append("..") 
#import d2lzh_pytorch as d2l
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

print(torch.__version__)
print(torchvision.__version__)
print(device)

结果:
1.13.1+cu117
0.14.1+cu117
cuda

二、定义AlexNet网络

1.定义

这里定义模型使用的方法是继承nn.Module,以类的形式定义模型,好处是模型结构一目了然,并且这种方法能自动初始化模型参数。

有一些注释是我自己添加的

class AlexNet(nn.Module):
    def __init__(self):
        super(AlexNet, self).__init__()
        self.conv = nn.Sequential(
            nn.Conv2d(1, 96, 11, 4), # in_channels, out_channels, kernel_size, stride, padding
            nn.ReLU(),
            # 最大池化计算类似于卷积,多了一个dilation扩大参数
            nn.MaxPool2d(3, 2), # kernel_size, stride
            # 减小卷积窗口,使用填充为2来使得输入与输出的高和宽一致,且增大输出通道数
            nn.Conv2d(96, 256, 5, 1, 2),
            nn.ReLU(),
            nn.MaxPool2d(3, 2),
            # 连续3个卷积层,且使用更小的卷积窗口。除了最后的卷积层外,进一步增大了输出通道数。
            # 前两个卷积层后不使用池化层来减小输入的高和宽
            nn.Conv2d(256, 384, 3, 1, 1),
            nn.ReLU(),
            nn.Conv2d(384, 384, 3, 1, 1),
            nn.ReLU(),
            nn.Conv2d(384, 256, 3, 1, 1),
            nn.ReLU(),
            nn.MaxPool2d(3, 2)
        )
         # 这里全连接层的输出个数比LeNet中的大数倍。使用丢弃层来缓解过拟合
        self.fc = nn.Sequential(
            nn.Linear(256*5*5, 4096),# 模型结构新方法
            nn.ReLU(),       # 新方法
            nn.Dropout(0.5), # 新方法
            nn.Linear(4096, 4096),
            nn.ReLU(),
            nn.Dropout(0.5),
            # 输出层。由于这里使用Fashion-MNIST,所以用类别数为10,而非论文中的1000
            nn.Linear(4096, 10),
        )

    def forward(self, img):
        feature = self.conv(img)
        output = self.fc(feature.view(img.shape[0], -1))
        return output

2.查看

查看模型结构

net = AlexNet()
print(net)

结果展示:
在这里插入图片描述
这里训练的数据集是FashionMNIST,下面是我自己算的一批大小为128数据在网络中的变化,如下图所示
在这里插入图片描述

三、读取数据

这里使用的数据集为FashionMNIST,该数据集大小为70000,其中训练集为60000,测试集为10000,一共包括10个类别,并且是灰度图像
这里的操作包括读取训练集和测试集,再将读取到的数据转成大小为(1,224,224)的张量,目的是方便训练

def load_data_fashion_mnist(batch_size, resize=None, root='~/Datasets/FashionMNIST'):
    """Download the fashion mnist dataset and then load into memory."""
    trans = []
    if resize:
        trans.append(torchvision.transforms.Resize(size=resize))
    # 将图像转换为张量的操作添加到列表中
    trans.append(torchvision.transforms.ToTensor())
    # 将多个图像变换操作按顺序组合成一个管道,便于批量处理图像
    transform = torchvision.transforms.Compose(trans)
    # 读取FashionMNIST数据,并对读到的数据进行transform转换
    mnist_train = torchvision.datasets.FashionMNIST(root=root, train=True, download=True, transform=transform)
    mnist_test = torchvision.datasets.FashionMNIST(root=root, train=False, download=True, transform=transform)
    # 将数据集封装成可迭代的数据加载器,用于模型训练和测试时以批量的方式加载数据
    train_iter = torch.utils.data.DataLoader(mnist_train, batch_size=batch_size, shuffle=True, num_workers=4)
    test_iter = torch.utils.data.DataLoader(mnist_test, batch_size=batch_size, shuffle=False, num_workers=4)

    return train_iter, test_iter

批量大小为128

batch_size = 128
# 如出现“out of memory”的报错信息,可减小batch_size或resize
train_iter, test_iter = load_data_fashion_mnist(batch_size, resize=224)

四、模型训练

1、定义评估准确率函数

def evaluate_accuracy(data_iter, net, device=None):
    if device is None and isinstance(net, torch.nn.Module):
        # 如果没指定device就使用net的device
        device = list(net.parameters())[0].device 
    acc_sum, n = 0.0, 0
    with torch.no_grad():
        for X, y in data_iter:
            if isinstance(net, torch.nn.Module):
                net.eval() # 评估模式, 这会关闭dropout
                acc_sum += (net(X.to(device)).argmax(dim=1) == y.to(device)).float().sum().cpu().item()
                net.train() # 改回训练模式
            else: # 自定义的模型, 3.13节之后不会用到, 不考虑GPU
                if('is_training' in net.__code__.co_varnames): # 如果有is_training这个参数
                    # 将is_training设置成False
                    acc_sum += (net(X, is_training=False).argmax(dim=1) == y).float().sum().item() 
                else:
                    acc_sum += (net(X).argmax(dim=1) == y).float().sum().item() 
            n += y.shape[0]
    return acc_sum / n

2、定义训练过程

def train_ch5(net, train_iter, test_iter, batch_size, optimizer, device, num_epochs):
    # 将网络模型net移动到指定的设备device上,加速计算
    net = net.to(device)
    print("training on ", device)
    loss = torch.nn.CrossEntropyLoss()
    for epoch in range(num_epochs):
        train_l_sum, train_acc_sum, n, batch_count, start = 0.0, 0.0, 0, 0, time.time()
        for X, y in train_iter:
            # 张量移动到指定设备上,模型和数据要设备一致且能加速计算
            X = X.to(device)
            y = y.to(device)
            
            y_hat = net(X)
            l = loss(y_hat, y)
            # 梯度清零
            optimizer.zero_grad()
            # 反向传播计算梯度
            l.backward()
            # 用于更新模型参数
            optimizer.step()
            train_l_sum += l.cpu().item()
            # y_hat.argmax(dim=1)会得到元素下标,表示图片所属的类别
            train_acc_sum += (y_hat.argmax(dim=1) == y).sum().cpu().item()
            # n是数据量
            n += y.shape[0]
            batch_count += 1
        test_acc = evaluate_accuracy(test_iter, net)
        print('epoch %d, loss %.4f, train acc %.3f, test acc %.3f, time %.1f sec'
              % (epoch + 1, train_l_sum / batch_count, train_acc_sum / n, test_acc, time.time() - start))

3、训练

lr, num_epochs = 0.001, 5
optimizer = torch.optim.Adam(net.parameters(), lr=lr)
train_ch5(net, train_iter, test_iter, batch_size, optimizer, device, num_epochs)

4、训练结果

在这里插入图片描述


总结

在对AlexNet网络学习中,学到了增加网络的深度和宽度能提升网络模型的性能,因为宽度能学习到更丰富的特征,深度能通过抽象特征不断提取知识,激活函数也能形象模型的效果。此外还学习到每个网络主要包括三部分,网络模型定义,读取数据,最后训练模型。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值