// Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
include <gflags/gflags.h>
include
include
include "model_deploy/common/include/paddle_deploy.h"
include "model_deploy/common/include/model_infer.h"
include // GetCurrentThreadId()
/*
模型初始化/注册接口
model_type: 初始化模型类型: det,seg,clas,paddlex
model_filename: 模型文件路径
params_filename: 参数文件路径
cfg_file: 配置文件路径
use_gpu: 是否使用GPU
gpu_id: 指定第x号GPU
paddlex_model_type: model_type为paddlx时,返回的实际paddlex模型的类型: det, seg, clas
/
extern "C" __declspec(dllexport) PaddleDeploy::Model InitModel(const char model_type, const char model_filename, const char params_filename, const char cfg_file, bool use_gpu, int gpu_id, char paddlex_model_type)
{
// create model
PaddleDeploy::Model model = PaddleDeploy::CreateModel(model_type); //FLAGS_model_type
output: result of pridict ,include label_map
/
extern "C" __declspec(dllexport) void Seg_ModelPredict(PaddleDeploy::Model model, const unsigned char img, int nWidth, int nHeight, int nChannel, unsigned char output)
{
//LOGC("INFO", "seg in thread id [%d]", GetCurrentThreadId());
// prepare data
std::vector imgs;
int nType = 0;
if (nChannel == 3)
{
nType = CV_8UC3;
//LOGC("INFO", "infer input img w=%d, h=%d, c=%d", nWidth, nHeight, nChannel);
}
else
{
//std::cout << "Only support 3 channel image." << std::endl;
LOGC("ERR", "Only support 3 channel images, but got channels ", nChannel);
return;
}
output: result of pridict ,include label_map
/
extern "C" __declspec(dllexport) void Seg_ModelBatchPredict(PaddleDeploy::Model model, const std::vector<unsigned char> imgs, int nWidth, int nHeight, int nChannel, std::vector<unsigned char> output)
{
std::vector results;
if (imgs.size() != output.size()) {
LOGC("ERR", "image batch size(%d) not match with results size(%d)", imgs.size(), output.size());
}
// Read image
int im_vec_size = imgs.size();
std::vector im_vec;
int nType = 0;
if (nChannel == 3)
{
nType = CV_8UC3;
}
else
{
LOGC("ERR", "Only support 3 channel images, but got channels ", nChannel);
return;
}
for (int i = 0; i < im_vec_size; i++) {
cv::Mat input = cv::Mat::zeros(cv::Size(nWidth, nHeight), nType);
memcpy(input.data, imgs[i], nHeight nWidth nChannel sizeof(uchar));
im_vec.emplace_back(std::move(input));
}
if (!model->Predict(im_vec, &results, 1)) {
LOGC("ERR", "predict batch images failed");
}
// batch修改:这里应该会得到返回的每张图的label_map,那么下面就应该分别处理results中每张图对应的label_map
for (int i = 0; i < im_vec_size; i++) {
std::vector result_map = results[i].seg_result->label_map.data; // vector -- 结果map
// 拷贝输出结果到输出上返回 -- 将vector转成unsigned char
memcpy(output[i], &result_map[0], result_map.size() * sizeof(uchar));
}
}
/*
识别推理接口
img: input for predicting.
nWidth: width of img.
nHeight: height of img.
nChannel: channel of img.
score: result of pridict ,include score
category: result of pridict ,include category_string
category_id: result of pridict ,include category_id
/
extern "C" __declspec(dllexport) void Cls_ModelPredict(PaddleDeploy::Model model, const unsigned char img, int nWidth, int nHeight, int nChannel, float score, char category, int category_id)
{
// prepare data
std::vector imgs;
int nType = 0;
if (nChannel == 3)
{
nType = CV_8UC3;
}
else
{
std::cout << "Only support 3 channel image." << std::endl;
return;
}
采用C#的部署方式,尝试了Github提供C++编译利用Cmake生产DLL后C#部署,普通加载模型是没问题的,用TensorRT加速加载模型就会报错误,提示内存受保护,我这边模型用的YOLOV3,用PaddleX训练的。 我的配置如下: 显卡是RTX3060 运行系统:Windows 部署方式:C# Cuda版本11.1 CuDnn版本v8.0.5.39 PaddleX版本2.1 推理库:PaddleInference TensorRT版本7.2.1.6(都是根据Cuda版本对应找的)
此问题搞了一个月了,还没没有成功,请大神解惑,是否PaddleX不支持TensorRT,因为给的示例里面没有用TensorRT, QQ群里和微信的PaddleX交流群也没有人成功过。
推理代码如下:
// Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License.
include <gflags/gflags.h>
include
include
include "model_deploy/common/include/paddle_deploy.h"
include "model_deploy/common/include/model_infer.h"
include // GetCurrentThreadId()
/*
paddlex_model_type: model_type为paddlx时,返回的实际paddlex模型的类型: det, seg, clas / extern "C" __declspec(dllexport) PaddleDeploy::Model InitModel(const char model_type, const char model_filename, const char params_filename, const char cfg_file, bool use_gpu, int gpu_id, char paddlex_model_type) { // create model PaddleDeploy::Model model = PaddleDeploy::CreateModel(model_type); //FLAGS_model_type
// model init model->Init(cfg_file);
// inference engine init PaddleDeploy::PaddleEngineConfig engine_config; engine_config.model_filename = model_filename; engine_config.params_filename = params_filename; engine_config.use_gpu = use_gpu; engine_config.gpu_id = gpu_id; bool init = model->PaddleEngineInit(engine_config); if (!init) { LOGC("ERR", "init model failed"); } else { LOGC("INFO", "init model successfully: use_gpu=%d, gpu_id=%d, model path=%s", use_gpu, gpu_id, model_filename); }
// det, seg, clas, paddlex if (strcmp(model_type, "paddlex") == 0) // 是paddlex模型,则返回具体支持的模型类型: det, seg, clas { // detector if (model->yamlconfig["model_type"].as() == std::string("detector"))
{
strcpy(paddlex_model_type, "det");
}
else if (model->yamlconfig["model_type"].as() == std::string("segmenter"))
{
strcpy(paddlex_model_type, "seg");
}
else if (model->yamlconfig["model_type"].as() == std::string("classifier"))
{
strcpy(paddlex_model_type, "clas");
}
}
return model;
}
// 初始化模型带tensorRT加速 // [suliang] 2021-12-15 增加5个输入参数:min_input_shape, max_input_shape, optim_input_shape分别代表输入尺寸的输入范围, precision代表计算精度(0=fp32,1=fp16,2=int8),min_subgraph_size代表最小优化子图 extern "C" __declspec(dllexport) PaddleDeploy::Model InitModel_TRT(const char model_type, const char model_filename, const char params_filename, const char cfg_file, bool use_gpu, int gpu_id, char paddlex_model_type, std::vectormin_input_shape, std::vectormax_input_shape, std::vectoroptim_input_shape, int precision, int min_subgraph_size)
{
// create model
PaddleDeploy::Model* model = PaddleDeploy::CreateModel(model_type); //FLAGS_model_type
}
extern "C" __declspec(dllexport) void Det_ModelPredict(PaddleDeploy::Model model, const unsigned char img, int nWidth, int nHeight, int nChannel, float output, int nBoxesNum, char* LabelList) { // prepare data std::vector imgs;
}
/*
output: result of pridict ,include label_map / extern "C" __declspec(dllexport) void Seg_ModelPredict(PaddleDeploy::Model model, const unsigned char img, int nWidth, int nHeight, int nChannel, unsigned char output) { //LOGC("INFO", "seg in thread id [%d]", GetCurrentThreadId()); // prepare data std::vector imgs;
int nType = 0; if (nChannel == 3) { nType = CV_8UC3; //LOGC("INFO", "infer input img w=%d, h=%d, c=%d", nWidth, nHeight, nChannel); } else { //std::cout << "Only support 3 channel image." << std::endl; LOGC("ERR", "Only support 3 channel images, but got channels ", nChannel); return; }
cv::Mat input = cv::Mat::zeros(cv::Size(nWidth, nHeight), nType); memcpy(input.data, img, nHeight nWidth nChannel * sizeof(uchar)); //cv::imwrite("D://modelinfercpp_275.bmp", input); imgs.push_back(std::move(input));
// predict std::vector results;
model->Predict(imgs, &results, 1);
// batch修改:这里应该会得到返回的每张图的label_map,那么下面就应该分别处理results中每张图对应的label_map
std::vector result_map = results[0].seg_result->label_map.data; // vector -- 结果map
//LOGC("INFO", "finish infer, with result_map length=%d", result_map.size());
// 拷贝输出结果到输出上返回 -- 将vector转成unsigned char
memcpy(output, &result_map[0], result_map.size() sizeof(uchar));
}
/*
output: result of pridict ,include label_map / extern "C" __declspec(dllexport) void Seg_ModelBatchPredict(PaddleDeploy::Model model, const std::vector<unsigned char> imgs, int nWidth, int nHeight, int nChannel, std::vector<unsigned char> output) { std::vector results;
if (imgs.size() != output.size()) {
LOGC("ERR", "image batch size(%d) not match with results size(%d)", imgs.size(), output.size());
}
// Read image
int im_vec_size = imgs.size();
std::vector im_vec;
int nType = 0; if (nChannel == 3) { nType = CV_8UC3; } else { LOGC("ERR", "Only support 3 channel images, but got channels ", nChannel); return; } for (int i = 0; i < im_vec_size; i++) { cv::Mat input = cv::Mat::zeros(cv::Size(nWidth, nHeight), nType); memcpy(input.data, imgs[i], nHeight nWidth nChannel sizeof(uchar)); im_vec.emplace_back(std::move(input)); } if (!model->Predict(im_vec, &results, 1)) { LOGC("ERR", "predict batch images failed"); } // batch修改:这里应该会得到返回的每张图的label_map,那么下面就应该分别处理results中每张图对应的label_map for (int i = 0; i < im_vec_size; i++) { std::vector result_map = results[i].seg_result->label_map.data; // vector -- 结果map
// 拷贝输出结果到输出上返回 -- 将vector转成unsigned char
memcpy(output[i], &result_map[0], result_map.size() * sizeof(uchar));
}
}
/*
category_id: result of pridict ,include category_id / extern "C" __declspec(dllexport) void Cls_ModelPredict(PaddleDeploy::Model model, const unsigned char img, int nWidth, int nHeight, int nChannel, float score, char category, int category_id) { // prepare data std::vector imgs;
int nType = 0; if (nChannel == 3) { nType = CV_8UC3; } else { std::cout << "Only support 3 channel image." << std::endl; return; }
cv::Mat input = cv::Mat::zeros(cv::Size(nWidth, nHeight), nType); memcpy(input.data, img, nHeight nWidth nChannel * sizeof(uchar)); cv::imwrite("D:\1.png", input); imgs.push_back(std::move(input));
// predict std::vector results;
//LOGC("INFO", "begin predict");
model->Predict(imgs, &results, 1);
//LOGC("INFO", "got pred result: score=%f", results[0].clas_result->score);
//LOGC("INFO", "got pred result: category_id=%d", results[0].clas_result->category_id);
//LOGC("INFO", "got pred result: category=%s", results[0].clas_result->category);
category_id = results[0].clas_result->category_id;
// 拷贝输出类别结果到输出上返回 -- string --> char
memcpy(category, results[0].clas_result->category.c_str(), strlen(results[0].clas_result->category.c_str()));
// 拷贝输出概率值返回
*score = results[0].clas_result->score;
}
/*
LabelList: result of pridict ,include LabelList / extern "C" __declspec(dllexport) void Mask_ModelPredict(PaddleDeploy::Model model, const unsigned char img, int nWidth, int nHeight, int nChannel, float box_output, unsigned char mask_output, int nBoxesNum, char* LabelList) { // prepare data std::vector imgs;
int nType = 0; if (nChannel == 3) { nType = CV_8UC3; } else { std::cout << "Only support 3 channel image." << std::endl; return; }
cv::Mat input = cv::Mat::zeros(cv::Size(nWidth, nHeight), nType); memcpy(input.data, img, nHeight nWidth nChannel * sizeof(uchar)); imgs.push_back(std::move(input));
// predict -- 多次点击单张推理时会出错 std::vector results;
model->Predict(imgs, &results, 1); // 在Infer处发生错误
nBoxesNum[0] = results[0].det_result->boxes.size(); // 得到单张图片预测的bounding box数 std::string label = "";
for (int i = 0; i < results[0].det_result->boxes.size(); i++) // 得到所有框的数据 { // 边界框预测结果 label = label + results[0].det_result->boxes[i].category + " "; // labelindex box_output[i 6 + 0] = results[0].det_result->boxes[i].category_id; // 类别的id // score box_output[i 6 + 1] = results[0].det_result->boxes[i].score; // 得分 //// box box_output[i 6 + 2] = results[0].det_result->boxes[i].coordinate[0]; // x1, y1, x2, y2 box_output[i 6 + 3] = results[0].det_result->boxes[i].coordinate[1]; // 左上、右下的顶点 box_output[i 6 + 4] = results[0].det_result->boxes[i].coordinate[2]; box_output[i 6 + 5] = results[0].det_result->boxes[i].coordinate[3];
} memcpy(LabelList, label.c_str(), strlen(label.c_str())); }
/*
// 新增二次封装:初始化 void ModelWrapper::InitModelEnter(const char model_type, const char model_dir, int gpu_id, bool use_trt, const std::vectormin_input_shape, const std::vectormax_input_shape, const std::vectoroptim_input_shape, int precision, int min_subgraph_size)
{
// 初始化线程池:创建指定个数线程,每个线程指定到线程池的一个线程号
pool = new ThreadPool(num_threads);
pool->init();
}
// 新增二次封装:单图推理 void ModelWrapper::SegPredictEnter(unsigned char imageData, int width, int height, int channels, unsigned char result_map) { cv::Mat src; if (channels == 1) { src = cv::Mat(height, width, CV_8UC1, imageData); cv::cvtColor(src, src, cv::COLOR_GRAY2BGR); } else { src = cv::Mat(height, width, CV_8UC3, imageData); } int predChannels = src.channels(); UCHAR* _imageData = src.data; auto future1 = pool->submit(Seg_ModelPredict, _model, _imageData, width, height, predChannels, result_map); future1.get(); }
// 检测模型 void ModelWrapper::DetPredictEnter(unsigned char imageData, int width, int height, int channels, float output, int nBoxesNum, char LabelList) { cv::Mat src; if (channels == 1) { src = cv::Mat(height, width, CV_8UC1, imageData); cv::cvtColor(src, src, cv::COLOR_GRAY2BGR); } else { src = cv::Mat(height, width, CV_8UC3, imageData); } int predChannels = src.channels(); UCHAR* _imageData = src.data; auto future1 = pool->submit(Det_ModelPredict, _model, _imageData, width, height, predChannels, output, nBoxesNum, LabelList); future1.get(); }
// 分类模型 void ModelWrapper::ClsPredictEnter(unsigned char imageData, int width, int height, int channels, float score, char category, int category_id) { cv::Mat src; if (channels == 1) { src = cv::Mat(height, width, CV_8UC1, imageData); cv::cvtColor(src, src, cv::COLOR_GRAY2BGR); } else { src = cv::Mat(height, width, CV_8UC3, imageData); } int predChannels = src.channels(); UCHAR* _imageData = src.data; auto future1 = pool->submit(Cls_ModelPredict, _model, _imageData, width, height, predChannels, score, category, category_id); future1.get(); }
// Mask模型 void ModelWrapper::MaskPredictEnter(unsigned char imageData, int width, int height, int channels, float box_output, unsigned char mask_output, int nBoxesNum, char LabelList) { cv::Mat src; if (channels == 1) { src = cv::Mat(height, width, CV_8UC1, imageData); cv::cvtColor(src, src, cv::COLOR_GRAY2BGR); } else { src = cv::Mat(height, width, CV_8UC3, imageData); } int predChannels = src.channels(); UCHAR _imageData = src.data; auto future1 = pool->submit(Mask_ModelPredict, _model, _imageData, width, height, predChannels, box_output, mask_output, nBoxesNum, LabelList); future1.get(); }
// 新增二次封装:模型资源释放 void ModelWrapper::DestructModelEnter() { // 释放线程池中所有线程 pool->shutdown(); if (pool != NULL) { delete pool; pool = NULL; } // 释放模型资源 if (_model != NULL) { DestructModel(_model); } }
// 新增二次封装接口api extern "C" __declspec(dllexport) ModelWrapper ModelObjInit(const char model_type, const char model_dir, int gpu_id, bool use_trt, const std::vectormin_input_shape, const std::vectormax_input_shape, const std::vectoroptim_input_shape, int precision, int min_subgraph_size)
{
ModelWrapper modelObj = new ModelWrapper();
modelObj->InitModelEnter(model_type, model_dir, gpu_id, use_trt, min_input_shape, max_input_shape, optim_input_shape, precision, min_subgraph_size);
return modelObj;
}
extern "C" __declspec(dllexport) void ModelObjDestruct(ModelWrapper * modelObj) { // 先释放模型内部的资源 modelObj->DestructModelEnter(); // 再释放堆区模型资源 delete modelObj; }
extern "C" __declspec(dllexport) void ModelObjPredict_Seg(ModelWrapper modelObj, unsigned char imageData, int width, int height, int channels, unsigned char* resultMap) { modelObj->SegPredictEnter(imageData, width, height, channels, resultMap); }
extern "C" __declspec(dllexport) void ModelObjPredict_Det(ModelWrapper modelObj, unsigned char imageData, int width, int height, int channels, float output, int nBoxesNum, char* LabelList) { modelObj->DetPredictEnter(imageData, width, height, channels, output, nBoxesNum, LabelList); }
extern "C" __declspec(dllexport) void ModelObjPredict_Cls(ModelWrapper modelObj, unsigned char imageData, int width, int height, int channels, float score, char category, int* category_id) { modelObj->ClsPredictEnter(imageData, width, height, channels, score, category, category_id); }
extern "C" __declspec(dllexport) void ModelObjPredict_Mask(ModelWrapper modelObj, unsigned char imageData, int width, int height, int channels, float box_output, unsigned char mask_output, int nBoxesNum, char LabelList) { modelObj->MaskPredictEnter(imageData, width, height, channels, box_output, mask_output, nBoxesNum, LabelList); }