【深度学习】:《PyTorch入门到项目实战》(十五):三大经典卷积神经网络架构:LeNet、AlexNet、VGG

news/2025/3/24 0:09:41/

【深度学习】:《PyTorch入门到项目实战》(十五):三大经典卷积神经网络架构:LeNet、AlexNet、VGG(代码实现及实际案例比较)

  • ✨本文收录于【深度学习】:《PyTorch入门到项目实战》专栏,此专栏主要记录如何使用PyTorch实现深度学习及其项目实战,尽量坚持每周持续更新,欢迎大家订阅!
  • 🌸个人主页:JOJO数据科学
  • 📝个人介绍:某985统计硕士在读
  • 💌如果文章对你有帮助,欢迎✌关注、👍点赞、✌收藏、👍订阅专栏
  • 参考资料:《动手学深度学习》

在这里插入图片描述

文章目录

  • 【深度学习】:《PyTorch入门到项目实战》(十五):三大经典卷积神经网络架构:LeNet、AlexNet、VGG(代码实现及实际案例比较)
  • 三大经典卷积神经网络架构:LeNet、AlexNet、VGG(代码实现及实际案例比较)
  • 1.Lenet
    • 1.1理论介绍
    • Fashion—MNIST数据集
    • 1.2代码实现
  • 2. AlexNet
    • 2.1 理论介绍
    • 2.2 代码实现
  • 3.VGG
    • 3.1 理论介绍
    • 3.2代码实现
    • 总结

三大经典卷积神经网络架构:LeNet、AlexNet、VGG(代码实现及实际案例比较)

1.Lenet

1.1理论介绍

经过前面的介绍,我们已经了解了卷积神经网络的基本模块,接下来我们来讨论几个经典的神经网络结构,首先介绍LeNet-5。LeNet是最早的卷积神经网络之一,其被提出用于识别手写数字和机器印刷字符。1998年,Yann LeCun第一次将LeNet卷积神经网络应用到图像分类上,在手写数字识别任务中取得了巨大成功。首先看看LeNet-5的网络结构,下图是原论文放出来的架构

image-20230711160836404

假设你有一张32×32×1的图片,LeNet-5可以识别图中的手写数字。由于LeNet-5是针对灰度图片训练的,所以图片的大小只有32×32×1。

LeNet的结构如下:

  • 输入层: 接收输入图像的尺寸为32x32x1。
  • 卷积层部分:
    • 卷积层1:6×5x5的卷积核,步长为1,填充为0,使用Sigmoid激活函数。
    • 平均池化层1:2x2的池化窗口,步长为2。
    • 卷积层2:16×5x5的卷积核,步长为1,填充为0,使用Sigmoid激活函数。
    • 平均池化层2:2x2的池化窗口,步长为2。
  • 全连接层部分
    • 全连接层1:120个神经元,使用Sigmoid激活函数。
    • 全连接层2:84个神经元,使用Sigmoid激活函数。
    • 全连接层3(输出层):10个神经元,对应10个手写数字类别,现在往往用softmax。

总的来说,如果我们从左往右看,随着网络越来越深,图像的高度和宽度在缩小,从最初的32×32缩小到28×28,再到14×1410×10,最后只有5×5。与此同时,随着网络层次的加深,通道数量一直在增加,从1增加到6个,再到16个。

这个神经网络中还有一种模式至今仍然经常用到,就是一个或多个卷积层后面跟着一个池化层,然后又是若干个卷积层再接一个池化层,然后是全连接层,最后是输出,这种排列方式很常用。

Fashion—MNIST数据集

原始的LeNet是在MNIST数据集上实现的,但是MNIST数据集在今天来说实在太简单了,我们使用一个稍微复杂一点的数据集Fashion-MNIST,为了方便我们后续比较几个模型的性能。

Fashion-MNIST数据集由Zalando Research创建,并且与经典的MNIST数据集具有相似的结构。它包含了来自10个不同类别的共计70000张灰度图像,每个类别包含7000张图像。这些类别分别是:T恤、裤子、套头衫、连衣裙、外套、凉鞋、衬衫、运动鞋、包和短靴。

每张图像的尺寸为28x28像素,并以灰度形式表示,像素值范围在0到255之间。Fashion-MNIST数据集已经被标记,因此每个图像都与其对应的类别标签相关联。这使得Fashion-MNIST成为评估机器学习模型在图像分类任务上表现的理想数据集。

Fashion-MNIST的目标是提供一个更具挑战性的数据集,用于测试和比较不同算法的性能。与MNIST数据集相比,Fashion-MNIST涵盖更复杂、多样化的图像内容,更能反映现实世界中的图像分类问题。

我们来简单的看一下数据集,我们可以利用torchvision来下载

import torch
import torchvision
import matplotlib.pyplot as plt# 加载Fashion-MNIST数据集
train_set = torchvision.datasets.FashionMNIST(root='./data', train=True, download=True)
test_set = torchvision.datasets.FashionMNIST(root='./data', train=False, download=True)# 查看数据集大小
print(f"训练集大小: {len(train_set)}")
print(f"测试集大小: {len(test_set)}")# 获取类别标签
labels = train_set.classes
print(f"类别标签: {labels}")# 随机显示几个样本图像
fig, axes = plt.subplots(2, 5, figsize=(10, 4))
for i, ax in enumerate(axes.flat):image, label = train_set[i]ax.imshow(image, cmap='gray')ax.set_title(labels[label])ax.axis('off')
plt.show()

image-20230716225012282

可以看到上面10张示例图,相对于手写数字识别(MNIST)数据集而言,更复杂一些,下面我们正式使用LeNet来对Fashion-MNIST数据集进行识别。

1.2代码实现

1.导入相关库

import torch
import torch.nn as nn
import torch.optim as optim
import torchvision
import torchvision.transforms as transforms
import matplotlib.pyplot as plt

2.定义LeNet框架

# 定义 LeNet 模型
class LeNet(nn.Module):def __init__(self):super(LeNet, self).__init__()self.conv1 = nn.Conv2d(1, 6, kernel_size=5,padding=2)self.avgpool = nn.AvgPool2d(kernel_size=2, stride=2)self.conv2 = nn.Conv2d(6, 16, kernel_size=5)self.fc1 = nn.Linear(16 * 5 * 5, 120)self.fc2 = nn.Linear(120, 84)self.fc3 = nn.Linear(84, 10)def forward(self, x):out = self.avgpool(torch.relu(self.conv1(x)))out = self.avgpool(torch.relu(self.conv2(out)))out = out.view(out.size(0), -1)out = torch.sigmoid(self.fc1(out))out = torch.sigmoid(self.fc2(out))out = self.fc3(out)return out

注意,在整个卷积块中,与上一层相比,每一层特征的高度和宽度都减小了,因此高度和宽度都减少了4个像素。 随着层叠的上升,通道的数量从输入时的1个,增加到第一个卷积层之后的6个,再到第二个卷积层之后的16个。 同时,每个池化层层的高度和宽度都减半。最后,每个全连接层减少维数,最终输出一个维数与结果分类数相匹配的输出。

设置gpu

# 设置gpu
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

3.导入Fashion-MINIST数据集

# 加载 Fashion-MNIST 数据集
transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.5,), (0.5,))
])
trainset = torchvision.datasets.FashionMNIST(root='./data', train=True,download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=64,shuffle=True, num_workers=2)
testset = torchvision.datasets.FashionMNIST(root='./data', train=False,download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=64,shuffle=False, num_workers=2)

4.初始化模型

# 初始化模型、损失函数和优化器
model = LeNet().to(device)
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.9)

这里我们使用交叉熵损失函数和小批量梯度下降(SGD)

5.模型训练和评估

num_epochs = 10
train_losses = []
test_losses = []for epoch in range(num_epochs):train_loss = 0.0test_loss = 0.0correct = 0total = 0# 训练模型model.train()for images, labels in trainloader:images, labels = images.to(device), labels.to(device)optimizer.zero_grad()outputs = model(images)loss = criterion(outputs, labels)loss.backward()optimizer.step()train_loss += loss.item()# 测试模型model.eval()with torch.no_grad():for images, labels in testloader:images, labels = images.to(device), labels.to(device)outputs = model(images)loss = criterion(outputs, labels)test_loss += loss.item()_, predicted = torch.max(outputs.data, 1)total += labels.size(0)correct += (predicted == labels).sum().item()avg_train_loss = train_loss / len(trainloader)avg_test_loss = test_loss / len(testloader)train_losses.append(avg_train_loss)test_losses.append(avg_test_loss)print(f"Epoch [{epoch+1}/{num_epochs}], Train Loss: {avg_train_loss:.4f}, Test Loss: {avg_test_loss:.4f}, Acc: {correct/total*100:.2f}%")# 绘制测试误差和训练误差曲线
plt.plot(train_losses, label='Training Loss')
plt.plot(test_losses, label='Testing Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend()
plt.show()
Epoch [1/10], Train Loss: 2.2963, Test Loss: 2.2134, Acc: 30.00%
Epoch [2/10], Train Loss: 0.9418, Test Loss: 0.6950, Acc: 75.43%
Epoch [3/10], Train Loss: 0.5754, Test Loss: 0.5239, Acc: 80.05%
Epoch [4/10], Train Loss: 0.4852, Test Loss: 0.4512, Acc: 83.23%
Epoch [5/10], Train Loss: 0.4302, Test Loss: 0.4255, Acc: 84.22%
Epoch [6/10], Train Loss: 0.3905, Test Loss: 0.3730, Acc: 85.98%
Epoch [7/10], Train Loss: 0.3644, Test Loss: 0.3640, Acc: 86.68%
Epoch [8/10], Train Loss: 0.3424, Test Loss: 0.3370, Acc: 87.41%
Epoch [9/10], Train Loss: 0.3253, Test Loss: 0.3261, Acc: 87.83%
Epoch [10/10], Train Loss: 0.3107, Test Loss: 0.3042, Acc: 88.74%

image-20230716225525277
可以看出经过10个epoch的训练后,测试精度达到88.74%,后续我们比较其与其他两个模型的差距

2. AlexNet

2.1 理论介绍

AlexNet,是以论文的第一作者Alex Krizhevsky的名字命名的,另外两位合著者是ilya SutskeverGeoffery Hinton。AlexNet在2012年在ImageNet图像分类挑战赛上取得了突破性的成果,其本质上和LeNet没有区别,可以看做是一个更深的LeNet,拥有更多的参数。AlexNet首先用一张227×227×3图像,论文中实际用的是224×224×3,实践中往往227×227×3更方便,我们来看一下ALexNet的基本框架

image-20230717002828572

  • 输入层: 接收输入图像的尺寸为227x227x3。
  • 卷积层部分:
    • 卷积层1: 96个11x11的卷积核,步长为4,填充为0,ReLU激活函数。
    • 最大池化层1: 3x3的池化窗口,步长为2。
    • 卷积层2: 256个5x5的卷积核,步长为1,填充为2,ReLU激活函数。
    • 最大池化层2: 3x3的池化窗口,步长为2。
    • 卷积层3: 384个3x3的卷积核,步长为1,填充为1,ReLU激活函数。
    • 卷积层4: 384个3x3的卷积核,步长为1,填充为1,ReLU激活函数。
    • 卷积层5: 256个3x3的卷积核,步长为1,填充为1,ReLU激活函数。
    • 最大池化层3:3x3的池化窗口,步长为2。
  • 全连接层部分:
    • 全连接层1: 4096个神经元,ReLU激活函数。
    • Dropout层1: 以0.5的概率随机将输入置为0。
    • 全连接层2: 4096个神经元,ReLU激活函数。
    • Dropout层2: 以0.5的概率随机将输入置为0。
    • 全连接层3(输出层): 1000个神经元,对应ImageNet的1000个类别。

实际上,AlexNet神经网络与LeNet有很多相似之处,不过AlexNet要大得多。正如前面讲到的LeNet,其大约有6万个参数,而AlexNet模型总共有5个卷积层,3个池化层和3个全连接层,参数量较大,约6000万个参数。同时,通过大输入图像尺寸和大尺寸的卷积核,使得网络能够更好地捕捉图像中的细节信息。此外,AlexNetLeNet表现更为出色的另一个原因是它使用了ReLu激活函数,以及在池化层中使用了maxpooling。于此同时,AlexNet引入了深度学习中的一些重要概念和技术,如使用ReLU激活函数、局部响应归一化(LRN)和Dropout正则化等。

2.2 代码实现

原文中AlexNet是在ImageNet上进行训练的,但是这里为了方便比较,以及节约训练时间,我们依旧在Fashion—MNIST数据集上进行训练。

1.定义AlexNet模型

#定义AlexNet
class AlexNet(nn.Module):def __init__(self, num_classes=10):super(AlexNet, self).__init__()self.features = nn.Sequential(nn.Conv2d(1, 96, kernel_size=11, stride=4),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.加载数据集

# 加载 Fashion-MNIST 数据集
transform = transforms.Compose([transforms.ToTensor(),transforms.Resize((227,227)),#将原始图像扩宽到227×227transforms.Normalize((0.5,), (0.5,))
])
trainset = torchvision.datasets.FashionMNIST(root='./data', train=True,download=True, transform=transform)
train_loader = torch.utils.data.DataLoader(trainset, batch_size=64,shuffle=True, num_workers=2)
testset = torchvision.datasets.FashionMNIST(root='./data', train=False,download=True, transform=transform)
test_loader = torch.utils.data.DataLoader(testset, batch_size=64,shuffle=False, num_workers=2)

3.初始化AlexNet模型

# 初始化AlexNet模型
model = AlexNet().to(device)
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)

由于Fashion-MNINST图像默认是28×28的,我们需要使用transforms.Resize将其增加到227×227,在实际中我们一般不会这样做。

4.模型训练和评估

# 训练AlexNet模型
num_epochs = 10
train_losses = []
test_losses = []for epoch in range(num_epochs):train_loss = 0.0test_loss = 0.0correct = 0total = 0# 训练模型model.train()for images, labels in train_loader:images, labels = images.to(device), labels.to(device)optimizer.zero_grad()outputs = model(images)loss = criterion(outputs, labels)loss.backward()optimizer.step()train_loss += loss.item()# 测试模型model.eval()with torch.no_grad():for images, labels in test_loader:images, labels = images.to(device), labels.to(device)outputs = model(images)loss = criterion(outputs, labels)test_loss += loss.item()_, predicted = torch.max(outputs.data, 1)total += labels.size(0)correct += (predicted == labels).sum().item()avg_train_loss = train_loss / len(train_loader)avg_test_loss = test_loss / len(test_loader)train_losses.append(avg_train_loss)test_losses.append(avg_test_loss)print(f"Epoch [{epoch+1}/{num_epochs}], Train Loss: {avg_train_loss:.4f}, Test Loss: {avg_test_loss:.4f}, Acc: {correct/total*100:.2f}%")# 绘制测试误差和训练误差曲线
plt.plot(train_losses, label='Training Loss')
plt.plot(test_losses, label='Testing Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend()
plt.show()
Epoch [1/10], Train Loss: 0.8024, Test Loss: 1.3865, Acc: 55.48%
Epoch [2/10], Train Loss: 0.4890, Test Loss: 0.4372, Acc: 83.66%
Epoch [3/10], Train Loss: 0.3692, Test Loss: 0.3832, Acc: 85.42%
Epoch [4/10], Train Loss: 0.3307, Test Loss: 0.3728, Acc: 86.03%
Epoch [5/10], Train Loss: 0.3030, Test Loss: 0.3281, Acc: 87.72%
Epoch [6/10], Train Loss: 0.2829, Test Loss: 0.3285, Acc: 87.78%
Epoch [7/10], Train Loss: 0.2697, Test Loss: 0.3515, Acc: 87.47%
Epoch [8/10], Train Loss: 0.2560, Test Loss: 0.3193, Acc: 88.24%
Epoch [9/10], Train Loss: 0.2466, Test Loss: 0.3005, Acc: 89.02%
Epoch [10/10], Train Loss: 0.2373, Test Loss: 0.3068, Acc: 89.00%

image-20230716225921965

可以看出AlexNet在Fashion-MNIST数据集上测试精度有所提升,突破了89%,这是因为AlexNet使用了更深更大的网络。

3.VGG

3.1 理论介绍

经过Lenet和AlexNet的介绍,我们可以发现使用更深更大的神经网络,能够带来更好的效果,这也是目前深度学习领域一直在做的事情,包括现在热门gpt4。但是AlexNet有一个问题是框架的设置太不规则,因此如何更好的设计更深更大的神经网络值得我们去思考。

为了实现这一目的,VGG模型(Visual Geometry Group)产生了,VGG由牛津大学的研究团队开发的深度卷积神经网络模型。VGG模型在2014年的ImageNet图像分类挑战赛中取得了很大的成功,并且在计算机视觉领域被广泛应用。

VGG模型的主要特点是它采用了非常小的卷积核(3x3)最大池化层(2x2),以及多个卷积和池化层的叠加。模型的深度可变,通过调整卷积和全连接层的数量来改变模型的深度。最常用的VGG模型有VGG16VGG19

VGG模型的主要优势是它具有非常好的表达能力和一致性,以及相对简单的结构。它通过多层卷积和池化层来逐渐提取图像的特征,并通过全连接层进行分类。这种结构使得模型能够捕获不同尺度下的图像特征,从而提高了模型的准确性,下面我们具体讲讲这种网络结构,如下图所示(VGG16

image-20230717002743938

VGG模型主要由VGG块和全连接层组成,通过多次叠加这些层来逐渐提取图像特征并进行分类。其中每一个VGG块都是由3×3的卷积层和2×2的池化层组成

下面是VGG16模型的详细结构:

  1. 输入层:接收输入图像的尺寸为224x224x3。

  2. VGG块部分:

    • 卷积层1-1:64个3x3的卷积核,填充为1,ReLU激活函数。

    • 卷积层1-2:64个3x3的卷积核,填充为1,ReLU激活函数。

    • 最大池化层1:2x2的池化窗口,步长为2

    • 卷积层2-1:128个3x3的卷积核,填充为1,ReLU激活函数。

    • 卷积层2-2:128个3x3的卷积核,填充为1,ReLU激活函数。

    • 最大池化层2:2x2的池化窗口,步长为2。

    • 卷积层3-1:256个3x3的卷积核,填充为1,ReLU激活函数。

    • 卷积层3-2:256个3x3的卷积核,填充为1,ReLU激活函数。

    • 卷积层3-3:256个3x3的卷积核,填充为1,ReLU激活函数。

    • 最大池化层3:2x2的池化窗口,步长为2。

    • 卷积层4-1:512个3x3的卷积核,填充为1,ReLU激活函数。

    • 卷积层4-2:512个3x3的卷积核,填充为1,ReLU激活函数。

    • 卷积层4-3:512个3x3的卷积核,填充为1,ReLU激活函数。

    • 最大池化层4:2x2的池化窗口,步长为2。

    • 卷积层5-1:512个3x3的卷积核,填充为1,ReLU激活函数。

    • 卷积层5-2:512个3x3的卷积核,填充为1,ReLU激活函数。

    • 卷积层5-3:512个3x3的卷积核,填充为1,ReLU激活函数。

    • 最大池化层5:2x2的池化窗口,步长为2。

  3. 全连接层部分:

    • 全连接层1:4096个神经元,ReLU激活函数。
    • Dropout层1:以0.5的概率随机将输入置为0。
    • 全连接层2:4096个神经元,ReLU激活函数。
    • Dropout层2:以0.5的概率随机将输入置为0。
    • 全连接层3(输出层):1000个神经元,对应ImageNet的1000个类别。

VGG16模型总共有13个卷积层和3个全连接层,参数量较大。该模型的设计思想是通过多层的小卷积核和池化层来逐渐缩小宽度,并提取出更高级别的图像特征。同时,使用ReLU激活函数来增强网络的非线性表达能力。最后通过全连接层进行分类。

随着网络的加深,图像的高度和宽度都在以一定的规律不断缩小,每次池化后刚好缩小一半,而通道数量在不断增加,而且刚好也是在每组卷积操作后增加一倍。也就是说,图像缩小的比例和通道数增加的比例是有规律的。

  • VGG使用可重复使用的卷积块构建深度卷积神经网络

  • 不同的卷积块个数和超参数可以得到不同系列的VGG(如:VGG16、VGG19)

3.2代码实现

1.VGG模型定义

原时VGG16模型定义如下

# 定义VGG16模型
class VGG16(nn.Module):def __init__(self, num_classes=1000):super(VGG16, self).__init__()self.features = nn.Sequential(nn.Conv2d(1, 64, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(64, 64, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=2, stride=2),nn.Conv2d(64, 128, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(128, 128, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=2, stride=2),nn.Conv2d(128, 256, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(256, 256, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(256, 256, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=2, stride=2),nn.Conv2d(256, 512, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(512, 512, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(512, 512, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=2, stride=2),nn.Conv2d(512, 512, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(512, 512, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(512, 512, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=2, stride=2))self.classifier = nn.Sequential(nn.Linear(512 * 7 * 7, 4096),nn.ReLU(inplace=True),nn.Dropout(),nn.Linear(4096, 4096),nn.ReLU(inplace=True),nn.Dropout(),nn.Linear(4096, num_classes))def forward(self, x):x = self.features(x)x = x.view(x.size(0), 512 * 7 * 7)x = self.classifier(x)return x

这样看上去有点冗余,为了方便更改架构,我们可以设置VGG块,然后根据VGG块来生成网络,后续的很多网络都用类似的想法。 VGG块定义如下

import torch
import torch.nn as nn
def vgg_block(num_convs, in_channels, out_channels):layers = []for _ in range(num_convs):layers.append(nn.Conv2d(in_channels, out_channels,kernel_size=3, padding=1))layers.append(nn.ReLU())in_channels = out_channelslayers.append(nn.MaxPool2d(kernel_size=2,stride=2))return nn.Sequential(*layers)

由于这里使用的数据集数量较小,考虑到性能问题,这里我们使用VGG-11,共有8个卷积层和3个全连接层。

conv_arch = ((1, 64), (1, 128), (2, 256), (2, 512), (2, 512))
def vgg(conv_arch):conv_blks = []in_channels = 1# 卷积层部分for (num_convs, out_channels) in conv_arch:conv_blks.append(vgg_block(num_convs, in_channels, out_channels))in_channels = out_channelsreturn nn.Sequential(*conv_blks, nn.Flatten(),# 全连接层部分nn.Linear(out_channels * 7 * 7, 4096), nn.ReLU(), nn.Dropout(0.5),nn.Linear(4096, 4096), nn.ReLU(), nn.Dropout(0.5),nn.Linear(4096, 10))net = vgg(conv_arch)

2.加载Fashion-MNIST数据集

import torch
import torch.nn as nn
import torch.optim as optim
import torchvision
import torchvision.transforms as transforms
import matplotlib.pyplot as plt# 设置使用的设备为GPU,如果没有GPU则使用CPU
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")# 加载Fashion-MNIST数据集
transform = transforms.Compose([transforms.ToTensor(),transforms.Resize((224,224)),#transforms.Normalize((0.5,), (0.5,))
])trainset = torchvision.datasets.FashionMNIST(root='./data', train=True,download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=64,shuffle=True, num_workers=2)testset = torchvision.datasets.FashionMNIST(root='./data', train=False,download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=64,shuffle=False, num_workers=2)

由于VGG输入图像要求为224×224,这里需要将Fashion—MNIST的图像大小更改,使用transforms.Resize函数。

3.初始化模型

model = net.to(device)
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.05)

4.模型训练和评估

# 训练模型
num_epochs = 10
train_losses = []
test_losses = []
train_accs = []
test_accs = []for epoch in range(num_epochs):train_loss = 0.0train_total = 0train_correct = 0model.train()for images, labels in trainloader:images, labels = images.to(device), labels.to(device)optimizer.zero_grad()outputs = model(images)loss = criterion(outputs, labels)loss.backward()optimizer.step()train_loss += loss.item()_, predicted = torch.max(outputs.data, 1)train_total += labels.size(0)train_correct += (predicted == labels).sum().item()train_loss /= len(trainloader)train_accuracy = 100.0 * train_correct / train_totaltrain_losses.append(train_loss)train_accs.append(train_accuracy)test_loss = 0.0test_total = 0test_correct = 0model.eval()with torch.no_grad():for images, labels in testloader:images, labels = images.to(device), labels.to(device)outputs = model(images)loss = criterion(outputs, labels)test_loss += loss.item()_, predicted = torch.max(outputs.data, 1)test_total += labels.size(0)test_correct += (predicted == labels).sum().item()test_loss /= len(testloader)test_accuracy = 100.0 * test_correct / test_totaltest_losses.append(test_loss)test_accs.append(test_accuracy)print(f"Epoch {epoch+1}/{num_epochs}: Train Loss: {train_loss:.4f}, Train Acc: {train_accuracy:.2f}%, Test Loss: {test_loss:.4f}, Test Acc: {test_accuracy:.2f}%")# 绘制训练误差和测试误差曲线
plt.figure(figsize=(10, 5))
plt.plot(range(1, num_epochs+1), train_losses, label='Train Loss')
plt.plot(range(1, num_epochs+1), test_losses, label='Test Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Training and Testing Loss')
plt.legend()
plt.show()# 绘制训练准确率和测试准确率曲线
plt.figure(figsize=(10, 5))
plt.plot(range(1, num_epochs+1), train_accs, label='Train Acc')
plt.plot(range(1, num_epochs+1), test_accs, label='Test Acc')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.title('Training and Testing Accuracy')
plt.legend()
plt.show()
Epoch 1/10: Train Loss: 2.2078, Train Acc: 15.18%, Test Loss: 0.9984, Test Acc: 65.97%
Epoch 2/10: Train Loss: 0.5435, Train Acc: 79.75%, Test Loss: 0.4182, Test Acc: 84.12%
Epoch 3/10: Train Loss: 0.3391, Train Acc: 87.61%, Test Loss: 0.3074, Test Acc: 88.30%
Epoch 4/10: Train Loss: 0.2872, Train Acc: 89.33%, Test Loss: 0.2830, Test Acc: 89.32%
Epoch 5/10: Train Loss: 0.2521, Train Acc: 90.65%, Test Loss: 0.2747, Test Acc: 90.11%
Epoch 6/10: Train Loss: 0.2228, Train Acc: 91.58%, Test Loss: 0.2585, Test Acc: 90.44%
Epoch 7/10: Train Loss: 0.1985, Train Acc: 92.61%, Test Loss: 0.2545, Test Acc: 91.10%
Epoch 8/10: Train Loss: 0.1767, Train Acc: 93.42%, Test Loss: 0.2654, Test Acc: 90.92%
Epoch 9/10: Train Loss: 0.1535, Train Acc: 94.28%, Test Loss: 0.2362, Test Acc: 91.81%
Epoch 10/10: Train Loss: 0.1324, Train Acc: 94.98%, Test Loss: 0.2662, Test Acc: 91.24%

image-20230717002337941

image-20230717002347934

我们对比三个架构在`Fashion-MNIST数据集上的结果,发现测试集的Accuracy,VGG-11表现最好,突破了0.91,AlexNet次之,LeNet最低,这说明使用更深的网络是能够提升图像识别性能的。

总结

我们介绍了三种经典的卷积神经网络架构:LeNet,AlexNet,VGG。他们的共同思想都是使用卷积层来学习图片的空间信息,提取特征,最后使用全连接层转换到我们要的分类空间。

LeNet是首个成功应用在手写数字识别数据集上的深度卷积神经网络,只有2个卷积层、两个池化层和三个全连接层

AlexNet在LeNet基础上使用了更多更深的卷积层,在2012年的ImageNet比赛上一战成名,从此引领了深度学习的浪潮

VGG在AlexNet的基础上构建了一个非常深的卷积神经网络,通过堆叠多个小尺寸的卷积核和池化层来逐步提取图像特征。它的设计简单一致,具有较好的性能和可迁移性,成为了深度学习研究中的重要里程碑之一。

从LeNet到AlexNet再到VGG,网络在不断的变深变大,模型参数也在不断增加,包括现在很多模型都是上亿个参数,这对数据集和硬件都有很高的要求,后续我们再介绍一些能够减少模型参数的方法。

在这里插入图片描述

🔎本章的介绍到此介绍,如果文章对你有帮助,请多多点赞、收藏、评论、关注支持!!


http://www.ppmy.cn/news/914862.html

相关文章

智慧校园能源管控系统

智慧校园能源管控系统是一种搭载了物联网技术、大数据技术、大数据等技术性智能化能源管理方法系统,致力于为学校提供更高效、安全性、可信赖的能源供应管理和服务。该系统包括了校内的电力工程、水、气、暖等各类能源,根据对能源的实时检测、数据统计分…

小米小爱同学PC版下载地址

https://www.microsoft.com/zh-cn/p/%E5%B0%8F%E7%88%B1%E5%90%8C%E5%AD%A6/9mw76kfhnz0c?activetabpivot:overviewtab

微信小程序支持windows PC版了

微信 PC 版新版本中,支持打开聊天中分享的小程序,开发者可下载安装微信 PC 版内测版本进行体验和适配。最新版微信开发者工具新增支持在微信 PC 版中预览小程序 查看详情 微信 PC 版内测版下载地址:https://dldir1.qq.com/weixin/Windows/WeC…

[抓包] 微信小程序(PC版)如何抓包

本文抓包环境: Win10,微信(PC版本) v3.9.2.20,Burp Suite v1.7.32,Proxifier v3.42 不需要使用安卓模拟器 一、下载安装好Burp Suite,Proxifier 链接: https://pan.baidu.com/s/1QMj7HIfQUR2QOuHFI-UqjQ 提取码: 3he…

企业微信PC版支持多个企业切换了

更新完成后 就可以切换了。

5 个最好的免费开源反病毒工具(PC版)

5 个最好的免费开源反病毒工具 PC版 防病毒软件使人们能够轻松使用手机、平板电脑和计算机,能够在网络上更安全地浏览,而不用担心将私人信息传播给其他人(或任何病毒) 一些好的防病毒软件还包含对来自其他计算机的威胁&#xff0…

PC端和移动端的区别你知道吗?

截至2015年11月,中国手机上网用户数已超过9.05亿,软件移动化成为一种趋势,移动产品经理成为了产品经理的一个重要分支,那么对于移动端和PC端到底有什么区别呢?在设计过程中有什么差异?下面我们逐一分析。 …

window下PC版 charles小程序抓包

记录一次charles小程序抓包遇到的坑 准备设置开始抓包 准备 charles 官网下载 设置 1.Charles 上安装 SSL 证书: 通过 Help->SSL Proxying->Install Charles Root Certificate 打开证书安装窗口:这里有一个坑,要 注意安装位置在受信…