【深度学习】:《PyTorch入门到项目实战》卷积神经网络2-5:LeNet、AlexNet、VGG

LeNet-AlexNet-ZFNet一维、二维复现pytorch-含视频手敲教程 不管学习什么,基础都是非常重要的,那想对深度学习模型进行创新来说,基础就是所有的经典模型,想要从模型角度进行创新,毫无疑问就需要了解不同类型模型的特点,然后在对每一类模型有一定基础的了解上,再进行创新,目前主要有的经典模型有 LeNet-AlexNet-ZFNet-VGGNets-GooLeNet-ResNet-DenseNet其中前四种属于对卷积层纵向改变,GooLeNet,开始对模型结构进行了横向的变化,接着为了解决网络退化问题,2015年便出现了有名的ResNet残差网络,2017年结GooLeNet 阅读详情

专栏介绍

  • ✨本文收录于【深度学习】:《PyTorch入门到项目实战》专栏,此专栏主要记录如何使用PyTorch实现深度学习算法及其项目实战,已经更新完成pytorch基础篇,目前正在更新卷积神经网络(CNN),接下来会陆续更新RNN、CV、NLP、搜推广等项目实战,尽量坚持每周持续更新,欢迎大家订阅!
  • 🌸个人主页:JOJO数据科学
  • 📝个人介绍:某985统计硕士在读
  • 💌如果文章对你有帮助,欢迎✌关注、👍点赞、✌收藏、👍订阅专栏
  • 参考资料:《动手学深度学习》

在这里插入图片描述

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×14、10×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.0
    test_loss = 0.0
    correct = 0
    total = 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 Sutskever和Geoffery 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万个参数。同时,通过大输入图像尺寸和大尺寸的卷积核,使得网络能够更好地捕捉图像中的细节信息。此外,AlexNet比LeNet表现更为出色的另一个原因是它使用了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×227
    transforms.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.0
    test_loss = 0.0
    correct = 0
    total = 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模型有VGG16和VGG19。

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_channels
    layers.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_channels

    return 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.0
    train_total = 0
    train_correct = 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()
        _, 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_total
    train_losses.append(train_loss)
    train_accs.append(train_accuracy)

    test_loss = 0.0
    test_total = 0
    test_correct = 0

    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)
            test_total += labels.size(0)
            test_correct += (predicted == labels).sum().item()

    test_loss /= len(testloader)
    test_accuracy = 100.0 * test_correct / test_total
    test_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,网络在不断的变深变大,模型参数也在不断增加,包括现在很多模型都是上亿个参数,这对数据集和硬件都有很高的要求,后续我们再介绍一些能够减少模型参数的方法。

🔎本章的介绍到此介绍,如果文章对你有帮助,请多多点赞、收藏、评论、订阅支持!!【深度学习】:《PyTorch入门到项目实战》

Pytorch深度学习(3) -- CNN及其进阶模型实现(LeNet AlexNet VGG NIN GooLeNet ) Pytorch深度学习(3) -- CNN及其进阶模型实现1.LeNet1.1 模型图1.2 模型实现1.3 计算准确率函数(下同,不赘述)1.4 训练、测试函数 (下同,不赘述)2.AlexNet2.1 模型图2.2 模型实现3.VGG3.1 模型图3.2 模型实现3.2.1 VGG-Block模块3.2.2 VGG整体实现4.NIN(串联多个卷积层代替全连接层)4.1 模型图4.2 模型实现4... 阅读详情

相关推荐

Pytorch之CNN:从代码认知CNN经典架构—基于Pytorch框架的代码实现经典卷积神经网络的算法集合(LeNet/AlexNet/VGG/NIN/GoogleNet/ResNet)

Pytorch之CNN:从代码认知CNN经典架构—基于Pytorch框架的代码实现经典卷积神经网络的算法集合(LeNet/AlexNet/VGG/NIN/GoogleNet/ResNet)

头部AI社区如有邀博主AI主题演讲请私信—心比天高,仗剑走天涯,保持热爱,奔赴向梦想!低调,专注,谦虚,自律,反思,成长,还算比较正能量的博主,公益免费传播…内心特别想在AI界做出一些可以推进历史进程影响力的技术(兴趣使然,有点小情怀,也有点使命感呀 5765

Pytorch实现CNN经典网络框架(LeNet、AlexNet、VGGNet、GoogLeNet、ResNet)

卷积神经网络可谓是现在深度学习领域中大红大紫的网络框架,尤其在计算机视觉领域更是一枝独秀。CNN从90年代的LeNet开始,21世纪初沉寂了10年,直到12年AlexNet开始又再焕发第二春,从ZF Net到VGG,GoogLeNet再到ResNet和最近的DenseNet,网络越来越深,架构越来越复杂,解决反向传播时梯度消失的方法也越来越巧妙。下面介绍几种网络的结构框架和代码实现。 1、LeNe...

小马日记 6160

PyTorch实战(5)——深度卷积神经网络

本文介绍了深度卷积神经网络 (Convolutional Neural Network, CNN) 的核心优势(如权重共享、分层特征提取)及架构演进( LeNet、AlexNet、ResNet 等),并基于 PyTorch 实现了 LeNet 模型。通过 CIFAR-10 数据集进行实战训练,详细展示了数据加载、模型构建、训练流程及评估方法。尽管 LeNet 结构简单,但其模块化设计和层次化特征提取思想为后续复杂 CNN 模型奠定了基础。

盼小辉丶的博客 1万+

经典CNN卷积神经网络发展史+论文+网络实现(PyTorch)

经典CNN卷积神经网络发展史+网络实现(PyTorch)

weixin_45897172的博客 6187

集成学习-模型融合(Lenet,Alexnet,Vgg)三个模型进行融合-附源代码-宇宙的尽头一定是融合模型而不是单个模型。

模型融合代码: import torch import torchvision import torchvision.models import numpy as np from collections import Counter from matplotlib import pyplot as plt from tqdm import tqdm from torch import nn from torch.utils.data import DataLoader from torchvision.

爱吃橘子的小翟 8368

白话详细解读(七)----- CBAM:Convolutional Block Attention Module

一、CBAM简介 论文链接:https://x.sci-hub.org.cn/scholar?hl=zh-TW&as_sdt=0%2C5&q=CBAM%3A+Convolutional+Block+Attention+Module&btnG=&oq=CB CBAM这篇论文是在2018年提出的,自提出之后,已经被引用上千次,可见其影响力。CBAM是一种专门为了卷积神经网络而设计的注意力模块,传统的卷积存在只关注局部信息,而往往忽略全局信息的弊端,以3*3卷积为例,滤波器有9个

奋斗の博客 1万+

手撕深度学习:经典CNN网络结构理解汇总Lenet、Alexnet、VGG、Googlenet、Resnet

这些网络在深度学习的发展过程中起到了至关重要的作用,它们的设计思想和创新点为后续的研究和应用提供了宝贵的经验和灵感。也算是对卷积神经网络的一个小总结了,对网络的单一手撕感觉在2024年这个时间节点已经没有必要了,寻求统一的方式对过往经典卷积神经网络进行汇总说明是快速进入下一阶段内容学习的小技巧。通过理解和掌握这五种经典的卷积神经网络结构,我们可以深入了解卷积神经网络的发展历程和设计思路,为后续的深度学习研究和应用奠定坚实的基础。在这一章节,我们将详细的给出五种模型的网络结构,以方便通用调用来实现模型训练。

Nathan0921的博客 2054

主流双目相机技术参数横向评测:从ZED到INDEMIND的深度解析

本文对主流双目相机进行了深度横向评测,涵盖ZED、Bumblebee、Leap Motion、DUO 3D及INDEMIND等国内外产品。文章详细解析了分辨率、帧率、视场角、基线等核心参数,并结合科研、机器人导航、无人机、工业检测等典型应用场景,提供了实战选型指南,帮助读者根据具体需求挑选最合适的双目视觉解决方案。

weixin_29212867的博客 637

PyTorch之LeNet、AlexNet、VGG、NiN、GoogleNet基本原理及代码实现

Inception块中可以自定义的超参数是每个层的输出通道数,我们以此来控制模型复杂度。

酒酿小圆子呀~ 1079

从零开始掌握机械臂运动控制:原理、建模与实践

本文系统介绍了机械臂运动控制的核心原理与实践方法。从运动学与动力学建模的基础理论出发,详细解析了经典PID控制与现代MPC(模型预测控制)算法的应用,并通过ROS与MATLAB仿真案例,指导读者从零开始实现机械臂的轨迹规划与精准控制,为工业自动化应用提供完整的技术路径。

weixin_29099217的博客 558

算法面经手撕系列(2)--手撕BatchNormlization

手动实现/手撕BatchNormlization

罟霖同学的站点 862

4大经典CNN全维度详解+实战代码(LeNet、AlexNet、VGG、GoogLeNet),小白必看!

想象你是一家快递分拣中心的分拣员,要根据包裹外观分类:CNN的核心就是模拟这种“从粗到细、层层递进”的特征提取逻辑——通过卷积层捕捉图像的局部特征,再通过池化层保留关键信息、压缩数据量,最后用全连接层完成分类决策。首个成功应用于手写数字识别的CNN模型,奠定了现代CNN的“卷积-池化-全连接”基本框架。卷积操作(C1层为例): 设输入特征图为 X∈RHin×Win×CinX \in \mathbb{R}^{H_{in} \times W_{in} \times C_{in}}X∈RHin​×Win​×Cin

2501_93508870的博客 996

Windows10内核逆向-2-KiSystemCall64的调用流程剖析

本文深入剖析了Windows 10 x64系统中KiSystemCall64函数的完整调用流程。从用户态触发syscall指令开始,详细讲解了如何通过swapgs切换内核栈、构建KTRAP_FRAME陷阱帧、进行SMAP/CFG等安全检查,到最终通过SSDT寻址并执行目标系统服务的全过程,揭示了系统调用从Ring 3到Ring 0切换的核心机制与安全设计。

weixin_29209805的博客 78

深度不学习——————卷积神经网络,LeNet,AlexNet,VGG详解以及PyTorch代码实现

卷积神经网络 卷积神经网络针对输入全部是图像的情况,将结构调整得更加合理,获得了不小的优势。与常规 神经网络不同,卷积神经网络的各层中的神经元是3维排列的:宽度、高度和深度(这里的深度指的是激活数据体的 第三个维度,而不是整个网络的深度,整个网络的深度指的是网络的层数)。举个例子,CIFAR-10中的图像是作为 卷积神经网络的输入,该数据体的维度是32x32x3(宽度,高度和深度)。我们将看到,...

qq_26249811的博客 2587

ResNet改进(51):基于轴向注意力机制的改进ResNet模型

本文介绍了一种结合轴向注意力机制的改进ResNet模型。 通过在传统CNN中引入轴向注意力,我们能够在保持计算效率的同时,增强模型对图像全局上下文的理解能力。这种混合架构结合了CNN的局部特征提取优势和注意力机制的全局建模能力,在图像识别任务中表现出色。 轴向注意力机制的应用不仅限于ResNet,也可以灵活地集成到其他CNN架构中。 未来可以探索更多注意力变体,或将其应用于特定领域任务,如医学图像分析、自动驾驶等需要精确空间理解的场景。 希望本文能帮助你理解如何将注意力机制与传统CNN结合,为你的计

2401_82355416的博客 356

基于Keil软件实现OLED显示(江协科技HAL库)

没有HAL库的OLED驱动文件,可以看过来

2401_82728381的博客 1447

经典CNN及PyTorch实现

许多现代卷积神经网络的研究都是建立在这些基础上的,包括: AlexNet。它是第一个在大规模视觉竞赛中击败传统计算机视觉模型的大型神经网络; 使用重复块的网络(VGG)。它利用许多重复的神经网络块; 网络中的网络(NiN)。它重复使用由卷积层和 1×1 卷积层(用来代替全连接层)来构建深层网络; 含并行连结的网络(GoogLeNet)。它使用并行连结的网络,通过不同窗口大小的卷积层和最大汇聚层来并行抽取信息; 残差网络(ResNet)。它通过残差块构建跨层的数据通道,是计算机视觉中最流行的体系架构。

EP的别三日 4428

Python 爬虫实战:爬取 B 站 UP 主的全部视频数据

本文详细介绍了基于Python开发B站UP主视频数据爬虫的技术方案。通过分析B站API接口,使用requests库发送HTTP请求并处理JSON数据,结合pandas进行结构化存储。文章重点解决了接口鉴权、分页爬取、反爬策略等核心难点,实现获取视频标题、播放量、点赞数等关键指标。同时强调数据爬取需遵守平台规范,仅限技术研究使用。该方案为B站视频内容分析提供了可靠的数据采集基础,具有实际应用价值。

2503_91057718的博客 2488

给电脑装上“眼睛”:CNN 卷积神经网络架构详解(LeNet/AlexNet/ResNet)

本文介绍了卷积神经网络(CNN)的核心组件和工作原理。CNN通过卷积层(局部连接、权值共享)提取图像特征,配合池化层降维压缩,最后经展平层连接全连接网络进行分类。文章详细讲解了卷积核、步长(Stride)、填充(Padding)、通道(Channels)等关键参数,并推导了特征图尺寸计算公式。此外,还概述了从LeNet到ResNet的经典CNN架构演进,重点介绍了ResNet的残差连接创新。最后给出了一个简单的PyTorch实现示例。CNN通过模仿人类视觉处理机制,有效解决了传统神经网络处理图像时的参数量爆

👨‍💻 12年全栈老兵 | 擅长把复杂的代码逻辑翻译成“人话” | 只讲听得懂的技术故事 🚀 2849

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

【AI 学习】深入解析卷积神经网络(CNN):理论、实现与应用

卷积神经网络(CNN)是计算机视觉领域的核心模型,能够自动提取图像特征并实现高效分类。本文系统介绍了CNN的发展背景、理论基础及实践应用,重点解析了局部感受野、参数共享和池化等核心设计理念,详细阐述了卷积层、池化层、全连接层等组件的工作原理。通过PyTorch框架实现了MNIST手写数字识别的CNN模型,并探讨了经典模型演进与优化策略。文章从理论到实践全面讲解CNN,为读者提供了计算机视觉领域的重要参考。

CodeSuc 的技术博客 4521

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

Pytorch总结十一之 神经网络模型:LeNet、AlexNet、VGG

Pytorch总结十之 神经网络模型:LeNet、AlexNet、VGG

yohnyang的博客 1341

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

【深度学习】经典CNN模型梳理与Pytorch实现:LeNet、AlexNet、NiN、VGGNet、ResNet

1. 前言 经典永不过时。这篇文章中,我们要回顾卷积神经网络发展史上几个经典模型:LeNet、AlexNet、NiN、VGGNet、ResNet,梳理它们的发展脉络,总结它们各自的特点,并借助Pytorch完成实现。 2. 模型及实现 2.1 LeNet LeNet是LeCun在1998年提出的用于解决手写数字识别任务的卷积神经网络模型,这一网络模型奠定了之后CNN的基本架构。它又被称为LeNet-5,5表示第5代版本。LeNet-5的基本结构是:卷积、池化、卷积、池化、全连接。 LeNet.

DwD-的博客 1744

Pytorch框架与经典卷积神经网络学习Day3|LeNet与AlexNet原理与实战

重叠池化增加了特征的丰富性。

weixin_74106693的博客 1175

【适合初学者】玩转CIFAR10—Pytorch复现LeNet,AlexNet,VGG,GoogLeNet,MobileNet,ResNet,DenseNet,Vision Transformer模型

本文对于AlexNet,VGG,GooGleNet,ResNet,DenseNet,MobileNet等主流的卷积神经网络模型,以及Vision Transformer等基于Transformer的模型在CIFAR10数据集上进行了详细的测试,测试内容包括测试集准确率、模型训练时间、模型参数量等。 所有的模型均使用相同的训练超参数设置(learning_rate,batch_size,epoch等)。 持续更新中。 General settings Data augmentation(Ran

cax1165 3836

LeNet、AlexNet、VGG、NiN、GoogLeNet

文章目录LeNet、AlexNet、VGG、NiN、GoogLeNet全连接层与卷积层的优势对比LeNetLeNet模型LeNet的pytorch实现AlexNetAlexNet模型AlexNet的pytorch实现VGGVGG模型VGG的实现NiN(网络中的网络)NiN模型NiN的pytorch实现GooLeNetInception块完整goolenet模型GooLeNet的pytorch小结 ...

ShyLab 818

Cifar-10图像分类/Pytorch/LeNet/AlexNet

又叫下采样层,目的是压缩数据,降低数据维度,和卷积有明显区别,采样2x2的选择框进行压缩,原来是28x28,采样后是14x14,通过选择框的数据求和再取平均值然后在乘上一个权值和加上一个偏置值,组成新的图片,每个特征平面采样的权值和偏置值相同,因此每个特征平面对应的采样层只两个待训练参数,总共有6张采样平面,总共待训练权值为:2x6=12。(6)第6,7,8层是全连接层,每一层的神经元的个数为4096,最终输出softmax为1000,因为上面介绍过,ImageNet这个比赛的分类个数为1000。

weixin_47546087的博客 4892
上一篇: 玩转数据可视化之R语言ggplot2:(十四)层级布局(一层一层增加你的绘图元素,使绘图更灵活)
下一篇: 【深度学习】:《PyTorch入门到项目实战》卷积神经网络2-6:NiN(Network in Network)和1×1卷积(附Pytorch源码)
JOJO数据科学
JOJO数据科学 优质创作者: 人工智能技术领域 优质创作者: 人工智能技术领域 领域专家: 数据科学与机器学习技术领域 领域专家: 数据科学与机器学习技术领域
博客等级 码龄7年 4万+粉丝 200原创
评论 24
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JOJO数据科学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值