开放能力
开发平台
行业应用
生态合作
开发与教学
资讯 社区 控制台
技术能力
语音技术
图像技术
文字识别
人脸与人体识别
视频技术
AR与VR
自然语言处理
知识图谱
数据智能
场景方案
部署方案
行业应用
智能教育
智能医疗
智能零售
智能工业
企业服务
智能政务
智能农业
信息服务
智能园区
智能硬件
EasyDL零门槛AI开发平台

    目标跟踪服务器端SDK集成文档-Linux-C++

    简介

    本文档介绍EasyEdge/EasyDL的Linux CPP SDK的使用方法。

    • 网络类型支持:图像分类,物体检测,图像分割,目标追踪
    • 硬件支持:

      • CPU 基础版: - x86_64 - 龙芯loongarch64 - 飞腾aarch64
      • CPU 加速版 - Intel Xeon with Intel®AVX2 and AVX512 - Intel Core Processors with AVX2 - Intel Atom Processors with SSE - AMD Core Processors with AVX2
      • NVIDIA GPU: x86_64 PC
      • 寒武纪 Cambricon MLU270
      • 比特大陆计算卡SC5+
    • 操作系统支持:Linux

    根据开发者的选择,实际下载的版本可能是以下版本之一:

    • EasyDL图像

      • x86 CPU 基础版
      • x86 CPU 加速版
      • Nvidia GPU 基础版
      • Nvidia GPU 加速版
      • x86 mlu270基础版
      • x86 SC5+基础版

    性能数据参考算法性能及适配硬件

    Release Notes

    时间 版本 说明
    2021.10.20 1.3.4 CPU加速版推理引擎优化升级,新增支持飞腾CPU、龙芯CPU服务器、比特大陆计算卡SC5+ BM1684、寒武纪MLU270;大幅提升EasyDL GPU加速版有损压缩加速模型的推理速度
    2021.08.19 1.3.2 CPU、GPU普通版及无损加速版新增支持EasyDL小目标检测,CPU普通版、GPU普通版支持检测模型的batch预测
    2021.06.29 1.3.1 CPU普通版、GPU普通版支持分类模型的batch预测,CPU加速版支持分类、检测模型的batch预测;GPU加速版支持CUDA11.1;视频流解析支持调整分辨率;预测引擎升级
    2021.05.13 1.3.0 新增视频流接入支持;模型发布新增多种加速方案选择;目标追踪支持x86平台的CPU、GPU加速版;展示已发布模型性能评估报告
    2021.03.09 1.2.1 GPU新增目标追踪支持, http server服务支持图片通过base64格式调用,EasyDL高性能检测模型和均衡检测模型CPU加速版新增量化压缩模型
    2021.01.27 1.1.0 EasyDL经典版分类高性能模型升级;部分SDK不再需要单独安装OpenCV
    2020.12.18 1.0.0 1.0版本发布!安全加固升级、性能优化、引擎升级、接口优化等多项更新
    2020.11.26 0.5.8 EasyDL经典版分类模型CPU加速版里新增量化压缩模型
    2020.10.29 0.5.7 新增CPU加速版支持:EasyDL经典版高精度、超高精度物体检测模型和EasyDL经典版图像分割模型
    2020.09.17 0.5.6 性能优化,支持更多模型
    2020.08.11 0.5.5 提升预测速度;支持百度昆仑芯片
    2020.05.15 0.5.3 优化性能,支持专业版更多模型
    2020.04.16 0.5.2 支持CPU加速版;CPU基础版引擎升级;GPU加速版支持多卡多线程
    2020.03.12 0.5.0 x86引擎升级;更新本地http服务接口;GPU加速版提速,支持批量图片推理
    2020.01.16 0.4.7 ARM引擎升级;增加推荐阈值支持
    2019.12.26 0.4.6 支持海思NNIE
    2019.11.02 0.4.5 移除curl依赖;支持自动编译OpenCV;支持EasyDL 专业版 Yolov3; 支持EasyDL经典版高精度物体检测模型升级
    2019.10.25 0.4.4 ARM引擎升级,性能提升30%; 支持EasyDL专业版模型
    2019.09.23 0.4.3 增加海思NNIE加速芯片支持
    2019.08.30 0.4.2 ARM引擎升级;支持分类高性能与高精度模型
    2019.07.25 0.4.1 引擎升级,性能提升
    2019.07.25 0.4.0 支持Xeye, 细节完善
    2019.06.11 0.3.3 paddle引擎升级;性能提升
    2019.05.16 0.3.2 新增NVIDIA GPU支持;新增armv7l支持
    2019.04.25 0.3.1 优化硬件支持
    2019.03.29 0.3.0 ARM64 支持;效果提升
    2019.02.20 0.2.1 paddle引擎支持;效果提升
    2018.11.30 0.1.0 第一版!

    2020-12-18: 【接口升级】 参数配置接口从1.0.0版本开始已升级为新接口,以前的方式被置为deprecated,并将在未来的版本中移除。请尽快考虑升级为新的接口方式,具体使用方式可以参考下文介绍以及demo工程示例,谢谢。

    快速开始

    SDK在以下环境中测试通过

    • x86_64, Ubuntu 16.04, gcc 5.4
    • x86_64, Ubuntu 18.04, gcc 7.4
    • Tesla P4, Ubuntu 16.04, cuda 9.0, cudnn 7.5
    • x86_64, Ubuntu 16.04, gcc 5.4, XTCL r1.0
    • aarch64, Kylin V10, gcc 7.3
    • loongarch64, Kylin V10, gcc 8.3
    • Bitmain SC5+ BM1684, Ubuntu 18.04, gcc 5.4
    • x86_64 MLU270,Ubuntu 18.04, gcc7.5

    依赖包括

    • cmake 3+
    • gcc 5.4 (需包含 GLIBCXX_3.4.22) ,gcc / glibc版本请以实际SDK ldd的结果为准
    • opencv3.4.11 (可选)
    • cuda9.0_cudnn7 (使用NVIDIA-GPU时必须)
    • XTCL 1.0.0.187 (使用昆仑服务器时必须)

    1. 安装依赖

    以下步骤均可选,请开发者根据实际运行环境选择安装。

    (可选) 安装cuda&cudnn

    在NVIDIA GPU上运行必须(包括GPU基础版,GPU加速版)

    对于GPU基础版,若开发者需求不同的依赖版本,请在PaddlePaddle官网 下载对应版本的libpaddle_fluid.so或参考其文档进行编译,覆盖lib文件夹下的相关库文件。

    (可选) 安装TensorRT

    在NVIDIA GPU上运行GPU加速版必须

    下载包中提供了对应 cuda9.0、cuda10.0、cuda10.2、cuda11.0和cuda11.1 五个版本的 SDK,cuda9.0 和 cuda10.0 的 SDK 默认依赖的 TensorRT 版本为 TensorRT7.0.0.11,cuda10.2 和 cuda11.0 的 SDK 默认依赖的 TensorRT 版本为 TensorRT7.1.3.4,cuda11.1 的 SDK 默认依赖的 TensorRT 版本为 TensorRT7.2.3.4,请在这里下载对应 cuda 版本的 TensorRT,并把其中的lib文件拷贝到系统lib目录,或其他目录并设置环境变量。

    (可选) 安装XTCL

    使用昆仑服务器及对应SDK时必须 请安装与1.0.0.187版本兼容的XTCL。必要时,请将运行库路径添加到环境变量。

    2. 使用序列号激活

    在控制台获取的序列号请通过参数配置结构体EdgePredictorConfig的成员函数set_config(easyedge::params::PREDICTOR_KEY_SERIAL_NUM, "this-is-serial-num")设置。

    具体请参考SDK自带的Demo.cpp文件的使用方法。

    3. 测试Demo

    模型资源文件默认已经打包在开发者下载的SDK包中。Demo工程直接编译即可运行。

    请先将tar包整体拷贝到具体运行的设备中,再解压缩编译; 在Intel CPU上运行CPU加速版,如果thirdparty里包含openvino文件夹的,必须在编译或运行demo程序前执行以下命令: source ${cpp_kit位置路径}/thirdparty/openvino/bin/setupvars.sh

    请在官网获取序列号,填写在demo.cpp

    部分SDK中已经包含预先编译的二进制,如 bin/easyedge_demo, bin/easyedge_serving,配置LD_LIBRARY_PATH后,可直接运行: LD_LIBRARY_PATH=../lib ./bin/easyedge_serving

    编译运行:

    cd src
    mkdir build && cd build
    cmake .. && make
    ./easyedge_image_inference {模型RES文件夹}  {测试图片路径}
    # 如果是NNIE引擎,使用sudo运行
    sudo ./easyedge_image_inference {模型RES文件夹}  {测试图片路径}

    如果希望SDK自动编译安装所需要的OpenCV库,修改cmake的optionEDGE_BUILD_OPENCVON即可。 SDK会自动从网络下载opencv源码,并编译需要的module、链接。注意,此功能必须需联网。

    cmake -DEDGE_BUILD_OPENCV=ON

    若需自定义library search path或者gcc路径,修改CMakeList.txt即可。

    demo运行效果:

     > ./easyedge_image_inference ../../../../RES 2.jpeg
    2019-02-13 16:46:12,659 INFO [EasyEdge] [easyedge.cpp:34] 140606189016192 Baidu EasyEdge Linux Development Kit 0.2.1(20190213)
    2019-02-13 16:46:14,083 INFO [EasyEdge] [paddlev2_edge_predictor.cpp:60] 140606189016192 Allocate graph success.
    2019-02-13 16:46:14,326 DEBUG [EasyEdge] [paddlev2_edge_predictor.cpp:143] 140606189016192 Inference costs 168 ms
    1, 1:txt_frame, p:0.994905 loc: 0.168161, 0.153654, 0.920856, 0.779621
    Done

    对于支持批量预测的模型和SDK,可在使用前修改demo_image_inference或demo_batch_inference里的batch_size再编译、执行。

    详情请参考下方使用说明-其他配置部分

    4. 测试Demo HTTP 服务

    编译demo完成之后,会同时生成一个http服务 运行

    # ./easyedge_serving {res_dir} {serial_key} {host, default 0.0.0.0} {port, default 24401}
     ./easyedge_serving ../../../RES "1111-1111-1111-1111" 0.0.0.0  24401

    后,日志中会显示

    HTTP is now serving at 0.0.0.0:24401

    字样,此时,开发者可以打开浏览器,http://{设备ip}:24401,选择图片来进行测试。

    对于目标追踪的模型,请选择一段视频,并耐心等待结果

    图片

    同时,可以调用HTTP接口来访问服务,具体参考下文接口说明。

    使用说明

    使用该方式,将运行库嵌入到开发者的程序当中。

    使用流程

    请优先参考Demo的使用流程。遇到错误,请优先参考文件中的注释解释,以及日志说明。

        // step 1: 配置模型资源目录
        EdgePredictorConfig config;
        config.model_dir = {模型文件目录};
        
        // step 2: 创建并初始化Predictor;在这里选择合适的引擎
        auto predictor = global_controller()->CreateEdgePredictor(config);
    
    
        // step 3-1: 预测图像
        auto img = cv::imread({图片路径});
        std::vector<EdgeResultData> results;
        predictor->infer(img, results);
    	
    	// step 3-2: 预测视频
    	std::vector<EdgeResultData> results;
    	FrameTensor frame_tensor;
        VideoConfig video_config;
        video_config.source_type = static_cast<SourceType>(video_type);  // source_type 定义参考头文件 easyedge_video.h
        video_config.source_value = video_src;
        /*
        ... more video_configs, 根据需要配置video_config的各选项
        */
        auto video_decoding = CreateVideoDecoding(video_config);
        while (video_decoding->next(frame_tensor) == EDGE_OK) {
            results.clear();
            if (frame_tensor.is_needed) {
                predictor->infer(frame_tensor.frame, results);
                render(frame_tensor.frame, results, predictor->model_info().kind);
            }
            //video_decoding->display(frame_tensor); // 显示当前frame,需在video_config中开启配置
            //video_decoding->save(frame_tensor); // 存储当前frame到视频,需在video_config中开启配置
        }

    输入图片不限制大小

    SDK参数配置

    SDK的参数通过EdgePredictorConfig::set_configglobal_controller()->set_config配置。set_config的所有key在easyedge_xxxx_config.h中。其中

    • PREDICTOR前缀的key是不同模型相关的配置,通过EdgePredictorConfig::set_config设置
    • CONTROLLER前缀的key是整个SDK的全局配置,通过global_controller()->set_config设置

    以序列号为例,KEY的说明如下:

    /**
     * @brief 序列号设置;序列号不设置留空时,SDK将会自动尝试使用本地已经激活成功的有效期内的序列号
     * 值类型:string
     * 默认值:空
     */
    static constexpr auto PREDICTOR_KEY_SERIAL_NUM = "PREDICTOR_KEY_SERIAL_NUM";

    使用方法如下:

    EdgePredictorConfig config;
    config.model_dir = ...;
    config.set_config(params::PREDICTOR_KEY_SERIAL_NUM, "1DB7-1111-1111-D27D");

    具体支持的运行参数配置列表可以参考开发工具包中的头文件的详细说明。

    相关配置均可以通过环境变量的方法来设置,对应的key名称加上前缀EDGE_即为环境变量的key。如序列号配置的环境变量key为EDGE_PREDICTOR_KEY_SERIAL_NUM,如指定CPU线程数的环境变量key为EDGE_PREDICTOR_KEY_CPU_THREADS_NUM。 注意:通过代码设置的配置会覆盖通过环境变量设置的值。

    初始化

    • 接口
    auto predictor = global_controller()->CreateEdgePredictor(config);
    predictor->init();

    若返回非0,请查看输出日志排查错误原因。

    预测图像

    • 接口
     /**
      * @brief
      * 通用接口
      * @param image: must be BGR , HWC format (opencv default)
      * @param result
      * @return
      */
     virtual int infer(
             cv::Mat& image, std::vector<EdgeResultData>& result
     ) = 0;
    
     /**
      * @brief
      * 批量图片推理接口
      * @param image: must be BGR , HWC format (opencv default)
      * @param result
      * @return
      */
     virtual int infer(
             std::vector<cv::Mat>& image, std::vector<std::vector<EdgeResultData>>& result
     ) = 0;

    图片的格式务必为opencv默认的BGR, HWC格式。

    • 返回格式

    EdgeResultData中可以获取对应的分类信息、位置信息。

    struct EdgeResultData {
        int index;  // 分类结果的index
        std::string label;  // 分类结果的label
        float prob;  // 置信度
    
        // 物体检测、图像分割时才有意义
        float x1, y1, x2, y2;  // (x1, y1): 左上角, (x2, y2): 右下角; 均为0~1的长宽比例值。
    
        // 图像分割的模型,该字段才有意义
        // 请注意:图像分割时,以下两个字段会比较大,使用完成之后请及时释放EdgeResultData
        cv::Mat mask;  // 0, 1 的mask
        std::string mask_rle;  // Run Length Encoding,游程编码的mask
    
        // 目标追踪模型,该字段才有意义
        int trackid;  // 轨迹id
        int frame;  // 处于视频中的第几帧
        EdgeTrackStat track_stat;  // 跟踪状态
    };

    关于矩形坐标

    x1 * 图片宽度 = 检测框的左上角的横坐标

    y1 * 图片高度 = 检测框的左上角的纵坐标

    x2 * 图片宽度 = 检测框的右下角的横坐标

    y2 * 图片高度 = 检测框的右下角的纵坐标

    关于图像分割mask

    cv::Mat mask为图像掩码的二维数组
    {
      {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
      {0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
      {0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
      {0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
      {0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
      {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    }
    其中1代表为目标区域,0代表非目标区域

    关于图像分割mask_rle

    该字段返回了mask的游程编码,解析方式可参考 http demo

    以上字段可以参考demo文件中使用opencv绘制的逻辑进行解析

    预测视频

    SDK 提供了支持摄像头读取、视频文件和网络视频流的解析工具类VideoDecoding,此类提供了获取视频帧数据的便利函数。通过VideoConfig结构体可以控制视频/摄像头的解析策略、抽帧策略、分辨率调整、结果视频存储等功能。对于抽取到的视频帧可以直接作为SDK infer 接口的参数进行预测。

    • 接口

    classVideoDecoding

        /**
         * @brief 获取输入源的下一帧
         * @param frame_tensor
         * @return
         */
        virtual int next(FrameTensor &frame_tensor) = 0;
    
        /**
         * @brief 显示当前frame_tensor中的视频帧
         * @param frame_tensor
         * @return
         */
        virtual int display(const FrameTensor &frame_tensor) = 0;
    
        /**
         * @brief 将当前frame_tensor中的视频帧写为本地视频文件
         * @param frame_tensor
         * @return
         */
        virtual int save(FrameTensor &frame_tensor) = 0;
    
        /**
         * @brief 获取视频的fps属性
         * @return
         */
        virtual int get_fps() = 0;
         /**
          * @brief 获取视频的width属性
          * @return
          */
        virtual int get_width() = 0;
    
        /**
         * @brief 获取视频的height属性
         * @return
         */
        virtual int get_height() = 0;

    struct VideoConfig

    /**
     * @brief 视频源、抽帧策略、存储策略的设置选项
     */
    struct VideoConfig {
        SourceType source_type;            // 输入源类型
        std::string source_value;          // 输入源地址,如视频文件路径、摄像头index、网络流地址
        int skip_frames{0};                // 设置跳帧,每隔skip_frames帧抽取一帧,并把该抽取帧的is_needed置为true
        int retrieve_all{false};           // 是否抽取所有frame以便于作为显示和存储,对于不满足skip_frames策略的frame,把所抽取帧的is_needed置为false
        int input_fps{0};                  // 在采取抽帧之前设置视频的fps
        Resolution resolution{Resolution::kAuto}; // 采样分辨率,只对camera有效
    
        bool enable_display{false};
        std::string window_name{"EasyEdge"};
        bool display_all{false};           // 是否显示所有frame,若为false,仅显示根据skip_frames抽取的frame
    
        bool enable_save{false};
        std::string save_path;             // frame存储为视频文件的路径
        bool save_all{false};              // 是否存储所有frame,若为false,仅存储根据skip_frames抽取的frame
    
        std::map::string, std::string> conf;
    };

    source_type:输入源类型,支持视频文件、摄像头、网络视频流三种,值分别为1、2、3。 source_value: 若source_type为视频文件,该值为指向视频文件的完整路径;若source_type为摄像头,该值为摄像头的index,如对于/dev/video0的摄像头,则index为0;若source_type为网络视频流,则为该视频流的完整地址。 skip_frames:设置跳帧,每隔skip_frames帧抽取一帧,并把该抽取帧的is_needed置为true,标记为is_needed的帧是用来做预测的帧。反之,直接跳过该帧,不经过预测。 retrieve_all:若置该项为true,则无论是否设置跳帧,所有的帧都会被抽取返回,以作为显示或存储用。 input_fps:用于抽帧前设置fps。 resolution:设置摄像头采样的分辨率,其值请参考easyedge_video.h中的定义,注意该分辨率调整仅对输入源为摄像头时有效。 conf:高级选项。部分配置会通过该map来设置。

    注意:

    1. 如果使用VideoConfigdisplay功能,需要自行编译带有GTK选项的opencv,默认打包的opencv不包含此项。
    2. 使用摄像头抽帧时,如果通过resolution设置了分辨率调整,但是不起作用,请添加如下选项:
    video_config.conf["backend"] = "2";

    3.部分设备上的CSI摄像头尚未兼容,如遇到问题,可以通过工单、QQ交流群或微信交流群反馈。

    具体接口调用流程,可以参考SDK中的demo_video_inference

    设置序列号

    请在网页控制台中申请序列号,并在init初始化前设置。 LinuxSDK 首次使用需联网授权。

    EdgePredictorConfig config;
    config.set_config(easyedge::params::PREDICTOR_KEY_SERIAL_NUM, "this-is-serial-num");

    日志配置

    设置 EdgeLogConfig 的相关参数。具体含义参考文件中的注释说明。

    EdgeLogConfig log_config;
    log_config.enable_debug = true;
    global_controller()->set_log_config(log_config);

    http服务

    1. 开启http服务

    http服务的启动可以参考demo_serving.cpp文件。

     /**
         * @brief 开启一个简单的demo http服务。
         * 该方法会block直到收到sigint/sigterm。
         * http服务里,图片的解码运行在cpu之上,可能会降低推理速度。
         * @tparam ConfigT
         * @param config
         * @param host
         * @param port
         * @param service_id service_id  user parameter, uri '/get/service_id' will respond this value with 'text/plain'
         * @param instance_num 实例数量,根据内存/显存/时延要求调整
         * @return
         */
        template<typename ConfigT>
        int start_http_server(
                const ConfigT &config,
                const std::string &host,
                int port,
                const std::string &service_id,
                int instance_num = 1);

    2. 请求http服务

    开发者可以打开浏览器,http://{设备ip}:24401,选择图片或视频来进行测试。

    http 请求方式一:无额外编码
    • 图片测试:不使用图片base64格式

    URL中的get参数:

    参数 说明 默认值
    threshold 阈值过滤, 0~1 如不提供,则会使用模型的推荐阈值

    HTTP POST Body即为图片的二进制内容(无需base64, 无需json)

    Python请求示例

    import requests
    
    with open('./1.jpg', 'rb') as f:
        img_data = f.read()
        result = requests.post(
    	    'http://127.0.0.1:24401/',
    	    params={'threshold': 0.1},
    	    data=img_data).json()

    Java请求示例

    • 视频测试

    Python请求示例 (注意:区别于图片预测,需指定Content-Type;否则会调用图片推理接口)

    import requests
    
    with open('./1.mp4', 'rb') as f:
        video_data = f.read()
        result = requests.post(
    	    'http://127.0.0.1:24401/',
    	    params={'threshold': 0.1},
    	    headers={'Content-Type': 'video'},
    	    data=video_data).json()
    http 请求方法二:图片使用base64格式

    HTTP方法:POST Header如下:

    参数
    Content-Type application/json

    Body请求填写

    • 分类网络: body 中请求示例
    {
    	"image": "<base64数据>"
    	"top_num": 5
    }

    body中参数详情

    参数 是否必选 类型 可选值范围 说明
    image string - 图像数据,base64编码,要求base64图片编码后大小不超过4M,最短边至少15px,最长边最大4096px,支持jpg/png/bmp格式 注意去掉头部
    top_num number - 返回分类数量,不填该参数,则默认返回全部分类结果
    • 检测和分割网络: Body请求示例:
    {
    	"image": "<base64数据>"
    }

    body中参数详情:

    参数 是否必选 类型 可选值范围 说明
    image string - 图像数据,base64编码,要求base64图片编码后大小不超过4M,最短边至少15px,最长边最大4096px,支持jpg/png/bmp格式 注意去掉头部
    threshold number - 默认为推荐阈值,也可自行根据需要进行设置

    http 返回数据

    字段 类型说明 其他
    error_code Number 0为成功,非0参考message获得具体错误信息
    results Array 内容为具体的识别结果。其中字段的具体含义请参考预测图像-返回格式一节
    cost_ms Number 预测耗时ms,不含网络交互时间

    返回示例

    {
        "cost_ms": 52,
        "error_code": 0,
        "results": [
            {
                "confidence": 0.94482421875,
                "index": 1,
                "label": "IronMan",
                "x1": 0.059185408055782318,
                "x2": 0.18795496225357056,
                "y1": 0.14762254059314728,
                "y2": 0.52510076761245728
            },
            {
                "confidence": 0.94091796875,
                "index": 1,
                "label": "IronMan",
                "x1": 0.79151463508605957,
                "x2": 0.92310667037963867,
                "y1": 0.045728668570518494,
                "y2": 0.42920106649398804
            }
          ]
    }

    其他配置

    1. 日志名称、HTTP 网页标题设置

    通过global_controller的set_config方法设置:

    global_controller()->set_config(easyedge::params::CONTROLLER_KEY_LOG_BRAND, "MY_BRAND");

    效果如下: 图片

    2. CPU线程数设置

    CPU线程数可通过 EdgePredictorConfig::set_config配置

    EdgePredictorConfig config;
    config.set_config(easyedge::params::PREDICTOR_KEY_CPU_THREADS_NUM, 4);

    3. 批量预测设置

    int batch_size = 2; // 使用前修改batch_size再编译、执行
    while (get_next_batch(imgs, img_files, batch_size, start_index)) {
        ...
    }

    GPU 加速版

    预测接口

    GPU 加速版 SDK 除了支持上面介绍的通用接口外,还支持图片的批量预测,预测接口如下:

     /**
      * @brief
      * GPU加速版批量图片推理接口
      * @param image: must be BGR , HWC format (opencv default)
      * @param result
      * @return
      */
     virtual int infer(
             std::vector<cv::Mat>& image,
             std::vector<std::vector<EdgeResultData>>& result
     ) = 0;
    
    /**
      * @brief
      * GPU加速版批量图片推理接口,带阈值
      * @related infer(cv::Mat & image, EdgeColorFormat origin_color_format, std::vector<EdgeResultData> &result, float threshold)
      */
    virtual int infer(
                std::vector<cv::Mat> &images,
                EdgeColorFormat origin_color_format,
                std::vector<std::vector<EdgeResultData>> &results,
                float threshold
    ) = 0;

    批量图片的预测接口的使用要求在调用 init 接口的时候设置一个有效的 PREDICTOR_KEY_GTURBO_MAX_BATCH_SIZE,其含义见下方参数配置接口的介绍。

    运行参数选项

    在上面的内容中我们介绍了如何使用EdgePredictorConfig进行运行参数的配置。针对GPU加速版开发工具包,目前EdgePredictorConfig的运行参数所支持的Key包括如下项:

    /**
     * @brief 当有同类型的多个设备的时候,使用哪一个设备,如:
     * GPU: 使用哪张GPU卡
     * EdgeBoard(VMX),Movidius NCS :使用哪一张加速卡
     * 值类型:int
     * 默认值:0
     */
    static constexpr auto PREDICTOR_KEY_DEVICE_ID = "PREDICTOR_KEY_DEVICE_ID";
    
    /**
     * @brief 生成最大 batch_size 为 max_batch_size 的优化模型,单次预测图片数量可以小于或等于此值
     * 值类型: int
     * 默认值:4
     */
    static constexpr auto PREDICTOR_KEY_GTURBO_MAX_BATCH_SIZE = "PREDICTOR_KEY_GTURBO_MAX_BATCH_SIZE";
    
    /**
     * @brief 设置device对应的GPU卡可以支持的最大并发量
     * 实际预测的时候对应GPU卡的最大并发量不超过这里设置的范围,否则预测请求会排队等待预测执行
     * 值类型: int
     * 默认值:1
     */
    static constexpr auto PREDICTOR_KEY_GTURBO_MAX_CONCURRENCY = "PREDICTOR_KEY_GTURBO_MAX_CONCURRENCY";
    
    /**
     * @brief 是否开启fp16模式预测,开启后预测速度会更快,但精度会略有降低。并且需要硬件支持fp16
     * 值类型: bool
     * 默认值:false
     */
    static constexpr auto PREDICTOR_KEY_GTURBO_FP16 = "PREDICTOR_KEY_GTURBO_FP16";
    
    /**
     * @brief 模型编译等级
     * 1:如果当前max_batch_size与历史编译产出的max_batch_size不相等时,则重新编译模型(推荐)
     * 2:无论历史编译产出的max_batch_size为多少,均根据当前max_batch_size重新编译模型
     * 值类型: int
     * 默认值:1
     */
    static constexpr auto PREDICTOR_KEY_GTURBO_COMPILE_LEVEL = "PREDICTOR_KEY_GTURBO_COMPILE_LEVEL";
    
    /**
     * @brief GPU工作空间大小设置
     * workspace_size = workspace_prefix * (1 << workspace_offset)
     * workspace_offset: 10 = KB, 20 = MB, 30 = GB
     * 值类型: int
     * 默认值:WORKSPACE_PREFIX: 100, WORKSPACE_OFFSET: 20,即100MB
     */
    static constexpr auto PREDICTOR_KEY_GTURBO_WORKSPACE_PREFIX = "PREDICTOR_KEY_GTURBO_WORKSPACE_PREFIX";
    static constexpr auto PREDICTOR_KEY_GTURBO_WORKSPACE_OFFSET = "PREDICTOR_KEY_GTURBO_WORKSPACE_OFFSET";
    
    /**
     * @brief 需要使用的dla core
     * 值类型: int
     * 默认值:-1(不使用)
     */
    static constexpr auto PREDICTOR_KEY_GTURBO_DLA_CORE = "PREDICTOR_KEY_GTURBO_DLA_CORE";
    
    /**
     * @brief 自定义缓存文件命名,默认即可
     * 值类型: string
     * 默认值: 根据配置自动生成
     */
    static constexpr auto PREDICTOR_KEY_GTURBO_CACHE_NAME = "PREDICTOR_KEY_GTURBO_CACHE_NAME";
    
    /**
     * @brief 序列号设置;序列号不设置留空时,SDK将会自动尝试使用本地已经激活成功的有效期内的序列号
     * 值类型:string
     * 默认值:空
     */
    static constexpr auto PREDICTOR_KEY_SERIAL_NUM = "PREDICTOR_KEY_SERIAL_NUM";

    PREDICTOR_KEY_GTURBO_CACHE_NAME:首次加载模型会先对模型进行编译优化,通过此值可以设置优化后的产出文件名,这在多进程加载同一个模型的时候是有用的。

    PREDICTOR_KEY_GTURBO_WORKSPACE_PREFIXPREDICTOR_KEY_GTURBO_WORKSPACE_OFFSET:设置运行时可以被用来使用的最大临时显存。

    PREDICTOR_KEY_GTURBO_MAX_BATCH_SIZE:此值用来控制批量图片预测可以支持的最大图片数,实际预测的时候单次预测图片数不可大于此值,但可以是不大于此值的任意图片数。

    PREDICTOR_KEY_DEVICE_ID:设置需要使用的 GPU 卡号。

    PREDICTOR_KEY_GTURBO_COMPILE_LEVEL:模型编译等级。通常模型的编译会比较慢,但编译产出是可以复用的。可以在第一次加载模型的时候设置合理的 max_batch_size 并在之后加载模型的时候直接使用历史编译产出。是否使用历史编译产出可以通过此值 compile_level 来控制。当此值为 0 时,表示忽略当前设置的 max_batch_size 而仅使用历史产出(无历史产出时则编译模型);当此值为 1 时,会比较历史产出和当前设置的 max_batch_size 是否相等,如不等,则重新编译;当此值为 2 时,无论如何都会重新编译模型。

    PREDICTOR_KEY_GTURBO_MAX_CONCURRENCY:通过此值设置单张 GPU 卡上可以支持的最大 infer 并发量,其上限取决于硬件限制。init 接口会根据此值预分配 GPU 资源,建议结合实际使用控制此值,使用多少则设置多少。注意:此值的增加会降低单次 infer 的速度,建议优先考虑 batch inference 和 multi predictor。

    PREDICTOR_KEY_GTURBO_FP16:默认是 fp32 模式,置 true 可以开启 fp16 模式预测,预测速度会有所提升,但精度也会略微下降,权衡使用。注意:不是所有模型都支持 fp16 模式。目前已知不支持fp16的模型包括:图像分类高精度模型。

    多线程预测

    GPU 加速版 SDK 的多线程分为单卡多线程和多卡多线程两种。 单卡多线程:创建一个 predictor,并通过 PREDICTOR_KEY_GTURBO_MAX_CONCURRENCY 控制单卡所支持的最大并发量,只需要 init 一次,多线程调用 infer 接口。 多卡多线程:多卡的支持是通过创建多个 predictor,每个 predictor 对应一张 GPU 卡,predictor 的创建和 init 的调用放在主线程,通过多线程的方式调用 infer 接口。

    已知问题

    1. 多线程时图片按线程分配不均 或 不同batch size的图片交叉调用infer接口时,部分结果错误 A:EasyDL图像分类高精度模型在有些显卡上可能存在此问题,可以考虑填充假图片数据到图片比较少的线程或batch以使得infer间的图片绝对平均。

    2. 显存持续增长或遇到 terminate called after throwing an instance of 'std::runtime_error' what(): Failed to create object A:部分显卡存在此问题,如果遇到此问题,请确认没有频繁调用 init 接口,通常调用 infer 接口即可满足需求。

    3. 开启 fp16 后,预测结果错误 A:不是所有模型都支持 fp16 模式。目前已知的不支持fp16的模型包括:图像分类高精度模型。目前不支持的将会在后面的版本陆续支持。

    昆仑服务器

    昆仑服务器SDK支持将EasyDL的模型部署到昆仑服务器上。SDK提供的接口风格一致,简单易用,轻松实现快速部署。Demo的测试可参考上文中的测试Demo部分。

    参数配置接口

    在上面的内容中我们介绍了如何使用EdgePredictorConfig进行运行参数的配置。针对昆仑服务器开发工具包,目前EdgePredictorConfig的运行参数所支持的Key包括如下项:

    /**
     * @brief 序列号设置;序列号不设置留空时,SDK将会自动尝试使用本地已经激活成功的有效期内的序列号
     * 值类型:string
     * 默认值:空
     */
    static constexpr auto PREDICTOR_KEY_SERIAL_NUM = "PREDICTOR_KEY_SERIAL_NUM";
    
    /**
     * @brief 当有同类型的多个设备的时候,使用哪一个设备,如:
     * 使用哪张加速卡
     * 值类型:int
     * 默认值:0
     */
    static constexpr auto PREDICTOR_KEY_DEVICE_ID = "PREDICTOR_KEY_DEVICE_ID";
    
    /**
     * @brief 设置需要同时预测的图片数量
     * 值类型: int
     * 默认值:1
     */
    static constexpr auto PREDICTOR_KEY_KUNLUN_BATCH_SIZE = "PREDICTOR_KEY_KUNLUN_BATCH_SIZE";

    PREDICTOR_KEY_DEVICE_ID:设置需要使用的加速卡的卡号。

    PREDICTOR_KEY_KUNLUN_BATCH_SIZE:设置单次预测可以支持的图片数量。

    使用方法:

    int batch_size = 1;
    config.set_config(easyedge::params::PREDICTOR_KEY_KUNLUN_BATCH_SIZE, batch_size);

    模型调优

    通过设置如下环境变量,可以在初始化阶段对模型调优,从而让预测的速度更快。

    export XPU_CONV_AUTOTUNE=5

    FAQ

    1. 如何处理一些 undefined reference?

    如:undefined reference to `curl_easy_setopt@CURL_OPENSSL_3'

    方案1:通过安装libcurl3 libcurl-openssl1.0-dev来解决。 方案2:如果开发者想不想使用低版本的openssl(如Ubuntu 18.04), 可以link静态库easyedge_static.a,自己指定需要的Library的版本:

    示例:修改CMakeList.txt

    find_package(CURL REQUIRED)
    target_link_libraries(easyedge_demo  ${OpenCV_LIBS} easyedge_static pthread ${CURL_LIBRARIES} verify_static ${其他需要的库})

    其中, 其他需要的库视具体sdk中包含的库而定。

    2. EasyDL SDK与云服务效果不一致,如何处理?

    后续我们会消除这部分差异,如果开发者发现差异较大,可联系我们协助处理。

    3. NVIDIA GPU预测时,报错显存不足

    如以下错误字样:

    paddle.fluid.core.EnforceNotMet: Enforce failed. Expected allocating <= available, but received allocating:20998686233 > available:19587333888.
    Insufficient GPU memory to allocation. at [/paddle/paddle/fluid/platform/gpu_info.cc:170]

    请根据显存大小和模型配置。调整合适的初始 fraction_of_gpu_memory。 参数的含义参考这里

    4. 如何将我的模型运行为一个http服务?

    目前cpp sdk暂未集成http运行方式; 0.4.7版本之后,可以通过start_http_server方法开启http服务。

    5. 运行NNIE引擎报permission denied

    日志显示:

    open sys: Permission denied
    open err
    : Permission denied
    open err
    : Permission denied

    请使用sudo在root下运行。

    6. 运行SDK报错 Authorization failed

    情况一:日志显示 Http perform failed: null respond

    在新的硬件上首次运行,必须联网激活。

    SDK 能够接受HTTP_PROXY 的环境变量通过代理处理自己的网络请求。如

    export HTTP_PROXY="http://192.168.1.100:8888"
    ./easyedge_demo ...

    情况二:日志显示failed to get/check device id(xxx)或者Device fingerprint mismatch(xxx)

    此类情况一般是设备指纹发生了变更,包括(但不局限于)以下可能的情况:

    • mac 地址变化
    • 磁盘变更
    • bios重刷

    以及系统相关信息。

    遇到这类情况,请确保硬件无变更,如果想更换序列号,请先删除 ~/.baidu/easyedge 目录,再重新激活。

    7. 使用libcurl请求http服务时,速度明显变慢

    这是因为libcurl请求continue导致server等待数据的问题,添加空的header即可

    headers = curl_slist_append(headers, "Expect:");

    8. 运行二进制时,提示 libverify.so cannot open shared object file

    可能cmake没有正确设置rpath, 可以设置LD_LIBRARY_PATH为sdk的lib文件夹后,再运行:

    LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../lib ./easyedge_demo

    9. 运行二进制时提示 libopencv_videoio.so.4.5: cannot open shared object file: No such file or directory

    同上面8的问题类似,没有正确设置动态库的查找路径,可通过设置LD_LIBRARY_PATH为sdk的thirdparty/opencv/lib文件夹解决

    export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:../thirdparty/opencv/lib
    (tips: 上面冒号后面接的thirdparty/opencv/lib路径以实际项目中路径为准,比如也可能是../../thirdparty/opencv/lib)

    10. 编译时报错:file format not recognized

    可能是因为在复制SDK时文件信息丢失。请将整个压缩包复制到目标设备中,再解压缩、编译

    11. 进行视频解码时,报错符号未找到、格式不支持、解析出的图片为空、无法设置抽帧

    请确保安装OpenCV时,添加了-DWITH_FFMPEG=ON选项(或者GStream选项),并且检查OpenCV的安装日志中,关于Video I/O段落的说明是否为YES

    --   Video I/O:
    --     DC1394:                      YES (ver 2.2.4)
    --     FFMPEG:                      YES
    --       avcodec:                   YES (ver 56.60.100)
    --       avformat:                  YES (ver 56.40.101)
    --       avutil:                    YES (ver 54.31.100)
    --       swscale:                   YES (ver 3.1.101)
    --       avresample:                NO
    --     libv4l/libv4l2:              NO
    --     v4l/v4l2:                    linux/videodev2.h

    如果为NO,请搜索相关解决方案,一般为依赖没有安装,以apt为例:

    apt-get install yasm libjpeg-dev libjasper-dev libavcodec-dev libavformat-dev libswscale-dev libdc1394-22-dev libgstreamer0.10-dev libgstreamer-plugins-base0.10-dev libv4l-dev python-dev python-numpy libtbb-dev libqt4-dev libgtk2.0-dev libfaac-dev libmp3lame-dev libopencore-amrnb-dev libopencore-amrwb-dev libtheora-dev libvorbis-dev libxvidcore-dev x264 v4l-utils ffmpeg

    12. GPU加速版运行有损压缩加速的模型,运算精度较标准模型偏低

    首先请保证数据集不会太小。其次可以通过将模型目录RES中的calibrationtable移除,并通过将PREDICTOR_KEY_GTURBO_FP16设置为true,使用FP16的运算精度重新评估模型效果。若依然不理想,可将calibrationtable移除并将PREDICTOR_KEY_GTURBO_FP16设置为false,从而使用更高精度的FP32的运算精度。

    上一篇
    目标跟踪服务器端SDK简介
    下一篇
    软硬一体方案