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

Linux集成文档-C

简介

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

  • 网络类型支持:图像分类,物体检测
  • 硬件支持:

    • CPU 基础版: x86_64
    • NVIDIA GPU: x86_64 PC
  • 操作系统支持:Linux

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

  • EasyDL图像

    • x86 CPU 基础版
    • Nvidia GPU 基础版

Release Notes

时间 版本 说明
2021.8.23 1.0.0 第一版!

快速开始

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

依赖包括

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

(可选) 安装TensorRT

下载包中提供了对应 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

请安装与1.0.0.187版本兼容的XTCL。必要时,请将运行库路径添加到环境变量。

2. 测试Demo

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

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

部分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

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绘制的逻辑进行解析

日志配置

设置 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请求示例

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. 批量预测设置

EdgePredictorConfig config;
config.set_config(params::PREDICTOR_KEY_VINO_MAX_BATCH_SIZE, 4); //CPU加速版特殊设置

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

CPU加速版设置PREDICTOR_KEY_VINO_MAX_BATCH_SIZE含义:此值用来控制批量图片预测可以支持的最大图片数,实际预测的时候单次预测图片数不可大于此值。实际预测图片数为std::min(PREDICTOR_KEY_VINO_MAX_BATCH_SIZE, batch_size)。

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. 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。 参数的含义参考这里

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

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

4. 运行NNIE引擎报permission denied

日志显示:

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

请使用sudo在root下运行。

5. 运行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 目录,再重新激活。

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

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

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

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

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

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

8. 运行二进制时提示 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)

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

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

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

请确保安装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
上一篇
专项适配硬件离线部署
下一篇
Linux集成文档-Python