tensorrt cuda函数编写

7 篇文章 0 订阅
4 篇文章 0 订阅

cu文件的编写


cuda编程手册地址, cuda基础

.h文件的编写

#ifndef TINYTRT_DECODE_H
#define TINYTRT_DECODE_H
#include "Trt.h"
#include "utils.h"
#include "YoloLayerPlugin/YoloLayerPlugin.hpp"
using namespace std;
struct Bbox {
    int left, right, top, bottom;
    int clsId;
    float score;
};
cudaError_t decode_gpu(vector<float> input,YoloKernel yolo_kernel,vector<Detection>& output);
float my_decode(vector<float> intput,YoloKernel yolo_kernel,vector<Detection>& output);
#endif //TINYTRT_DECODE_H

可以看出decode.h只有两个函数一个是cpu段的解码,一个是gpu段的解码,可以将cpu段解码的代码写进decode.cu文件中,也可以单独写进decode.cpp中.

.cpp

#include "decode.h"
float my_Logist(float data){ return 1./(1. + exp(-data)); }
float my_decode(vector<float> intput,YoloKernel yolo_kernel,vector<Detection>& output)
{
    YoloKernel yolo=yolo_kernel;
    int stride=yolo.width*yolo.height;
    for(int i=0;i<yolo.width*yolo.height;i++)
    {
        for(int j=0;j<3;j++)
        {
            int begin_id=7*stride*j+i;
            int obj_id=begin_id+4*stride;
            float obj_prob=my_Logist(intput[obj_id]);
            if(obj_prob<0.7)
                continue;
            int class_id=-1;
            float max_prob=0.7;
            for(int k=0;k<2;k++)
            {
                float temp_prob=my_Logist(intput[begin_id+(5+k)*stride])*obj_prob;
                if(temp_prob>max_prob)
                {
                    class_id=k;
                    max_prob=temp_prob;
                }
                if(class_id>=0)
                {
                    Detection det;
                    int row=i/yolo.width;
                    int cols=i%yolo.height;
                    float a=my_Logist(intput[begin_id]);
                    float b=my_Logist(intput[begin_id+stride]);
                    det.bbox[0]=(cols+a)/yolo.width;
                    det.bbox[1]=(row+b)/yolo.height;
                    det.bbox[2]=exp(intput[begin_id+2*stride])*yolo.anchors[2*j];
                    det.bbox[3]=exp(intput[begin_id+3*stride])*yolo.anchors[2*j+1];
                    det.classId=class_id;
                    det.prob=max_prob;
                    output.emplace_back(det);
                }
            }
        }
    }
}

cpu端的解码没有什么可讲的,理解模型最后输出的是什么就可以.
模型最后的输出是一个batch*(channel*(box+1+class))yolo.wyolo.h的float数组,box指的是x,y,w,h.1代表的是这个anchor内有没有目标,class代表的是种类.

.cu

#include "decode.h"
#include "Trt.h"
#include "utils.h"
#include "math.h"
#include <iostream>
#include <fstream>
#include <cmath>
#include "../plugin/YoloLayerPlugin/YoloLayerPlugin.hpp"
__device__ float Logist1(float data){ return 1./(1. + exp(-data)); };
__global__ void caldetection(const float* input,float* output,int noelements,int yolowidth,int yoloheight,
                             const float anchors[6],int classes,int outputElem)
{
    int idx=threadIdx.x+blockDim.x*blockIdx.x;
    if(idx>noelements)return;
    int stride=yoloheight*yolowidth;
    int bnidx=idx/stride;
    int curidx=idx-bnidx*stride;
    const float* curinput=input+bnidx*(7)*stride*3;
    for(int k=0;k<3;k++)
    {
        int beginidx=(7*stride)*k+curidx;
        int objidx=beginidx+stride*4;
        float objprob=Logist1(curinput[objidx]);
        if(objprob <= 0.7)
            continue;
        int row = curidx / yolowidth;
        int cols = curidx % yolowidth;
        int classId = -1;
        float maxProb = IGNORE_THRESH;
        for (int c = 0;c<2;++c){
            float cProb =  Logist1(curinput[beginidx + (5 + c) * stride]) * objprob;
            if(cProb > maxProb){
                maxProb = cProb;
                classId = c;
            }
        }
        if(classId >= 0) {
            float *curOutput = output + bnidx*outputElem;
            int resCount = (int)atomicAdd(curOutput,1);
            char* data = (char * )curOutput + sizeof(float) + resCount*sizeof(Detection);
            Detection* det =  (Detection*)(data);
            det->bbox[0] = (cols + Logist1(curinput[beginidx]))/ yolowidth;
            det->bbox[1] = (row + Logist1(curinput[beginidx+stride]))/ yoloheight;
            det->bbox[2] = exp(curinput[beginidx+2*stride]) * anchors[2*k];
            det->bbox[3] = exp(curinput[beginidx+3*stride]) * anchors[2*k + 1];
            float tem_cla=float(classId);
            det->classId = llround(double(tem_cla));
            det->prob = maxProb;
        }
    }

}
cudaError_t decode_gpu(vector<float> input,YoloKernel yolo_kernel,vector<Detection>& output)
{
    float* temp_input;
    int input_num=input.size();
    CUDA_CHECK(cudaMalloc(&temp_input,input.size()*sizeof(float)));
    CUDA_CHECK(cudaMemcpy(temp_input,&input[0],input.size()*sizeof(float),cudaMemcpyHostToDevice));
    float* output1;
    void* devAnchor;
    size_t AnchorLen = sizeof(float)* CHECK_COUNT*2;
    CUDA_CHECK(cudaMalloc(&devAnchor,AnchorLen));
    int outputElem = 1;
    outputElem+=yolo_kernel.width*yolo_kernel.height*3*sizeof(Detection)/sizeof(float);
    CUDA_CHECK(cudaMalloc(&output1,sizeof(float)*outputElem));

    int numelem=yolo_kernel.width*yolo_kernel.height;
    CUDA_CHECK(cudaMemcpyAsync(devAnchor,yolo_kernel.anchors,AnchorLen,cudaMemcpyHostToDevice));
    caldetection<<<(yolo_kernel.width*yolo_kernel.height+512-1)/512,512>>>
    (temp_input,output1,numelem,yolo_kernel.width,yolo_kernel.height,(float *)devAnchor,2,outputElem);

    cudaError_t cudaStatus;
    cudaFree(devAnchor);
    float* out_host{};
    CUDA_CHECK(cudaMallocHost(&out_host,sizeof(float)*outputElem));

  CUDA_CHECK(cudaMemcpy(out_host,output1,sizeof(float)*outputElem,cudaMemcpyDeviceToHost));
//    printf("第一个输出%f,第二个输出%f",out_host[0],out_host[1]);

    for(int k=0;k<int(out_host[0]);k++)
    {
        Detection temp;
        temp.bbox[0]=out_host[6*k+1];
        temp.bbox[1]=out_host[6*k+2];
        temp.bbox[2]=out_host[6*k+3];
        temp.bbox[3]=out_host[6*k+4];
        temp.classId=out_host[6*k+5];
        temp.prob=out_host[6*k+6];
        output.push_back(temp);
    }
    cudaStatus = cudaGetLastError();
    if (cudaStatus != cudaSuccess) {
        std::cerr << "CUDA error " << cudaGetErrorString(cudaStatus) << " at " << __FILE__ << ":" << __LINE__ << std::endl;


    }
    return cudaGetLastError();

.cu文件中要注意,kernel函数中不能debug进去,也不能将中间结果输出到txt中查看,(目前水平是这样),因此只能靠printf调试,还是很麻烦的.
注意__device__,global,__host__的区别,__device__由gpu调用在gpu上执行,global__由cpu调用在GPU上执行.所以decode.cu的核函数为__global,再进去__global__函数前,要将cpu中的数据拷贝到gpu,还要在gpu上申请输出的空间块(这个空间要大于等于你所需要的空间)
这一块指针,空间申请之类的c++,cuda语法还要多多研究,先谈点现在简单的理解.

 float* temp_input;
    CUDA_CHECK(cudaMalloc(&temp_input,input.size()*sizeof(float)));
    CUDA_CHECK(cudaMemcpy(temp_input,&input[0],input.size()*sizeof(float),cudaMemcpyHostToDevice));
    void* devAnchor;
    size_t AnchorLen = sizeof(float)* CHECK_COUNT*2;
    CUDA_CHECK(cudaMalloc(&devAnchor,AnchorLen));
    CUDA_CHECK(cudaMemcpy(devAnchor,yolo_kernel.anchors,AnchorLen,cudaMemcpyHostToDevice));
    float* output1;
    int outputElem = 1;
    outputElem+=yolo_kernel.width*yolo_kernel.height*3*sizeof(Detection)/sizeof(float);
    CUDA_CHECK(cudaMalloc(&output1,sizeof(float)*outputElem));

关于cudaMalloc()和cudaMemcpy()函数的使用详见cuda编程手册.
注意核函数中要用到的所有host数据都要cpy到device在送入核函数.

float* out_host{};
CUDA_CHECK(cudaMallocHost(&out_host,sizeof(float)*outputElem));
CUDA_CHECK(cudaMemcpy(out_host,output1,sizeof(float)*outputElem,cudaMemcpyDeviceToHost));

这一步是将device中的值cpy到host处理,要不gpu中的值是不可见状态.

caldetection<<<(yolo_kernel.width*yolo_kernel.height+512-1)/512,512>>>
    (temp_input,output1,numelem,yolo_kernel.width,yolo_kernel.height,(float *)devAnchor,2,outputElem);

注意下kernel函数的调用,使用的是<<<block,thread>>>形式,其block,thread可以是一维,也可以是二维,每个的idx是确认好的.核函数简单理解就是同时进行很多for循环,这一部分还要多看多写.

cudaFree(devAnchor)
cudaFree(output1);
cudaFreeHost(out_host);

最后使用完要记得释放指针,避免报段错误.

int nByte=sizeof(float)*nElem;
float *res_h=(float*)malloc(nByte);
memset(res_h,0,nByte);
free(res_h);

常见的c++内存拷贝

float *curOutput = output + bnidx*outputElem;
int resCount = (int)atomicAdd(curOutput,1);
char* data = (char * )curOutput + sizeof(float) + resCount*sizeof(Detection);
Detection* det =  (Detection*)(data);
det->bbox[0] = (cols + Logist1(curinput[beginidx]))/ yolowidth;

注意下atomicADD()的使用,大概是用来多线程计数的.指针数组申请时一定要分配空间块大小及地址.还有强制类型转换的用法.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小涵涵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值