caffe模型TensorRT部署实践(一)

2023-05-16

参考代码

TensorRT安装包下的samples/sampleMNIST/sampleMNIST.cpp

1.设置使用的gpu id,如果不设置,默认使用第0块。

cudaSetDevice(3); //set device id

2.定义模型的输入输出和logger

static const int INPUT_H = 299; //输入图像高
static const int INPUT_W = 299;//输入图像宽
static const int CHANNELS = 3;//输入图像通道
static const int OUTPUT_SIZE = 1536;//输出特征维度
static Logger gLogger;

const char* INPUT_BLOB_NAME = "data";//deploy文件中定义的输入层名称
const char* OUTPUT_BLOB_NAME = "pool_8x8_s2";//deploy文件中定义的输出层名称

3.定义GIE模型,并将训练好的caffe模型转换到GIE模型

// create a GIE model from the caffe model and serialize it to a stream
IHostMemory *gieModelStream{nullptr};
caffeToGIEModel("deploy.prototxt", "inceptionv4.caffemodel", std::vector < std::string > { OUTPUT_BLOB_NAME }, 1, gieModelStream);

4.准备输入图像,可以采用opencv读取,也可用其他方式,根据情况编写与处理部分,最终存入一个float*中

    float data[INPUT_H*INPUT_W*CHANNELS];

    cv::Mat im = imread("gap.jpg") ;
    cv::resize(im, im, cv::Size(INPUT_W, INPUT_H));
    int mean_data[] = {104, 117, 123}; //均值
    float *pdata = data;
    for(int c = 0; c < CHANNELS; ++c)
    {
        for(int h = 0; h < INPUT_H; ++h)
        {
            for(int w = 0; w < INPUT_W; ++w)
            {
                *pdata++ = float(im.at<Vec3b>(h,w)[c] - mean_data[c]) ;
            }
        }
    }
   

5. 反序列化前向引擎

    // deserialize the engine
    IRuntime* runtime = createInferRuntime(gLogger);
    ICudaEngine* engine = runtime->deserializeCudaEngine(gieModelStream->data(), gieModelStream->size(), nullptr);
    if (gieModelStream) gieModelStream->destroy();

6.开始前向推断

    IExecutionContext *context = engine->createExecutionContext();

    std::cout << "begin inference\n";
    // run inference
    CProTimer timet;
    float prob[OUTPUT_SIZE];
    doInference(*context, data, prob, 1);

    std::cout << "end inference " << timet.GetTime(true) << "\n";

7.释放资源并输出结果

    // destroy the engine
    context->destroy();
    engine->destroy();
    runtime->destroy();

    // print a histogram of the output distribution
    std::cout << "\n\n";
    for (unsigned int i = 0; i < OUTPUT_SIZE; i++)
    {
        std::cout << prob[i] << " ";
    }
    std::cout << std::endl;

caffeToGIEModel和doInference可参考开头给出的示例cpp。

void caffeToGIEModel(const std::string& deployFile,             // name for caffe prototxt
                     const std::string& modelFile,              // name for model
                     const std::vector<std::string>& outputs,   // network outputs
                     unsigned int maxBatchSize,                 // batch size - NB must be at least as large as the batch we want to run with)
                     IHostMemory *&gieModelStream)    // output buffer for the GIE model
{
    // create the builder
    IBuilder* builder = createInferBuilder(gLogger);

    // parse the caffe model to populate the network, then set the outputs
    INetworkDefinition* network = builder->createNetwork();
    ICaffeParser* parser = createCaffeParser();
    const IBlobNameToTensor* blobNameToTensor = parser->parse(locateFile(deployFile, directories).c_str(),
                                                              locateFile(modelFile, directories).c_str(),
                                                              *network,
                                                              nvinfer1::DataType::kFLOAT);

    // specify which tensors are outputs
    for (auto& s : outputs)
        network->markOutput(*blobNameToTensor->find(s.c_str()));

    // Build the engine
    builder->setMaxBatchSize(maxBatchSize);
    builder->setMaxWorkspaceSize(1 << 20);

    ICudaEngine* engine = builder->buildCudaEngine(*network);
    assert(engine);

    // we don't need the network any more, and we can destroy the parser
    network->destroy();
    parser->destroy();

    // serialize the engine, then close everything down
    gieModelStream = engine->serialize();
    engine->destroy();
    builder->destroy();
    shutdownProtobufLibrary();
}
void doInference(IExecutionContext& context, float* input, float* output, int batchSize)
{
    const ICudaEngine& engine = context.getEngine();
    // input and output buffer pointers that we pass to the engine - the engine requires exactly IEngine::getNbBindings(),
    // of these, but in this case we know that there is exactly one input and one output.
    assert(engine.getNbBindings() == 2);
    void* buffers[2];

    // In order to bind the buffers, we need to know the names of the input and output tensors.
    // note that indices are guaranteed to be less than IEngine::getNbBindings()
    int inputIndex = engine.getBindingIndex(INPUT_BLOB_NAME),
        outputIndex = engine.getBindingIndex(OUTPUT_BLOB_NAME);

    // create GPU buffers and a stream
    CHECK(cudaMalloc(&buffers[inputIndex], batchSize * CHANNELS * INPUT_H * INPUT_W * sizeof(float)));
    CHECK(cudaMalloc(&buffers[outputIndex], batchSize * OUTPUT_SIZE * sizeof(float)));

    cudaStream_t stream;
    CHECK(cudaStreamCreate(&stream));

    // DMA the input to the GPU,  execute the batch asynchronously, and DMA it back:
    CHECK(cudaMemcpyAsync(buffers[inputIndex], input, batchSize * CHANNELS * INPUT_H * INPUT_W * sizeof(float), cudaMemcpyHostToDevice, stream));
    context.enqueue(batchSize, buffers, stream, nullptr);
    CHECK(cudaMemcpyAsync(output, buffers[outputIndex], batchSize * OUTPUT_SIZE*sizeof(float), cudaMemcpyDeviceToHost, stream));
    cudaStreamSynchronize(stream);

    // release the stream and the buffers
    cudaStreamDestroy(stream);
    CHECK(cudaFree(buffers[inputIndex]));
    CHECK(cudaFree(buffers[outputIndex]));
}

8. 编写MakeFile文件并编译

代码需依赖cuda, cudnn 和TensorRT库,gcc版本5.3以上,其他库可根据自身需要设定

OPENCV_INC_DIR="/user/3rdparty/opencv-3.1.0/include/"
OPENCV_LIB_DIR="/user/3rdparty/opencv-3.1.0/lib/"
CUDA_INC_DIR="/user/3rdparty/cuda/include/"
CUDA_LIB_DIR="/user/3rdparty/cuda/lib64/"
CUDNN_INC_DIR="/user/3rdparty/cudnn_7.0.5/include/"
CUDNN_LIB_DIR="/user/3rdparty/cudnn_7.0.5/lib64/"
TENSORRT_INC_DIR="/user/3rdparty/TensorRT-4.0.0.3/include/"
TENSORRT_LIB_DIR="/user/3rdparty/TensorRT-4.0.0.3/lib/"

export PATH=/user/3rdparty/gcc-5.3.0/bin:$PATH

INCLUFLAGS = -I${OPENCV_INC_DIR} \
             -I${CUDA_INC_DIR} -I${CUDNN_INC_DIR}\
             -I../common/ \
             -I${TENSORRT_INC_DIR}

LIBFLAGS = -L${OPENCV_LIB_DIR} -lopencv_imgcodecs -lopencv_imgproc -lopencv_core -lopencv_highgui \
           -L${CUDA_LIB_DIR} -L${CUDNN_LIB_DIR} -lcudnn -lcublas -lcudart_static -lnvToolsExt -lcudart \
           -L${TENSORRT_LIB_DIR} -lnvinfer -lnvparsers -lnvinfer_plugin

LIBFLAGS += -lrt -ldl -lpthread

SOURCES = main.cpp  

CXXFLAGS = -Wall -std=c++11 

EXE = inceptionv4_tensorrt

OBJECTS = $(subst .c,.o,$(SOURCES:%.cpp=%.o))

all:
    g++ -o $(EXE) $(SOURCES) $(CXXFLAGS) $(INCLUFLAGS) $(LIBFLAGS)
clean:
    rm -f $(OBJECTS) $(EXE)

9.精度和速度对比

TensorRT的float32模型与原始caffe精度基本无差异,但速度快很多,单batch的平均gpu前向速度是原始caffe模型的4~5倍左右,优化还是很给力。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

caffe模型TensorRT部署实践(一) 的相关文章

随机推荐

  • C++ 通过TCP Socket实现简单Http服务器

    实现一个简单的Http服务器 xff0c 基于windows 平台 总共五个文件 HttpServer hpp HttpServer cpp Utils hpp Utils cpp main cpp Utils hpp span class
  • Java并发编程--自旋锁的实现和使用

    1 自旋锁介绍 自旋锁是这样一类锁 xff1a 当线程等待加锁时 xff0c 不会阻塞 xff0c 不会进入等待状态 xff0c 而是保持运行状态 大致的思路是 xff1a 让当前线程不停地的在循环体内执行 xff0c 当循环的条件被其他线
  • [Ubuntu] 可用云盘-尝试记录

    Ubuntu可用云盘 xff1a https github com Aruelius cloud189 说明 xff1a 这是一个调用天翼云API的开源命令行工具 xff0c 基于Python编写 xff1b 天翼云官方没有客户端支持Lin
  • 【无人机】基于遗传算法实现无人机编队位置规划附matlab代码

    1 内容介绍 现代社会的无人机成本造价低 不易损耗 轻巧灵便 易躲藏 能精确打击 目标这些特点 xff0c 使其在一些高危任务中发挥了不可替代的作用 5 无人机的用处主要有两种 xff1a 民用和军事 在民用方面 xff0c 我们可以运用无
  • 【路径规划】基于DWA实现机器人动态避障附matlab代码

    1 内容介绍 DWA 算法是基于机器人运动学与动力学理论的一种局部避障算法 xff0c 它将对机器人的位置控制转换为对机器人的速度控制 DWA 算法可以概括为三步 一是根据机器人自身的限制以及环境制约将速度的采样空间约束在一定范围内 二是根
  • 飞控pixhawk硬件框架

    本文转载于 xff1a https blog csdn net csshuke article details 78952026 xfeff xfeff 1 Phxhawk连接线路 2 Phxhawk硬件芯片列表 处理器 STM32F427
  • PCB_layout_misc

    AD的规则设置参考 https blog csdn net geek monkey article details 80249217 一些PCB厂家的工艺 嘉立创https www jlc com portal vtechnology ht
  • 怎样把经纬度坐标转换为空间直角坐标

    怎样把经纬度坐标转换为空间直角坐标 假设你的空间直角坐标以地球球心为原点 原点到北极为正z轴 原点到经纬度 0 0 为正x轴 那么纬度a 北正南负 经度b 东正西负 的空间直角坐标为 x 61 Rcos a cos b y 61 Rcos
  • APM添加参数

    APM添加参数 参考 https ardupilot org dev docs code overview adding a new parameter html 添加应用参数模块 例如 battery Parameters h k par
  • pixhawk6x/5x 电源插座/插头的型号

    型号 xff1a molex CLIK Mate 5024430670 5024390600
  • intellij idea: git tag操作 及 master branch相互合并操作

    git tag和git branches区别 xff1f tag就像是里程碑标志的一个点 branch是一个新的征程的一条线 tag是静态的 是只读的 不能修改 而branch是要往前走的 稳定版本备份用tag 新功能开发多人用branch
  • C++之STL和Boost

    最近一年我电话面试了数十位 C 43 43 应聘者 xff0c 惯用的暖场问题是 工作中使用过 STL 的哪些组件 xff1f 使用过 Boost 的哪些组件 xff1f 得到的答案大多集中在 vector map 和 shared ptr
  • ubuntu 下安装intel realsense驱动

    在安装之前一定要确保系统是ubuntu 14 04 3 64位 xff01 在安装之前一定要确保系统是ubuntu 14 04 3 64位 xff01 在安装之前一定要确保系统是ubuntu 14 04 3 64位 xff01 重要的事情说
  • windows下安装numpy,scipy遇到的问题总结

    最近开始研究3D手势识别 xff0c 下载的源码包是基于python的 xff0c 需要用到扩展包numpy scipy等 xff0c 安装过程汇总遇到的问题总结如下 xff1a 1 安装numpy 下载numpy编译包 xff0c 进入该
  • Linux大数据处理踩坑实录

    最近开发需要在linux服务器上做大数据处理 xff0c 由于对Linux开发并不是很熟悉 xff0c 因此踩了很多坑 xff0c 先作如下记录 xff1a 1 bash shell实现多进程 背景如下 需要从hadoop的hdfs上向服务
  • Deep Compression阅读理解及Caffe源码修改

    更新 xff1a 没想到这篇文章写出后有这么多人关注和索要源码 xff0c 有点受宠若惊 说来惭愧 xff0c 这个工作当时做的很粗糙 xff0c 源码修改的比较乱 xff0c 所以一直不太好拿出手 最近终于有时间整理了一下代码并开源出来了
  • Tensorflow 离线安装跳坑总结

    TensorFlow作为目前最被看好的深度学习开源框架 xff0c 又顶着Google爸爸的光环 xff0c 使得很多CNN网络的部署都基于此框架 最近开始研究GAN xff08 生成对抗网络 xff09 xff0c 鉴于大部分源码都基于T
  • ARM NEON常用函数总结

    NEON 技术是 ARM Cortex A 系列处理器的 128 位 SIMD xff08 单指令 xff0c 多数据 xff09 架构扩展 xff0c 旨在为消费性多媒体应用程序提供灵活 强大的加速功能 xff0c 从而显著改善用户体验
  • TensorRT cuda8.0 cudnn 7.0.5 tar包安装

    总体步骤参考这篇文章 https zhuanlan zhihu com p 35468450 1 准备环境 TensorRT 依赖cuda和cudnn xff0c 且根据下载的TensorRT版本 xff0c 需要严格保证cuda和cudn
  • caffe模型TensorRT部署实践(一)

    参考代码 TensorRT安装包下的samples sampleMNIST sampleMNIST cpp 1 设置使用的gpu id xff0c 如果不设置 xff0c 默认使用第0块 cudaSetDevice 3 set device