From 9e9771f4bc760974521a0c9c48516cb3cf4a5db4 Mon Sep 17 00:00:00 2001 From: weiwei Date: Mon, 3 Apr 2023 18:45:05 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8DAI=E5=AD=90=E7=B3=BB=E7=BB=9F?= =?UTF-8?q?NNRt=E9=83=A8=E4=BB=B6=E7=9A=84=E8=AE=BE=E5=A4=87=E5=BC=80?= =?UTF-8?q?=E5=8F=91=E6=8C=87=E5=AF=BC=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: weiwei --- .../subsystems/figures/nnrt_dev_flow.png | Bin 23989 -> 19611 bytes .../subsystems/subsys-ai-nnrt-guide.md | 464 +++++++++--------- 2 files changed, 241 insertions(+), 223 deletions(-) diff --git a/zh-cn/device-dev/subsystems/figures/nnrt_dev_flow.png b/zh-cn/device-dev/subsystems/figures/nnrt_dev_flow.png index ab008db12eaae364195d7097b02af5a6f624c325..ca50b6ac1800e972a5a5f5dcb116771ac8730360 100644 GIT binary patch literal 19611 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%0DCns3(lf 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 literal 23989 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 依赖说明:该教程展示的rk3568 CPU接入NNRt并没有实际去写CPU的驱动,而是借用了Mindspore-Lite的CPU算子,故会依赖MindSpore-Lite的动态库以及头文件,实际开发时并不需要依赖MindSpore-Lite的任何库或者头文件。 +当需要将一款AI加速芯片接入NNRt的时候,可以参考下文。下文以RK3568芯片为例,展示RK3568 CPU如何通过HDI接口接入NNRt,并完成AI模型推理。 +> 依赖说明:该教程展示的RK3568 CPU接入NNRt并没有实际去写CPU的驱动,而是借用了MindSpore Lite的CPU算子,故会依赖MindSpore Lite的动态库以及头文件,实际开发时并不需要依赖MindSpore Lite的任何库或者头文件。 ### 开发流程 专用加速芯片接入NNRt的整体流程如下: @@ -45,242 +45,243 @@ NNRt通过HDI接口实现与设备芯片的对接,由HDI接口实现跨进程 ### 开发步骤 开发者具体可通过以下步骤实现芯片对接NNRt: -1. 开源社区下载OpenHarmony的代码,编译drivers_interface部件,生成HDI接口的头文件。 - - 1. [下载源码](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/get-code/sourcecode-acquire.md)。 - - 2. 编译接口IDL文件。 - ```shell - ./build.sh --product-name productname –ccache --build-target drivers_interface_nnrt - ``` - > productname为产品名称,此处为rk3568. - - 编译完成后,在```out/rk3568/gen/drivers/interface/nnrt```目录下生成HDI头文件,默认语言类型为C++;若需要生成C类型的头文件,请在编译之前使用如下命令对```drivers/interface/nnrt/v1_0/BUILD.gn```文件中的```language```配置项进行设置。 - - ```shell - language = "c" - ``` - - 生成头文件目录如下所示: - ```text - out/rk3568/gen/drivers/interface/nnrt - └── v1_0 - ├── drivers_interface_nnrt__libnnrt_proxy_1.0_external_deps_temp.json - ├── drivers_interface_nnrt__libnnrt_stub_1.0_external_deps_temp.json - ├── innrt_device.h # 设备接口头文件 - ├── iprepared_model.h # 编译AI模型对象头文件 - ├── libnnrt_proxy_1.0__notice.d - ├── libnnrt_stub_1.0__notice.d - ├── model_types.cpp # AI模型结构定义实现文件 - ├── model_types.h # AI模型结构定义头文件 - ├── nnrt_device_driver.cpp # 设备驱动实现参考样例 - ├── nnrt_device_proxy.cpp - ├── nnrt_device_proxy.h - ├── nnrt_device_service.cpp # 设备服务端实现参考样例 - ├── nnrt_device_service.h # 设备服务端头文件 - ├── nnrt_device_stub.cpp - ├── nnrt_device_stub.h - ├── nnrt_types.cpp # 数据类型定义实现文件 - ├── nnrt_types.h # 数据类型定义头文件 - ├── node_attr_types.cpp # AI模型算子属性定义实现文件 - ├── node_attr_types.h # AI模型算子属性定义 - ├── prepared_model_proxy.cpp - ├── prepared_model_proxy.h - ├── prepared_model_service.cpp # 编译AI模型对象服务端实现参考样例 - ├── prepared_model_service.h # 编译AI模型对象服务端头文件 - ├── prepared_model_stub.cpp - └── prepared_model_stub.h - ``` - -2. 实现HDI服务。 - - 1. 在drivers/peripheral目录下新建开发目录,用于HDI服务开发,开发目录结构如下所示。 - ```text - drivers/peripheral/nnrt - ├── BUILD.gn # 代码编译脚本文件 - ├── bundle.json - └── hdi_cpu_service # 自定义目录 - ├── BUILD.gn # 代码编译脚本文件 - ├── include - │   ├── nnrt_device_service.h # 设备服务端头文件 - │   ├── node_functions.h # 非必须,由具体实现决定 - │   ├── node_registry.h # 非必须,由具体实现决定 - │   └── prepared_model_service.h # 编译AI模型对象服务端头文件 - └── src - ├── nnrt_device_driver.cpp # 设备驱动实现文件 - ├── nnrt_device_service.cpp # 设备服务端实现文件 - ├── nnrt_device_stub.cpp # 非必须,由具体实现决定 - ├── node_attr_types.cpp # 非必须,由具体实现决定 - ├── node_functions.cpp # 非必须,由具体实现决定 - ├── node_registry.cpp # 非必须,由具体实现决定 - └── prepared_model_service.cpp # 编译AI模型对象服务端实现文件 - ``` - - 2. 实现设备驱动,无特殊需求可直接使用步骤1中生成的nnrt_device_driver.cpp文件,否则根据具体驱动开发。 - 3. 实现服务接口,可参考nnrt_device_service.cpp和prepared_model_service.cpp实现文件,接口定义可以参考[NNRt的HDI接口定义](https://gitee.com/openharmony/drivers_interface/tree/master/nnrt)。 - - 4. 编译驱动和服务的实现文件为共享库。 - - 在```drivers/peripheral/nnrt/hdi_cpu_service/```下新建```BUILD.gn```文件,文件内容如下所示,相关参数配置内容可参考[Build教程](https://gitee.com/openharmony/build). +#### 生成HDI头文件 +开源社区下载OpenHarmony的代码,编译drivers_interface部件,生成HDI接口的头文件。 - ```shell - import("//build/ohos.gni") - import("//drivers/hdf_core/adapter/uhdf2/uhdf.gni") - - ohos_shared_library("libnnrt_service_1.0") { - include_dirs = [] - sources = [ - "src/nnrt_device_service.cpp", - "src/prepared_model_service.cpp", - "src/node_registry.cpp", - "src/node_functions.cpp", - "src/node_attr_types.cpp" - ] - public_deps = [ "//drivers/interface/nnrt/v1_0:nnrt_idl_headers" ] - external_deps = [ - "hdf_core:libhdf_utils", - "hiviewdfx_hilog_native:libhilog", - "ipc:ipc_single", - "c_utils:utils", - ] +1. [下载源码](../get-code/sourcecode-acquire.md)。 - install_images = [ chipset_base_dir ] - subsystem_name = "hdf" - part_name = "drivers_peripheral_nnrt" - } +2. 编译接口IDL文件。 + ```shell + ./build.sh --product-name productname –ccache --build-target drivers_interface_nnrt + ``` + > productname为产品名称,此处为RK3568。 - ohos_shared_library("libnnrt_driver") { - include_dirs = [] - sources = [ "src/nnr_device_driver.cpp" ] - deps = [ "//drivers/peripheral/nnrt/hdi_cpu_service:libnnrt_service_1.0" ] - - external_deps = [ - "hdf_core:libhdf_host", - "hdf_core:libhdf_ipc_adapter", - "hdf_core:libhdf_utils", - "hiviewdfx_hilog_native:libhilog", - "ipc:ipc_single", - "c_utils:utils", - ] + 编译完成后,在```out/rk3568/gen/drivers/interface/nnrt```目录下生成HDI头文件,默认语言类型为C++。若需要生成C类型的头文件,请在编译之前使用如下命令对```drivers/interface/nnrt/v1_0/BUILD.gn```文件中的```language```配置项进行设置。 - install_images = [ chipset_base_dir ] - subsystem_name = "hdf" - part_name = "drivers_peripheral_nnrt" - } + ```shell + language = "c" + ``` + + 生成头文件目录如下所示: + ```text + out/rk3568/gen/drivers/interface/nnrt + └── v1_0 + ├── drivers_interface_nnrt__libnnrt_proxy_1.0_external_deps_temp.json + ├── drivers_interface_nnrt__libnnrt_stub_1.0_external_deps_temp.json + ├── innrt_device.h # 设备接口头文件 + ├── iprepared_model.h # 编译AI模型对象头文件 + ├── libnnrt_proxy_1.0__notice.d + ├── libnnrt_stub_1.0__notice.d + ├── model_types.cpp # AI模型结构定义实现文件 + ├── model_types.h # AI模型结构定义头文件 + ├── nnrt_device_driver.cpp # 设备驱动实现参考样例 + ├── nnrt_device_proxy.cpp + ├── nnrt_device_proxy.h + ├── nnrt_device_service.cpp # 设备服务端实现参考样例 + ├── nnrt_device_service.h # 设备服务端头文件 + ├── nnrt_device_stub.cpp + ├── nnrt_device_stub.h + ├── nnrt_types.cpp # 数据类型定义实现文件 + ├── nnrt_types.h # 数据类型定义头文件 + ├── node_attr_types.cpp # AI模型算子属性定义实现文件 + ├── node_attr_types.h # AI模型算子属性定义 + ├── prepared_model_proxy.cpp + ├── prepared_model_proxy.h + ├── prepared_model_service.cpp # 编译AI模型对象服务端实现参考样例 + ├── prepared_model_service.h # 编译AI模型对象服务端头文件 + ├── prepared_model_stub.cpp + └── prepared_model_stub.h + ``` + +#### 实现HDI服务 + +1. 在drivers/peripheral目录下新建开发目录,用于HDI服务开发,开发目录结构如下所示: + ```text + drivers/peripheral/nnrt + ├── BUILD.gn # 代码编译脚本文件 + ├── bundle.json + └── hdi_cpu_service # 自定义目录 + ├── BUILD.gn # 代码编译脚本文件 + ├── include + │   ├── nnrt_device_service.h # 设备服务端头文件 + │   ├── node_functions.h # 非必须,由具体实现决定 + │   ├── node_registry.h # 非必须,由具体实现决定 + │   └── prepared_model_service.h # 编译AI模型对象服务端头文件 + └── src + ├── nnrt_device_driver.cpp # 设备驱动实现文件 + ├── nnrt_device_service.cpp # 设备服务端实现文件 + ├── nnrt_device_stub.cpp # 非必须,由具体实现决定 + ├── node_attr_types.cpp # 非必须,由具体实现决定 + ├── node_functions.cpp # 非必须,由具体实现决定 + ├── node_registry.cpp # 非必须,由具体实现决定 + └── prepared_model_service.cpp # 编译AI模型对象服务端实现文件 + ``` + +2. 实现设备驱动,无特殊需求可直接使用步骤1中生成的nnrt_device_driver.cpp文件,否则根据具体驱动开发。 + +3. 实现服务接口,可参考nnrt_device_service.cpp和prepared_model_service.cpp实现文件,接口定义可以参考[NNRt的HDI接口定义](https://gitee.com/openharmony/drivers_interface/tree/master/nnrt)。 + +4. 编译驱动和服务的实现文件为共享库。 + + 在```drivers/peripheral/nnrt/hdi_cpu_service/```下新建```BUILD.gn```文件,文件内容如下所示,相关参数配置内容可参考[Build教程](https://gitee.com/openharmony/build)。 + + ```shell + import("//build/ohos.gni") + import("//drivers/hdf_core/adapter/uhdf2/uhdf.gni") + + ohos_shared_library("libnnrt_service_1.0") { + include_dirs = [] + sources = [ + "src/nnrt_device_service.cpp", + "src/prepared_model_service.cpp", + "src/node_registry.cpp", + "src/node_functions.cpp", + "src/node_attr_types.cpp" + ] + public_deps = [ "//drivers/interface/nnrt/v1_0:nnrt_idl_headers" ] + external_deps = [ + "hdf_core:libhdf_utils", + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_single", + "c_utils:utils", + ] + + install_images = [ chipset_base_dir ] + subsystem_name = "hdf" + part_name = "drivers_peripheral_nnrt" + } + + ohos_shared_library("libnnrt_driver") { + include_dirs = [] + sources = [ "src/nnr_device_driver.cpp" ] + deps = [ "//drivers/peripheral/nnrt/hdi_cpu_service:libnnrt_service_1.0" ] + + external_deps = [ + "hdf_core:libhdf_host", + "hdf_core:libhdf_ipc_adapter", + "hdf_core:libhdf_utils", + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_single", + "c_utils:utils", + ] + + install_images = [ chipset_base_dir ] + subsystem_name = "hdf" + part_name = "drivers_peripheral_nnrt" + } + + group("hdf_nnrt_service") { + deps = [ + ":libnnrt_driver", + ":libnnrt_service_1.0", + ] + } + ``` - group("hdf_nnrt_service") { + 将```group("hdf_nnrt_service")```添加到```drivers/peripheral/nnrt/BUILD.gn```文件中,以便在更上目录层级就能引用。 + ```shell + if (defined(ohos_lite)) { + group("nnrt_entry") { + deps = [ ] + } + } else { + group("nnrt_entry") { deps = [ - ":libnnrt_driver", - ":libnnrt_service_1.0", + "./hdi_cpu_service:hdf_nnrt_service", ] } - ``` + } + ``` - 将```group("hdf_nnrt_service")```添加到```drivers/peripheral/nnrt/BUILD.gn```文件中,以便在更上目录层级就能引用。 - ```shell - if (defined(ohos_lite)) { - group("nnrt_entry") { - deps = [ ] - } - } else { - group("nnrt_entry") { - deps = [ - "./hdi_cpu_service:hdf_nnrt_service", + 新建```drivers/peripheral/nnrt/bundle.json```用于定义新增的```drivers_peripheral_nnrt```部件。 + ```json + { + "name": "drivers_peripheral_nnrt", + "description": "Neural network runtime device driver", + "version": "3.2", + "license": "Apache License 2.0", + "component": { + "name": "drivers_peripheral_nnrt", + "subsystem": "hdf", + "syscap": [""], + "adapter_system_type": ["standard"], + "rom": "1024KB", + "ram": "2048KB", + "deps": { + "components": [ + "ipc", + "hdf_core", + "hiviewdfx_hilog_native", + "c_utils" + ], + "third_part": [ + "bounds_checking_function" + ] + }, + "build": { + "sub_component": [ + "//drivers/peripheral/nnrt:nnrt_entry" + ], + "test": [ + ], + "inner_kits": [ ] } } - ``` + } + ``` - 新建```drivers/peripheral/nnrt/bundle.json```用于定义新增的```drivers_peripheral_nnrt```部件。 - ```json - { - "name": "drivers_peripheral_nnrt", - "description": "Neural network runtime device driver", - "version": "3.2", - "license": "Apache License 2.0", - "component": { - "name": "drivers_peripheral_nnrt", - "subsystem": "hdf", - "syscap": [""], - "adapter_system_type": ["standard"], - "rom": "1024KB", - "ram": "2048KB", - "deps": { - "components": [ - "ipc", - "hdf_core", - "hiviewdfx_hilog_native", - "c_utils" - ], - "third_part": [ - "bounds_checking_function" - ] - }, - "build": { - "sub_component": [ - "//drivers/peripheral/nnrt:nnrt_entry" - ], - "test": [ - ], - "inner_kits": [ - ] +#### 声明HDI服务 + + 在对应产品的uhdf hcs配置文件中声明用户态驱动与服务,例如针对RK3568服务需要在```vendor/hihope/rk3568/hdf_config/uhdf/device_info.hcs```文件中新增如下配置: + ```text + nnrt :: host { + hostName = "nnrt_host"; + priority = 50; + uid = ""; + gid = ""; + caps = ["DAC_OVERRIDE", "DAC_READ_SEARCH"]; + nnrt_device :: device { + device0 :: deviceNode { + policy = 2; + priority = 100; + moduleName = "libnnrt_driver.z.so"; + serviceName = "nnrt_device_service"; } - } } - ``` + } + ``` +> 注意:修改hcs文件需要删除out目录重新编译,才能生效。 -3. 声明HDI服务。 - - 在对应产品的uhdf hcs配置文件中声明用户态驱动与服务,例如,针对rk3568服务需要在```vendor/hihope/rk3568/hdf_config/uhdf/device_info.hcs```文件中新增如下配置: - ```text - nnrt :: host { - hostName = "nnrt_host"; - priority = 50; - uid = ""; - gid = ""; - caps = ["DAC_OVERRIDE", "DAC_READ_SEARCH"]; - nnrt_device :: device { - device0 :: deviceNode { - policy = 2; - priority = 100; - moduleName = "libnnrt_driver.z.so"; - serviceName = "nnrt_device_service"; - } - } - } - ``` - > 注意:修改hcs文件需要删除out目录重新编译,才能生效。 +#### 配置host进程用户ID和组ID + 对于新增的nnrt_host进程的场景,需要配置对应进程的用户ID和组ID。 进程的用户ID在文件```base/startup/init/services/etc/passwd```中配置,进程的组ID在文件```base/startup/init/services/etc/group```中配置。 + ```text + # 在base/startup/init/services/etc/passwd新增 + nnrt_host:x:3311:3311:::/bin/false -4. 配置host进程用户和组。 - - 对于新增的nnrt_host进程的场景,需要配置对应进程的用户ID和组ID。 进程的用户ID在文件```base/startup/init/services/etc/passwd```中配置,进程的组ID在文件```base/startup/init/services/etc/group```中配置。 - ```text - # 在base/startup/init/services/etc/passwd新增 - nnrt_host:x:3311:3311:::/bin/false - - # 在base/startup/init/services/etc/group新增 - nnrt_host:x:3311: - ``` + # 在base/startup/init/services/etc/group新增 + nnrt_host:x:3311: + ``` -5. SeLinux配置。 +#### 配置SELinux - OHOS已经开启SELinux特性,需要对新增的进程和服务配置相应的SELinux规则,用于运行host进程启动访问某些资源、发布HDI服务。 +OpenHarmony已经开启SELinux特性,需要对新增的进程和服务配置相应的SELinux规则,用于运行host进程启动访问某些资源、发布HDI服务。 - 1. 在```base/security/selinux/sepolicy/ohos_policy/drivers/adapter/vendor/type.te```文件中配置nnrt_host进程安全上下文,新增配置如下: +1. 在```base/security/selinux/sepolicy/ohos_policy/drivers/adapter/vendor/type.te```文件中配置nnrt_host进程安全上下文,新增配置如下: ```text # 新增配置 type nnrt_host, hdfdomain, domain; ``` > nnrt_host为上文配置的进程名称。 - 2. 由于SeLinux是白名单访问的权限机制,需要根据实际权限需求配置,将服务启动起来之后,通过以下dmesg命令可能查看avc告警, - avc告警会给出缺少的权限,SeLinux的配置也可以参考[OpenHarmony SeLinux子系统的说明](https://gitee.com/openharmony/security_selinux/blob/master/README.md)。 +2. 由于SeLinux是白名单访问的权限机制,需要根据实际权限需求配置。将服务启动之后,可通过以下dmesg命令查看avc告警, +avc告警会给出缺少的权限。SeLinux的配置也可以参考[OpenHarmony SeLinux子系统的说明](https://gitee.com/openharmony/security_selinux/blob/master/README.md)。 ```shell hdc_std shell dmesg | grep nnrt ``` - 3. 新建nnrt_host.te配置文件,将权限配置到nnrt_host.te文件中。 +3. 新建nnrt_host.te配置文件,将权限配置到nnrt_host.te文件中。 ```shell # 创建nnrt文件夹 mkdir base/security/selinux/sepolicy/ohos_policy/drivers/peripheral/nnrt @@ -292,7 +293,7 @@ NNRt通过HDI接口实现与设备芯片的对接,由HDI接口实现跨进程 touch base/security/selinux/sepolicy/ohos_policy/drivers/peripheral/nnrt/vendor/nnrt_host.te ``` - 4. 将所需的权限写入nnrt_host.te文件中,比如: +4. 将所需的权限写入nnrt_host.te文件中,比如: ```text allow nnrt_host dev_hdf_kevent:chr_file { ioctl }; allow nnrt_host hilog_param:file { read }; @@ -301,18 +302,32 @@ NNRt通过HDI接口实现与设备芯片的对接,由HDI接口实现跨进程 allow sh nnrt_host:fd { use }; ``` -6. 删除out目录编译整个系统。 - ```shell - # 删除out目录 - rm -rf ./out - - # 编译 - ./build.sh --product-name rk3568 –ccache --jobs=4 - ``` +#### 配置部件编译入口 +以RK3568产品为例: +```shell +vim //productdefine/common/inherit/chipset_common.json +``` +在"subsystems", "subsystem":"hdf", "components"中添加: +```shell +{ + "component": "drivers_peripheral_foo", + "features": [] +} +``` + +#### 删除out目录并编译整个系统 +```shell +# 删除out目录 +rm -rf ./out + +# 编译 +./build.sh --product-name rk3568 –ccache --jobs=4 +``` ### 调测验证 服务开发完成后,可以使用XTS用例验证基本功能和兼容性,开发者可通过以下步骤进行验证: + 1. 编译NNRt的hats用例,用例在```test/xts/hats/hdf/nnrt```目录下。 ```shell # 进入hats目录 @@ -341,7 +356,7 @@ NNRt通过HDI接口实现与设备芯片的对接,由HDI接口实现跨进程 hdc_std shell "/data/local/tmp/HatsHdfNnrtFunctionTest" ``` - 所有hats用例执行成功,可以看到测试报告通过47个用例,说明服务通过了兼容性测试。 + 所有hats用例执行成功,可以看到测试报告显示已通过47个用例,说明服务通过了兼容性测试。 ```text ... [----------] Global test environment tear-down @@ -352,13 +367,16 @@ NNRt通过HDI接口实现与设备芯片的对接,由HDI接口实现跨进程 ### 开发实例 完整Demo代码可以参考[社区实现](https://gitee.com/openharmony/ai_neural_network_runtime/tree/master/example/drivers)。 + 1. 拷贝```example/driver/nnrt```目录到```drivers/peripheral```路径下。 ```shell cp -r example/driver/nnrt drivers/peripheral ``` + 2. 补充bundle.json文件到```drivers/peripheral/nnrt```,bundle.json参考本教程上面的[开发步骤](#开发步骤)章节。 -3. 由于Demo依赖MindSpore-Lite CPU算子,故需要添加MindSpore-Lite依赖文件。 - - 下载MindSpore-Lite的头文件,[mindspore 1.5.0](https://ms-release.obs.cn-north-4.myhuaweicloud.com/1.5.0/MindSpore/lite/release/linux/mindspore-lite-1.5.0-linux-x64.tar.gz)。 + +3. 由于Demo依赖MindSpore Lite CPU算子,故需要添加MindSpore Lite依赖文件。 + - 下载MindSpore Lite的头文件,[MindSpore Lite 1.5.0](https://ms-release.obs.cn-north-4.myhuaweicloud.com/1.5.0/MindSpore/lite/release/linux/mindspore-lite-1.5.0-linux-x64.tar.gz)。 - 在```drivers/peripheral/nnrt```目录下新建mindspore目录,用于存放mindspore依赖库和头文件。 ```shell mkdir drivers/peripheral/nnrt/mindspore @@ -372,7 +390,7 @@ NNRt通过HDI接口实现与设备芯片的对接,由HDI接口实现跨进程 # 拷贝mindspore schema文件 cp third_party/mindspore/mindspore/lite/schema/* drivers/peripheral/nnrt/hdi_cpu_service/include/mindspore_schema/ ``` - - 编译MindSpore-Lite的动态库,并将动态库放到mindspore目录下。 + - 编译MindSpore Lite的动态库,并将动态库放到mindspore目录下。 ```shell # 编译mindspore动态库 ./build.sh --product-name rk3568 -ccaache --jobs 4 --build-target mindspore_lib @@ -383,4 +401,4 @@ NNRt通过HDI接口实现与设备芯片的对接,由HDI接口实现跨进程 # 将mindspore动态拷贝到drivers/peripheral/nnrt/mindspore/mindspore。 cp out/rk3568/package/phone/system/lib/libmindspore-lite.huawei.so drivers/peripheral/nnrt/mindspore/mindspore/ ``` - 4. 其他配置请参考本教程上面的[开发步骤](#开发步骤)章节。 \ No newline at end of file +4. 其他配置请参考本教程上面的[开发步骤](#开发步骤)章节。 \ No newline at end of file -- GitLab