SDK设计说明
前言
ModelBox端侧SDK基于开源ModelBox构建,可以参考 https://modelbox-ai.com/modelbox-book/basic-conception/basic-conception.html 掌握ModelBox基本概念。modelbox开源代码链接:https://github.com/modelbox-ai/modelbox
SDK整体结构设计
SDK设计目标:开箱即用。SDK会打包所有的依赖(只有linux需要自己安装opencv-python,linux使用sdk自带的env_set.sh -i 安装依赖,注意opencv-python一定要切换到root下安装)SDK设计了一套命令行工具方便开发者进行开发,这一套命令行和开源是有差异的,ModelBox SDK(端侧版本)使用的是python编译的命令行脚本,开源使用的是shell的命令行脚本。
SDK win版本直接解压到英文目录路径下,linux版本目前都采用run包的方式,chmod +x run包以后,运行安装sdk。win-sdk的升级,解压以后,把之前的workspace拷贝到新的sdk里面就可以了。
SDK的组成部分:
- connect_wizard(win sdk独有)运行connect_wizard.exe可以连接开发板,设计推流地址等
- modelbox-***: modelbox SDK,包含了SDK所有依赖包,注意在SDK内只能有一个modelbox-开头的目录,如果有多个,SDK命令行工具create.py会报错
- python-embed: win sdk独有,内嵌python,打包的时候会打包这个目录,保证在不同的win机器上python环境的一致性
- create.py:SDK命令行工具,vscode可视化工具正在开发中,目前暂时只能使用SDK命令行工具。win下推荐使用create.bat,linux下使用python3 create.py,注意这里和开源是不一样的(开源使用的是modelbox-tool),如果要保持和开源一致体验,可以采用create.py -t editor启动流程图编辑器,SDK命令行工具其主要功能如下:
- 创建工程:create.py -t server -n car_det_prj -s car_det, 如果不带-s那么会创建一个空的工程,默认是一个http收发的空工程,加了-s 会从solution模板创建一个工程,sdk默认自带一个car_det车辆检测的工程,其它的模板需要使用solution.py从网上下载。一般情况下我们都创建server的工程,project工程不支持从配置传入输入输出配置。所有的配置只能配在graph图内。
- 创建功能单元: create.py -t c++ -n my_flowuint_name -p car_det_prj, 这个就是在car_det_prj工程内创建c++工程,-t后面还可以是python,infer
- 打包工程: create.py -t rpm -n car_det_prj -k 123456.mypass,打包工程成一个可以部署在hilens上的rpm包,如果不带-k,则模型不加密,否则加密模型(同时需要把模型秘钥填到hilens控制台内)
- 启动一个graph图编辑器: create.py -t editor -i 192.168.2.111:1114,这个编译器里面也可以创建工程和功能单元,如果不带-i 默认使用127.0.0.1:1114的ip地址。运行命令的log内会告诉你打开哪个网址。
- solution.py 模板下载脚本,win使用solution.bat 先用-l 看看网上有什么脚本,再用-s 下载模板,最后用create.py 或者流程图编辑器创建对应模板的工程。
- env_set.bat(linux是env_set.sh) 环境配置脚本,linux可以用env_set.sh -i 安装所需要的包(比如python-opencv等),执行了env_set.bat后还可以直接执行modelbox-tool,比如执行modelbox-tool.exe driver -info -path (sdk的flowunit目录)-details可以查看功能单元的具体说明。
工程目录结构设计
目录结构设计目标:尽可能的完善,不同的内容放在不同的目录,以便SDK工具能够尽可能的做自动化处理。

- graph目录包含modelbox的运行图,图是modelbox的基本概念,modelbox本质上类似gstreamer,是去运行一个连接图(不同的功能单元连接起来,形成一个流式处理)。
这个好处是程序的整体逻辑是一个文本,代码类似搭建积木一样,同时去除了二进制依赖,代码的并行度比较高。但是其坏处代码灵活度会降低,从传统代码改造会有一定的难度(可以参考ffmpeg和gstreamer的区别,比如https://blog.csdn.net/acs713/article/details/91406931)。
同时这里也要注意和开源的设计区别,由于主要考虑端侧场景,一个app只运行一个图,所以如果输入输出不同,图就是不一样的。最主要的有比如输入是本地摄像头或者输入是视频,这个由于输入功能单元不同,导致图也不同(功能单元是模块化设计的,不可能把所有功能都塞入一个功能单元).
SDK设计了一个入口运行脚本,在win下是main.bat,其可以带2个参数。
第一个参数是选择图,graph里面的图都是按照工程目录名_功能选择名.toml这样命名的,所以如果工程名是hello,用main.bat camera 那么运行的是graph里面的hello_camera.toml,如果用main.bat default,那么运行的是graph里面的hello.toml.
第二个参数是选择log级别,默认是warn,可以使用main.bat default info切换到info日志(日志一共有 debug,info,warn,error,off这几个级别,off就是不打印日志)
- .vscode目录里面包含了launch.json,这个是create.py SDK命令行工具创建工程的时候自动产生的,注意在win上只产生python的调试选项(win上目前还有问题,只支持python调试,同时在调试的时候模型只能跑在cpu上),在linux可以产生c++和python的调试选项(每个图对应产生),用户可以打开这个工程目录(在workspace下的一个个工程目录),点击run and debug图标,直接进行调试
- bin目录下包含工程启动入口脚本main.bat(或者main.sh), python_debug.py(python调试的时候入口文件,所以python调试运行效率会比较低,无法多核并行处理)。同时还包含了mock_task.toml(或者mock_task_xxx.toml)。
这个mock文件是本地运行的关键控制文件,是在本地模拟云端部署的一个配置文件。具体配置说明将在其它章节说明,需要注意的是如果用 main.bat camera运行,那么SDK会尝试读取mock_task_camera.toml如果没有这个文件,才去读取mock_task.toml文件,这样设计的好处是不同的图可以对应不同的toml配置文件(如果有必要的话),不需要反复修改这个文件。
- CMake和flowunit_cpp都是c++功能单元对应的目录,其中CMake放置CMake文件,比如找某个包的等,flowunit_cpp放c++功能单元源码(create.py创建c++功能单元会自动放置在flowunit_cpp里面),如果创建了c++功能单元,build工程的时候会自动编译此c++功能单元
- data目录可以放应用本身需要的数据文件,这里只能放只读的文件,需要写的文件需要指定目录为hilens_data_dir。其对应的环境变量为$ {HILENS_APP_ROOT}/data和$ {HILENS_DATA_DIR}。
这样设计的目的是hilens部署是多实例的,一个应用可以启动多个实例,所以应用本身是放在一个只读文件夹中,只有$ {HILENS_DATA_DIR}这个目录是当前实例可写的。在mock仿真本地运行的时候,这个$ {HILENS_DATA_DIR}对应的是当前工程目录下的hilens_data_dir(运行的时候动态创建,创建工程的时候没有),在云侧部署下发到端侧设备的时候,这个目录由$ {HILENS_DATA_DIR}指定。
- dependence目录:这个目录是放应用的依赖。SDK和镜像不同,镜像依赖都打包在镜像内,但是如果我们跑的是rpm包,依赖怎么安装呢?一种办法是利用os的依赖安装方式,但是这个部署安装比较麻烦,依赖网络,而且还有可能导致冲突。ModelBox-SDK rpm包运行方式采用的是全依赖打包的方式,python和动态库都是使用应用内的包,对宿主机的影响最小(当然这样会导致应用包比较大,但是怎么着也比镜像小多了)。
dependence目录内包含有lib,python和wheel目录,里面都有readme说明,其中lib放动态库,wheel放python安装包(如果你需要用wheel包安装的话),而其他pip安装的python包写在modelbox_requirements.txt内(注意一般情况下不需要写opencv-python和numpy,如果写了,会把这2个包安装在应用内,会导致应用体积过大,我们假设os的python已经安装了这2个包)。
其中python的安装原理是在运行或者编译的时候检测modelbox_requirements.txt和python目录内的installed_modelbox_requirements.txt文件是否一致, 如果你修改了modelbox_requirements.txt,就会重新安装python包到应用dependence目录的python目录内。注意: 如果你修改了wheel包,那么需要手动删除python目录内的installed_modelbox_requirements.txt。重新激活python安装流程。
- etc目录:这里是历史遗留问题:内部包含python功能单元的源码,和c++功能单元编译好的动态库。其实是应该直接在上层目录,去掉etc目录,这样会更好一点。
- model目录: 创建推理功能单元会自动创建在这里,这个设计的好处是把模型给单独的放在一个目录内,以便后来create.py打包应用的时候自动做模型加密。建议model目录内模型配置都使用相对路径,也就是模型和模型配置文件是在一个文件夹,使用./xxx.模型后缀这样的命名方式,不然自动模型加密有可能会报错。
- build_project.sh:如果有c++功能单元,需要手动执行这个文件(win用git-bash执行),否则一般不需要手动执行。这个里面主要执行的有:toml文件转换成linux格式,win格式会导致运行异常;c++功能单元编译,python包安装,用户自定义编译脚本等
- CMakeLists.txt (一般不需要修改)
- rpm_copyothers.sh :rpm打包的时候,添加或者删除rpm目录下的文件的用户自定义脚本,通常不需要修改
solution设计
所有的solution都放在sdk的solution目录内,比如win是在modelbox-win10-x64\solution内。里面默认带一个car_det目录:
common和win10目录内的内容组合产生和普通工程目录类似的目录结构。这个是因为放在OBS的solution支持多架构,common代表支持所有架构的通用内容。所以目录结构是这样的。如果自己写的solution,那么可以仅仅有win10目录(rk就是rknpu,或者rknpu2目录)
solution本质上是一个可运行的工程,只是不用打包一些工程自动创建的内容,比如bin内的main.bat等,同时graph里面名称一定要和solution名保持一致,比如car_det有car_det.toml或者car_det_http.toml等,在这些toml文件里面,建议使用MODULENAME来定义图名,这个图名会在创建工程的时候被自动替换。
开源rockchip代码简介
代码地址:https://github.com/modelbox-ai/modelbox/tree/main/src/drivers/devices/rockchip
通常的适配一个modelbox硬件版本,是在devices下增加一个目录,比如rockchip,然后实现core(内存,设备抽象)和对应的flowunit(图像处理,比如硬件解码,缩放功能单元,还有推理功能单元)
- core实现的有:device_rockchip.cc实现设备发现,发现有几个加速设备,每个加速设备支持多大内存等;rockchip_memory.cc内存抽象,这个是关键实现,实现设备的硬件内存抽象。(待改进点,内存抽象目前不支持2d内存,在内存抽象的地方获取不到内存的宽高),内存抽象实现的功能是: 如果一个rk的功能单元连到一个cpu的功能单元,会自动转换内存,从rk(mppbuffer内存)转到cpu host普通内存(但是mpp buffer是带stride的,宽是16整除的)所以目前转换后cpu内存也是带stride的,如果需要获取不带stride的,目前方案是使用rk_cpuimg功能单元)
- flowunit:硬件功能单元实现,硬件功能单元和普通功能单元区别就是获取到的内存或者输出的内存是基于硬件内存的。通常在不同的设备之间会有类似的功能单元,这样可以保证不同设备的应用迁移的便利性。rockchip还带一个local-camera功能单元(端侧都带这个),实现usb摄像头的读取。
- 注意事项:目前开源的代码设备名改了,SDK用的是rknpu,开源的用的是rockchip,注意需要改改graph图里面的设备名
- 功能单元分类:可以参考 https://developer.huaweicloud.com/signup/75594146e5ed4482a87b088c3cd12aa3 4.AI应用开发:通过本门课程了解ModelBox的功能单元,并实现AI应用开发
了解不同类型功能单元能实现的功能