系统环境
- Ubuntu 18.04
- CUDA 10.1
- cuDNN 7.6.5
获取LibTorch
从官网下载LibTorch的GPU版本二进制包。注意版本。
我之前PyTorch用的是1.4版本,因此LibTorch保持同版本,修改下载地址如下:
https://download.pytorch.org/libtorch/cu101/libtorch-cxx11-abi-shared-with-deps-1.4.0.zip
百度云下载地址,有cpu后缀的是CPU版本的,没有的是GPU版本的。
链接: https://pan.baidu.com/s/1mSHh66CIzO6hzVE4-2Ytkw 密码: cb24
解压后即可使用。
CMakeLists.txt编写
cmake_minimum_required(VERSION 3.7)
project(deploy)
set(CMAKE_CXX_STANDARD 11)
# 指定文件夹位置
set(OPENCV_DIR /home/luzhan/软件/opencv-3.4.3)
#set(Torch_DIR /home/luzhan/软件/libtorch_cpu/share/cmake/Torch)
set(Torch_DIR /home/luzhan/软件/libtorch_gpu/share/cmake/Torch)
set(CUDA_TOOLKIT_ROOT_DIR /usr/local/cuda)
# 自动查找包
find_package(Torch REQUIRED)
find_package(OpenCV 3.4.3 REQUIRED)
# 添加源程序
add_executable(deploy
main.cpp
)
# 添加头文件
include_directories(${OpenCV_INCLUDE_DIRS} ./include)
# 加入库文件位置
target_link_libraries(deploy
${OpenCV_LIBS}
-pthread
-lMVSDK
/lib/libMVSDK.so
)
target_link_libraries(deploy
${TORCH_LIBRARIES}
)
主程序代码
/**
* @author starrysky
* @date 2020/08/16
* @version 1.0
* @details LibTorch调用PyTorch已经训练好的模型, 对传入的OpenCV的灰度图进行分类
*/
#include <torch/script.h>
#include <torch/torch.h>
#include <vector>
#include <opencv2/opencv.hpp>
#include "opencv2/imgcodecs.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
#include <opencv2/tracking.hpp>
class DigitalRecognition {
private:
torch::jit::script::Module module;
torch::Device device;
const int IMAGE_COLS = 28;
const int IMAGE_ROWS = 28;
public:
/**
* 默认使用CPU,可通过标志位开启使用GPU
* @param use_cuda 是否使用GPU
* @param model_path 模型文件路径
*/
explicit DigitalRecognition(bool use_cuda = false,
const std::string &model_path = "../model/model.pt") : device(torch::kCPU) {
if ((use_cuda) && (torch::cuda::is_available())) {
std::cout << "CUDA is available! Training on GPU." << std::endl;
device = torch::kCUDA;
}
module = torch::jit::load(model_path, device);
}
/**
* 单张图片分类器
* @param img 图片,cv::Mat类型
* @return 分类结果
*/
int matToDigital(cv::Mat &img) {
// 正则化
img.convertTo(img, CV_32FC1, 1.0f / 255.0f);
// 模型用的是 28*28 的单通道灰度图
cv::resize(img, img, cv::Size(IMAGE_COLS, IMAGE_ROWS));
// 将 OpenCV 的 Mat 转换为 Tensor, 注意两者的数据格式
// OpenCV: H*W*C 高度, 宽度, 通道数
auto input_tensor = torch::from_blob(img.data, {1, IMAGE_COLS, IMAGE_ROWS, 1});
// Tensor: N*C*H*W 数量, 通道数, 高度, 宽度
// 数字表示顺序
input_tensor = input_tensor.permute({0, 3, 1, 2}).to(device);
// 添加数据
std::vector<torch::jit::IValue> inputs;
inputs.emplace_back(input_tensor);
// 模型计算
at::Tensor output = module.forward(inputs).toTensor();
std::cout << output.slice(/*dim=*/1, /*start=*/0, /*end=*/7) << '\n';
// 输出分类的结果
int ans = output.argmax(1).item().toInt();
std::cout << "当前机器人编号: " << ans << std::endl;
return ans;
}
};
int main() {
DigitalRecognition digitalRecognition;
cv::Mat img = cv::imread("../image/1.jpg", CV_8UC1);
digitalRecognition.matToDigital(img);
return 0;
}