首页 > 其他分享 >ResNet50的猫狗分类训练及预测

ResNet50的猫狗分类训练及预测

时间:2023-04-12 15:46:51浏览次数:37  
标签:loss ResNet50 val 训练 分类 train import path save

相比于之前写的ResNet18,下面的ResNet50写得更加工程化一点,这还适用与其他分类。

我的代码文件结构

  

 

1. 数据处理

  首先已经对数据做好了分类

  

 

 

   文件夹结构是这样

  开始划分数据集

  split_data.py

import os
import random
import shutil


def move_file(target_path, save_train_path, save_val_pathm, scale=0.1):

    file_list = os.listdir(target_path)
    random.shuffle(file_list)

    number = int(len(file_list) * scale)
    train_list = file_list[number:]
    val_list = file_list[:number]

    for file in train_list:
        target_file_path = os.path.join(target_path, file)
        save_file_path = os.path.join(save_train_path, file)
        shutil.copyfile(target_file_path, save_file_path)
    for file in val_list:
        target_file_path = os.path.join(target_path, file)
        save_file_path = os.path.join(save_val_pathm, file)
        shutil.copyfile(target_file_path, save_file_path)


def split_classify_data(base_path, save_path, scale=0.1):
    folder_list = os.listdir(base_path)
    for folder in folder_list:
        target_path = os.path.join(base_path, folder)
        save_train_path = os.path.join(save_path, 'train', folder)
        save_val_path = os.path.join(save_path, 'val', folder)
        if not os.path.exists(save_train_path):
            os.makedirs(save_train_path)
        if not os.path.exists(save_val_path):
            os.makedirs(save_val_path)
        move_file(target_path, save_train_path, save_val_path, scale)
        print(folder, 'finish!')


if __name__ == '__main__':
    base_path = r'C:\Users\Administrator.DESKTOP-161KJQD\Desktop\save_dir'
    save_path = r'C:\Users\Administrator.DESKTOP-161KJQD\Desktop\dog_cat'
    # 验证集比例
    scale = 0.1
    split_classify_data(base_path, save_path, scale)

  运行完以上代码的到的文件夹结构

    

 

 

   一个训练集数据,一个验证集数据

  

2.数据集的导入

  我这个文件写了一个数据集的导入和一个学习率更新的函数。数据导入是通用的

  tools.py

import os
import time

import cv2
import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
import torchvision
from torch.autograd.variable import Variable
from torch.utils.tensorboard import SummaryWriter
from torchvision import datasets, transforms
from torch.utils.data import Dataset, DataLoader
from torch.optim.lr_scheduler import ExponentialLR, LambdaLR
from torchvision.models import ResNet50_Weights
from tqdm import tqdm
from classify_cfg import *

mean = MEAN
std = STD


def get_dataset(base_dir='', input_size=160):
    dateset = dict()
    transform_train = transforms.Compose([
        # 分辨率重置为input_size
        transforms.Resize(input_size),
        transforms.RandomRotation(15),
        # 对加载的图像作归一化处理, 并裁剪为[input_sizexinput_sizex3]大小的图像(因为这图片像素不一致直接统一)
        transforms.CenterCrop(input_size),
        transforms.ToTensor(),
        transforms.Normalize(mean=mean, std=std)
    ])

    transform_val = transforms.Compose([
        transforms.Resize(input_size),
        transforms.RandomRotation(15),
        transforms.CenterCrop(input_size),
        transforms.ToTensor(),
        transforms.Normalize(mean=mean, std=std)
    ])
    base_dir_train = os.path.join(base_dir, 'train')
    train_dataset = datasets.ImageFolder(root=base_dir_train, transform=transform_train)
    # print("train_dataset=" + repr(train_dataset[1][0].size()))
    # print("train_dataset.class_to_idx=" + repr(train_dataset.class_to_idx))
    # print(train_dataset.classes)
    classes = train_dataset.classes
    # classes = train_dataset.class_to_idx
    classes_num = len(train_dataset.classes)

    base_dir_val = os.path.join(base_dir, 'val')
    val_dataset = datasets.ImageFolder(root=base_dir_val, transform=transform_val)

    dateset['train'] = train_dataset
    dateset['val'] = val_dataset

    return dateset, classes, classes_num


def update_lr(epoch, epochs):
    """
    假设开始的学习率lr是0.001,训练次数epochs是100
    当epoch<33时是lr * 1
    当33<=epoch<=66 时是lr * 0.5
    当66<epoch时是lr * 0.1
    """
    if epoch == 0 or epochs // 3 > epoch:
        return 1
    elif (epochs // 3 * 2 >= epoch) and (epochs // 3 <= epoch):
        return 0.5
    else:
        return 0.1

 

3.训练模型

  数据集导入好了以后,选择模型,选择优化器等等,然后开始训练。

  mytrain.py

import os
import time

import cv2
import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim
import torchvision
from torch.autograd.variable import Variable
from torch.utils.tensorboard import SummaryWriter
from torch.utils.data import Dataset, DataLoader
from torch.optim.lr_scheduler import ExponentialLR, LambdaLR
from torchvision.models import ResNet50_Weights
# from tqdm import tqdm
from classify_cfg import *
from tools import get_dataset, update_lr


def train(model, dateset, epochs, batch_size, device, optimizer, scheduler, criterion, save_path):
    train_loader = DataLoader(dateset.get('train'), batch_size=batch_size, shuffle=True)
    val_loader = DataLoader(dateset.get('val'), batch_size=batch_size, shuffle=True)

    # 保存为tensorboard文件
    write = SummaryWriter(save_path)
    # 训练过程写入txt
    f = open(os.path.join(save_path, 'log.txt'), 'w', encoding='utf-8')

    best_acc = 0
    for epoch in range(epochs):
        train_correct = 0.0
        model.train()
        sum_loss = 0.0
        accuracy = -1
        total_num = len(train_loader.dataset)
        # print(total_num, len(train_loader))
        # loop = tqdm(enumerate(train_loader), total=len(train_loader))
        batch_count = 0
        for batch_idx, (data, target) in enumerate(train_loader):
            start_time = time.time()
            data, target = Variable(data).to(device), Variable(target).to(device)
            output = model(data)
            loss = criterion(output, target)
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()

            print_loss = loss.data.item()
            sum_loss += print_loss
            train_predict = torch.max(output.data, 1)[1]
            if torch.cuda.is_available():
                train_correct += (train_predict.cuda() == target.cuda()).sum()
            else:
                train_correct += (train_predict == target).sum()
            accuracy = (train_correct / total_num) * 100
            # loop.set_description(f'Epoch [{epoch+1}/{epochs}]')
            # loop.set_postfix(loss=loss.item(), acc='{:.3f}'.format(accuracy))
            batch_count += len(data)
            end_time = time.time()
            s = f'Epoch:[{epoch+1}/{epochs}] Batch:[{batch_count}/{total_num}] train_acc: {"{:.2f}".format(accuracy)} ' \
                f'train_loss: {"{:.3f}".format(loss.item())} time: {int((end_time-start_time)*1000)} ms'
            # print(f'Epoch:[{epoch+1}/{epochs}]', f'Batch:[{batch_count}/{total_num}]',
            #       'train_acc:', '{:.2f}'.format(accuracy), 'train_loss:', '{:.3f}'.format(loss.item()),
            #       'time:', f'{int((end_time-start_time)*1000)} ms')
            print(s)
            f.write(s+'\n')

        write.add_scalar('train_acc', accuracy, epoch)
        write.add_scalar('train_loss', loss.item(), epoch)
        # print(optimizer.param_groups[0]['lr'])
        scheduler.step()
        if best_acc < accuracy:
            best_acc = accuracy
            torch.save(model, os.path.join(save_path, 'best.pt'))

        if epoch+1 == epochs:
            torch.save(model, os.path.join(save_path, 'last.pt'))

        # 预测验证集
        # if (epoch+1) % 5 == 0 or epoch+1 == epochs:
        model.eval()
        test_loss = 0.0
        correct = 0.0
        total_num = len(val_loader.dataset)
        # print(total_num, len(val_loader))
        with torch.no_grad():
            for data, target in val_loader:
                data, target = Variable(data).to(device), Variable(target).to(device)
                output = model(data)
                loss = criterion(output, target)
                _, pred = torch.max(output.data, 1)
                if torch.cuda.is_available():
                    correct += torch.sum(pred.cuda() == target.cuda())
                else:
                    correct += torch.sum(pred == target)
                print_loss = loss.data.item()
                test_loss += print_loss
            acc = correct / total_num * 100
            avg_loss = test_loss / len(val_loader)
        s = f"val acc: {'{:.2f}'.format(acc)} val loss: {'{:.3f}'.format(avg_loss)}"
        # print('val acc: ', '{:.2f}'.format(acc), 'val loss: ', '{:.3f}'.format(avg_loss))
        print(s)
        f.write(s+'\n')
        write.add_scalar('val_acc', acc, epoch)
        write.add_scalar('val_loss', avg_loss, epoch)
        # loop.set_postfix(val_loss='{:.3f}'.format(avg_loss), val_acc='{:.3f}'.format(acc))

    f.close()


if __name__ == '__main__':
    device = DEVICE
    epochs = EPOCHS
    batch_size = BATCH_SIZE
    input_size = INPUT_SIZE
    lr = LR
    # ---------------------------训练-------------------------------------
    # 图片的路径
    base_dir = r'C:\Users\Administrator.DESKTOP-161KJQD\Desktop\dog_cat'
    # 保存的路径
    save_path = r'C:\Users\Administrator.DESKTOP-161KJQD\Desktop\dog_cat_save'
    dateset, classes, classes_num = get_dataset(base_dir, input_size=input_size)
    # model = torchvision.models.resnet50(pretrained=True)
    model = torchvision.models.resnet50(weights=ResNet50_Weights.IMAGENET1K_V1)
    num_ftrs = model.fc.in_features
    model.fc = nn.Linear(num_ftrs, classes_num)
    model.to(DEVICE)
    # # 损失函数,交叉熵损失函数
    criteon = nn.CrossEntropyLoss()
    # 选择优化器
    optimizer = optim.SGD(model.parameters(), lr=lr)
    # 学习率更新
    # scheduler = ExponentialLR(optimizer, gamma=0.9)
    scheduler = LambdaLR(optimizer, lr_lambda=lambda epoch: update_lr(epoch, epochs))
    # 开始训练
    train(model, dateset, epochs, batch_size, device, optimizer, scheduler, criteon, save_path)
    # 将label保存起来
    with open(os.path.join(save_path, 'labels.txt'), 'w', encoding='utf-8') as f:
        f.write(f'{classes_num} {classes}')

  训练结束以后,在保存路径下会得到下面的文件

  

 

  最好的模型,最后一次的模型,标签的列表,训练的记录和tensorboard记录

  在该路径下执行 tensorboard --logdir=.  

  

 

  然后在浏览器打开给出的地址,即可看到数据训练过程的绘图

 4.对图片进行预测

  考虑对于用户来说,用户是在网页或者手机上上传一张图片进行预测,所以这边是采用二进制数据。

  mypredict.py

  

import cv2
import numpy as np
import torch

from classify_cfg import *



def img_process(img_betys, img_size, device):

    img_arry = np.asarray(bytearray(img_betys), dtype='uint8')
    # im0 = cv2.imread(img_betys)
    im0 = cv2.imdecode(img_arry, cv2.IMREAD_COLOR)
    image = cv2.resize(im0, (img_size, img_size))
    image = np.float32(image) / 255.0
    image[:, :, ] -= np.float32(mean)
    image[:, :, ] /= np.float32(std)
    image = image.transpose((2, 0, 1))
    im = torch.from_numpy(image).unsqueeze(0)
    im = im.to(device)
    return im


def predict(model_path, img, device):
    model = torch.load(model_path)
    model.to(device)
    model.eval()
    predicts = model(img)
    # print(predicts)
    _, preds = torch.max(predicts, 1)
    pred = torch.squeeze(preds)
    # print(pred)
    return pred


if __name__ == '__main__':
    mean = MEAN
    std = STD
    device = DEVICE
    classes = ['狗', '猫']
    # # 预测
    model_path = r'C:\Users\Administrator.DESKTOP-161KJQD\Desktop\dog_cat_save\best.pt'
    img_path = r'C:\Users\Administrator.DESKTOP-161KJQD\Desktop\save_dir\狗\000000.jpg'
    with open(img_path, 'rb') as f:
        img_betys = f.read()
    img =img_process(img_betys, 160, device)
    # print(img.shape)
    # print(img)
    pred = predict(model_path, img, device)
    print(classes[int(pred)])

 

标签:loss,ResNet50,val,训练,分类,train,import,path,save
From: https://www.cnblogs.com/moon3496694/p/17310038.html

相关文章

  • Java语言在Spark3.2.4集群中使用Spark MLlib库完成朴素贝叶斯分类器
    一、贝叶斯定理贝叶斯定理是关于随机事件A和B的条件概率,生活中,我们可能很容易知道P(A|B),但是我需要求解P(B|A),学习了贝叶斯定理,就可以解决这类问题,计算公式如下:  P(A)是A的先验概率P(B)是B的先验概率P(A|B)是A的后验概率(已经知道B发生过了)P(B|A)是B的后验概率(已经知道A发生过了)二......
  • 西南民族大学 春季 2023 训练赛 6
    题目详情-L1-1今天我要赢(pintia.cn)voidsolve(){cout<<"I'mgonnawin!Today!"<<endl;cout<<"2022-04-23"<<endl;}题目详情-L1-2种钻石(pintia.cn)voidsolve(){intv;cin>>n>......
  • 康复训练の树形DP
    所有代码的开头头文件,宏定义和命名空间如下#include<bits/stdc++.h>#defineTptemplate<typenameTy>#defineTstemplate<typenameTy,typename...Ar>#definelllonglong#defineCIconstint#defineRIint#defineWwhile#definegcgetchar#definemax(x,y)......
  • 利用envi计算二分类(多分类)精度评价指标及混淆矩阵计算
    前言  导师需要我将预测的几个结果单独计算出每一张图的精度评价,包含以下指标:iou,recall,F1。  因为他说我利用代码批量计算的结果有误。  如果是这样的话可就坏了,希望我的结果没有出太多错误,不然已经做过计算的某些内容又需要全部重新计算了。利用envi计算精度指标使用t......
  • 数据挖掘中聚类和分类有什么区别
         分类(classification)是这样的过程:它找出描述并区分数据类或概念的模型(或函数),以便能够使用模型预测类标记未知的对象类。分类分析在数据挖掘中是一项比较重要的任务,目前在商业上应用最多。分类的目的是学会一个分类函数或分类模型(也常常称作分类器),该模型能把......
  • 聚类与分类区别2
       在分类中,对于目标数据库中存在哪些类是知道的,要做的就是将每一条记录分别属于哪一类标记出来。聚类需要解决的问题是将已给定的若干无标记的模式聚集起来使之成为有意义的聚类,聚类是在预先不知道目标数据库到底有多少类的情况下,希望将所有的记录组成不同的类或者说聚类,并且......
  • C# Timer定时器分类
    关于C#中timer类 在C#里关于定时器类就有4个   1、System.Windows.Forms:【基于UI】System.Windows.Forms命名空间下的Timer控件,它直接继承自Componet。Timer控件只有绑定了Tick事件和设置Enabled=True后才会自动计时,停止计时可以用Stop()方法控制,通过Stop()停止之后,如......
  • 20230410 训练记录:最小瓶颈路 / lca
    初识最小瓶颈路其实是上海那道著名的铜牌题,其次就是P1396营救。P1967[NOIP2013提高组]货车运输/最小瓶颈路https://www.luogu.com.cn/problem/P1967\(\mathcalO(m\logm+(n+q)\logn)\)最大生成树(森林)两点间最小边权,直接在倍增lca向上爬的时候更新答案。问......
  • 2023年牛客基础训练营2-I
    题目链接:https://ac.nowcoder.com/acm/contest/46810/I乱搞题,但是有一些差分思想在里面。先将所有的$$x_i都设置为第一个等级。注意到一个性质,不是所有的h都可以使答案发生变化。然后我们可以先求出所有可以使\(x_i\)发生变化的h的最小值,接着从小到大枚举所有h。所有\(x_i都会......
  • 10-面向对象综合训练综合练习
    练习一:文字版格斗游戏需求:​ 格斗游戏,每个游戏角色的姓名,血量,都不相同,在选定人物的时候(new对象的时候),这些信息就应该被确定下来。举例:​ 程序运行之后结果为:​ 姓名为:乔峰 血量为:100​ 姓名为:鸠摩智 血量为:100​ 乔峰举起拳头打了鸠摩智一下,造成了XX点伤害,鸠摩智还剩......