pytorch初学习记录之CIFAR10数据分类网络

最近尝试学习使用了深度学习框架pytorch,记录如下内容。主要是分析例程CIFAR10数据分类网络。

1,网络的定义

网络部分的定义主要是两个部分。

(1)组成网络的各个模块定义。如卷积层,池化层,全连接层等。

a. 卷积层定义。

卷积层定义使用函数torch.nn.Conv2d(),主要参数包括in_channels,out_channels,kernel_size等。这里主要介绍这三个参数的含义和使用方法。in_channels是输入数据的通道数,如,若是第一层卷积,输入是一个RGB图像,则in_channels=3;若不是第一次卷积层,即前面已有卷积等操作,则in_channels等于上一层操作的输出的图像的数量值。out_channels代表卷积核的数量,也代表这层卷积输出的图像数量。kernel_size是卷积参数,可以是整数或者图元tuple类型。若是整数类型,则宽和高的参数是一样的。关于卷积中的channel参数的理解可以参照下面的链接:

https://blog.csdn.net/qq_34107425/article/details/104117670

下面是一张彩色图像经过一层卷积的过程:

如一张彩色图像的尺寸参数为32 * 32 * 3;卷积参数为torch.nn.Conv2d(3,6,5);则可以看到kernel_size = 5 * 5 * 3,in_channel = 3, out_channel = 6; 则经过这层卷积的输出为(32-5+1) * (32-5+1) * 6.

b. 池化层定义。

以2维池化为例。函数torch.nn.MaxPool2d()用于图像的池化。主要参数为kernel_size, stride_size。kernel_size参数是池化时的参数,包括宽和高,可以是整数或者图元tuple类型,是整数时,宽和高相等。stride_size是滑动尺寸参数,也包括宽和高,同样的,可以是整数或者图元tuple类型,是整数时,宽和高相等。池化操作通常在卷积层后面进行操作。

如下是一个池化操作的过程:

上一层卷积的输出为 28 * 28 * 6,再经过一个池化层torch.nn.MaxPool2d(2,2),可知池化kernel_size = 2 * 2,stride_size = 2 * 2。即对卷积层输出的6个输出分别进行池化操作得到14 * 14 * 6的尺寸。

c. 全连接层定义。

全连接层就是矩阵和向量相乘在加上一个向量的操作了。全连接层函数使用torch.nn.Linear()进行操作,主要参数就是矩阵的行数和列数,即输入行数尺寸的数据,输出列数尺寸的数据。即全连接权重参数的尺寸就是行数乘以列数。

如下是一个全连接层的使用过程:

上一层数据的输出尺寸为16 * 5 * 5的行,使用全连接函数torch.nn.Linear(16 * 5 * 5,120),则可知全连接层的输出尺寸是120。

(2)网络的前向计算过程,即整个网络的前向流程。

这部分就是将网络各模块层进行组织成一个完整的网络结构。如卷积层1->激活计算->池化层1->卷积层2->激活计算->池化层2->数据reshape操作->全连接层1->激活计算->全连接层2->激活计算->全连接层3->输出。

下面是例程的网络定义部分代码。

# 定义一个卷积神经网络
import torch.nn as nn  # 神经网络模块
import torch.nn.functional as F # 激活函数模块
class Net(nn.Module):
# 网络组成子模块的定义
def __init__(self): 
    super(Net, self).__init__() 
    self.conv1 = nn.Conv2d(3, 6, 5)
    self.pool = nn.MaxPool2d(2, 2)
    self.conv2 = nn.Conv2d(6, 16, 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):
    x = self.pool(F.relu(self.conv1(x)))
    x = self.pool(F.relu(self.conv2(x)))
    x = x.view(-1, 16 * 5 * 5) #相当于 reshape 成 16 * 5 * 5 列, 行数自适应
    x = F.relu(self.fc1(x))
    x = F.relu(self.fc2(x))
    x = self.fc3(x)
    return x

net = Net()

2,网络的训练过程

a, 在进行网络训练之前需要进行损失函数的选择和优化函数的选择。

损失函数用于计算训练输出和目标输出之间的差距,如torch.nn.CrossEntropyLoss(),这个是交叉熵损失函数,常用于分类问题中。详见下面两个链接:
https://blog.csdn.net/geter_CS/article/details/84857220

https://blog.csdn.net/Jeremy_lf/article/details/102725285

优化函数是用于反向计算时计算更新权重等参数等的优化算法。如torch.optim.SGD()函数等。基本使用需要搞懂参数的设置。

b, 网络的训练过程主要是两个嵌套循环过程。

外层循环是整个训练数据集的多次训练过程,常用epoch代表,这是为了充分利用训练数据,使得训练得到很好的结果。

内层训练就是训练数据集的一次训练过程,每次循环是一个前向和反向过程的结束,也是一个batch数据的训练过程。一次循环过程包括:一个batch数据及其标签的获取;一次正向过程的计算,一次损失函数的计算,一次损失反向计算,一次模型更新等。

下面为此例程的训练过程代码:

# 定义损失函数和优化器
import torch.optim as optim
criterion = nn.CrossEntropyLoss() # 交叉熵损失
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
#训练网络
for epoch in range(2):  
running_loss = 0.0
for i, data in enumerate(trainloader, 0):
    # 获取输入
    inputs, labels = data
    # print(inputs.size())
    # print(labels.size())
    # 梯度置0
    optimizer.zero_grad()
    # 正向传播,反向传播,优化
    outputs = net(inputs)
    # print(outputs.size())
    loss = criterion(outputs, labels)
    # print(loss.size())
    loss.backward()
    optimizer.step() # 更新模型
    # 打印状态信息
    running_loss += loss.item() # 每个batch训练得到的损失求和
    if i % 2000 == 1999:  # 每2000批次(batch)打印一次
        print('[%d, %5d] loss: %.3f' %
              (epoch + 1, i + 1, running_loss / 2000))
        running_loss = 0.0

print('Finished Training')

3,网络的测试过程

例程中测试主要从三个方面:

1,随机从测试集中选择一个batch的数据进行分类预测,输出类别名称与实际的类别进行比较。代码如下:

# 测试
dataiter = iter(testloader)
images, labels = dataiter.next()

# 显示图片
imshow(torchvision.utils.make_grid(images))
print('GroundTruth: ', ' '.join('%5s' % classes[labels[j]] for j in range(4)))

outputs = net(images) #

_, predicted = torch.max(outputs, 1) #

print('Predicted: ', ' '.join('%5s' % classes[predicted[j]]
                              for j in range(4)))

2,对整个测试集数据进行分类测试,计算分类正确率。

# 整个测试集测试
correct = 0
total = 0
with torch.no_grad():
    for data in testloader:
        images, labels = data
        outputs = net(images)
        _, predicted = torch.max(outputs.data, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()

print('Accuracy of the network on the 10000 test images: %d %%' % (
    100 * correct / total))

3,多整个测试集进行分类识别,计算每一类别的识别正确率。

# 识别
class_correct = list(0. for i in range(10))
class_total = list(0. for i in range(10))
with torch.no_grad():
    for data in testloader:
        images, labels = data
        outputs = net(images)
        _, predicted = torch.max(outputs, 1)
        c = (predicted == labels).squeeze()
        for i in range(4):
            label = labels[i]
            class_correct[label] += c[i].item()
            class_total[label] += 1


for i in range(10):
    print('Accuracy of %5s : %2d %%' % (
        classes[i], 100 * class_correct[i] / class_total[i]))

4,数据获取和预处理等补充代码

# pytorch实列 训练一个分类器
# step1: 读取和归一化CIFAR10
import torch
import torchvision
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
import numpy as np

# if __name__ == '__main__':
transform = transforms.Compose([transforms.ToTensor(),
                                transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])

trainset = torchvision.datasets.CIFAR10(root='./data', train=True,
                                        download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=4,
                                          shuffle=True)  #, num_workers = 2

testset = torchvision.datasets.CIFAR10(root='./data', train=False,
                                       download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=4,
                                         shuffle=False)  #, num_workers = 2

classes = ('plane', 'car', 'bird', 'cat',
           'deer', 'dog', 'frog', 'horse', 'ship', 'truck')


# 展示一些训练图像
def imshow(img):
    img = img / 2 + 0.5
    npimg = img.numpy()
    plt.imshow(np.transpose(npimg, (1, 2, 0)))
    plt.show()


# 获取随机数据
dataiter = iter(trainloader)
images, labels = dataiter.next()
# # 展示图像
# imshow(torchvision.utils.make_grid(images))
# # 显示图像标签
# print(''.join('%5s' % classes[labels[j]] for j in range(4)))

5,遇到的两个问题及其解决方法:

a, 数据集下载过慢问题。

解决办法:按住control,鼠标点击代码中torchvision.datasets.CIFAR10的CIFAR10的,跳到cifar.py文件,将url = "https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz"改为url = “http://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz”。速度明显提升。

b, torch.utils.data.DataLoader(trainset, batch_size=4,
shuffle=True, num_workers = 2) 函数中加上num_workers参数后出现错误。

解决办法:在代码中加入if name == ‘main’: (如代码所示)。

但是加上后,数据加载明显速度变慢。参考链接:
https://github.com/pytorch/pytorch/issues/12831

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值