[零基础][最简单的教程]图像多分类问题的解决——基于resnet50的pytorch的实现

文章目录

前言

文章的宗旨是使小白不懂原理也可以快速入手,傻瓜式操作。

整个文章的逻辑从所有深度学习的模型的通用框架开始介绍,再推广到用pytorch进行图像识别问题的模型基本框架。由于笔者也是初学深度学习与pytorch,因此仅以此篇,分享给同样初学pytorch,且对深度学习的一些原理不是很了解的朋友,帮助大家更快的上手一个图像分类项目
PS:如果读者觉得啰嗦,直接跳到代码部分进行复制就好了,那部分教你如何正确的复制与微调。

提示:以下是本篇文章正文内容,下面案例可供参考

一、开始任务的前提条件

1.装了anoconda与pytorch

具体教程可以搜B站UP主”深度之眼官方账号”的视频”pytorch安装指南!”

[零基础][最简单的教程]图像多分类问题的解决——基于resnet50的pytorch的实现
建议在安装前把原来机器上的python给卸载了,编译器直接用pycharm,这样就可以避免出现一堆莫名其妙的BUG,导致安装一天都失败
注1:如果浏览器下载慢的话,可以把链接复制到迅雷下载,迅雷会员便宜。
注2:用pycharm创建项目后,要给它的虚拟环境配置解释器,得用anoconda里的python.exe,所以你得记住anoconda的安装路径是在哪里,不然后期慢慢搜索会很折磨的
注3:如果你没有GUP,跟着教程安装的pytorch时,得下载cpu版本,而不是cuda版本

; 二、深度学习通用框架

本部分转载至知乎的一篇文章,强烈建议大家先看一眼,保证心中有数。
链接: 点击进入知乎原文.

所有的深度学习模型过程都可以形式化如下图:

[零基础][最简单的教程]图像多分类问题的解决——基于resnet50的pytorch的实现
1、输入处理模块 (X 输入数据,变成网络能够处理的Tensor类型)

2、模型构建模块 (主要负责从输入的数据,得到预测的y^, 这就是我们经常说的前向过程)

3、定义代价函数和优化器模块 (注意,前向过程只会得到模型预测的结果,并不会自动求导和更新,是由这个模块进行处理)

4、构建训练过程 (迭代训练过程,就是上图表情包的训练迭代过程)

这几个模块分别与上图的数字标号1,2,3,4进行一一对应!

; 三、修改代码前,使用者需要明确的问题

本框架无须过多的理解深度学习的很多概念,只要你完成三个事情即可复制本代码,改一下直接使用。

1.图片分成三个集,并放在正确的位置

①图片分集
假设你有5个类,每个类有10张图片,你可以把每个类的图片都按照8:1:1的比例分成训练集,验证集和测试集,每个集中都装着5个文件夹,这5个文件夹名字为类名,装着这个类的图片。
训练集的作用是训练数据,验证集的作用是在每轮模型训练后,时时测试模型的性能
测试集是,当所有轮数都跑完之后,再测试,看看模型性能究竟如何
那么我分完之后,这三份图片应该放哪里呢?

②正确的位置
假设你的.py文件放在文件夹pythonProject里,那么你需要在文件夹A里面再创建一个文件夹,名为dataset 。然后你进入dataset,在dataset里面创建三个文件夹,分别为train,valid,test

(这步一定要做对,除了文件夹pythonProject的名字可以任意取,其余文件夹的名字必须和我一样)

[零基础][最简单的教程]图像多分类问题的解决——基于resnet50的pytorch的实现
[零基础][最简单的教程]图像多分类问题的解决——基于resnet50的pytorch的实现
[零基础][最简单的教程]图像多分类问题的解决——基于resnet50的pytorch的实现

; 2.明确你是几分类问题

如果你有5类,你就是5分类问题,到时候代码里只用改几处就可以了

3.明确你是使用的模型网络

本文使用的模型是resnet50,你可以根据你需要的网络自行修改,我会在代码里指出哪里需要修改

点击链接,里面提供了pytorch支持的模型网络
链接: 点击查看pytorch支持的网络.

四、图像分类通用pytorch框架——具体代码实现

跟深度学习的通用框架一样,分四步
一、输入处理模块
0.引入库
1.数据增强
2.加载数据集
二、模型构建模块
三、定义代价函数和优化器模块
四、构建训练过程
3.训练与验证
4.训练与验证结果的可视化展示
5.测试

一、输入处理模块

0.引入库

代码如下:

这个不要更改,直接复制就行


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

import numpy as np
import matplotlib.pyplot as plt
import os
os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"
print("0导入库完成")

1.数据增强

代码如下(示例):
这个也直接复制就行

image_transforms = {
    'train': transforms.Compose([
        transforms.RandomResizedCrop(size=256, scale=(0.8, 1.0)),
        transforms.RandomRotation(degrees=15),
        transforms.RandomHorizontalFlip(p=0.5),
        transforms.CenterCrop(size=224),
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406],
                             [0.229, 0.224, 0.225])
    ]),
    'valid': transforms.Compose([
        transforms.Resize(size=256),
        transforms.CenterCrop(size=224),
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406],
                             [0.229, 0.224, 0.225])
    ])
}
print("1.数据增强完成")

2.加载数据集

代码如下(示例):
这里只有一个参数需要改,就是num_classes=5这一行
需要把5改成你自己的类数


dataset = 'dataset'
train_directory = os.path.join(dataset, 'train')
valid_directory = os.path.join(dataset, 'valid')
test_directory = os.path.join(dataset , 'test')
batch_size = 32
num_classes = 5

data = {
    'train': datasets.ImageFolder(root=train_directory, transform=image_transforms['train']),

    'valid': datasets.ImageFolder(root=valid_directory, transform=image_transforms['valid']),
    'test': datasets.ImageFolder(root=test_directory, transform=image_transforms['valid'])
}

train_data_size = len(data['train'])
valid_data_size = len(data['valid'])
test_data_size = len(data['test'])

train_data = DataLoader(data['train'], batch_size=batch_size, shuffle=True)

valid_data = DataLoader(data['valid'], batch_size=batch_size, shuffle=True)
test_data = DataLoader(data['test'], batch_size=batch_size, shuffle=True)

print("训练集数据量为:{},验证集数据量为:{},验证集数据量为{}".format(train_data_size, valid_data_size,test_data_size))

print("2.加载数据完毕")

二、加载模型

代码如下(示例):
这里有两处需要修改
1.nn.Linear(256,5)
其中这个5需要改成你的所需分类数
2.resnet50 = models.resnet50(pretrained=True)
可以把resnet50换成你想要的网络模型,如你要用alexnet,则改成:
alexnet = models.alexnet(pretrained=True)


resnet50 = models.resnet50(pretrained=True)

for param in resnet50.parameters():
    param.requires_grad = False

fc_inputs = resnet50.fc.in_features
resnet50.fc = nn.Sequential(
    nn.Linear(fc_inputs, 256),
    nn.ReLU(),
    nn.Dropout(0.4),
    nn.Linear(256, 5),
    nn.LogSoftmax(dim=1)
)

三、定义损失函数、优化器

代码如下(示例):
复制即可


loss_func = nn.NLLLoss()
optimizer = optim.Adam(resnet50.parameters())
print("3.模型载入完毕")

四、构建训练过程(训练、验证、测试)

3.训练与验证

代码如下(示例):
这个直接复制,这个代码段定义了一个训练与验证函数(把这个过程封装起来了)


def train_and_valid(model, loss_function, optimizer, epochs=25):
    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
    history = []
    best_acc = 0.0
    best_epoch = 0

    for epoch in range(epochs):
        epoch_start = time.time()
        print("Epoch: {}/{}".format(epoch + 1, epochs))

        model.train()

        train_loss = 0.0
        train_acc = 0.0
        valid_loss = 0.0
        valid_acc = 0.0

        for i, (inputs, labels) in enumerate(train_data):
            inputs = inputs.to(device)
            labels = labels.to(device)

            optimizer.zero_grad()

            outputs = model(inputs)

            loss = loss_function(outputs, labels)

            loss.backward()

            optimizer.step()

            train_loss += loss.item() * inputs.size(0)

            ret, predictions = torch.max(outputs.data, 1)
            correct_counts = predictions.eq(labels.data.view_as(predictions))

            acc = torch.mean(correct_counts.type(torch.FloatTensor))

            train_acc += acc.item() * inputs.size(0)

        with torch.no_grad():
            model.eval()

            for j, (inputs, labels) in enumerate(valid_data):
                inputs = inputs.to(device)
                labels = labels.to(device)

                outputs = model(inputs)

                loss = loss_function(outputs, labels)

                valid_loss += loss.item() * inputs.size(0)

                ret, predictions = torch.max(outputs.data, 1)

                correct_counts = predictions.eq(labels.data.view_as(predictions))

                acc = torch.mean(correct_counts.type(torch.FloatTensor))

                valid_acc += acc.item() * inputs.size(0)

        avg_train_loss = train_loss / train_data_size
        avg_train_acc = train_acc / train_data_size

        avg_valid_loss = valid_loss / valid_data_size
        avg_valid_acc = valid_acc / valid_data_size

        history.append([avg_train_loss, avg_valid_loss, avg_train_acc, avg_valid_acc])

        if best_acc < avg_valid_acc:
            best_acc = avg_valid_acc
            best_epoch = epoch + 1

        epoch_end = time.time()

        print(
            "Epoch: {:03d}, Training: Loss: {:.4f}, Accuracy: {:.4f}%, \n\t\tValidation: Loss: {:.4f}, Accuracy: {:.4f}%, Time: {:.4f}s".format(
                epoch + 1, avg_valid_loss, avg_train_acc * 100, avg_valid_loss, avg_valid_acc * 100,
                epoch_end - epoch_start
            ))
        print("Best Accuracy for validation : {:.4f} at epoch {:03d}".format(best_acc, best_epoch))
        torch.save(model.state_dict(), '.\dataset'+'_model_' + str(epoch + 1) + '.pt')

    return model, history

注1:这里是一个开关作用,当你想训练的时候,就把istrain的值设置为1。当整个代码全部执行完之后,如果你还想测试,但不想再训练,就把istrain的值设置为0
注2:nun_epochs=30的意思是我要训练30轮。这个值可以由你自己定。当你调试代码的时候,这个值可以设置为1或2,帮助你快速判断代码是否出错。

istrain=1
if istrain:
    num_epochs = 30
    trained_model, history = train_and_valid(resnet50, loss_func, optimizer, num_epochs)

这一步运行完之后,正确的话会在窗口看到以下的文字:

[零基础][最简单的教程]图像多分类问题的解决——基于resnet50的pytorch的实现
需要你记住这里的一个数字,最佳轮数。
对于我而言,这次准确率最佳的轮数是第18轮。所以我需要记住18这个数。对于你而言,这个数可能不是18,可能是1-30里的任何一个数,记住它,最佳轮数。(PS:大家应该看的懂英语吧)

4.训练与可视化展示

代码如下(示例):
可以直接复制
ispicshow=1时会展示,等于0时不展示


ispicshow=0
if ispicshow:
    history = np.array(history)
    plt.plot(history[:, 0:2])
    plt.legend(['Tr Loss', 'Val Loss'])
    plt.xlabel('Epoch Number')
    plt.ylabel('Loss')
    plt.ylim(0, 1)
    plt.savefig(dataset + '_loss_curve.png')
    plt.show()

    plt.plot(history[:, 2:4])
    plt.legend(['Tr Accuracy', 'Val Accuracy'])
    plt.xlabel('Epoch Number')
    plt.ylabel('Accuracy')
    plt.ylim(0, 1)
    plt.savefig(dataset + '_accuracy_curve.png')
    plt.show()

5.测试

代码如下(示例):

首先定义了一个测试函数(封装了测试过程)
在这个测试函数的第一行,即
resnet50.load_state_dict(torch.load(‘.\dataset’ + ‘ model‘ + ’18’ + ‘.pt’))这行
这里面有个数字,18.他就是刚才要你记住的最佳轮数。把它换成你自己机器运行后显示的最佳轮数即可


def test(model,loss_function):
    resnet50.load_state_dict(torch.load('.\dataset' + '_model_' + '18' + '.pt'))
    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
    test_loss = 0.0
    test_acc = 0.0
    test_start = time.time()
    with torch.no_grad():
        model.eval()
    for j, (inputs, labels) in enumerate(test_data):
        inputs = inputs.to(device)
        labels = labels.to(device)

        outputs = model(inputs)

        loss = loss_function(outputs, labels)

        test_loss += loss.item() * inputs.size(0)

        ret, predictions = torch.max(outputs.data, 1)

        correct_counts = predictions.eq(labels.data.view_as(predictions))

        acc = torch.mean(correct_counts.type(torch.FloatTensor))

        test_acc += acc.item() * inputs.size(0)

    avg_test_loss = test_loss / test_data_size
    avg_test_acc = test_acc / test_data_size
    test_end = time.time()

    print(
        "test: Loss: {:.4f}, Accuracy: {:.4f}%, Time: {:.4f}s".format(
            avg_test_loss, avg_test_acc * 100,
            test_end - test_start
        ))

istest=1表示可以进行训练,等于0表示不能
如果你用的模型不是resnet,则你需要把 test(resnet50,loss_func)中的resnet50改成你自己选择的模型网络。例如,如果你最开始选的是用alexnet,则需要改成:test(alexnet,loss_func)

istest=1
if istest:
    test(resnet50,loss_func)

至此,傻瓜式教学就结束了,不懂原理的同学可以根据自己的需要改改就能用了

总结

本文其实是对另一个作者的代码理解后的重新组织,帮助更多的小白快速入手。相对于原文章( 点击阅读原文.),本文封装了更多的细节,只提供了几个对开发者或使用者修改的接口,一定程度上降低了图像分类的门槛。

如果大家想继续深入学习,而不是玩玩而已的话,还是需要先慢慢打好基础再来进入实战。

Original: https://blog.csdn.net/Gambler_Yushen/article/details/114855882
Author: Gambler_Yushen
Title: [零基础][最简单的教程]图像多分类问题的解决——基于resnet50的pytorch的实现

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/665764/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球