当前位置: 首页 > news >正文

tf模型在C++部署

tensorflow训练好的模型使用ONNX Runtime在C++部署

环境

  • ubuntu20.04
  • cuda 11.6
  • cudnn 8.2.4

参考链接

  • onnxruntime (C++/CUDA) 编译安装及部署
    https://blog.csdn.net/weixin_44684139/article/details/123504222
  • Ubuntu下的onnxruntime(c++)编译 https://blog.csdn.net/weixin_42990464/article/details/126636122
  • PyTorch模型C++部署
    https://blog.csdn.net/mightbxg/article/details/119237326
  • onnxruntime源码编译 https://blog.csdn.net/wuqingshan2010/article/details/106372580
  • 全网最详细 ONNXRuntime C++/Java/Python 资料 https://zhuanlan.zhihu.com/p/414317269

ONNX Runtime

ONNX (Open Neural Network Exchange) 是微软和脸书主导的深度学习开发工具生态系统,ONNX Runtime (简称 ORT) 则是微软开发的跨平台高性能机器学习训练与推理加速器,根据官方的说法推理/训练速度最高能有 17X/1.4X 的提升,其优异的性能非常适合深度学习模型部署。

克隆

git clone --recursive https://github.com/Microsoft/onnxruntime
cd onnxruntime/
git checkout v1.13.0

ONNXRuntime版本和cuda、cudnn版本要对应,具体参考官方链接:https://onnxruntime.ai/docs/execution-providers/CUDA-ExecutionProvider.html。
这里选择了1.13.0版本

ONNX RuntimeCUDAcuDNN
1.14 /1.13.1 / 1.1311.68.2.4 (Linux) / 8.5.0.96 (Windows)

编译

./build.sh --skip_tests --use_cuda --config Release --build_shared_lib --parallel --cuda_home /usr/local/cuda-11.6 --cudnn_home /usr/local/cuda-11.6

–use_cuda表示build with CUDA support,cuda_home和cudnn_home指向cuda和cudnn的安装路径

  • 注意
    编译过程中会链接其它github仓库(大概几十个),可能因为网络问题导致编译失败,需要科学上网或者手动添加镜像源
cd ${your git repo root}
cd .git
vim config

修改为:

[core]
    repositoryformatversion = 0
    filemode = true
    bare = false
    logallrefupdates = true
    ignorecase = true
    precomposeunicode = true
[remote "origin"]
    url = https://github.com.cnpmjs.org/microsoft/onnxruntime.git
    fetch = +refs/tags/v1.13.0:refs/tags/v1.13.0

编译完成,安装

cd ./build/Linux/release
make install DESTDIR=想要安装的路径

配置环境变量

# onnxruntime
export ONNX_HOME=/home/user/3rd-party/onnx/usr/local
export PATH=$PATH:$ONNX_HOME/bin
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$ONNX_HOME/lib
export LIBRARY_PATH=$LIBRARY_PATH:$ONNX_HOME/lib
export C_INCLUDE_PATH=$C_INCLUDE_PATH:$ONNX_HOME/include
export CPLUS_INCLUDE_PATH=$CPLUS_INCLUDE_PATH:$ONNX_HOME/include

测试代码

#include <iostream>
#include <vector>
#include <chrono>
#include <string>
#include <vector>
#include <onnxruntime/core/session/onnxruntime_cxx_api.h>

using namespace std;


int main()
{
    Ort::Env env(ORT_LOGGING_LEVEL_WARNING, "test");
    Ort::SessionOptions session_options;

    OrtCUDAProviderOptions cuda_options{
          0,
          OrtCudnnConvAlgoSearch::EXHAUSTIVE,
          std::numeric_limits<size_t>::max(),
          0,
          true
      };

    session_options.AppendExecutionProvider_CUDA(cuda_options);
    const char* model_path = "../model_test.onnx";

    Ort::Session session(env, model_path, session_options);
    // print model input layer (node names, types, shape etc.)
    Ort::AllocatorWithDefaultOptions allocator;

    // print number of model input nodes
    size_t num_input_nodes = session.GetInputCount();

    std::vector<const char*> input_node_names = {"input_0", "input_1"};
    std::vector<const char*> output_node_names = {"dense_2", "tf.math.multiply_2"};

    std::vector<int64_t> input_node_dims = {1, 50, 9};
    std::vector<int64_t> input_node_dims2 = {1, 50, 2};
    
    // 设置输入
    size_t input_tensor_size = 50 * 9;
    size_t input_tensor_size2 = 50 * 2;
    std::vector<float> input_tensor_values(input_tensor_size);
    std::vector<float> input_tensor_values2(input_tensor_size2);

    //测试100次所需的推理时间
    auto start = std::chrono::system_clock::now();
    for(int i=0; i<10; i++)
    {   
        // 测试每次推理所需时间
        auto start2 = std::chrono::system_clock::now();
        for (unsigned int i = 0; i < input_tensor_size; i++)
            input_tensor_values[i] = 1.f;
        for (unsigned int i = 0; i < input_tensor_size2; i++)
            input_tensor_values2[i] = 1.f;
        // create input tensor object from data values 
        auto memory_info = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault);
        auto memory_info2 = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault);
        Ort::Value input_tensor = Ort::Value::CreateTensor<float>(memory_info, input_tensor_values.data(),
                                                                input_tensor_size, input_node_dims.data(), 3);
        Ort::Value input_tensor2 = Ort::Value::CreateTensor<float>(memory_info2, input_tensor_values2.data(),
                                                                input_tensor_size2, input_node_dims2.data(), 3);
        std::vector<Ort::Value> ort_inputs;
        ort_inputs.push_back(std::move(input_tensor));
        ort_inputs.push_back(std::move(input_tensor2));
        auto output_tensors = session.Run(Ort::RunOptions{nullptr}, input_node_names.data(), ort_inputs.data(),
                                        ort_inputs.size(), output_node_names.data(), 1);
        float* floatarr = output_tensors[0].GetTensorMutableData<float>();
        for (int i=0; i<4; i++)
        {
            std::cout<<floatarr[i]<<std::endl;
        }

        auto end2 = std::chrono::system_clock::now();
        std::chrono::duration<double> elapsed_seconds2 = end2-start2;
        std::cout << "elapsed time: " << elapsed_seconds2.count() << "s\n";
    }
    auto end = std::chrono::system_clock::now();
    std::chrono::duration<double> elapsed_seconds = end-start;
    std::cout << "elapsed time: " << elapsed_seconds.count() << "s\n";

    return 0;
}

CMakeLists

cmake_minimum_required(VERSION 3.13)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_BUILD_TYPE Debug)

link_directories(
    /home/onnx/lib
)

add_executable(onnx onnx_test.cpp)
target_link_libraries(onnx onnxruntime onnxruntime_providers_shared)

相关文章:

  • 【产品经理】常用需求优先级评估模型
  • CCM调试的理论依据
  • libvirt零知识学习4 —— libvirt源码编译安装(2)
  • leetcode每日一题:1005. K 次取反后最大化的数组和
  • this\super\statis\abstract关键字作用
  • Spring Boot 3.0系列【22】应用篇之嵌入式 Servlet 容器
  • 位置编码Positional Encoding
  • 【XXL-JOB】XXL-JOB定时处理视频转码
  • 二、ModBus协议解析
  • AI绘画关键词网站推荐 :轻松获取百万个提示词!完全免费
  • Mybatis中使用in()查询
  • 关于笔记本电脑插上网线没反应的解决方案
  • 第16天-性能压测:压力测试,性能监控,优化QPS,Nginx动静分离
  • selenium + python自动化测试环境搭建
  • 金融监管科技业务中的AI应用:上市公司公告信息风险识别
  • “Material Design”设计规范在 ComponentOne For WinForm 的全新尝试!
  • 【Under-the-hood-ReactJS-Part0】React源码解读
  • Apache Zeppelin在Apache Trafodion上的可视化
  • happypack两次报错的问题
  • HTTP中GET与POST的区别 99%的错误认识
  • JavaScript中的对象个人分享
  • Java比较器对数组,集合排序
  • js作用域和this的理解
  • Laravel Mix运行时关于es2015报错解决方案
  • mysql_config not found
  • Python爬虫--- 1.3 BS4库的解析器
  • Spark RDD学习: aggregate函数
  • text-decoration与color属性
  • Vue小说阅读器(仿追书神器)
  • 警报:线上事故之CountDownLatch的威力
  • 码农张的Bug人生 - 初来乍到
  • 如何用vue打造一个移动端音乐播放器
  • 如何优雅地使用 Sublime Text
  • 小试R空间处理新库sf
  • 译米田引理
  • ​插件化DPI在商用WIFI中的价值
  • # 睡眠3秒_床上这样睡觉的人,睡眠质量多半不好
  • #if #elif #endif
  • (Git) gitignore基础使用
  • (博弈 sg入门)kiki's game -- hdu -- 2147
  • (四)TensorRT | 基于 GPU 端的 Python 推理
  • (一)插入排序
  • ./mysql.server: 没有那个文件或目录_Linux下安装MySQL出现“ls: /var/lib/mysql/*.pid: 没有那个文件或目录”...
  • .bat文件调用java类的main方法
  • .NET Core WebAPI中封装Swagger配置
  • .net core 依赖注入的基本用发
  • .NET Standard 的管理策略
  • .NET 服务 ServiceController
  • .net 重复调用webservice_Java RMI 远程调用详解,优劣势说明
  • .NET/C# 反射的的性能数据,以及高性能开发建议(反射获取 Attribute 和反射调用方法)
  • @ConfigurationProperties注解对数据的自动封装
  • []sim300 GPRS数据收发程序
  • [2024最新教程]地表最强AGI:Claude 3注册账号/登录账号/访问方法,小白教程包教包会
  • [Android 数据通信] android cmwap接入点
  • [BZOJ 1040] 骑士