You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

624 lines
21 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* @Author: xiewenji 527774126@qq.com
* @Date: 2025-09-03 10:44:31
* @LastEditors: xiewenji 527774126@qq.com
* @LastEditTime: 2025-09-06 22:29:55
* @FilePath: /AI_SO_Test/AIEngineModule/src/AIModel_Impl.cpp
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
#include "AIModel_Impl.h"
#include "CUDA_DataChange.cuh"
AIModel_Impl::AIModel_Impl()
{
m_bInitSuccess = false;
m_GPU_Engine.clear();
m_modelNodeList.clear();
m_pNode_input_0 = NULL;
m_pNode_input_1 = NULL;
m_pNode_output_0 = NULL;
m_pNode_output_1 = NULL;
m_pNode_output_2 = NULL;
m_DetGPUStream.clear();
m_nLast_GPUStreamIdx.store(0);
m_nALLStreamNum = 0;
}
AIModel_Impl::~AIModel_Impl()
{
}
int AIModel_Impl::Init(AIModelRun_Config config)
{
m_modelRun_Config.Copy(config);
printf(">>> %s Init Start \n", m_modelRun_Config.strName.c_str());
if (m_bInitSuccess)
{
printf("strName %s Init Success %d ************ return \n", m_modelRun_Config.strName.c_str(), m_bInitSuccess);
return 0;
}
int re = 0;
re = ModelRunConfigCheck(m_modelRun_Config);
if (re != 0)
{
printf("strName %s Init Error =%d run Config error \n", m_modelRun_Config.strName.c_str(), re);
return re;
}
// 不同显卡 单独 载入模型
if (m_modelRun_Config.gpuconfig.gpu_0)
{
re = LoadEngine(0);
// 加载失败
if (re != 0)
{
}
}
if (m_modelRun_Config.gpuconfig.gpu_1)
{
re = LoadEngine(1);
// 加载失败
if (re != 0)
{
}
}
int nGPUNum = m_GPU_Engine.size();
// 模型载入失败
if (nGPUNum <= 0 || nGPUNum > 2)
{
printf(" %s model Init error \n", m_modelRun_Config.strName.c_str());
return 2;
}
for (int i = 0; i < m_modelNodeList.size(); i++)
{
if (m_modelNodeList.at(i).type == AI_Buffer_Type_INPUT)
{
if (m_pNode_input_0 == NULL)
{
m_pNode_input_0 = &m_modelNodeList.at(i);
input_0.copy(*m_pNode_input_0);
}
else
{
m_pNode_input_1 = &m_modelNodeList.at(i);
input_1.copy(*m_pNode_input_1);
}
}
else
{
if (m_pNode_output_0 == NULL)
{
m_pNode_output_0 = &m_modelNodeList.at(i);
output_0.copy(*m_pNode_output_0);
}
else if (m_pNode_output_1 == NULL)
{
m_pNode_output_1 = &m_modelNodeList.at(i);
output_1.copy(*m_pNode_output_1);
}
else
{
m_pNode_output_2 = &m_modelNodeList.at(i);
output_2.copy(*m_pNode_output_2);
}
}
}
if (m_pNode_input_0 == NULL || m_pNode_output_0 == NULL)
{
printf(" %s model Init error \n", m_modelRun_Config.strName.c_str());
return 3;
}
int streamNum = m_GPU_Engine.at(0)->cudaSteams.size();
// 生产推理用的 参数信息
if (m_GPU_Engine.size() > 1)
{
if (m_GPU_Engine.at(0)->cudaSteams.size() != m_GPU_Engine.at(1)->cudaSteams.size())
{
printf(" %s model Init error \n", m_modelRun_Config.strName.c_str());
return 3;
}
}
if (streamNum <= 0)
{
printf(" %s model Init streamNum error \n", m_modelRun_Config.strName.c_str());
return 4;
}
// 显示初始化信息
if (true)
{
printf("Model Name :%s GUP engine Num %ld\n", m_modelRun_Config.strName.c_str(), m_GPU_Engine.size());
for (const auto &ge : m_GPU_Engine)
{
printf(" gpu %d status %d strem Num %ld \n", ge->nGPUIdx, ge->bsucc, ge->cudaSteams.size());
for (const auto &psteam : ge->cudaSteams)
{
printf(" steam %d \n", psteam->nstreamIdx);
for (const auto &pcon : psteam->streamConfigList)
{
printf(" type %d [chw] %d %d %d input %p output %p\n",
pcon->nodeConfig.type, pcon->nodeConfig.channel, pcon->nodeConfig.height, pcon->nodeConfig.width,
pcon->gpu_buffers, pcon->gpu_ImgData);
}
}
}
}
// 把所有gup 的所有stream 都放到一起,方便调用。
for (int i = 0; i < streamNum; i++)
{
for (int igpu = 0; igpu < nGPUNum; igpu++)
{
std::shared_ptr<Det_GPU_Stram> temDetStream = std::make_shared<Det_GPU_Stram>();
temDetStream->nGPUIdx = m_GPU_Engine.at(igpu)->nGPUIdx;
temDetStream->engine = m_GPU_Engine.at(igpu)->engine;
temDetStream->cuda_stream = m_GPU_Engine.at(igpu)->cudaSteams.at(i);
m_DetGPUStream.push_back(temDetStream);
}
}
m_nALLStreamNum = m_DetGPUStream.size();
printf("========********* Model Name :%s GUP engine Num %ld **************=============\n", m_modelRun_Config.strName.c_str(), m_GPU_Engine.size());
for (const auto steam : m_DetGPUStream)
{
printf(">>> gpu %d stream %d \n",
steam->nGPUIdx, steam->cuda_stream->nstreamIdx);
}
m_bInitSuccess = true;
// warm-up首次推理会触发 TensorRT/CUDA 懒初始化kernel 加载、workspace 分配、首次 enqueueV3 建图等),
// 提前用一张空图预热,避免首张检测图耗时飙升。
{
cv::Mat warmIn = InitMat(m_pNode_input_0->channel, m_pNode_input_0->width, m_pNode_input_0->height);
cv::Mat warmOut;
int warmRe = AIDet(warmIn, warmOut);
if (warmRe != 0)
{
printf("%s warm-up error = %d\n", m_modelRun_Config.strName.c_str(), warmRe);
}
}
return 0;
}
cv::Mat AIModel_Impl::InitMat(int channel, int w, int h)
{
if (w <= 0 || h <= 0 || channel <= 0 || channel > 3)
{
return cv::Mat();
}
cv::Mat dst;
if (channel == 1)
{
dst = cv::Mat(h, w, CV_8UC1, cv::Scalar(0));
}
else
{
dst = cv::Mat(h, w, CV_8UC3, cv::Scalar(0, 0, 0));
}
return dst;
}
int AIModel_Impl::AIDet(const cv::Mat &inImg, cv::Mat &outimg)
{
// 1、准备数据
if (m_pNode_input_0 == NULL || m_pNode_output_0 == NULL)
{
printf("AIDet: Node Config INput output Node error \n");
return 1;
}
// std::this_thread::sleep_for(std::chrono::milliseconds(2)); // Sleep for 100 milliseconds
uchar *p_indata_0 = (uchar *)inImg.data;
outimg = InitMat(m_pNode_output_0->channel, m_pNode_output_0->width, m_pNode_output_0->height);
uchar *p_outdata_1 = (uchar *)outimg.data;
if (!m_bInitSuccess)
{
return 2;
}
AI_Det_In_1_Out_1(m_pNode_input_0, m_pNode_output_0, p_indata_0, p_outdata_1);
return 0;
}
int AIModel_Impl::AIDet(const cv::Mat &inImg, cv::Mat &outimg0, cv::Mat &outimg1)
{
return 0;
}
int AIModel_Impl::AIClass(const cv::Mat &inImg, float *fmaxScore)
{
// 1、准备数据
if (m_pNode_input_0 == NULL || m_pNode_output_0 == NULL)
{
printf("AIDet: Node Config INput output Node error \n");
return -1;
}
if (!m_bInitSuccess)
{
return -2;
}
uchar *p_indata_0 = (uchar *)inImg.data;
int class_dix = 0;
class_dix = AI_Det_In_1_Out_1_class(p_indata_0, fmaxScore);
return class_dix;
}
// 检测模型的运行参数是否合法,是否正常
int AIModel_Impl::ModelRunConfigCheck(AIModelRun_Config &runConfig)
{
// GPU 数量判断
if (runConfig.gpuconfig.GetNum() == 0)
{
return 1;
}
if (runConfig.strPath == "")
{
printf(" %s model path is error \n", runConfig.strName.c_str());
return 2;
}
if (runConfig.Stream_num <= 0)
{
runConfig.Stream_num = 1;
}
if (runConfig.Stream_num > 4)
{
runConfig.Stream_num = 4;
}
return 0;
}
// 载入模型。。。。
int AIModel_Impl::LoadEngine(int ngpuIdx)
{
std::shared_ptr<GPU_Engine> gpuEngine = std::make_shared<GPU_Engine>();
gpuEngine->engine = std::make_shared<Engine>(ngpuIdx);
gpuEngine->nGPUIdx = ngpuIdx;
if (!gpuEngine->engine)
{
printf("Engine Create error\n");
return -1;
}
// 1、加载模型
bool reload = gpuEngine->engine->loadFromFile(m_modelRun_Config.strPath);
if (!reload)
{
printf("GPU %d Load error %s\n", ngpuIdx, m_modelRun_Config.strPath.c_str());
printf("Load model error\n");
return -2;
}
printf("%s GPU %d Load succ %s\n", m_modelRun_Config.strName.c_str(), ngpuIdx, m_modelRun_Config.strPath.c_str());
// 2、 解析 egengine的 相关信息
int re = GetEngineInfo1(gpuEngine);
if (re != 0)
{
return re;
}
// 没有输入输出 节点。
if (m_modelNodeList.size() <= 0 || m_modelNodeList.size() > MAX_MODEL_NODE_NUM)
{
printf("Load model input output error\n");
return -3;
}
cudaSetDevice(ngpuIdx);
// 3、 申请显存
for (int i = 0; i < m_modelRun_Config.Stream_num; i++)
{
std::shared_ptr<Cuda_Stream_Config> cudasteam = std::make_shared<Cuda_Stream_Config>();
cudasteam->nstreamIdx = i;
if (cudaStreamCreate(&cudasteam->stream) != cudaSuccess)
{
printf("Failed to create CUDA stream\n");
return -4;
}
cudasteam->context = std::unique_ptr<nvinfer1::IExecutionContext>(
gpuEngine->engine->engine_->createExecutionContext());
// printf("----- stream %d \n", i);
// 初始化 数据 内存
for (int j = 0; j < m_modelNodeList.size(); j++)
{
std::shared_ptr<Stream_Node_Config> steamNodeconfig = std::make_shared<Stream_Node_Config>();
steamNodeconfig->nodeConfig.copy(m_modelNodeList.at(j));
cudaMalloc(&steamNodeconfig->gpu_buffers, steamNodeconfig->nodeConfig.floatsize);
cudaMalloc(&steamNodeconfig->gpu_ImgData, steamNodeconfig->nodeConfig.ucharsize);
// 分类 的模型
if (m_modelRun_Config.IsClass)
{
if (steamNodeconfig->cpu_floatData)
{
delete steamNodeconfig->cpu_floatData;
steamNodeconfig->cpu_floatData = NULL;
}
steamNodeconfig->cpu_floatData = new float[steamNodeconfig->nodeConfig.datalength];
}
printf("-----******GPU %d stream %d cuda malloc %d inOrout %d [chw] %d*%d*%d \n",
ngpuIdx, i, j, steamNodeconfig->nodeConfig.type, steamNodeconfig->nodeConfig.channel,
steamNodeconfig->nodeConfig.height, steamNodeconfig->nodeConfig.width);
if (m_modelNodeList.at(j).type == AI_Buffer_Type_INPUT)
{
if (cudasteam->pstreamNode_input_0 == nullptr)
{
cudasteam->pstreamNode_input_0 = steamNodeconfig;
}
else
{
cudasteam->pstreamNode_input_1 = steamNodeconfig;
}
}
else
{
if (cudasteam->pstreamNode_output_0 == nullptr)
{
cudasteam->pstreamNode_output_0 = steamNodeconfig;
}
else if (cudasteam->pstreamNode_output_1 == nullptr)
{
cudasteam->pstreamNode_output_1 = steamNodeconfig;
}
else
{
cudasteam->pstreamNode_output_2 = steamNodeconfig;
}
}
cudasteam->streamConfigList.push_back(steamNodeconfig);
}
gpuEngine->cudaSteams.push_back(cudasteam);
}
gpuEngine->bsucc = true;
m_GPU_Engine.push_back(gpuEngine);
return 0;
}
int AIModel_Impl::GetEngineInfo1(std::shared_ptr<GPU_Engine> &pgpuengine)
{
int nInputNum = pgpuengine->engine->getNbBindings();
m_modelNodeList.erase(m_modelNodeList.begin(), m_modelNodeList.end());
m_modelNodeList.clear();
for (int i = 0; i < nInputNum; i++)
{
Node_Config node_config;
std::string name = pgpuengine->engine->getBindingName(i);
node_config.name = name;
Dims dims = pgpuengine->engine->getBindingDims(i);
if (pgpuengine->engine->bindingIsInput(i))
{
std::cout << "Input: " << name << "\n";
node_config.type = AI_Buffer_Type_INPUT;
}
else
{
std::cout << "Output: " << name << "\n";
node_config.type = AI_Buffer_Type_OUTPUT;
}
std::cout << "dims.nbDims: " << dims.nbDims << "\n";
if (dims.nbDims == 4)
{
switch (m_modelRun_Config.inputType)
{
case Input_CHW:
node_config.channel = dims.d[1];
node_config.height = dims.d[2];
node_config.width = dims.d[3];
break;
case Input_HWC:
node_config.height = dims.d[1];
node_config.width = dims.d[2];
node_config.channel = dims.d[3];
break;
default:
node_config.channel = dims.d[1];
node_config.height = dims.d[2];
node_config.width = dims.d[3];
break;
}
}
else if (dims.nbDims == 3)
{
switch (m_modelRun_Config.inputType)
{
case Input_CHW:
node_config.channel = dims.d[0];
node_config.height = dims.d[1];
node_config.width = dims.d[2];
break;
case Input_HWC:
node_config.height = dims.d[0];
node_config.width = dims.d[1];
node_config.channel = dims.d[2];
break;
default:
node_config.channel = dims.d[0];
node_config.height = dims.d[1];
node_config.width = dims.d[2];
break;
}
}
else if (dims.nbDims == 2)
{
node_config.channel = 1;
node_config.height = dims.d[0];
node_config.width = dims.d[1];
}
else if (dims.nbDims == 1)
{
node_config.channel = 1;
node_config.height = dims.d[0];
node_config.width = 1;
}
else
{
printf("engine C H W is error\n");
return -2;
}
node_config.CalDataSize();
m_modelNodeList.push_back(node_config);
printf("dim: ");
for (int di = 0; di < dims.nbDims; di++)
{
printf(" %ld ", dims.d[di]);
}
printf(" \n");
printf("C H W [%d %d %d]\n", node_config.channel, node_config.height, node_config.width);
}
return 0;
}
int AIModel_Impl::AI_Det_In_1_Out_1(Node_Config *pConfig_in, Node_Config *pConfig_out, const unsigned char *p_indata_0, unsigned char *p_outdata_1)
{
// printf("=== s1 ");
std::shared_ptr<Det_GPU_Stram> pdetStream;
if (GetStream(pdetStream) != 0 || !pdetStream)
{
printf("AI_Det_In_1_Out_1: GetStream error \n");
return 3;
}
// printf("=== s2 ");
std::lock_guard<std::mutex> lock(pdetStream->AI_mutex);
// printf(" ss g %d s %d -- ", pdetStream->nGPUIdx, pdetStream->cuda_stream->nstreamIdx);
// // 设置 显卡ID
cudaSetDevice(pdetStream->nGPUIdx);
cudaMemcpyAsync(pdetStream->cuda_stream->pstreamNode_input_0->gpu_ImgData,
p_indata_0, pConfig_in->ucharsize, cudaMemcpyHostToDevice, pdetStream->cuda_stream->stream);
// // // 在显存中 图片数据从 uchar 转到 float
Cuda_ucharToFloat_stream((unsigned char *)pdetStream->cuda_stream->pstreamNode_input_0->gpu_ImgData,
(float *)pdetStream->cuda_stream->pstreamNode_input_0->gpu_buffers, pConfig_in->datalength, pdetStream->cuda_stream->stream);
pdetStream->cuda_stream->context->setTensorAddress(pConfig_in->name.c_str(), pdetStream->cuda_stream->pstreamNode_input_0->gpu_buffers);
pdetStream->cuda_stream->context->setTensorAddress(pConfig_out->name.c_str(), pdetStream->cuda_stream->pstreamNode_output_0->gpu_buffers);
pdetStream->cuda_stream->context->enqueueV3(pdetStream->cuda_stream->stream);
Cuda_FloatTouchar_stream((float *)pdetStream->cuda_stream->pstreamNode_output_0->gpu_buffers,
(unsigned char *)pdetStream->cuda_stream->pstreamNode_output_0->gpu_ImgData, pConfig_out->datalength, pdetStream->cuda_stream->stream);
cudaMemcpyAsync(p_outdata_1, pdetStream->cuda_stream->pstreamNode_output_0->gpu_ImgData,
pConfig_out->ucharsize, cudaMemcpyDeviceToHost, pdetStream->cuda_stream->stream);
cudaStreamSynchronize(pdetStream->cuda_stream->stream);
// printf("**ee g %d s %d ** \n", pdetStream->nGPUIdx, pdetStream->cuda_stream->nstreamIdx);
return 0;
}
int AIModel_Impl::GetStream(std::shared_ptr<Det_GPU_Stram> &pdetStream)
{
if (m_nALLStreamNum <= 0 || m_DetGPUStream.empty())
{
return 1;
}
// 多线程并发时原子轮询分配 stream
int sidx = m_nLast_GPUStreamIdx.load();
while (true)
{
int next = sidx + 1;
if (next >= m_nALLStreamNum)
{
next = 0;
}
if (m_nLast_GPUStreamIdx.compare_exchange_weak(sidx, next))
{
sidx = next;
break;
}
// CAS 失败时 sidx 已被更新为当前实际值,重新计算 next
}
pdetStream = m_DetGPUStream.at(sidx);
return 0;
}
int AIModel_Impl::AI_Det_In_1_Out_1_class(unsigned char *p_indata_0, float *fmaxScore)
{
std::shared_ptr<Det_GPU_Stram> pdetStream;
if (GetStream(pdetStream) != 0 || !pdetStream)
{
printf("AI_Det_In_1_Out_1_class: GetStream error \n");
*fmaxScore = 0.0f;
return -3;
}
// printf("=== s2 ");
std::lock_guard<std::mutex> lock(pdetStream->AI_mutex);
// printf(" ss g %d s %d -- ", pdetStream->nGPUIdx, pdetStream->cuda_stream->nstreamIdx);
// // 设置 显卡ID
std::shared_ptr<Stream_Node_Config> p_input_0 = pdetStream->cuda_stream->pstreamNode_input_0;
std::shared_ptr<Stream_Node_Config> p_output_0 = pdetStream->cuda_stream->pstreamNode_output_0;
cudaSetDevice(pdetStream->nGPUIdx);
cudaMemcpyAsync(p_input_0->gpu_ImgData, p_indata_0,
p_input_0->nodeConfig.ucharsize, cudaMemcpyHostToDevice, pdetStream->cuda_stream->stream);
// // // 在显存中 图片数据从 uchar 转到 float
Cuda_ucharToFloat_stream((unsigned char *)p_input_0->gpu_ImgData,
(float *)p_input_0->gpu_buffers, p_input_0->nodeConfig.datalength, pdetStream->cuda_stream->stream);
pdetStream->cuda_stream->context->setTensorAddress(p_input_0->nodeConfig.name.c_str(), p_input_0->gpu_buffers);
pdetStream->cuda_stream->context->setTensorAddress(p_output_0->nodeConfig.name.c_str(), p_output_0->gpu_buffers);
pdetStream->cuda_stream->context->enqueueV3(pdetStream->cuda_stream->stream);
cudaMemcpyAsync(p_output_0->cpu_floatData, p_output_0->gpu_buffers,
p_output_0->nodeConfig.floatsize, cudaMemcpyDeviceToHost, pdetStream->cuda_stream->stream);
cudaStreamSynchronize(pdetStream->cuda_stream->stream);
int label = F2softmaxId(p_output_0->cpu_floatData, p_output_0->nodeConfig.datalength, fmaxScore);
return label;
}
int AIModel_Impl::F2softmaxId(float *data, int class_num, float *fmaxScore)
{
int cls_num = class_num;
float total = 0;
for (int i = 0; i < cls_num; i++)
{
// std::cout<<"data["<<i<<"]="<<data[i]<<std::endl;
total += exp(data[i]);
}
// std::cout<<"total="<<total<<std::endl;
// std::vector<float> output;//这样才可以用push_back-但相比于=更耗时
std::vector<float> output(cls_num);
for (int i = 0; i < output.size(); i++)
{
float outi = (float)exp(data[i]) / (float)total;
output[i] = outi;
// output.push_back(outi);
// std::cout<<"output["<<i<<"]="<<output[i]<<std::endl;
}
int max_id = 0;
float max_score = 0;
for (int i = 0; i < output.size(); i++)
{
// std::cout << "output[" << i << "]=" << output[i] << std::endl;
if (output[i] > max_score)
{
max_id = i;
max_score = output[i];
}
}
*fmaxScore = max_score;
// std::cout << "F2softmaxId()----------------------------------max_score=" << max_score << std::endl; // 1023dyy
// std::cout << "F2softmaxId()----------------------------------max_id=" << max_id << std::endl; // 1023dyy
return max_id;
}