[深度应用]·实战掌握PyTorch图片分类简明教程

个人网站--> http://www.yansongsong.cn/

项目GitHub地址--> https://github.com/xiaosongshine/image_classifier_PyTorch/

1.引文

深度学习的比赛中,图片分类是很常见的比赛,同时也是很难取得特别高名次的比赛,因为图片分类已经被大家研究的很透彻,一些开源的网络很容易取得高分。如果大家还掌握不了使用开源的网络进行训练,再慢慢去模型调优,很难取得较好的成绩。

我们在[PyTorch小试牛刀]实战六·准备自己的数据集用于训练讲解了如何制作自己的数据集用于训练,这个教程在此基础上,进行训练与应用。

2.数据介绍

数据 下载地址

这次的实战使用的数据是交通标志数据集,共有62类交通标志。其中训练集数据有4572张照片(每个类别大概七十个),测试数据集有2520张照片(每个类别大概40个)。数据包含两个子目录分别train与test:

为什么还需要测试数据集呢?这个测试数据集不会拿来训练,是用来进行模型的评估与调优。

train与test每个文件夹里又有62个子文件夹,每个类别在同一个文件夹内:

我从中打开一个文件间,把里面图片展示出来:

其中每张照片都类似下面的例子,100*100*3的大小。100是照片的照片的长和宽,3是什么呢?这其实是照片的色彩通道数目,RGB。彩色照片存储在计算机里就是以三维数组的形式。我们送入网络的也是这些数组。

3.网络构建

1.导入Python包,定义一些参数

import torch as t
import torchvision as tv
import os
import time
import numpy as np
from tqdm import tqdm class DefaultConfigs(object): data_dir = "./traffic-sign/"
data_list = ["train","test"] lr = 0.001
epochs = 10
num_classes = 62
image_size = 224
batch_size = 40
channels = 3
gpu = "0"
train_len = 4572
test_len = 2520
use_gpu = t.cuda.is_available() config = DefaultConfigs()

  

2.数据准备,采用PyTorch提供的读取方式(具体内容参考[PyTorch小试牛刀]实战六·准备自己的数据集用于训练

注意一点Train数据需要进行随机裁剪,Test数据不要进行裁剪了

normalize = tv.transforms.Normalize(mean = [0.485, 0.456, 0.406],
std = [0.229, 0.224, 0.225]
) transform = {
config.data_list[0]:tv.transforms.Compose(
[tv.transforms.Resize([224,224]),tv.transforms.CenterCrop([224,224]),
tv.transforms.ToTensor(),normalize]#tv.transforms.Resize 用于重设图片大小
) ,
config.data_list[1]:tv.transforms.Compose(
[tv.transforms.Resize([224,224]),tv.transforms.ToTensor(),normalize]
)
} datasets = {
x:tv.datasets.ImageFolder(root = os.path.join(config.data_dir,x),transform=transform[x])
for x in config.data_list
} dataloader = {
x:t.utils.data.DataLoader(dataset= datasets[x],
batch_size=config.batch_size,
shuffle=True
)
for x in config.data_list
}

  

3.构建网络模型(使用resnet18进行迁移学习,训练参数为最后一个全连接层 t.nn.Linear(512,num_classes)) 

def get_model(num_classes):

    model = tv.models.resnet18(pretrained=True)
for parma in model.parameters():
parma.requires_grad = False
model.fc = t.nn.Sequential(
t.nn.Dropout(p=0.3),
t.nn.Linear(512,num_classes)
)
return(model)

  

如果电脑硬件支持,可以把下述代码屏蔽,则训练整个网络,最终准确率会上升,训练数据会变慢。

for parma in model.parameters():
parma.requires_grad = False

  

模型输出

ResNet(
(conv1): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)
(bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace)
(maxpool): MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)
(layer1): Sequential(
(0): BasicBlock(
(conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace)
(conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)
(1): BasicBlock(
(conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace)
(conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)
)
(layer2): Sequential(
(0): BasicBlock(
(conv1): Conv2d(64, 128, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
(bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace)
(conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(downsample): Sequential(
(0): Conv2d(64, 128, kernel_size=(1, 1), stride=(2, 2), bias=False)
(1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)
)
(1): BasicBlock(
(conv1): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace)
(conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)
)
(layer3): Sequential(
(0): BasicBlock(
(conv1): Conv2d(128, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
(bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace)
(conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(downsample): Sequential(
(0): Conv2d(128, 256, kernel_size=(1, 1), stride=(2, 2), bias=False)
(1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)
)
(1): BasicBlock(
(conv1): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace)
(conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)
)
(layer4): Sequential(
(0): BasicBlock(
(conv1): Conv2d(256, 512, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
(bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace)
(conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(downsample): Sequential(
(0): Conv2d(256, 512, kernel_size=(1, 1), stride=(2, 2), bias=False)
(1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)
)
(1): BasicBlock(
(conv1): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace)
(conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)
)
(avgpool): AvgPool2d(kernel_size=7, stride=1, padding=0)
(fc): Sequential(
(0): Dropout(p=0.3)
(1): Linear(in_features=512, out_features=62, bias=True)
)
)

  

4.训练模型(支持自动GPU加速,GPU使用教程参考:[开发技巧]·PyTorch如何使用GPU加速

def train(epochs):

    model = get_model(config.num_classes)
print(model)
loss_f = t.nn.CrossEntropyLoss()
if(config.use_gpu):
model = model.cuda()
loss_f = loss_f.cuda() opt = t.optim.Adam(model.fc.parameters(),lr = config.lr)
time_start = time.time() for epoch in range(epochs):
train_loss = []
train_acc = []
test_loss = []
test_acc = []
model.train(True)
print("Epoch {}/{}".format(epoch+1,epochs))
for batch, datas in tqdm(enumerate(iter(dataloader["train"]))):
x,y = datas
if (config.use_gpu):
x,y = x.cuda(),y.cuda()
y_ = model(x)
#print(x.shape,y.shape,y_.shape)
_, pre_y_ = t.max(y_,1)
pre_y = y
#print(y_.shape)
loss = loss_f(y_,pre_y)
#print(y_.shape)
acc = t.sum(pre_y_ == pre_y) loss.backward()
opt.step()
opt.zero_grad()
if(config.use_gpu):
loss = loss.cpu()
acc = acc.cpu()
train_loss.append(loss.data)
train_acc.append(acc)
#if((batch+1)%5 ==0):
time_end = time.time()
print("Batch {}, Train loss:{:.4f}, Train acc:{:.4f}, Time: {}"\
.format(batch+1,np.mean(train_loss)/config.batch_size,np.mean(train_acc)/config.batch_size,(time_end-time_start)))
time_start = time.time() model.train(False)
for batch, datas in tqdm(enumerate(iter(dataloader["test"]))):
x,y = datas
if (config.use_gpu):
x,y = x.cuda(),y.cuda()
y_ = model(x)
#print(x.shape,y.shape,y_.shape)
_, pre_y_ = t.max(y_,1)
pre_y = y
#print(y_.shape)
loss = loss_f(y_,pre_y)
acc = t.sum(pre_y_ == pre_y) if(config.use_gpu):
loss = loss.cpu()
acc = acc.cpu() test_loss.append(loss.data)
test_acc.append(acc)
print("Batch {}, Test loss:{:.4f}, Test acc:{:.4f}".format(batch+1,np.mean(test_loss)/config.batch_size,np.mean(test_acc)/config.batch_size)) t.save(model,str(epoch+1)+"ttmodel.pkl") if __name__ == "__main__":
train(config.epochs)

  

训练结果如下:

def train(epochs):

    model = get_model(config.num_classes)
print(model)
loss_f = t.nn.CrossEntropyLoss()
if(config.use_gpu):
model = model.cuda()
loss_f = loss_f.cuda() opt = t.optim.Adam(model.fc.parameters(),lr = config.lr)
time_start = time.time() for epoch in range(epochs):
train_loss = []
train_acc = []
test_loss = []
test_acc = []
model.train(True)
print("Epoch {}/{}".format(epoch+1,epochs))
for batch, datas in tqdm(enumerate(iter(dataloader["train"]))):
x,y = datas
if (config.use_gpu):
x,y = x.cuda(),y.cuda()
y_ = model(x)
#print(x.shape,y.shape,y_.shape)
_, pre_y_ = t.max(y_,1)
pre_y = y
#print(y_.shape)
loss = loss_f(y_,pre_y)
#print(y_.shape)
acc = t.sum(pre_y_ == pre_y) loss.backward()
opt.step()
opt.zero_grad()
if(config.use_gpu):
loss = loss.cpu()
acc = acc.cpu()
train_loss.append(loss.data)
train_acc.append(acc)
#if((batch+1)%5 ==0):
time_end = time.time()
print("Batch {}, Train loss:{:.4f}, Train acc:{:.4f}, Time: {}"\
.format(batch+1,np.mean(train_loss)/config.batch_size,np.mean(train_acc)/config.batch_size,(time_end-time_start)))
time_start = time.time() model.train(False)
for batch, datas in tqdm(enumerate(iter(dataloader["test"]))):
x,y = datas
if (config.use_gpu):
x,y = x.cuda(),y.cuda()
y_ = model(x)
#print(x.shape,y.shape,y_.shape)
_, pre_y_ = t.max(y_,1)
pre_y = y
#print(y_.shape)
loss = loss_f(y_,pre_y)
acc = t.sum(pre_y_ == pre_y) if(config.use_gpu):
loss = loss.cpu()
acc = acc.cpu() test_loss.append(loss.data)
test_acc.append(acc)
print("Batch {}, Test loss:{:.4f}, Test acc:{:.4f}".format(batch+1,np.mean(test_loss)/config.batch_size,np.mean(test_acc)/config.batch_size)) t.save(model,str(epoch+1)+"ttmodel.pkl") if __name__ == "__main__":
train(config.epochs)

  

训练10个Epoch,测试集准确率可以到达0.86,已经达到不错效果。通过修改参数,增加训练,可以达到更高的准确率。

[深度应用]·实战掌握PyTorch图片分类简明教程的更多相关文章

  1. [深度应用]·实战掌握Dlib人脸识别开发教程

    [深度应用]·实战掌握Dlib人脸识别开发教程 个人网站--> http://www.yansongsong.cn/ 项目GitHub地址--> https://github.com/xi ...

  2. Go 语言图片处理简明教程

    虽然 Go 语言主要用于 Web 后端以及各类中间件和基础设施开发,也难免遇到一些图像处理的需求.Go 语言提供的 image 标准库提供了基本的图片加载.裁剪.绘制等能力,可以帮助我们实现一些绘图需 ...

  3. 对比学习:《深度学习之Pytorch》《PyTorch深度学习实战》+代码

    PyTorch是一个基于Python的深度学习平台,该平台简单易用上手快,从计算机视觉.自然语言处理再到强化学习,PyTorch的功能强大,支持PyTorch的工具包有用于自然语言处理的Allen N ...

  4. 深度学习之神经网络核心原理与算法-caffe&keras框架图片分类

    之前我们在使用cnn做图片分类的时候使用了CIFAR-10数据集 其他框架对于CIFAR-10的图片分类是怎么做的 来与TensorFlow做对比. Caffe Keras 安装 官方安装文档: ht ...

  5. [深度应用]·Keras实现Self-Attention文本分类(机器如何读懂人心)

    [深度应用]·Keras实现Self-Attention文本分类(机器如何读懂人心) 配合阅读: [深度概念]·Attention机制概念学习笔记 [TensorFlow深度学习深入]实战三·分别使用 ...

  6. TensorFlow 2.0 深度学习实战 —— 浅谈卷积神经网络 CNN

    前言 上一章为大家介绍过深度学习的基础和多层感知机 MLP 的应用,本章开始将深入讲解卷积神经网络的实用场景.卷积神经网络 CNN(Convolutional Neural Networks,Conv ...

  7. TensorFlow深度学习实战---图像识别与卷积神经网络

    全连接层网络结构:神经网络每两层之间的所有结点都是有边相连的. 卷积神经网络:1.输入层 2.卷积层:将神经网络中的每一个小块进行更加深入地分析从而得到抽象程度更高的特征. 3 池化层:可以认为将一张 ...

  8. 源码分析——迁移学习Inception V3网络重训练实现图片分类

    1. 前言 近些年来,随着以卷积神经网络(CNN)为代表的深度学习在图像识别领域的突破,越来越多的图像识别算法不断涌现.在去年,我们初步成功尝试了图像识别在测试领域的应用:将网站样式错乱问题.无线领域 ...

  9. 深度学习实战篇-基于RNN的中文分词探索

    深度学习实战篇-基于RNN的中文分词探索 近年来,深度学习在人工智能的多个领域取得了显著成绩.微软使用的152层深度神经网络在ImageNet的比赛上斩获多项第一,同时在图像识别中超过了人类的识别水平 ...

随机推荐

  1. 【bzoj3598】: [Scoi2014]方伯伯的商场之旅

    Description 方伯伯有一天去参加一个商场举办的游戏.商场派了一些工作人员排成一行.每个人面前有几堆石子.说来也巧,位置在 i 的人面前的第 j 堆的石子的数量,刚好是 i 写成 K 进制后的 ...

  2. [HNOI2015]菜肴制作 拓扑序

    逆序最大字典序拓扑序 反向建边,逆序字典序最大.. #include<cstdio> #include<cstring> #include<iostream> #i ...

  3. Java语言编程 - Java第一个程序HelloWorld

    3.1 新建Java文件 首先新建一个文件夹,用于存放写的Java程序,例如我存放Java程序的位置为” D:\Files\code\java”. 在该文件夹中,右键新建一个文本文档 将文件名重命名为 ...

  4. 女皇武则天:我不愿被 extends

    01. 利用继承,我们可以基于已存在的类构造一个新类.继承的好处在于,子类可以复用父类的非 private 的方法和非 private 成员变量. is-a 是继承的一个明显特征,就是说子类的对象引用 ...

  5. 整合X-Admin前端框架改造ABP

    “站在巨人的肩膀上”,这样一来,不要万事亲恭,在值得的方向上节约时间,毕竟人生就这么一次.在接触ABP以来,一直想花点时间整合LayUI前端框架到ABP中,进而能够逐渐打磨出一套适合自己的框架,开发习 ...

  6. SLAM+语音机器人DIY系列:(五)树莓派3开发环境搭建——1.安装系统ubuntu_mate_16.04

    摘要 通过前面一系列的铺垫,相信大家对整个miiboo机器人的DIY有了一个清晰整体的认识.接下来就正式进入机器人大脑(嵌入式主板:树莓派3)的开发.本章将从树莓派3的开发环境搭建入手,为后续ros开 ...

  7. DateUtil日期工具类

    目录 (1)需要导入的包 (2)DateUtil类 (1)需要导入的包 主要用于Strings.isNullOrEmpty(date) <!--string处理类--> <depen ...

  8. 设计模式之外观模式——Java语言描述

    外观模式隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口.它想现有的系统添加了一个接口,以隐藏系统的复杂性 介绍 意图 为子系统中的一组接口提供了一个一致的界面,外观模式定义了一个高层接 ...

  9. HTML5最佳实践web app

    简介 本文重点关注如何充分利用HTML5和CSS让web app运行更加流畅. Tip 1: 使用web storage代替cookie cookie最大的缺陷是在每一次HTTP请求中都会携带所有符合 ...

  10. 基于flexbox纯css框架的解析

    学CSS很好的一个方法大概是先用纯CSS来实现一个自己的框架,然后便可以在之后的使用中对一开始可能很粗糙的框架做细致的优化与改进,删除些冗余,添加些功能之类的. 当然,为了避免一开始写框架时候的时候手 ...