AI计算机视觉笔记二十五:ResNet50训练部署教程

本文涉及的产品
函数计算FC,每月15万CU 3个月
简介: 该项目旨在训练ResNet50模型并将其部署到RK3568开发板上。首先介绍了ResNet50网络,该网络由何恺明等人于2015年提出,解决了传统卷积神经网络中的退化问题。项目使用车辆分类数据集进行训练,并提供了数据集下载链接。环境搭建部分详细描述了虚拟环境的创建和所需库的安装。训练过程中,通过`train.py`脚本进行了15轮训练,并可视化了训练和测试结果。最后,项目提供了将模型转换为ONNX和PT格式的方法,以便在RK3568上部署。

ResNet50训练主要还是想部署到RK3568开发板上,先记录下训练和转成ONNX模型过程。

一、 Resnet50简介

   ResNet50网络是2015年由微软实验室的何恺明提出,获得ILSVRC2015图像分类竞赛第一名。在ResNet网络提出之前,传统的卷积神经网络都是将一系列的卷积层和池化层堆叠得到的,但当网络堆叠到一定深度时,就会出现退化问题。 残差网络的特点是容易优化,并且能够通过增加相当的深度来提高准确率。其内部的残差块使用了跳跃连接,缓解了在深度神经网络中增加深度带来的梯度消失问题。

image.png

二、数据集下载

   本教程以车辆分类算法为例,数据集的百度网盘下载链接为:
https://pan.baidu.com/s/1pkYm9AA3s3WDM7GecShlbQ 提取码:6666​

解压完成后得到以下两个文件夹:
image.png
打开可以看到一共10类汽车:

image.png
image.png

三、环境搭建

1、创建虚拟环境

conda create -n Resnet50_env python=3.8 -y

2、激活环境

conda activate Resnet50_env
注意:使用的是CPU版本,电脑无GPU

3、安装环境

pip install numpy
pip install torch
pip install torchvision
pip install matplotlib
至此,环境安装完成,开始训练

四、 ResNet50图像分类训练

直接上源码:train.py

# -#-coding:utf-8 -*-

import os
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.data import DataLoader
from torchvision import datasets, transforms
import matplotlib.pyplot as plt
from PIL import ImageFile
ImageFile.LOAD_TRUNCATED_IMAGES = True

# 2.定义超参数
BATCH_SIZE = 16  # 每批处理的数据
DEVICE = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')  # 放在cuda或者cpu上训练
EPOCHS = 15  # 训练数据集的轮次
modellr = 1e-3

# 3.构建pipeline,对图像做处理
pipeline = transforms.Compose([
    # 分辨率重置为256
    transforms.Resize(256),
    # 对加载的图像作归一化处理, 并裁剪为[224x224x3]大小的图像(因为这图片像素不一致直接统一)
    transforms.CenterCrop(224),
    # 将图片转成tensor
    transforms.ToTensor(),
    # 正则化,模型出现过拟合现象时,降低模型复杂度
    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])

# 图片路径(训练图片和测试图片的)
base_dir_train = 'G:/enpei_Project_Code/22_Resnet50_bus/1.data/datasets/train'
base_dir_val = 'G:/enpei_Project_Code/22_Resnet50_bus/1.data/datasets/val'

# 4. 加载数据集
train_dataset = datasets.ImageFolder(root=base_dir_train, transform=pipeline)
print("train_dataset=" + repr(train_dataset[1][0].size()))
print("train_dataset.class_to_idx=" + repr(train_dataset.class_to_idx))
# 创建训练集的可迭代对象,一个batch_size地读取数据,shuffle设为True表示随机打乱顺序读取
train_loader = DataLoader(train_dataset, batch_size=BATCH_SIZE, shuffle=True)

# 测试集
val_dataset = datasets.ImageFolder(root=base_dir_val, transform=pipeline)
print(val_dataset)
print("val_dataset=" + repr(val_dataset[1][0].size()))
print("val_dataset.class_to_idx=" + repr(val_dataset.class_to_idx))
# 创建测试集的可迭代对象,一个batch_size地读取数据
val_loader = DataLoader(val_dataset, batch_size=BATCH_SIZE, shuffle=True)


# 获得一批测试集的数据
images, labels = next(iter(val_loader))
print(images.shape)
print(labels.shape)


# 损失函数,交叉熵损失函数
criterion = nn.CrossEntropyLoss()

# 使用预训练模型
resnet_model = torchvision.models.resnet50(pretrained=True)
num_ftrs = resnet_model.fc.in_features
resnet_model.fc = nn.Linear(num_ftrs, 10)
resnet_model.to(DEVICE)
# 选择简单暴力的Adam优化器,学习率调低
optimizer = optim.Adam(resnet_model.parameters(), lr=modellr)
#optimizer = optim.SGD(net.parameters(), lr = 0.01)

train_loss_list = []
train_accuracy_list = []
test_loss_list = []
test_accuracy_list = []
train_iteration_list = []
test_iteration_list = []


best_val_acc = 0


# 定义训练方法
def train(model, device, train_loader, optimizer, epoch):
    iteration = 0
    train_correct = 0.0
    model.train()
    sum_loss = 0.0
    total_num = len(train_loader.dataset)
    print(total_num, len(train_loader))
    for batch_idx, (data, target) in enumerate(train_loader):
        # 获取数据与标签
        data, target = Variable(data).to(device), Variable(target).to(device)

        # 梯度清零
        optimizer.zero_grad()

        # 计算损失
        output = model(data)
        loss = criterion(output, target)

        #反向传播
        loss.backward()

        #更新参数
        optimizer.step()

        print_loss = loss.data.item()
        sum_loss += print_loss
        _, train_predict = torch.max(output.data, 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
        print("Epoch: %d , Batch: %3d , Loss : %.8f,train_correct:%d , train_total:%d , accuracy:%.6f" % (
            epoch + 1, batch_idx + 1, loss.item(), train_correct, total_num, accuracy))
        # 存在集合画图
        if (epoch + 1) == EPOCHS:  # 只画出最后一个epoch时候的准确度变化曲线
            iteration += 1
            train_loss_list.append(loss.item())
            train_iteration_list.append(iteration)
            train_accuracy_list.append(accuracy)


# 定义验证方法
def val(model, device, val_loader, epoch):
    print("=====================预测开始=================================")
    iteration = 0
    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)
        """
            因为调用这个方法的时候就是每次结束训练一次之后调用
        """
        # iteration += 1
        # 存入集合准备画图
        test_loss_list.append(avg_loss)
        test_accuracy_list.append(acc)
        test_iteration_list.append(epoch)
        print('\nVal set: Average loss: {:.4f}, Accuracy: {}/{} ({:.6f}%)\n'.format(
            avg_loss, correct, len(val_loader.dataset), acc))

        global best_val_acc
        if acc > best_val_acc:
            best_val_acc = acc
            print("Best Accuracy:{:.6f}%".format(best_val_acc))
            torch.save(resnet_model.state_dict(), 'best-{:.6f}.model.pth'.format(best_val_acc))  # 保存模型


# 训练
for epoch in range(EPOCHS):
    train(resnet_model, DEVICE, train_loader, optimizer, epoch)
    val(resnet_model, DEVICE, val_loader, epoch)
    #torch.save(resnet_model, 'model.pth')  # 保存模型

# 可视化测试机的loss和accuracy
plt.figure(1)
plt.plot(test_iteration_list, test_loss_list)
plt.title("ResNet50 test loss")
plt.ylabel("loss")
plt.xlabel("Number of test iteration")
plt.show()

plt.figure(2)
plt.plot(test_iteration_list, test_accuracy_list)
plt.title("ResNet50 test accuracy")
plt.xlabel("Number of test iteration")
plt.ylabel("accuracy")
plt.show()

# 可视化训练集loss和accuracy
plt.figure(3)
plt.plot(train_iteration_list, train_loss_list)
plt.title("ResNet50 train loss")
plt.xlabel("Number of train iteration")
plt.ylabel("accuracy")
plt.show()

plt.figure(4)
plt.plot(train_iteration_list, train_accuracy_list)
plt.title("ResNet50 train accuracy")
plt.xlabel("Number of train iteration")
plt.ylabel("accuracy")
plt.show()

代码需要注意的是数据集路径,用的是绝对路径,自行修改。
image.png
代码训练的epoch是15,等待一段时间吧!

五、测试模型

测试模型脚本predict.py

import os
from PIL import Image
import cv2
import torch
import torch.nn as nn
from torch.autograd.variable import Variable
import torchvision
from torchvision import transforms

# 0-SUV, 1-BUS, 2-family sedan, 3-fire engine, 4-heavy truck, 
# 5-jeep, 6-mini bus, 7-racing car, 8-taxi, 9-truck

def predict_single_image():

    MODEL_SAVE_FILE = 'best-82.000000.model.pth'
    device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')

    model = torchvision.models.resnet50()
    num_ftrs = model.fc.in_features
    model.fc = nn.Linear(num_ftrs, 10)
    model.to(device)

    model.load_state_dict(torch.load(MODEL_SAVE_FILE,map_location='cpu'))


    model = torch.nn.DataParallel(model,device_ids=[0])
    model.eval()

    img = cv2.imread("test.jpg")
    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    image = Image.fromarray(img)

    pipeline = transforms.Compose([
    # 分辨率重置为256
    transforms.Resize(256),
    # 对加载的图像作归一化处理, 并裁剪为[224x224x3]大小的图像(因为这图片像素不一致直接统一)
    transforms.CenterCrop(224),
    # 将图片转成tensor
    transforms.ToTensor(),
    # 正则化,模型出现过拟合现象时,降低模型复杂度
    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
    ])

    image = pipeline(image)
    image = image.unsqueeze(0)
    print(image.shape)

    input_var = Variable(image).float().to(device)
    output = model(input_var)
    print("output:", output)
    print("output.shape:", output.shape)

    soft_output = torch.softmax(output, dim=-1)
    print("soft_output:", soft_output)

    percent, predicted = torch.max(soft_output.data, 1)
    print("percent:", percent)
    print("predicted:", predicted)

    '''
    USE_GPU = torch.cuda.is_available()
    if USE_GPU:
        inputs = inputs.cuda()
    if not os.path.exists(MODEL_SAVE_FILE):
        print('can not find model save file.')
        exit()
    else:
        if USE_GPU:
            model.load_state_dict(torch.load(MODEL_SAVE_FILE))
        else:
            model.load_state_dict(torch.load(MODEL_SAVE_FILE, map_location=lambda storage, loc: storage))
        outputs = model(inputs)
        _, prediction_tensor = torch.max(outputs.data, 1)
        if USE_GPU:
            prediction = prediction_tensor.cpu().numpy()[0][0]
            print('predict: ', prediction)
            print('this is {}'.format(classes_name[prediction]))
        else:
            prediction = prediction_tensor.numpy()[0][0]
            print('predict: ', prediction)
            print('this is {}'.format(classes_name[prediction]))
    '''


predict_single_image()

运行

python predict.py
image.png

六、模型转换

1、转成onnx模型

pth_to_onnx.py

import torch
import torch.nn as nn
import torchvision
from torch.autograd.variable import Variable


MODEL_SAVE_FILE = 'best-82.000000.model.pth'
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')

model = torchvision.models.resnet50()
num_ftrs = model.fc.in_features
model.fc = nn.Linear(num_ftrs, 10)
model.to(device)

model.load_state_dict(torch.load(MODEL_SAVE_FILE,map_location='cpu'))

batch_size = 1  #批处理大小

# #set the model to inference mode
model.eval()

d_input = Variable(torch.randn(1, 3, 224, 224))
export_onnx_file = "10class_ResNet50.onnx"        # 目的ONNX文件名
torch.onnx.export(model, d_input, export_onnx_file, opset_version=12,verbose=True)

这里需要注意的 是opset_version算子,rk3568用12
python pth_to_onnx.py
image.png
onnx模型是我需要的,打算部署到rk3568,需要把onnx模型转成rknn模型,后续测试

2、转成pt模型

pth_to_pt.py

import torch
import torch.nn as nn
import torchvision


MODEL_SAVE_FILE = 'best-82.000000.model.pth'
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')

model = torchvision.models.resnet50()
num_ftrs = model.fc.in_features
model.fc = nn.Linear(num_ftrs, 10)
model.to(device)

model.load_state_dict(torch.load(MODEL_SAVE_FILE,map_location='cpu'))

model.eval()

example = torch.rand(1,3,224,224).to(device)
traced_script_module = torch.jit.trace(model, example)
traced_script_module.save('./10class_ResNet50.pt')

运行转换:

python pth_to_pt.py

相关实践学习
部署Stable Diffusion玩转AI绘画(GPU云服务器)
本实验通过在ECS上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。
相关文章
|
18天前
|
人工智能 并行计算 安全
从零到一,打造专属AI王国!大模型私有化部署全攻略,手把手教你搭建、优化与安全设置
【10月更文挑战第24天】本文详细介绍从零开始的大模型私有化部署流程,涵盖需求分析、环境搭建、模型准备、模型部署、性能优化和安全设置六个关键步骤,并提供相应的示例代码,确保企业能够高效、安全地将大型AI模型部署在本地或私有云上。
166 7
|
18天前
|
人工智能 安全 网络安全
揭秘!大模型私有化部署的全方位安全攻略与优化秘籍,让你的AI项目稳如磐石,数据安全无忧!
【10月更文挑战第24天】本文探讨了大模型私有化部署的安全性考量与优化策略,涵盖数据安全、防火墙配置、性能优化、容器化部署、模型更新和数据备份等方面,提供了实用的示例代码,旨在为企业提供全面的技术参考。
53 6
|
1月前
|
人工智能 C语言 Windows
Ollama部署在线ai聊天
本文介绍了如何在Windows系统上安装和部署AI聊天模型Ollama,包括安装步骤、模型安装、运行模型项目,以及使用Ollama生成C语言平衡二叉树的完整代码。
73 2
Ollama部署在线ai聊天
|
21天前
|
人工智能 数据安全/隐私保护 UED
RAG让AI大模型更懂业务解决方案部署使用体验
根据指导文档,部署过程得到了详细步骤说明的支持,包括环境配置、依赖安装及代码示例,确保了部署顺利进行。建议优化知识库问题汇总,增加部署失败案例参考,以提升用户体验。整体解决方案阅读与部署体验良好,有助于大型语言模型在特定业务场景的应用,未来可加强行业适应性和用户隐私保护。
60 5
|
19天前
|
人工智能 分布式计算 数据可视化
大模型私有化部署全攻略:硬件需求、数据隐私、可解释性与维护成本挑战及解决方案详解,附示例代码助你轻松实现企业内部AI应用
【10月更文挑战第23天】随着人工智能技术的发展,企业越来越关注大模型的私有化部署。本文详细探讨了硬件资源需求、数据隐私保护、模型可解释性、模型更新和维护等方面的挑战及解决方案,并提供了示例代码,帮助企业高效、安全地实现大模型的内部部署。
43 1
|
19天前
|
人工智能 分布式计算 数据可视化
大模型私有化部署全攻略:硬件需求、数据隐私、可解释性与维护成本挑战及解决方案详解,附示例代码助你轻松实现企业内部AI应用
【10月更文挑战第23天】随着人工智能技术的发展,大模型在各领域的应用日益广泛。然而,将其私有化部署到企业内部面临诸多挑战,如硬件资源需求高、数据隐私保护、模型可解释性差、更新维护成本高等。本文探讨了这些挑战,并提出了优化硬件配置、数据加密、可视化工具、自动化更新机制等解决方案,帮助企业顺利实现大模型的私有化部署。
51 1
|
24天前
|
Serverless 数据安全/隐私保护 前端开发
大模型代码能力体验报告之贪吃蛇小游戏《一》:Claude.ai篇 - 生成、预览和快速部署的serverless一条龙
本文介绍了通过Claude.ai生成并优化Web版贪吃蛇游戏的过程,展示了其强大的代码生成功能及用户友好的界面设计。从初始版本的快速生成到根据用户反馈调整游戏速度,再到提供多种实用工具如文件管理、版本控制和一键部署,Claude.ai不仅是一个代码助手,更像是一个全面的serverless开发平台。文中还呼吁国内厂商关注此类技术的发展。
|
28天前
|
自然语言处理 IDE 测试技术
通义灵码史上最全使用教程:秀一秀AI编程新肌肉
通义灵码是阿里云推出的一款智能编码辅助工具,基于通义大模型,提供行级/函数级实时续写、自然语言生成代码、单元测试生成、代码优化、注释生成、代码解释、研发智能问答、异常报错排查等功能。它支持 Visual Studio Code 和 JetBrains IDEs,适配多 IDE 原生设计,帮助开发者高效、流畅地编码。官方提供了详细的下载和安装指南,以及丰富的功能介绍和使用指南。
225 3
|
29天前
|
人工智能 弹性计算 自然语言处理
《触手可及,函数计算玩转 AI 大模型》解决方案体验与部署评测
在AI技术快速发展的背景下,大模型正推动各行业的智能化转型。企业为抓住机遇,纷纷寻求部署AI大模型以满足特定业务需求。阿里云函数计算凭借按量付费、卓越弹性和快速交付等优势,为企业提供了高效、安全的AI大模型部署方案。本文将详细介绍阿里云函数计算的技术解决方案及其在文生文、图像生成和语音生成等领域的应用实例,展示其在降低成本、提高效率和增强灵活性方面的显著优势。
|
30天前
|
人工智能 自然语言处理 搜索推荐
【通义】AI视界|微软Copilot Studio推出新功能,帮助企业更便捷地构建和部署AI代理
本文介绍了近期科技领域的五大重要动态:马斯克旗下xAI发布首个API,苹果内部研究显示ChatGPT比Siri准确率高25%,微软Copilot Studio推出新功能,霍尼韦尔与谷歌合作引入Gemini AI,浑水创始人建议买入科技七巨头股票。更多资讯请访问【通义】。

热门文章

最新文章