当前位置:   article > 正文

AI练手系列(一)—— 利用Pytorch训练CIFAR-10数据集_使用pytorch 训练一个图片识别模型cifar10

使用pytorch 训练一个图片识别模型cifar10

本文通过记录在pytorch中训练CIFAR-10数据集的一些过程,实现一个基本的数据集的分类,并在此过程中加强对图片、张量、CNN网络的理解,并尝试去总结一些训练技巧,记录一个新手对数据及网络的理解。

CIFAR—10数据集

CIFAR-10数据集包含10个类别的60000个32x32彩色图像,每个类别6000个图像。 有50000张训练图像和10000张测试图像。数据集地址如下:

The CIFAR-10 dataset

示例如下:

image-20200605080246175

接下来我们要做的事情便是利用各种CNN的网络模型,在训练集上训练我们的模型,然后在测试集上测试模型的泛化能力,然后不断调节各种超参数及网络模型的细节,已到达在测试集上有更高的分类准确率的目的。

代码实现

代码实现如下:

import torch
import torch.nn as nn
import torch.optim as optim
import torchvision
import torchvision.datasets as datasets
import torchvision.transforms as transforms
import matplotlib.pyplot as plt 
import io
import sys
import os

#超参数定义
EPOCH = 100
BATCH_SIZE = 64
LR = 0.001
#数据集加载
#对训练集及测试集数据的不同处理组合
transform_train = transforms.Compose([
    transforms.RandomHorizontalFlip(),
    transforms.RandomGrayscale(),
    transforms.ToTensor(),
    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
transform_test = transforms.Compose([     
    transforms.ToTensor(),
    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
#将数据加载进来,本地已经下载好, root=os.getcwd()为自动获取与源码文件同级目录下的数据集路径   
train_data = datasets.CIFAR10(root=os.getcwd(), train=True,transform=transform_train,download=False)
test_data =datasets.CIFAR10(root=os.getcwd(),train=False,transform=transform_test,download=False)

#数据分批
from torch.utils.data import DataLoader
#使用DataLoader进行数据分批,dataset代表传入的数据集,batch_size表示每个batch有多少个样本
#shuffle表示在每个epoch开始的时候,对数据进行重新排序
#数据分批之前:torch.Size([3, 32, 32]):Tensor[[32*32][32*32][32*32]],每一个元素都是归一化之后的RGB的值;数据分批之后:torch.Size([64, 3, 32, 32])
#数据分批之前:train_data([50000[3*[32*32]]])
#数据分批之后:train_loader([50000/64*[64*[3*[32*32]]]])
train_loader = DataLoader(dataset=train_data,batch_size=BATCH_SIZE,shuffle=True,num_workers=2)
test_loader = DataLoader(dataset=test_data,batch_size=BATCH_SIZE,shuffle=True,num_workers=2)

#模型加载,有多种内置模型可供选择
model = torchvision.models.densenet201(pretrained=False)

#定义损失函数,分类问题使用交叉信息熵,回归问题使用MSE
criterion = nn.CrossEntropyLoss()
#torch.optim来做算法优化,该函数甚至可以指定每一层的学习率,这里选用Adam来做优化器,还可以选其他的优化器
optimizer = optim.Adam(model.parameters(),lr=LR)

#设置GPU
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
#模型和输入数据都需要to device
mode  = model.to(device)

#模型训练
from torch.utils.tensorboard import SummaryWriter
writer = SummaryWriter('cifar-10')
for epoch in range(EPOCH):
    for i,data in enumerate(train_loader):
        #取出数据及标签
        inputs,labels = data
        #数据及标签均送入GPU或CPU
        inputs,labels = inputs.to(device),labels.to(device)
        
        #前向传播
        outputs = model(inputs)
        #计算损失函数
        loss = criterion(outputs,labels)
        #清空上一轮的梯度
        optimizer.zero_grad()
        
        #反向传播
        loss.backward()
        #参数更新
        optimizer.step()
        #利用tensorboard,将训练数据可视化
        if  i%50 == 0:
            writer.add_scalar("Train/Loss", loss.item(), epoch*len(train_loader)+i)
        #print('it’s training...{}'.format(i))
    print('epoch{} loss:{:.4f}'.format(epoch+1,loss.item()))

#保存模型参数
torch.save(model,'cifar10_densenet161.pt')
print('cifar10_densenet161.pt saved')

#模型加载
model = torch.load('cifar10_densenet161.pt')
#测试
#model.eval()
model.train()

correct,total = 0,0
for j,data in enumerate(test_loader):
    inputs,labels = data
    inputs,labels = inputs.to(device),labels.to(device)
    #前向传播
    outputs = model(inputs)
    _, predicted = torch.max(outputs.data,1)
    total =total+labels.size(0)
    correct = correct +(predicted == labels).sum().item()
    #准确率可视化
    if  j%20 == 0:
        writer.add_scalar("Train/Accuracy", 100.0*correct/total, j)
        
print('准确率:{:.4f}%'.format(100.0*correct/total))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103

训练过程

以下整理训练过程的大致情况

trick:

A:model.eval()换成了model.train()

B:pretrained=True

C:优化器使用SGD

D:0-50,lr=0.01;50-150,lr=0.001,150-200,lr=0.0001

E:transform_train,transform_test

F:num_workers=2

先试了一下各个模型在同等条件下的表现,EPOCH选的比较小,是为了更快的得出结果:

ModelEPOCHBATCH_SIZELRTricksMin_LossAccuracy
Resnet5010640.001-0.757368.0700%
Resnet10110640.001-1.113452.9000%
Resnet15010640.001-1.307651.0700%
Resnet1810640.001-0.236467.7100%
Resnet3410640.001-0.427471.9800%
Densenet16110640.001-0.135573.8000%
Densenet20110640.001-0.254077.7300%

可以看出:同样使用Resnet,并不是网络层数越多网络表现越好;同等条件下Densenet的表现更好,而且很明显;同样使用Densenet,网络层数越深,效果越好,但实际运行时耗时较多。

选用Densenet161及Densenet201作为基准模型,开始调整其他参数:

ModelEPOCHBATCH_SIZELRTricksMin_LossAccuracy
Densenet16110640.001-0.135573.8000%
30640.001-0.003979.4600%
200640.001-0.0000(e73)
0.0002(e37)
81.5100%
Densenet16110640.001A0.140178.0000%
10320.001A0.147078.8200%
101280.001A0.227077.8300%
105120.001A0.239174.5100%
10640.0001A0.139264.0600%
37320.001A0.001279.4100%
10640.001A+B0.531676.6300%
Densenet20110640.001-0.254077.7300%
10640.001C1.062753.7300%
200640.001D0.0000(e62)80.8600%
10640.001E+F0.305178.8100%

可以看出,在epoch=10、batch_size=64,lr=0.001的同等条件下,densenet201的效果要好于densenet161,而且batch_size=32的效果也要更好,但分批设置LR(D)的效果还没看出来,从数据看几个trick中,A、E、F对于提升准确率也是有帮助的,B貌似起到了负效果,C严重影响了模型的训练。接下来设置一组参数:

ModelEPOCHBATCH_SIZELRTricksTimesMin_LossAccuracy
densenet201100320.001AEF8H0.0001(E87)83.2100%

果然,效果达到了最佳,那还能不能继续改进呢。比如加上D(分段设置lr),会不会更好一点呢:经过一晚上的训练之后结果如下:

(D:e1-e24:0.01,e25-e79:0.001,e80-e100:0.0005)

ModelEPOCHBATCH_SIZELRTricksTimesMin_LossAccuracy
densenet201100320.001ADEF8H0.0002(E86)82.5300%

效果上来看没有之前好。那就这样吧,在这个上面浪费了太多的时间,暂且这样。

总结:网络层数的加深一般能起到比较积极的作用;训练的循环次数加深在一定范围内对网络模型训练的正向作用较大;合适且较小的BATCH_SIZE能在数据量一定的情况下提升训练效果;变化的学习率可能会起到比较好的作用,但是这个变化本身也是很难设定的;优化器的选取也十分重要;数据的预处理、模型的小细节也可以为优化网络作出一份贡献。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/214854
推荐阅读
相关标签
  

闽ICP备14008679号