BasicVSR++模型转JIT并用c++libtorch推理

BasicVSR++模型转JIT并用c++libtorch推理

安装BasicVSR++ 环境

1.下载源码

git clone https://github.com/ckkelvinchan/BasicVSR_PlusPlus.git

2. 新建一个conda环境

conda create -n BasicVSRPLUSPLUS  python=3.8 -y
conda activate BasicVSRPLUSPLUS  

3. 安装pytorch

pytorch官网 安装合适的版本
我这里是CUDA11.6版本

conda install pytorch==1.13.1 torchvision==0.14.1 torchaudio==0.13.1 pytorch-cuda=11.6 -c pytorch -c nvidia

4. 安装 mim 和 mmcv-full

pip install openmim
mim install mmcv-full

5. 安装 mmedit

pip install mmedit

6. 下载模型文件

下载模型文件放在这里chkpts/basicvsr_plusplus_reds4.pth

7. 测试一下能否正常运行

python demo/restoration_video_demo.py configs/basicvsr_plusplus_reds4.py chkpts/basicvsr_plusplus_reds4.pth data/demo_000 results/demo_000

在这里插入图片描述
在这里插入图片描述
OK ! 环境正常!下面开始转换工作

转换为JIT模型

在demo下新建一个转换脚本

import os
import cv2
import mmcv
import numpy as np
import torch
from mmedit.core import tensor2img
from mmedit.apis import init_model


def main():
    # 加载模型并设置为评估模式
    model = init_model("configs/basicvsr_plusplus_reds4.py",
                       "chkpts/basicvsr_plusplus_reds4.pth", device=torch.device('cuda', 0))
    model.eval()

    # 准备一个示例输入
    src1 = cv2.imread("./data/img/00000000.png")
    src = cv2.cvtColor(src1, cv2.COLOR_BGR2RGB)
    src = torch.from_numpy(src / 255.).permute(2, 0, 1).float()
    src = src.unsqueeze(0)

    input_arg = torch.stack([src], dim=1)
    input_arg = input_arg.to(torch.device('cuda', 0))  # 确保输入在GPU上

    # # 执行模型推理
    # with torch.no_grad():  # 在推理时不需要计算梯度
    #     result = model(input_arg, test_mode=True)['output'].cpu()
    # output_i = tensor2img(result)
    # mmcv.imwrite(output_i, "./test.png")

    # 模型转换
    traced_model = torch.jit.trace(model.generator, input_arg)
    torch.jit.save(traced_model, "basicvsrPP.pt")

    # 测试
    res = traced_model(input_arg)
    out = tensor2img(res)
    mmcv.imwrite(out, "./testoo.png")


if __name__ == '__main__':
    main()

用c++ libtorch推理

/*
 * @Author: Liangbaikai
 * @LastEditTime: 2024-03-29 11:28:42
 * @Description: 视频超分
 * Copyright (c) 2024 by Liangbaikai, All Rights Reserved.
 */

#pragma once
#include <iostream>
#include <torch/script.h>
#include <torch/torch.h>
#include <opencv2/opencv.hpp>
#include <vector>
#include <c10/cuda/CUDACachingAllocator.h>

namespace LIANGBAIKAI_BASE_MODEL_NAME
{
    class lbk_video_super_resolution_basicPP
    {
    public:
        lbk_video_super_resolution_basicPP() = default;

        virtual ~lbk_video_super_resolution_basicPP()
        {
            c10::cuda::CUDACachingAllocator::emptyCache();
            // cudaDeviceReset();
        }

        /**
         * @description: 初始化
         * @param {string} &modelpath 模型文件
         * @param {int} gpuid GPU的id
         * @return {*}成功返回0,失败返回-1
         */
        int init(const std::string &modelpath, int gpuid = 0)
        {
            try
            {
                _mymodule = std::make_unique<torch::jit::script::Module>(torch::jit::load(modelpath));
            }
            catch (const c10::Error &e)
            {
                std::cerr << "Error loading the model " << modelpath << std::endl;
                std::cerr << "Error " << e.what() << std::endl;
                return -1;
            }
            _gpuid = gpuid;

            if ((_gpuid < 0) || (!torch::cuda::is_available()))
            {
                _device = std::make_unique<torch::Device>(torch::kCPU);
                _mymodule->to(at::kCPU);
            }
            else
            {
                _device = std::make_unique<torch::Device>(torch::kCUDA, _gpuid);
                _mymodule->to(at::kCUDA, _gpuid);
            }

            _mymodule->eval();
            _modelsuccess = true;
            return 0;
        }

        /**
         * @description: 推理
         * @param {Mat} &inputpic 输入图片
         * @param {Mat} &outputpic 输出结果
         * @param {bool} showlog  是否打印日志
         * @return {*} 成功返回0,失败返回-1
         */
        int inference(cv::Mat &inputpic, cv::Mat &outputpic, bool showlog = false)
        {
            if (inputpic.empty() || (inputpic.channels() != 3))
            {
                std::cout << "input data ERROR" << std::endl;
                return -1;
            }

            if (!_modelsuccess)
            {
                std::cout << "model has not been inited!" << std::endl;
                return -1;
            }

            // torch::DeviceGuard 是一个类,它的作用是确保在使用完设备(如CPU或GPU)后,能够正确地将设备恢复到使用前的状态。
            torch::DeviceGuard device_guard(*_device); // 作用域内所有操作都在指定设备上运行,离开此作用域恢复

            cv::transpose(inputpic, inputpic); // 顺时针旋转

            // 将图片转换为tensor
            cv::Mat img_float;
            inputpic.convertTo(img_float, CV_32FC3, 1.0 / 255);
            torch::Tensor img_tensor = torch::from_blob(img_float.data, {img_float.rows, img_float.cols, 3}, torch::kFloat32).permute({2, 1, 0});
            img_tensor = (img_tensor - 0.5) / 0.5;
            img_tensor = (img_tensor + 1) / 2;
            img_tensor = torch::clamp(img_tensor, 0, 1);

            torch::Tensor src_unsqueezed = img_tensor.unsqueeze(0).to(*_device); // 将tensor转移到GPU上

            std::vector<torch::Tensor> tensors_to_stack = {src_unsqueezed}; // 创建一个包含 src 的 vector

            torch::Tensor input_arg = torch::stack(tensors_to_stack, 1); // 沿着维度1堆叠tensors

            if (showlog)
            {
                std::cout << input_arg.sizes() << std::endl;
            }

            torch::NoGradGuard no_grad; // 暂时禁用梯度计算
            auto output_dict = _mymodule->forward({input_arg});

            torch::Tensor output_data;
            if (output_dict.isTensor())
            {
                output_data = output_dict.toTensor().to(at::kCPU); // 如果是Tensor,则通过toTensor()方法获取它
                if (showlog)
                {
                    std::cout << "out shape: " << output_data.sizes() << std::endl;
                }
            }
            else
            {
                if (showlog)
                {
                    std::cerr << "The IValue does not contain a Tensor." << std::endl;
                }
            }

            float *f = output_data.data_ptr<float>();

            int output_width = output_data.size(3);
            int output_height = output_data.size(4);
            int size_pic = output_width * output_height;

            std::vector<cv::Mat> rgbChannels(3);
            rgbChannels[0] = cv::Mat(output_width, output_height, CV_32FC1, f);
            rgbChannels[1] = cv::Mat(output_width, output_height, CV_32FC1, f + size_pic);
            rgbChannels[2] = cv::Mat(output_width, output_height, CV_32FC1, f + size_pic + size_pic);

            rgbChannels[0].convertTo(rgbChannels[0], CV_8UC1, 255);
            rgbChannels[1].convertTo(rgbChannels[1], CV_8UC1, 255);
            rgbChannels[2].convertTo(rgbChannels[2], CV_8UC1, 255);

            merge(rgbChannels, outputpic);

            return 0;
        }

    private:
        bool _modelsuccess = false;
        int _gpuid = 0;
        std::unique_ptr<torch::Device> _device;
        std::unique_ptr<torch::jit::script::Module> _mymodule;
    };

}
#include <unistd.h>
#include"lbk_video_super_resolution.hpp"
using namespace LIANGBAIKAI_BASE_MODEL_NAME;
int main(int argc,char *argv[])
{
    if(argc < 5){
        std::cout << "./test 模型  GPUid(cpu传-1) 输入图片 输出图片" << std::endl;
        return -1;
    }
    std::string modelfile = argv[1];
    int gpuid = atoi(argv[2]);
    std::string imgfile = argv[3];
    std::string outfile = argv[4];

    cv::Mat src = cv::imread(imgfile);


    lbk_video_super_resolution_basicPP test;
    if(0 > test.init(modelfile,gpuid)){
        std::cout << "init failed" << std::endl;
        return -1;
    }
    cv::Mat out;
    int rec = test.inference(src,out,true);
    if(rec >= 0){
        cv::imwrite(outfile, out);
    }

    return 0;
}

效果

在这里插入图片描述

在这里插入图片描述

  • 10
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在 C++使用 YOLOv5,您需要进行以下步骤: 1. 安装 LibTorch 您需要从 PyTorch 官网下载适合您操作系统和 CUDA 版本的 LibTorch。 2. 下载 YOLOv5 模型 您可以从 YOLOv5 的官方 GitHub 仓库下载预训练模型。 3. 加载模型 您可以使用 `torch::jit::load()` 函数加载模型。例如: ```c++ torch::jit::script::Module module = torch::jit::load("path/to/model.pt"); ``` 4. 推理 首先,您需要将输入图像换为 Tensor。您可以使用 OpenCV 或其他图像处理库来完成此操作。例如: ```c++ cv::Mat img = cv::imread("path/to/image.jpg"); cv::Mat img_float; img.convertTo(img_float, CV_32F, 1.0 / 255.0); torch::Tensor tensor_image = torch::from_blob( img_float.data, {1, img_float.rows, img_float.cols, 3}).permute({0, 3, 1, 2}); ``` 然后,您可以将 Tensor 传递到模型中进行推理。例如: ```c++ at::Tensor result = module.forward({tensor_image}).toTensor(); ``` 5. 解析输出 YOLOv5 模型的输出是一个包含所有检测结果的 Tensor。您需要解析此 Tensor 来提取检测结果。例如: ```c++ float* result_data = result.data_ptr<float>(); for (int i = 0; i < result.size(1); i++) { float* class_data = result_data + i * result.size(2); for (int j = 0; j < result.size(2); j++) { float* box_data = class_data + j * result.size(3); // 解析检测结果并进行后续处理 } } ``` 这是一个基本的 YOLOv5 部署流程。但是,由于 YOLOv5 的实现比较复杂,还有一些细节需要注意。建议您在实现时参考 YOLOv5 官方的 PyTorch 实现和其他开源项目,如 yolov5_cpp。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值