模型部署与推理--利用libtorch模型部署与推理

文章目录

    • 1从pytorch导出pt文件
    • 2下载并配置libtorch
    • 3推理
    • 4结果:
      • 时间对比:
      • 推理结果:
    • 参考

以deeplabv3plus为例讲解怎么利用libtorch部署在c++上模型。关于libtorch和pt文件请参考我之前的博客。

1从pytorch导出pt文件

if __name__ == '__main__':    # 读取模型pth文件model_path = r'F:\dataset\CoverSegData_train_result\deeplab-resnet-20250606\model_best.pth.tar'if not os.path.exists(model_path):raise FileNotFoundError(f"Model file {model_path} does not exist.")model = DeepLab(num_classes=2, backbone='resnet', output_stride=16, sync_bn=False, freeze_bn=False)checkpoint = torch.load(model_path, weights_only=False)model.load_state_dict(checkpoint['state_dict'])# model.cuda()  # 将模型移动到GPUmodel.eval()  # 设置模型为评估模式# 导出为torchscript格式dumpy = torch.randn(1, 3, 1024, 1024)  # 假设输入是1张1024x1024的RGB图像# dumpy = dumpy.cuda()  # 将输入数据移动到GPU# 使用torch.jit.trace进行模型跟踪trace_model = torch.jit.trace(model, dumpy)   export_path = r'F:\dataset\CoverSegData_train_result\deeplab-resnet-20250606\deeplab_resnet_exported.pt'trace_model.save(export_path)print(f"Model exported to {export_path}")
这里使用了trace模式,什么是trace和script模式参考之前的博客。注意一点,无论是否需要在gpu上部署,这里都不需要将模型和数据移动到gpu上(我注释的内容),我亲测过速度没有差异。

2下载并配置libtorch

从官网下载getstart页面下载,这里有些需要注意的地方:
1、如果你想在cpu上推理,选择cpu版本
2、选择gpu版本,既可以在cpu上推理也可以在gpu上推理
3、选择的libtorch,cuda版本要和训练时候的pytorch,cuda版本相同.如果训练的时候是高版本的pytorch、cuda而部署的时候选择低版本的libtorch可能会有问题。
下载的时候选择release版本,下载之后解压,得到libtorch动态库。打开vs2022,新建控制台文件,切换到release-x64,然后打开属性(以下是如何在vs添加动态库并调用动态库的过程,网上很多教程)

配置属性–>常规中修改c++版本c++17

在C+±>常规–>包含目录中添加:
libtorch_dir是解压之后的文件夹

libtorch_dir/include
libtorch_dir/include/torch/csrc/api/include

链接器–>常规–>库目录添加

libtorch_dir/lib

链接器–>输入–>附加依赖项添加

libtorch_dir\lib\*.lib;

调试–>工作目录中添加

libtorch_dir/lib

属性 --> 链接器 --> 命令行 --> 其他选项”中添加:

/INCLUDE:?warp_size@cuda@at@@YAHXZ

3推理

下面就是cpu和gpu推理代码:

#include <torch/script.h>
#include<torch/cuda.h>
#include <opencv2/opencv.hpp>
#include <iostream>
#include <chrono>
#include <filesystem>namespace fs = std::filesystem;// 图像预处理函数
torch::Tensor preprocess(cv::Mat& image) {// 转换BGR到RGBcv::cvtColor(image, image, cv::COLOR_BGR2RGB);// 调整尺寸// cv::resize(image, image, cv::Size(resize_width, resize_height));// 转换为Tensorauto tensor = torch::from_blob(image.data,{ image.rows, image.cols, 3 },torch::kByte);// 转换为CHW格式并归一化到[0,1]tensor = tensor.permute({ 2, 0, 1 })  // HWC -> CHW.to(torch::kFloat32)      // 转换为float.div(255);                // 归一化到[0,1]// 手动实现ImageNet标准化torch::Tensor mean = torch::tensor({ 0.485, 0.456, 0.406 }).view({ 3, 1, 1 });torch::Tensor std = torch::tensor({ 0.229, 0.224, 0.225 }).view({ 3, 1, 1 });tensor = (tensor - mean) / std;return tensor.unsqueeze(0); // 添加batch维度
}// 创建PASCAL VOC颜色映射表
std::vector<cv::Vec3b> get_pascal_voc_colormap() {std::vector<cv::Vec3b> colormap(256);// PASCAL VOC标准21类颜色映射colormap[0] = cv::Vec3b(0, 0, 0);       // 背景 - 黑色colormap[1] = cv::Vec3b(128, 0, 0);     // 飞机colormap[2] = cv::Vec3b(0, 128, 0);     // 自行车colormap[3] = cv::Vec3b(128, 128, 0);   // 鸟colormap[4] = cv::Vec3b(0, 0, 128);     // 船colormap[5] = cv::Vec3b(128, 0, 128);   // 瓶子colormap[6] = cv::Vec3b(0, 128, 128);   // 公交车colormap[7] = cv::Vec3b(128, 128, 128); // 汽车colormap[8] = cv::Vec3b(64, 0, 0);      // 猫colormap[9] = cv::Vec3b(192, 0, 0);     // 椅子colormap[10] = cv::Vec3b(64, 128, 0);    // 牛colormap[11] = cv::Vec3b(192, 128, 0);   // 餐桌colormap[12] = cv::Vec3b(64, 0, 128);    // 狗colormap[13] = cv::Vec3b(192, 0, 128);   // 马colormap[14] = cv::Vec3b(64, 128, 128);  // 摩托车colormap[15] = cv::Vec3b(192, 128, 128); // 人colormap[16] = cv::Vec3b(0, 64, 0);      // 盆栽colormap[17] = cv::Vec3b(128, 64, 0);    // 羊colormap[18] = cv::Vec3b(0, 192, 0);     // 沙发colormap[19] = cv::Vec3b(128, 192, 0);   // 火车colormap[20] = cv::Vec3b(0, 64, 128);    // 显示器/电视// 为其他可能的类别生成随机颜色for (int i = 21; i < 256; ++i) {colormap[i] = cv::Vec3b(rand() % 256, rand() % 256, rand() % 256);}return colormap;
}// 应用颜色映射到分割结果
cv::Mat apply_colormap(const cv::Mat& segmentation, const std::vector<cv::Vec3b>& colormap) {cv::Mat color_result(segmentation.size(), CV_8UC3);for (int y = 0; y < segmentation.rows; ++y) {for (int x = 0; x < segmentation.cols; ++x) {int class_idx = segmentation.at<uchar>(y, x);color_result.at<cv::Vec3b>(y, x) = colormap[class_idx];}}return color_result;
}// 保存分割结果
void save_segmentation_results(const cv::Mat& original_image,const cv::Mat& segmentation,const std::vector<cv::Vec3b>& colormap,const fs::path& output_dir,const std::string& filename
) {// 确保输出目录存在fs::create_directories(output_dir);// 保存原始图像fs::path orig_path = output_dir / "original";fs::create_directories(orig_path);cv::imwrite((orig_path / filename).string(), original_image);// 保存原始分割结果(类别索引)fs::path seg_path = output_dir / "segmentation";fs::create_directories(seg_path);cv::imwrite((seg_path / filename).string(), segmentation);// 应用颜色映射并保存彩色分割结果cv::Mat color_seg = apply_colormap(segmentation, colormap);fs::path color_path = output_dir / "color_segmentation";fs::create_directories(color_path);cv::imwrite((color_path / filename).string(), color_seg);// 创建并保存叠加在原始图像上的分割结果cv::Mat overlay;cv::addWeighted(original_image, 0.7, color_seg, 0.3, 0, overlay);fs::path overlay_path = output_dir / "overlay";fs::create_directories(overlay_path);cv::imwrite((overlay_path / filename).string(), overlay);
}// 强制CUDA同步的通用方法
//void cuda_synchronize(torch::Device device) {
//    if (!device.is_cuda()) return;
//
//    try {
//        // 方法1: 使用item()强制同步
//        auto dummy = torch::zeros({ 1 }, torch::TensorOptions().device(device));
//        dummy.item();
//    }
//    catch (...) {
//        try {
//            // 方法2: 使用CPU访问强制同步
//            auto dummy = torch::zeros({ 1 }, torch::TensorOptions().device(device));
//            auto cpu_copy = dummy.to(torch::kCPU);
//        }
//        catch (...) {
//            // 方法3: 使用简单计算
//            auto dummy = torch::ones({ 1 }, torch::TensorOptions().device(device));
//            dummy = dummy * 2;
//            dummy = dummy.to(torch::kCPU);
//        }
//    }
//}void run_inference(const std::string& model_path,const std::string& image_dir,const std::string& output_dir,torch::Device device
) {// 加载模型torch::jit::script::Module module;try {module = torch::jit::load(model_path);module.to(device);module.eval();std::cout << "Model loaded on: " << device << std::endl;}catch (const c10::Error& e) {std::cerr << "Error loading model: " << e.what() << std::endl;return;}// 创建颜色映射表auto colormap = get_pascal_voc_colormap();// 遍历目录中的图像for (const auto& entry : fs::directory_iterator(image_dir)) {if (entry.path().extension() != ".jpg" &&entry.path().extension() != ".jpeg" &&entry.path().extension() != ".png") continue;// 读取原始图像(用于保存)cv::Mat original_image = cv::imread(entry.path().string());if (original_image.empty()) {std::cerr << "Failed to load: " << entry.path() << std::endl;continue;}// 复制用于预处理cv::Mat image = original_image.clone();// 预处理auto input_tensor = preprocess(image);input_tensor = input_tensor.to(device);// 预热(第一次运行可能较慢){torch::NoGradGuard no_grad;module.forward({ input_tensor });torch::cuda::synchronize();}// 计时开始auto start = std::chrono::high_resolution_clock::now(); 推理torch::Tensor output;{torch::NoGradGuard no_grad;output = module.forward({ input_tensor }).toTensor();torch::cuda::synchronize();}// 计时结束auto end = std::chrono::high_resolution_clock::now();auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);std::cout << entry.path().filename() << " inference time: "<< duration.count() << " ms" << std::endl;// 处理分割结果 --------------------------------------------// 获取预测类别 (argmax)torch::Tensor preds = output.argmax(1).squeeze(0); // [H, W]// 转换为CPUpreds = preds.to(torch::kCPU).to(torch::kUInt8);// 转换为OpenCV Matcv::Mat segmentation(preds.size(0), preds.size(1), CV_8UC1);std::memcpy(segmentation.data, preds.data_ptr(), preds.numel() * sizeof(uchar));// 将分割结果调整回原始图像尺寸cv::Mat segmentation_resized;cv::resize(segmentation, segmentation_resized, original_image.size(),0, 0, cv::INTER_NEAREST);// 保存结果save_segmentation_results(original_image,segmentation_resized,colormap,fs::path(output_dir) / device.str(),entry.path().filename().string());}
}int main() {输出: “cuda::is_available(): 0”,显卡未调用起来std::cout << "cuda::is_available():" << torch::cuda::is_available() << std::endl;const std::string model_path = "F:\\dataset\\CoverSegData_train_result\\deeplab-resnet-20250606\\deeplab_resnet_exported.pt";const std::string image_dir = "F:\\dataset\\test";const std::string output_dir = "F:\\dataset\\test_results\\libtorch";// 创建主输出目录fs::create_directories(output_dir);// CPU推理测试std::cout << "\n=== CPU Inference ===" << std::endl;run_inference(model_path, image_dir, output_dir, torch::kCPU);// GPU推理测试 (如果可用)if (torch::cuda::is_available()) {std::cout << "\n=== GPU Inference ===" << std::endl;run_inference(model_path, image_dir, output_dir, torch::kCUDA);}else {std::cout << "CUDA not available. Skipping GPU inference." << std::endl;}return 0;
}

4结果:

时间对比:

libtorch c++推理用时
在这里插入图片描述

pytorchGPU推理时间:
在这里插入图片描述

python版本onnxruntime推理时间:
在这里插入图片描述

三者用时差不多

推理结果:

libtorch c++、pytorchGPU、onnxruntime
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

libtorch c++、pytorchGPU推理结果接近和onnxruntime推理结果差异有点大,未找到原因。

参考

1
2
3

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.tpcf.cn/news/913031.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

芯得EP.21丨基于极海APM32F4的TencentOS Tiny实时操作系统移植详解

《APM32芯得》系列内容为用户使用APM32系列产品的经验总结&#xff0c;均转载自21ic论坛极海半导体专区&#xff0c;全文未作任何修改&#xff0c;未经原文作者授权禁止转载。 如遇技术问题&#xff0c;可前往 极海半导体开发者论坛 1 前言 最近在了解TencentOS的特性&#xf…

【Docker基础】Docker数据持久化与卷(Volume)介绍

目录 1 Docker数据持久化概述 1.1 为什么需要数据持久化 1.2 Docker数据管理方式对比 2 Docker卷(Volume)核心概念 2.1 数据卷基本特性 2.2 卷类型详解 2.2.1 命名卷(Named Volumes) 2.2.2 匿名卷(Anonymous Volumes) 2.2.3 主机绑定卷(Host Volumes) 3 数据卷操作全…

yolo8,10,11之处理不平衡类别问题

一、前言 使用 yolo11进行目标检测时&#xff0c;发现训练数据集存在类别数量不平衡的情况&#xff0c;查阅了一下资料&#xff0c;可采取以下方法。 二、样本增强 少数类的框是独立存在于图片中&#xff0c;则可通过颜色、亮度、几何变换等方法人为增加少数类的样本数&#x…

基于 51 单片机做的二十四点小游戏

用 51 单片机做的二十四点小游戏 一、任务要求 设计一个模拟纸牌 24 点玩法的单片机模拟器&#xff0c;由单片机随机发出四个牌点&#xff0c;测试者在实验板按键上输入计算过程&#xff0c;单片机判断计算结果是否正确&#xff0c;并评定测试者的成绩。 【基本要求】&#…

Hadoop WordCount 程序实现与执行指南

Hadoop WordCount 程序实现与执行指南 下面是使用Python实现的Hadoop WordCount程序,包含完整的Mapper和Reducer部分。 这个程序可以在PyCharm中本地测试,也可以部署到远程Hadoop集群上运行。 mapper.py import sys# 从标准输入读取数据 for line in sys.stdin:# 移除行首…

数据可视化:5 分钟读懂其核心价值与技术实践

为什么数据可视化成为企业数字化转型的“必修课”&#xff1f;在信息爆炸的时代&#xff0c;企业每天产生海量数据&#xff0c;从客户行为到销售业绩&#xff0c;从供应链运作到市场趋势。如何从这些原始数据中快速提炼有价值的信息&#xff1f;如何将复杂数据转化为直观易懂的…

Python 量化交易安装使用教程

一、什么是量化交易&#xff1f; 量化交易是通过数学模型和计算机程序&#xff0c;自动化地执行证券买卖决策的交易方式。Python 凭借其丰富的生态和强大的数据处理能力&#xff0c;成为量化交易的首选语言。 二、环境准备 建议使用 Anaconda 安装 Python 3.8&#xff0c;方便…

从 PostgreSQL 到 DolphinDB:数据实时同步一站式解决方案

随着越来越多的用户使用 DolphinDB&#xff0c;各种不同的应用的场景也对 DolphinDB 的数据接入提出了不同的要求。部分用户需要将 PostgreSQL 的数据实时同步到 DolphinDB 中来&#xff0c;以满足在 DolphinDB 中使用数据的实时性需求。本篇教程将介绍使用 Debezium 来实时捕获…

关于联咏(Novatek )白平衡色温坐标系探究

目录 一、疑问 二、结论 三、分析 四、释疑 五、仿真模拟 一、疑问 为什么Novatek的白平衡色温坐标系是这个样子的呢?各条直线和曲线分别代表什么含义呢?色温坐标系中所标定的参数代表什么含义呢?如何标定新增一些特殊的光源呢?二、结论

Protein FID:AI蛋白质结构生成模型评估新指标

一、引言&#xff1a;蛋白质生成模型面临的评估挑战 近年来&#xff0c;AI驱动的蛋白质结构生成模型取得了令人瞩目的进展&#xff0c;但如何有效评估这些模型的质量却一直是一个悬而未决的问题。虽然实验验证仍然是金标准&#xff0c;但计算机模拟评估对于快速开发和比较机器…

Vim 高效编辑指南:从基础操作到块编辑的进阶之路

文章目录🔠 一、基础编辑命令(生存必备)⚡ 二、进阶操作:可视化块模式 (Ctrl+v)典型应用场景🚀 三、效率提升技巧💡 四、配置建议(~/.vimrc)结语作为开发者最强大的文本编辑器之一,Vim 的高效操作离不开其命令模式(Normal Mode)。本文将系统性地介绍 Vim 的核心编…

docker学习第一天框架学习以及在redhat7.9安装操作

一.docker是什么。 Docker 是一个开源的容器化平台&#xff0c;通过将应用程序及其依赖项&#xff08;如代码、运行时环境、系统工具等&#xff09;打包到轻量级、可移植的容器中&#xff0c;实现「一次构建&#xff0c;处处运行」的现代化开发模式。它利用了 Linux 内核特性来…

QT控件 使用Font Awesome开源图标库修改QWidget和QML两种界面框架的控件图标

又一个月快要结束了&#xff0c;在这里总结下分别在QWidget和QML两种界面设计模式中应用Font Awesome开源图标库&#xff0c;修改界面的显示图标效果&#xff0c; AriaNg是aria2的可视化web界面工具,其中的图标大都是Font AWesome中的字体图标&#xff0c;某位曾经尝试将AriaNg…

Qt Quick 与 QML(四)qml中的Delegate系列委托组件

一、概念 在QML中&#xff0c;Delegate是一种非常重要的组件&#xff0c;特别是在使用ListView、GridView、PathView等视图组件时。Delegate用于定义每个列表或网格中的项目是如何展示的。通过自定义Delegate&#xff0c;你可以控制每个项目的外观和行为。 Delegate通常是一个…

android图片优化

在 Android 中加载大图时&#xff0c;如果不进行优化处理&#xff0c;很容易导致内存溢出&#xff08;OOM&#xff09;和应用卡顿。以下是几种高效处理大图加载的方法和最佳实践&#xff1a; 1. 使用图片加载库&#xff08;推荐&#xff09; 成熟的第三方库已经处理了内存管理…

【机器人】复现 DOV-SG 机器人导航 | 动态开放词汇 | 3D 场景图

DOV-SG 建了动态 3D 场景图&#xff0c;并使用LLM大型语言模型进行任务分解&#xff0c;从而能够在交互式探索过程中对 3D 场景图进行局部更新。 来自RA-L 2025&#xff0c;适合长时间的 语言引导移动操作&#xff0c;动态开放词汇 3D 场景图。 论文地址&#xff1a;Dynamic …

mongodb 中dbs 时,local代表的是什么

在 MongoDB 中&#xff0c;local 是一个内置的系统数据库&#xff0c;用于存储当前 MongoDB 实例&#xff08;或副本集节点&#xff09;的元数据和内部数据&#xff0c;与其他数据库不同&#xff0c;local 数据库的数据不会被复制到副本集的其他成员。 local 数据库的核心作用 …

Spring Cloud(微服务部署与监控)

&#x1f4cc; 摘要 在微服务架构中&#xff0c;随着服务数量的增长和部署复杂度的提升&#xff0c;如何高效部署、持续监控、快速定位问题并实现自动化运维成为保障系统稳定性的关键。 本文将围绕 Spring Cloud 微服务的部署与监控 展开&#xff0c;深入讲解&#xff1a; 微…

音频动态压缩算法曲线实现

Juce实现动态压缩曲线绘制 动态范围压缩算法&#xff08;Dynamic Range Compression&#xff0c;DRC&#xff09;是将音频信号的动态范围映射到一个较小的范围内的过程&#xff0c;即降低较高的峰值的信号电平&#xff0c;而不处理较安静的部分。DRC被广泛用于音频录制、制作工…

技术视界 | OpenLoong 控制框架:打造通用人形机器人智能系统的中枢基座

在人形机器人向通用性、智能化方向加速演进的当下&#xff0c;控制系统的角色正在发生根本变化&#xff1a;它不再只是底层驱动的接口适配层&#xff0c;也不只是策略调用的转译引擎&#xff0c;而是成为连接具身模型、异构本体与多样化任务的“中枢神经系统”。 在 2025 年张…