下面展示一下怎么在PyTorch中构建一个简单的卷积神经网络

import torch
import torch.nn as nn
import torch.utils.data
import torch.optim as optim
from torchvision import datasets, transforms

"""首先读取数据,分别构建训练集和测试集(验证集),DataLoader来迭代取数据"""

# 定义超参数
input_size = 28    # 图像的总尺寸28*28
num_classes = 10      # 标签的总类数量
num_epochs = 3           # 训练的总循环数量
batch_size = 64            # 一个批次的大小,64张图片

# 训练集
train_dataset = datasets.MNIST(root='./data', train=True, transform=transforms.ToTensor(), download=True)
# 测试集
test_dataset = datasets.MNIST(root='./data', train=False, transform=transforms.ToTensor())

# 构建batch数据
train_loader = torch.utils.data.DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True)
test_loader = torch.utils.data.DataLoader(dataset=test_dataset, batch_size=batch_size, shuffle=True)

"""
卷积网络模块构建
一般卷积层,relu层,池化层可以写成一个套餐
注意卷积最后结果还是一个特征图,需要把图转换成向量才能做分类或者回归任务
"""
class CNN(nn.Module):
    def __init__(self):
        super(CNN, self).__init__()
        self.conv1 = nn.Sequential(  # 输入大小(1, 28, 28)
            nn.Conv2d(
                in_channels=1,       # 灰度图
                out_channels=16,     # 要得到多少个特征图
                kernel_size=5,       # 卷积核大小
                stride=1,            # 步长
                padding=2,           # 如果希望卷积后大小和原来一样,需要设置padding=(kernal_size-1)/2 if stride=1
            ),
            nn.ReLU(),               # relu层
            nn.MaxPool2d(kernel_size=2),    # 进行池化操作(2*2区域),输出结果为:(16, 14, 14)
        )
        self.conv2 = nn.Sequential(         # 下一个套餐的输入是(16, 14, 14)
            nn.Conv2d(16, 32, 5, 1, 2),     # 输出(32, 14, 14)
            nn.ReLU(),                      # relu层
            nn.MaxPool2d(2),                # 输出(32, 7, 7)
        )
        self.out = nn.Linear(32 * 7 * 7, 10)   # 全连接层得到的结果
    def forward(self, x):
        x = self.conv1(x)
        x = self.conv2(x)
        x = x.view(x.size(0), -1)     # flatten操作,结果为:(batch_size, 32 * 7 * 7)
        out_put = self.out(x)
        return out_put

"""准确率作为评估标准"""
def accuracy(predictions, labels):
    pred = torch.max(predictions.data, 1)[1]
    rights = pred.eq(labels.data.view_as(pred)).sum()  # # rights 就是正确的意思
    return rights, len(labels)

"""训练网络模型"""
# 实例化
net = CNN()
# 损失函数
criterion = nn.CrossEntropyLoss()
# 优化器
optimizer = optim.Adam(net.parameters(), lr=0.001)  # 定义优化器,普通的随机梯度下降算法
# 开始训练循环
for epoch in range(num_epochs):
    # 当前epoch的结果保存下来
    train_rights = []
    for batch_idx, (data, target) in enumerate(train_loader):   # 针对容器中的每一批进行循环
        net.train()
        output = net(data)
        loss = criterion(output, target)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        right = accuracy(output, target)
        train_rights.append(right)
        if batch_idx % 100 == 0:
            net.eval()
            val_rights = []
            for (data, target) in test_loader:
                output = net(data)
                right = accuracy(output, target)
                val_rights.append(right)
            # 准确率计算
            train_r = (sum([tup[0] for tup in train_rights]), sum([tup[1] for tup in train_rights]))
            val_r = (sum([tup[0] for tup in val_rights]), sum([tup[1] for tup in val_rights]))
            print('当前epoch: {} [{} / {} ({:.0f}%)]\t损失: {:.6f}\t训练集准确率: {:.2f}%\t测试集准确率: {:.2f}%'.format(
                epoch, batch_idx * batch_size, len(train_loader.dataset),
                100. * batch_idx / len(train_loader),
                loss.data,
                100. * train_r[0].numpy() / train_r[1],
                100. * val_r[0].numpy() / val_r[1]))

代码解析:

<1>准备工作

1.导入实现代码功能所需的工具库

train在python中代表什么_pytorch

2.设置超参数以及数据准备

2.1 先定义好训练需要的基本参数

train在python中代表什么_人工智能_02

2.2 训练集和测试集直接用现成的MNIS数据集

这里MNIST数据集是 PyTorch中自带的,当然要是没有下载。程序运行的时候也会自动下载

train在python中代表什么_train在python中代表什么_03

2.3 构建batch数据

这里可以看到训练集和测试集每个batch都是选择64张图片,并不打乱顺序

train在python中代表什么_train在python中代表什么_04

torch.utils.data.DataLoader主要是对数据进行 batch 的划分。

在训练模型时使用到此函数,用来 把训练数据分成多个小组 ,此函数 每次抛出一组数据 。直至把所有的数据都抛出。就是做一个数据的初始化。

train在python中代表什么_学习_05

其中以下参数比较重要:

1. dataset:(数据类型 dataset)

输入的数据类型,这里是原始数据的输入。

2. batch_size:(数据类型 int)

批训练数据量的大小,根据具体情况设置即可(默认:1)。PyTorch训练模型时调用数据不是一行一行进行的(这样太没效率),而是一捆一捆来的。这里就是定义每次喂给神经网络多少行数据,如果设置成1,那就是一行一行进行(个人偏好,PyTorch默认设置是1)。每次是随机读取大小为batch_size。如果dataset中的数据个数不是batch_size的整数倍,这最后一次把剩余的数据全部输出。若想把剩下的不足batch size个的数据丢弃,则将drop_last设置为True,会将多出来不足一个batch的数据丢弃。

3. shuffle:(数据类型 bool)

洗牌。默认设置为False。在每次迭代训练时是否将数据洗牌,默认设置是False。将输入数据的顺序打乱,是为了使数据更有独立性,但如果数据是有序列特征的,就不要设置成True了。

<2>卷积网络模块的构建

卷积网络中通常把卷积层,relu层,池化层等放在一起

在该模型中设计了两个卷积模块conv1和conv2

train在python中代表什么_深度学习_06

然后每个卷积模块中包含一个卷积层,一个relu层和一个最大池化层

train在python中代表什么_train在python中代表什么_07

1. nn.Module

pytorch的核心基类nn.Module,所有的网络层都是继承于这个类。

看一下Module的定义,其中也包括了构建模型的示例用法

train在python中代表什么_人工智能_08

2. nn.Sequential

train在python中代表什么_深度学习_09

从命名来看,nn.Sequential就是一个序列容器,用于搭建神经网络的模块被按照被传入构造器的顺序添加到nn.Sequential()容器中。除此之外,一个包含神经网络模块的OrderedDict也可以被传入nn.Sequential()容器中。利用nn.Sequential()搭建好模型架构,模型前向传播时调用forward()方法,模型接收的输入首先被传入nn.Sequential()包含的第一个网络模块中。然后,第一个网络模块的输出传入第二个网络模块作为输入,按照顺序依次计算并传播,直到nn.Sequential()里的最后一个模块输出结果。

调用forward()方法进行前向传播时,for循环按照顺序遍历nn.Sequential()中存储的网络模块,并以此计算输出结果,并返回最终的计算结果。

train在python中代表什么_学习_10

3. nn.Conv2d

二维卷积运算,二维卷积应该是最常用的卷积方式了,在Pytorch的nn模块中,封装了nn.Conv2d()类作为二维卷积的实现。使用方法和普通的类一样,先实例化再使用。


torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True, padding_mode='zeros', device=None, dtype=None)


功能:对多个输入平面组成的输入信号应用2D卷积运算,常用于图像处理

train在python中代表什么_pytorch_11

4 第二个卷积模块的注意的地方

train在python中代表什么_深度学习_12

5. nn.Linear

nn.Linear()是用于设置网络中的全连接层的,需要注意在二维图像处理的任务中,全连接层的输入与输出一般都设置为二维张量,形状通常为[batch_size, size],不同于卷积层要求输入输出是四维张量。其用法与形参说明如下:

def __init__(self, in_features: int, out_features: int, bias: bool = True,
             device=None, dtype=None) -> None:

train在python中代表什么_深度学习_13

直白点说,前面图像经过卷积池化等操作后还是图,但是我们最终要得到的是10类标签

train在python中代表什么_深度学习_14

in_features指的是输入的二维张量的大小,输入图片的特征共有多少个

out_features指的是输出的二维张量的大小,当然,它也代表了该全连接层的神经元个数。

in_features由输入张量的形状决定,out_features则决定了输出张量的形状

6. 向前传播

train在python中代表什么_深度学习_15

forward()方法是实际的网络转换。forward 方法是将输入张量映射到预测输出张量的映射。

<3>准确率作为评估标准

卷积网络中有诸多评估指标,这里使用准确率作为评估

train在python中代表什么_人工智能_16

1. torch.max()

torch.max(input) → Tensor

返回输入tensor中所有元素的最大值

torch.max(input, dim, keepdim=False, out=None) -> (Tensor, LongTensor)

按维度dim 返回最大值

torch.max)(a,0) 返回每一列中最大值的那个元素,且返回索引(返回最大元素在这一列的行索引

torch.max(a,1) 返回每一行中最大值的那个元素,且返回其索引(返回最大元素在这一行的列索引)

train在python中代表什么_人工智能_17

2. rights = pred.eq(labels.data.view_as(pred)).sum()

这句意思就是输出最大值的索引位置,这个索引位置和真实值的索引位置比较相等的做统计就是这个批次准确的个数用来做统计分析

<4>训练网络模型并输出

train在python中代表什么_学习_18