PyTorch 2简介:卷积神经网络

78c7b40a64b027fbfc57e89455b5e652.png

介绍

在本系列的上一部分中,我们使用了CIFAR-10数据集,并介绍了PyTorch的基础知识:

  • 张量及其相关操作

  • 数据集和数据加载器

  • 构建基本的神经网络

  • 基本模型的训练和评估

我们为CIFAR-10数据集中的图像分类开发的模型只能在验证集上达到53%的准确率,并且在一些类别(如鸟类和猫类)的图像分类上表现非常困难(约33-35%的准确率)。这是预期的,因为我们通常会使用卷积神经网络进行图像分类。在本教程系列的这一部分,我们将专注于卷积神经网络(CNN)并改善在CIFAR-10上的图像分类性能。

CNN基础知识

在我们深入代码之前,让我们讨论卷积神经网络的基础知识,以便更好地理解我们的代码在做什么。如果你已经对CNN的工作原理感到熟悉,可以跳过本节。

与前一部分中开发的前馈网络相比,卷积神经网络具有不同的架构,并由不同类型的层组成。在下图中,我们可以看到典型CNN的一般架构,包括它可能包含的不同类型的层。

f9f00365f181be8fdb030fe2e9d626ab.png

卷积网络中通常包含的三种类型的层是:

  • 卷积层(红色虚线框)

  • 池化层(蓝色虚线框)

  • 全连接层(红色和紫色实线框)

卷积层

CNN的定义组件和第一层是卷积层,它由以下部分组成:

  • 输入数据(在本例中为图像)

  • 滤波器

  • 特征图

将卷积层与全连接层区分开来的关键是卷积运算。我们不会详细讨论卷积的定义,但如果你真的感兴趣并想深入了解其数学定义以及一些具体的示例,我强烈推荐阅读这篇文章,它在解释数学定义方面做得非常好

https://betterexplained.com/articles/intuitive-convolution/#Part_3_Mathematical_Properties_of_Convolution

卷积相对于密集连接层(全连接层)在图像数据中的优势何在?简而言之,密集连接层会学习输入中的全局模式,而卷积层具有学习局部和空间模式的优势。这可能听起来有些模糊或抽象,所以让我们看一个例子来说明这是什么意思。

0813202bbec589d82ee59d33be16598f.png

在图片的左侧,我们可以看到一个基本的2D黑白图像的4是如何在卷积层中表示的。

红色方框是滤波器/特征检测器/卷积核,在图像上进行卷积操作。在右侧是相同图像在一个密集连接层中的表示。你可以看到相同的9个图像像素被红色的卷积核框起来。请注意,在左侧,像素在空间上是分组的,与相邻的像素相邻。然而,在右侧,这相同的9个像素不再是相邻的。

通过这个例子,我们可以看到当图像被压平并表示为完全连接/线性层时,空间/位置信息是如何丢失的。这就是为什么卷积神经网络在处理图像数据时更强大的原因。输入数据的空间结构得到保留,图像中的模式(边缘、纹理、形状等)可以被学习。

这基本上是为什么在图像上使用卷积神经网络的原因,但现在让我们讨论一下如何实现。让我们来看看我们的输入数据的结构,我们一直在谈论的那些叫做“滤波器”的东西,以及当我们将它们放在一起时卷积是什么样子。

输入数据

CIFAR-10数据集包含60,000个32x32的彩色图像,每个图像都表示为一个3D张量。每个图像将是一个(32,32,3)的张量,其中的维度是32(高度)x 32(宽度)x 3(R-G-B颜色通道)。下图展示了从数据集中分离出来的飞机全彩色图像的3个不同的颜色通道(RGB)。

04107932cbdfba184cc63e093acdfebd.png

通常将图像视为二维的,所以很容易忘记它们实际上是以三维表示的,因为它们有3个颜色通道!

滤波器

在卷积层中,滤波器(也称为卷积核或特征检测器)是一组权重数组,它以滑动窗口的方式在图像上进行扫描,计算每一步的点积,并将该点积输出到一个称为特征图的新数组中。这种滑动窗口的扫描称为卷积。让我们看一下这个过程的示例,以帮助理解正在发生的事情。

一个3x3的滤波器(蓝色)对输入(红色)进行卷积,生成一个特征图(紫色):

f969f1c70a022991c81dd7468d1e794f.gif

在每个卷积步骤中计算点积的示意图:

f1b970866f53ebb611f64df3db950a86.gif

需要注意的是,滤波器的权重在每个步骤中保持不变。就像在全连接层中的权重一样,这些值在训练过程中进行学习,并通过反向传播在每个训练迭代后进行调整。

这些示意图并不能完全展示所有情况。当训练一个卷积神经网络时,模型不仅在卷积层中使用一个滤波器是很常见的。通常在一个卷积层中会有32或64个滤波器,实际上,在本教程中,我们将在一个层中使用多达96个滤波器来构建我们的模型。

最后,虽然滤波器的权重是需要训练的主要参数,但卷积神经网络也有一些可以调整的超参数:

  • 层中的滤波器数量

  • 滤波器的维度

  • 步幅(每一步滤波器移动的像素数)

  • 填充(滤波器如何处理图像边界)

我们不会详细讨论这些超参数,因为本文不旨在全面介绍卷积神经网络,但这些是需要注意的重要因素。

池化层

池化层与卷积层类似,都是通过滤波器对输入数据(通常是从卷积层输出的特征图)进行卷积运算。

然而,池化层的功能不是特征检测,而是降低维度或降采样。最常用的两种池化方法是最大池化和平均池化。在最大池化中,滤波器在输入上滑动,并在每一步选择具有最大值的像素作为输出。在平均池化中,滤波器输出滤波器所经过像素的平均值。

全连接层

最后,在卷积和池化层之后,卷积神经网络通常会有全连接层,这些层将在图像分类任务中执行分类,就像本教程中的任务一样。

现在,我们已经了解了卷积神经网络的结构和操作方式,让我们开始进行有趣的部分,在PyTorch中训练我们自己的CNN模型!

设置

与本教程的第一部分一样,我建议使用Google Colab进行跟随,因为你的Python环境已经安装了PyTorch和其他库,并且有一个GPU可以用于训练模型。

因此,如果你使用的是Colab,请确保使用GPU,方法是转到“运行时”(Runtime)并点击“更改运行时类型”。

3ed12437616e3ae90ce4fda51cceb017.png

在对话框中选择GPU并保存。

6be8c4a93663c28e3aac90194eef3886.png

现在你可以在Colab中使用GPU了,并且我们可以使用PyTorch验证你的设备。

因此,首先,让我们处理导入部分:

import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision.utils import make_grid
from torchvision.datasets import CIFAR10
from torchvision import transforms
from torchvision import utils
from torchvision.utils import make_grid
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
import pandas as pd

如果你想检查你可以访问的GPU是什么,请键入并执行torch.cuda.get_device_name(0),你应该会看到设备输出。Colab有几种不同的GPU选项可供选择,因此你的输出将根据你所能访问的内容而有所不同,但只要你在运行此代码时没有看到“RuntimeError: No CUDA GPUs are available”错误,那么你正在使用GPU!

我们可以将GPU设备设置为device,以便在开发模型时将其分配给GPU,如果没有CUDA GPU设备可用,我们也可以使用CPU。

device = "cuda" if torch.cuda.is_available() else "cpu"
print(device)
# cuda

接下来,让我们设置一个随机种子,以便我们的结果是可重现的,并下载我们的训练数据并设置一个转换,将图像转换为张量并对数据进行归一化。

torch.manual_seed(42)
transform = transforms.Compose(
    [transforms.ToTensor(),
     transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]
)
training_data = CIFAR10(root="cifar",
                        train = True,
                        download = True,
                        transform=transform)

test_data = CIFAR10(root = "cifar",
                    train = False,
                    download = True,
                    transform = transform)

一旦下载完成,让我们查看数据集中的类别:

classes = training_data.classes
classes
#['airplane',
# 'automobile',
# 'bird',
# 'cat',
# 'deer',
# 'dog',
# 'frog',
# 'horse',
# 'ship',
# 'truck']

最后,让我们设置训练和测试数据加载器:

batch_size = 24

train_dataloader = DataLoader(training_data, batch_size=batch_size, shuffle=True, num_workers=0)
test_dataloader = DataLoader(test_data, batch_size=batch_size, shuffle=True, num_workers=0)

for X, y in train_dataloader:
  print(f"Shape of X [N, C, H, W]: {X.shape}")
  print(f"Shape of y: {y.shape} {y.dtype}")
  break

#Shape of X [N, C, H, W]: torch.Size([24, 3, 32, 32])
#Shape of y: torch.Size([24]) torch.int64

现在我们准备构建我们的模型!

构建CNN

在PyTorch中,nn.Conv2d是用于图像输入数据的卷积层。Conv2d的第一个参数是输入中的通道数,在我们的第一层卷积层中,我们将使用3,因为彩色图像将有3个颜色通道。

在第一个卷积层之后,该参数将取决于前一层输出的通道数。第二个参数是在该层中卷积操作输出的通道数。这些通道是卷积层介绍中讨论的特征图。最后,第三个参数将是卷积核或滤波器的大小。这可以是一个整数值,如3表示3x3的卷积核,或者是一个元组,如(3,3)。因此,我们的卷积层将采用nn.Conv2d(in_channels, out_channels, kernel_size)的形式。还可以添加其他可选参数,包括(但不限于)步幅(stride)、填充(padding)和膨胀(dilation)。在我们的卷积层conv4中,我们将使用stride=2。

在一系列卷积层之后,我们将使用一个扁平化层将特征图扁平化,以便能够输入到线性层中。为此,我们将使用nn.Flatten()。我们可以使用nn.BatchNorm1d()应用批量归一化,并需要将特征数作为参数传递。

最后,我们使用nn.Linear()构建线性的全连接层,第一个参数是特征数

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值