ModelBox
新手入门
【2022 ModelBox实战营】第一个应用

发布于30个月以前

  • 0
  • 1
  • 1717

发布于30个月以前

ModelBox AI应用开发——第一个应用

本文将使用ModelBox开发一个简单的视频应用:读取摄像头,解码出视频帧,再输出原始画面到本地屏幕。读者将了解到ModelBox应用开发的基本流程和应用的基本结构。

1. 传统开发模式

ModelBox采用Pipeline模式开发和运行AI应用,这与我们熟悉的开发方式是不同的。例如,对于上面介绍的应用:读取摄像头并输出原始画面,如果采用Python + OpenCV,代码如下:

import cv2

# 初始化摄像头,参数0表示设备的第一个摄像头
cap = cv2.VideoCapture(0)

# 判断初始化是否成功
if not cap.isOpened():
    print('failed to open camera 0')
    exit()

while True:
    # 读取一帧视频图像,ret表示读取是否成功
    ret, frame = cap.read()

    # 打开一个名为camera_test的窗口,显示图像
    cv2.imshow('camera_test', frame)

    # 阻塞等待键盘响应1ms,如果按下q键则跳出循环
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# 释放摄像头资源
cap.release()

# 关闭所有窗口
cv2.destroyAllWindows()

这个应用在运行时包含下面几个步骤:

  • 初始化摄像头
  • 解码,读取视频帧
  • 窗口显示
  • 释放摄像头

可以看到,在传统的开发方式中,应用的每个步骤对应一段代码块或者几个函数调用,开发者通过代码将所有步骤串联起来,自行控制应用的入口和完整流程。

2. ModelBox Pipeline模式

这个应用如果使用ModelBox进行开发,包括如下几个开发步骤:

  • 创建工程
  • 修改流程图
  • 添加功能单元
  • 修改输入输出配置
  • 用启动脚本执行应用

也就是说,ModelBox的Pipeline模式,首先需要将应用的流程图构建出来,再分别实现图中的每个模块(ModelBox中称为“功能单元”),对于上面的视频应用:读取摄像头并输出原始画面,对应的ModelBox流程图如下所示:

可以看到,Pipeline模式就像一个流水线,将复杂的数据处理过程分为多个功能单元,通过预先设定好的流程来处理输入的数据,每个功能单元的输出即是下一个功能单元的输入。开发者要做的是定义流程图和实现其中的每个功能单元,之后应用的运行将由框架来调度。在Pipeline模式下,每个功能单元支持并行处理,从而实现高效的数据处理。

接下来我们给出该应用在ModelBox中的完整开发过程:

1)创建工程

ModelBox sdk目录下使用create.bat创建camera_test工程

PS ███> .\create.bat -t server -n camera_test
sdk version is modelbox-xxx
success: create camera_test in ███\modelbox\workspace

create.bat工具的参数中,-t表示所创建实例的类型,包括serverModelBox工程)、python(Python功能单元)、c++(C++功能单元)、infer(推理功能单元)等;-n表示所创建实例的名称,开发者自行命名。

如果是第一次创建工程,在ModelBox sdk目录下,将会自动生成workspace文件夹,此文件夹将作为ModelBox应用的默认目录。workspace目录下会创建出camera_test工程,工程目录结构如下所示:

[project_name]
|--bin
|  |--main.bat:应用执行入口(如果是Linux系统,入口是main.sh)
|  |--mock_task.toml:应用在本地执行时的输入输出配置,目前支持本地视频文件、本地摄像头、网络摄像头等输入源,本地视频文件、本地屏幕、rtsp视频流等输出
|--CMake:存放一些自定义CMake函数
|--data:存放应用运行所需要的图片、视频、文本、配置等数据
|--dependence
|  |--modelbox_requirements.txt:应用运行依赖的外部库在此文件定义
|--etc
|  |--flowunit:应用所需的功能单元存放在此目录
|  |  |--cpp:存放自定义的C++功能单元编译后的动态链接库
|  |  |--[flowunit_name1]:自定义的Python功能单元目录
|  |  |--[flowunit_name2]:自定义的Python功能单元目录
|  |  |-- ...
|--flowunit_cpp:存放C++功能单元的源代码
|  |--[flowunit_name3]:自定义的C++功能单元目录
|  |--[flowunit_name4]:自定义的C++功能单元目录
|  |-- ...
|--graph:存放流程图,其中默认流程图与工程同名
|  |--[project_name].toml:与工程同名的默认流程图
|  |--modelbox.conf:modelbox相关配置
|--hilens_data_dir:存放应用输出的结果文件、日志、性能统计信息
|--model:推理功能单元目录
|  |--[flowunit_name5]:推理功能单元目录
|  |--[flowunit_name6]:推理功能单元目录
|  |-- ...
|--build_project.sh:应用构建脚本
|--CMakeLists.txt
|--rpm:打包rpm时生成的目录,将存放rpm包所需数据
|--rpm_copyothers.sh:rpm打包时的辅助脚本

2)修改流程图

camera_test工程graph目录下默认生成了一个与工程同名的camera_test.toml流程图,将其内容修改为(以Windows版ModelBox为例):

# Copyright (c) Huawei Technologies Co., Ltd. 2022. All rights reserved.

[driver]
# 功能单元的扫描路径,包含在[]中,多个路径使用,分隔
# ${HILENS_APP_ROOT} 表示当前应用的实际路径
# ${HILENS_MB_SDK_PATH} 表示ModelBox核心库的实际路径
dir = [
    "${HILENS_APP_ROOT}/etc/flowunit",
    "${HILENS_APP_ROOT}/etc/flowunit/cpp",
    "${HILENS_APP_ROOT}/model",
    "${HILENS_MB_SDK_PATH}/flowunit",
]
skip-default = true

[profile]
# 通过配置profile和trace开关启用应用的性能统计
profile = false                       # 是否记录profile信息,每隔60s记录一次统计信息
trace = false                         # 是否记录trace信息,在任务执行过程中和结束时,输出统计信息
dir = "${HILENS_DATA_DIR}/mb_profile" # profile/trace信息的保存位置

[flow]
desc = "camera example for modelbox" # 应用的简单描述

[graph]
format = "graphviz" # 流程图的格式,当前仅支持graphviz
graphconf = """digraph camera_test {
    node [shape=Mrecord]
    queue_size = 1
    batch_size = 1

    # 定义节点,即功能单元及其属性
    input1[type=input, flowunit=input, device=cpu, deviceid=0]
    data_source_parser2[type=flowunit, flowunit=data_source_parser, device=cpu, deviceid=0]
    local_camera3[type=flowunit, flowunit=local_camera, device=cpu, deviceid=0, pix_fmt="bgr", cam_width=1280, cam_height=720]
    video_out4[type=flowunit, flowunit=video_out, device=cpu, deviceid=0]

    # 定义边,即功能间的数据传递关系
    input1:input -> data_source_parser2:in_data
    data_source_parser2:out_video_url -> local_camera3:in_camera_packet
    local_camera3:out_camera_frame -> video_out4:in_video_frame
}"""

ModelBox使用TOML语法编写各类配置文件,在流程图的toml文件中,包含如下部分:

  • driver:配置功能单元的扫描路径,应用可能会用到的功能单元通常包括ModelBox核心库中内置的功能单元、该应用添加的Python功能单元、C++功能单元(动态链接库)、推理功能单元等
  • profile:包含几个配置项——是否记录应用运行时的性能数据,以及该数据的记录位置。性能数据将使用json文件记录,可在Chrome浏览器的tracing页面加载
  • graph:使用Graphviz DOT语言描述的流程图,描述了该应用所需的功能单元,以及功能单元间的数据传递关系
  • flow:该应用的简单描述

ModelBox流程图的描述采用Graphviz DOT语法表达,关于DOT语法,可以查看Graphviz DOT的指导。流程图的描述主要包括节点和边的定义,格式如下:

  • 节点的定义格式为:
node_name[type=flowunit, flowunit=flowunit_name, key=value]

其中,node_name为节点名称,可自行定义;key为节点的配置属性,每个节点不同,value为属性值,常用属性包括节点运行的设备和设备编号(device/deviceid)、batch_size/queue_size(也可以在图中定义全局batch_size/queue_size)等;type参数指定节点类型,可以是input(整个路程图的输入端口), output(整个路程图的输出端口), flowunit(功能单元,配合flowunit=xxx指定该功能单元的执行实体),若未指定默认为flowunit。可以理解为其中配置的flowunit_name是功能单元类名称,node_name是功能单元实例名称。

  • 边的定义格式为:
flowunit_name1:out_port -> flowunit_name2:in_port

其中,flowunit_name1/flowunit_name2为需要连接的两个节点的名称,out_port为前一个节点的输出端口名称,in_port为后一个节点的输入端口名称。

本应用的graph描述即对应本章开头给出的流程图,其中使用了如下4个ModelBox内置的输入端口/功能单元:

  • inputModelBox默认的流程图输入端口,用于接收图外部的输入配置,每个流程图都应该以该节点开始
  • data_source_parser:解析输入数据源,本地执行时可解析bin/mock_task.toml文件中的输入配置,通过HiLens部署运行时可解析HiLens控制台上配置的输入源(后面教程中会介绍)
  • local_camera:本地摄像头解码功能单元,可读取PC自带摄像头或者USB摄像头,常用属性中包括解码后的图像格式(pix_fmt)、图像宽高(cam_width/cam_height)等
  • video_out:视频输出功能单元,可将视频通过本地视频文件、本地屏幕、rtsp视频流等形式输出,本地执行时输出形式由bin/mock_task.toml文件中的输出配置指定,通过HiLens部署运行时通过HiLens控制台上配置的输出指定(后面教程中会介绍)

3)添加功能单元

camera_test应用只需要ModelBox内置的功能单元,无需开发者另外开发其他功能单元,后面的教程将会介绍如何自定义功能单元。

4)修改输入输出配置

本应用需要打开PC自带摄像头,解码出视频帧并输出到本地屏幕,我们打开工程目录下bin/mock_task.toml文件,修改其中的任务输入和任务输出配置为如下内容:

# 任务输入配置,mock模拟目前仅支持一路rtsp或者本地url, 当前支持以下几种输入方式:
# 1. rtsp摄像头或rtsp视频流:type="rtsp", url="rtsp://xxx.xxx"  (type为rtsp的时候,支持视频中断自动重连)
# 2. 设备自带摄像头或者USB摄像头:type="url",url="摄像头编号" (比如 0 或者 1 等,需配合local_camera功能单元使用)
# 3. 本地视频文件:type="url",url="视频文件路径" (请使用${HILENS_APP_ROOT}宏,表示当前应用的实际路径)
# 4. http服务:type="url", url="http://xxx.xxx"(指的是任务作为http服务启动,此处需填写对外暴露的http服务地址,需配合httpserver类的功能单元使用)
[input]
type = "url"
url = "0"  # 表示0号摄像头,即PC自带摄像头,若PC无摄像头需外接USB摄像头

# 任务输出配置,当前支持以下几种输出方式:
# 1. rtsp视频流:type="local", url="rtsp://xxx.xxx"
# 2. 本地屏幕:type="local", url="0:xxx" (设备需要接显示器,系统需要安装桌面)
# 3. 本地视频文件:type="local",url="视频文件路径" (请使用${HILENS_APP_ROOT}宏,表示当前应用的实际路径)
# 4. http服务:type="webhook", url="http://xxx.xxx" (指的是任务产生的数据上报给某个http服务,此处需填写上传的http服务地址)
[output]
type = "local"
url = "0:camera_test"  # 表示名为camera_test的窗口

该流程图在本地运行时的逻辑过程是:data_source_parser解析bin/mock_task.toml文件中配置的0号摄像头,local_camera打开该编号的摄像头并解码出视频帧,video_out将图像输出到本地屏幕中名为camera_test的窗口中。

5)用启动脚本执行应用

启动应用前执行build_project.sh进行工程构建,该脚本将编译自定义的C++功能单元(本应用不涉及)、将应用运行时会用到的配置文件转码为Unix格式(防止执行过程中的格式错误):

PS ███> .\build_project.sh
...
PS ███>

然后执行bin/main.bat运行应用:

PS ███> .\bin\main.bat

...

将会自动弹出实时的摄像头视频画面:

如果想要关闭这个实时推理应用,关闭窗口是不行的,请点击右下角Terminal中的kill按钮结束此应用:

3. 小结

通过本教程,我们可以看到,使用ModelBox框架开发应用,是一个类似搭积木的过程,如果应用所需的功能模块ModelBox都已内置,开发者无需编写代码,就可以拖拽出应用流程图出来,非常方便。

课程打卡

根据本次课程学习的内容,在自己的环境进行复现,并将复现的程序运行界面,连同网页右上方的华为云账号截图发至打卡贴上,详细打卡规则参见活动页面或参考2022ModelBox实战营活动打卡 (huaweicloud.com)

LLM初学者

作者相关内容

【2022 ModelBox实战营】第一个应用
发布于30个月以前
【2022 ModelBox实战营】通用Python功能单元
发布于30个月以前
【ModelBox客流分析实战营】ModelBox端云协同AI开发套件(Windows)SDK安装篇
发布于28个月以前
【2022 ModelBox实战营】推理功能单元
发布于30个月以前
ModelBox开发案例 - 使用YOLO v3做口罩检测
发布于34个月以前

暂无数据

热门内容推荐

ModelArts JupyterLab常见问题解决办法
ModelArts开发者 发布于45个月以前
为医生打造专属数字分身!华为云联合万木健康打造医疗医学科普和患者教育数字人引擎
HWCloudAI 发布于20个月以前
图数据库 | 聊聊超级快的图上多跳过滤查询
弓役是也 发布于23个月以前
ModelArts准备工作_简易版
ModelArts开发者 发布于46个月以前
”智蔗见智·向新而生”广西第二届人工智能大赛baseline使用教程
追乐小王子 发布于31个月以前

暂无数据