如何使用C++调用Pytorch模型进行推理测试:使用libtorch库

如何使用C++调用Pytorch模型进行推理测试:使用libtorch库

一、环境准备
1,linux:以ubuntu 22.04系统为例
1. 准备CUDA和CUDNN

有两种方式配置cuda和cudnn,一种是在系统环境安装,可以参考:深度学习环境配置——ubuntu安装CUDA与CUDNN

还有一种是在conda虚拟环境使用cudatoolkit-dev包,具体可以参考:Installing-and-Test-PyTorch-C-API-on-Ubuntu-with-GPU-enabled

我选择的方式是在系统环境安装cuda12.1和cudnn8.9.2。

可使用如下命令查看是否安装成功:

NVCC -V
cat /usr/local/cuda/include/cudnn_version.h | grep CUDNN_MAJOR -A 2

image-20240625103837610

2. 准备C++环境

安装gcc, cmake和GLIBC,用apt install即可

可使用如下命令是否查看是否安装成功:

gcc --version
cmake --version
ldd --version

image-20240625103749911

3, 下载libtorch文件

去pytoch官网https://pytorch.org/下载即可:

image-20240625103946244

可使用如下命令下载并解压:

wget https://download.pytorch.org/libtorch/cu121/libtorch-cxx11-abi-shared-with-deps-2.3.1%2Bcu121.zip
unzip libtorch-cxx11-abi-shared-with-deps-2.3.1+cu121.zip

将libtorch路径配置到path变量:

vim ~/.bashrc

最后一行加入:

export LD_LIBRARY_PATH=/path/to/libtorch/lib:$LD_LIBRARY_PATH

注意将/path/to/libtorch替换为实际的path,我这里是/mnt/data1/zq/libtorch

查看是否成功:

source ~/.bashrc
echo $LD_LIBRARY_PATH

image-20240625110447696

4, 编写测试libtorch是否安装成功

创建main.cpp文件,内容如下:

#include <torch/torch.h>
#include <iostream>

int main() {
    if (torch::cuda::is_available()) {
        std::cout << "CUDA is available! Running on GPU." << std::endl;
        // 创建一个随机张量并将其移到GPU上
        torch::Tensor tensor_gpu = torch::rand({2, 3}).cuda();
        std::cout << "Tensor on GPU:\n" << tensor_gpu << std::endl;
    } else {
        std::cout << "CUDA not available! Running on CPU." << std::endl;
        // 创建一个随机张量并保持在CPU上
        torch::Tensor tensor_cpu = torch::rand({2, 3});
        std::cout << "Tensor on CPU:\n" << tensor_cpu << std::endl;
    }
    return 0;
}

编译和运行

创建CMakeLists.txt文件,内容如下:

cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
project(test_project)

# Setting the C++ standard to C++17
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# If additional compiler flags are needed
add_compile_options(-Wall -Wextra -pedantic)

# Setting the location of LibTorch
set(Torch_DIR "/path/to/libtorch/share/cmake/Torch")
find_package(Torch REQUIRED)

# Specify the name of the executable and the corresponding source file
add_executable(test_project main.cpp)

# Linking LibTorch libraries
target_link_libraries(test_project "${TORCH_LIBRARIES}")

# Set the output directory for the executable
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

/path/to/libtorch替换为实际的path

编译并测试:

mkdir build
cd build
cmake ..
make 

编译完成之后,应该会出现一个bin目录,其中有一个test_project文件,直接运行即可看到输出。

image-20240625111448917

出现CUDAFloatType说明,libtorch的GPU版本安装成功。

2, windows: 以win10系统为例
1, 准备CUDA和CUDNN

可参考:Windows10下CUDA与cuDNN的安装

2,准备C++编译环境

这一步需要配置cmake, mingw。可参考:Windows 配置 C/C++ 开发环境

建议直接安装Visual Studio这个IDE,可参考:Windows libtorch C++部署GPU版

3,下载安装libtorch

参考这个视频:

win10系统上LibTorch的安装和使用(cuda10.1版本)

一个很水的LibTorch教程(1)

4. 注意事项

windows环境我没有做测试,不保证一定可以成功。linux环境是亲自测试的,保证可以复现

二、C++代码封装Pytorch模型测试:以resnet-18分类为例
1, 安装opencv用于读取图像

需要使用opencv来读取图像数据,可通过如下命令安装:

sudo apt install libopencv-dev
dpkg -l | grep libopencv # 查看是否安装成功
2,用python导出训练好的pytorch模型

在将PyTorch模型应用于C++环境之前,需要将其转换为TorchScript。这可以通过两种方式实现:tracingscripting。可以通过如下代码导出训练好的ResNet-18模型:

import torch
import torchvision

# 加载预训练的模型
model = torchvision.models.resnet18(pretrained=True)

# 将模型设置为评估模式
model.eval()

# 创建一个示例输入
example_input = torch.rand(1, 3, 224, 224)  # 模型输入的大小

# 使用tracing导出模型
traced_script_module = torch.jit.trace(model, example_input)
traced_script_module.save("resnet18.pt")
3,编写C++代码测试

创建main.cpp文件,内容如下:

#include <torch/script.h>
#include <torch/torch.h>
#include <opencv2/opencv.hpp>
#include <iostream>
#include <filesystem>

// Function to transform image to tensor
torch::Tensor transform_image(const cv::Mat& image) {
    cv::Mat img_transformed;
    cv::cvtColor(image, img_transformed, cv::COLOR_BGR2RGB);
    cv::resize(img_transformed, img_transformed, cv::Size(224, 224));
    img_transformed.convertTo(img_transformed, CV_32FC3, 1.0/255);
    auto img_tensor = torch::from_blob(img_transformed.data, {img_transformed.rows, img_transformed.cols, 3}, torch::kFloat);
    img_tensor = img_tensor.permute({2, 0, 1});
    img_tensor = torch::data::transforms::Normalize<torch::Tensor>({0.485, 0.456, 0.406}, {0.229, 0.224, 0.225})(img_tensor);
    img_tensor = img_tensor.unsqueeze(0);
    return img_tensor;
}

// Load the model and classify an image
void classify_image(const std::string& model_path, const std::string& image_path) {
    // Load the model
    torch::jit::script::Module model = torch::jit::load(model_path);
    model.eval(); // Switch to evaluation mode

    // Load and transform the image
    cv::Mat image = cv::imread(image_path, cv::IMREAD_COLOR);
    if (image.empty()) {
        std::cerr << "Could not read the image: " << image_path << std::endl;
        return;
    }
    torch::Tensor tensor_image = transform_image(image);

    // Perform inference
    torch::Tensor output = model.forward({tensor_image}).toTensor();
    int64_t pred = output.argmax(1).item<int64_t>();

    std::cout << "The image is classified as class index: " << pred << std::endl;
}

int main(int argc, char* argv[]) {
    std::string model_path = "resnet18.pt"; // Default model path
    std::string image_path = "default_image.jpg"; // Default image path
	
    // 从命令行接受两个参数, 分别作为model_path和image_path
    if (argc >= 3) {
        model_path = argv[1];
        image_path = argv[2];
    } else {
        std::cout << "Using default model and image paths." << std::endl;
    }

    classify_image(model_path, image_path);
    return 0;
}

创建CMakeLists.txt,内容如下:

cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
project(ImageClassification)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 设置LibTorch的位置, /path/to/libtorch替换为实际路径
set(Torch_DIR "/path/to/libtorch/share/cmake/Torch")
find_package(Torch REQUIRED)

find_package(OpenCV REQUIRED)

add_executable(ImageClassification main.cpp)
target_link_libraries(ImageClassification "${TORCH_LIBRARIES}" "${OpenCV_LIBS}")

编译并运行:

mkdir build && cd build
cmake ..
make

在build目录下会出现ImageClassification这个可执行文件,直接运行传入model_path和image_path即可。

image-20240625114911739

  • 17
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 好的,这是一个比较复杂的任务,需要分几个步骤来完成。下面是大致的步骤: 1. 使用 C++ 编写动态链接封装 YOLOv5,可以使用 OpenCV 来读取图像和进行预处理。 2. 导入 ONNX 模型,可以使用 ONNX Runtime 来加载和运行 ONNX 模型。 3. 实现前向推理代码,将输入图像喂给 ONNX 模型,并获取输出结果。 4. 将输出结果进行解析,得到检测框和分类结果。 5. 使用 LaView 软件进行调用测试。 下面是详细的步骤: 1. 使用 C++ 编写动态链接封装 YOLOv5,可以使用 OpenCV 来读取图像和进行预处理。 首先,需要下载 YOLOv5 的源码,并编译生成可执行文件。然后,将可执行文件中的预测部分封装成一个动态链接,提供给其他程序调用。 以下是一个简单的示例代码,它使用 OpenCV 读取图像,对图像进行预处理(将图像缩放到模型输入大小),并将预处理后的图像传递给 YOLOv5 进行预测: ```cpp #include "yolov5.h" #include <opencv2/opencv.hpp> YoloV5::YoloV5() { // 初始化 YOLOv5 模型 // ... } std::vector<ObjectDetectionResult> YoloV5::detect(const cv::Mat& image) { // 对图像进行预处理 cv::Mat input_image; cv::resize(image, input_image, cv::Size(640, 640)); // 将图像缩放到模型输入大小 // 将输入图像传递给 YOLOv5 进行预测 // ... // 解析输出结果,得到检测框和分类结果 std::vector<ObjectDetectionResult> results; // ... return results; } ``` 2. 导入 ONNX 模型,可以使用 ONNX Runtime 来加载和运行 ONNX 模型。 首先,需要将 YOLOv5 的 PyTorch 模型导出为 ONNX 格式。然后,可以使用 ONNX Runtime 来加载和运行 ONNX 模型。 以下是一个简单的示例代码,它使用 ONNX Runtime 加载和运行 ONNX 模型: ```cpp #include <onnxruntime_cxx_api.h> Ort::Env env(ORT_LOGGING_LEVEL_WARNING, "test"); // 初始化 ONNX Runtime 环境 Ort::SessionOptions session_options; session_options.SetIntraOpNumThreads(1); session_options.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_ALL); Ort::Session session(env, "model.onnx", session_options); // 加载 ONNX 模型 Ort::AllocatorWithDefaultOptions allocator; // 准备输入数据 std::vector<int64_t> input_shape = {1, 3, 640, 640}; Ort::Value input_tensor = Ort::Value::CreateTensor<float>(allocator, input_data.data(), input_shape.data(), input_shape.size()); // 运行模型 auto output_tensors = session.Run(Ort::RunOptions{nullptr}, input_names.data(), &input_tensor, input_names.size(), output_names.data(), output_names.size()); ``` 3. 实现前向推理代码,将输入图像喂给 ONNX 模型,并获取输出结果。 在使用 ONNX Runtime 运行 ONNX 模型之前,需要先准备输入数据,然后将输入数据传递给模型。在获取输出结果后,需要对输出结果进行解析,得到检测框和分类结果。 以下是一个简单的示例代码,它实现了前向推理代码: ```cpp #include <onnxruntime_cxx_api.h> std::vector<ObjectDetectionResult> YoloV5::detect(const cv::Mat& image) { // 对图像进行预处理 cv::Mat input_image; cv::resize(image, input_image, cv::Size(640, 640)); // 将图像缩放到模型输入大小 // 准备输入数据 std::vector<float> input_data = prepare_input_data(input_image); // 运行模型 auto output_tensors = session.Run(Ort::RunOptions{nullptr}, input_names.data(), &input_tensor, input_names.size(), output_names.data(), output_names.size()); // 解析输出结果,得到检测框和分类结果 std::vector<ObjectDetectionResult> results = parse_output_data(output_tensors); return results; } ``` 4. 将输出结果进行解析,得到检测框和分类结果。 解析输出结果是实现动态链接的一个重要部分。在解析输出结果之前,需要先了解模型的输出格式。 YOLOv5 模型的输出格式为一个包含多个数组的结构体,每个数组对应一个输出层的输出。每个数组的形状为 (batch_size, num_anchors * (num_classes + 5), grid_size, grid_size),其中,batch_size 为 1,num_anchors 为每个格子预测的锚框数量,num_classes 为类别数量,grid_size 为输出特征图的大小。 以下是一个简单的示例代码,它解析了 YOLOv5 模型的输出结果,得到检测框和分类结果: ```cpp #include <onnxruntime_cxx_api.h> std::vector<ObjectDetectionResult> YoloV5::parse_output_data(const Ort::Value& output_tensor) { std::vector<ObjectDetectionResult> results; // 获取输出数据 auto output_data = output_tensor.GetTensorMutableData<float>(); // 解析输出数据 // ... return results; } ``` 5. 使用 LaView 软件进行调用测试。 最后,可以使用 LaView 软件调用动态链接,并测试模型的性能和准确度。 在 LaView 中,可以使用 DLL 节点调用动态链接,通过设置节点的输入和输出参数,将图像传递给动态链接,获取检测框和分类结果。 以下是一个简单的示例代码,它在 LaView 中使用 DLL 节点调用动态链接: ```cpp #include <opencv2/opencv.hpp> #include "yolov5.h" YoloV5 yolo_v5; int main() { // 读取图像 cv::Mat image = cv::imread("test.jpg"); // 调用动态链接进行检测 auto results = yolo_v5.detect(image); // 显示结果 for (auto& result : results) { cv::rectangle(image, result.rect, cv::Scalar(0, 255, 0), 2); cv::putText(image, result.label, result.rect.tl(), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(0, 0, 255), 2); } cv::imshow("result", image); cv::waitKey(0); return 0; } ``` ### 回答2: 首先,编写动态链接封装yolov5可以按以下步骤操作: 1. 下载yolov5的源码并解压。 2. 在C语言中创建一个动态链接的项目。 3. 在项目中包含yolov5的源码文件,并根据需要进行配置。 4. 编写C语言代码来调用yolov5的函数和方法,例如加载模型进行目标检测等。 5. 编译项目生成动态链接文件(.dll或.so文件)。 然后,导入onnx模型可以按以下步骤操作: 1. 将onnx模型文件拷贝到你的项目文件夹中。 2. 在C代码中使用相应的来导入onnx模型。 3. 调用相应的函数或方法来加载导入的模型。 最后,使用laview进行调用测试可以按以下步骤操作: 1. 下载laview,并安装到你的计算机上。 2. 在laview中创建一个测试项目,导入你编写的动态链接文件。 3. 使用laview提供的界面和功能,调用动态链接中的函数来进行yolov5目标检测测试。 4. 检查测试结果,并根据需要进行调试和优化。 总之,根据以上步骤,你可以使用C语言编写动态链接封装yolov5,导入onnx模型,并使用laview进行调用测试。 ### 回答3: 要使用C语言编写动态链接封装Yolov5并导入ONNX模型,可以按照以下步骤进行: 1. 首先,你需要了解Yolov5的模型结构和ONNX模型的导入方式。Yolov5是一个目标检测算法,可以使用C语言实现其网络结构和相关函数。而ONNX模型可以使用相关的C导入并进行推理。 2. 在C语言中,你需要编写一个动态链接,其中封装了Yolov5的模型结构和相关函数。你可以创建一个名为"yolov5.c"的文件,并在其中实现Yolov5的网络结构和相关函数。 3. 下一步是导入ONNX模型。你可以使用ONNX Runtime来加载ONNX模型,并进行推理。在"yolov5.c"文件中,你需要添加相应的ONNX Runtime的引用,并编写导入ONNX模型的代码。 4. 在导入ONNX模型后,你可以使用LaView进行调用测试。LaView是一个图像处理,可以用于在视觉算法中加载和处理图像数据。你可以在"yolov5.c"文件中添加相应的LaView的引用,并编写相应的调用测试代码。 5. 最后,你需要编译动态链接使用适当的编译器命令,将"yolov5.c"文件编译成动态链接。确保将ONNX Runtime和LaView链接到动态链接中。 完成以上步骤后,你就可以使用这个动态链接进行Yolov5的目标检测,并使用LaView对图像进行处理和展示。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值