1# AI业务子系统<a name="ZH-CN_TOPIC_0000001083278044"></a> 2 3- [简介](#section187321516154516) 4- [目录](#section571610913453) 5- [约束](#section5748426453) 6- [使用](#section7981135212144) 7- [相关仓](#section10492183517430) 8- [AI引擎开发导航](#section6808423133718) 9 10## 简介<a name="section187321516154516"></a> 11 12AI业务子系统是OpenHarmony提供原生的分布式AI能力的子系统。本次开源范围是提供了统一的AI引擎框架,实现算法能力快速插件化集成。框架中主要包含插件管理、模块管理和通信管理等模块,对AI算法能力进行生命周期管理和按需部署。后续,会逐步定义统一的AI能力接口,便于AI能力的分布式调用。同时,提供适配不同推理框架层级的统一推理接口。 13 14**图 1** AI引擎框架<a name="fig17296164711526"></a> 15![](figures/AI引擎框架.png "AI引擎框架") 16 17## 目录<a name="section571610913453"></a> 18 19``` 20/foundation/ai/engine # AI子系统主目录 21├── interfaces 22│ └── kits # AI子系统对外接口 23└── services 24│ ├── client # AI子系统Client模块 25│ │ ├── client_executor # Client模块执行主体 26│ │ └── communication_adapter # Client模块通信适配层,支持拓展 27│ ├── common # AI子系统公共工具、协议模块 28│ │ ├── platform 29│ │ ├── protocol 30│ │ └── utils 31│ └── server # AI子系统服务端模块 32│ │ ├── communication_adapter # Server模块通信适配层,支持拓展 33│ │ ├── plugin 34│ │ ├── asr 35│ │ └── keyword_spotting # ASR算法插件参考:唤醒词识别 36│ │ └── cv 37│ │ └── image_classification # CV算法插件参考:图片分类 38│ │ ├── plugin_manager 39│ │ └── server_executor # Server模块执行主体 40``` 41 42## 约束<a name="section5748426453"></a> 43 44* **语言限制**:C/C++语言 45 46* **操作系统限制**:OpenHarmony操作系统 47 48* **AI服务启动的约束与限制**:SAMGR(System Ability Manager)启动且运行正常 49 50## 使用<a name="section7981135212144"></a> 51 521. **AI业务子系统编译** 53 54 轻量级AI引擎框架模块,代码所在路径://foundation/ai/engine/services 55 56 编译指令如下: 57 58 1. **设置编译路径** 59 60 ``` 61 hb set -root dir(项目代码根目录) 62 ``` 63 64 2. **设置编译产品**(执行后用方向键和回车进行选择): 65 66 ``` 67 hb set -p 68 ``` 69 70 3. **执行编译**: 71 72 ``` 73 hb build -f(编译全仓) 74 或者 hb build ai_engine(只编译ai_engine组件) 75 ``` 76 77 >**注意**:hb相关配置请参考编译构建子系统**build\_lite** 78 792. **插件开发**(以唤醒词识别为例) 80 81 位置://foundation/ai/engine/services/server/plugin/asr/keyword\_spotting 82 83 >**注意**:插件需要实现server提供的IPlugin接口和IPluginCallback接口 84 85 ``` 86 #include "plugin/i_plugin.h 87 class KWSPlugin : public IPlugin { // Keywords Spotting Plugin(KWSPlugin)继承IPlugin算法插件基类public: 88 KWSPlugin(); 89 ~KWSPlugin(); 90 91 const long long GetVersion() const override; 92 const char* GetName() const override; 93 const char* GetInferMode() const override; 94 95 int32_t Prepare(long long transactionId, const DataInfo &amp;inputInfo, DataInfo &amp;outputInfo) override; 96 int32_t SetOption(int optionType, const DataInfo &amp;inputInfo) override; 97 int32_t GetOption(int optionType, const DataInfo &amp;inputInfo, DataInfo &amp;outputInfo) override; 98 int32_t SyncProcess(IRequest *request, IResponse *&amp;response) override; 99 int32_t AsyncProcess(IRequest *request, IPluginCallback*callback) override; 100 int32_t Release(bool isFullUnload, long long transactionId, const DataInfo &amp;inputInfo) override; 101 . 102 . 103 . 104 }; 105 ``` 106 107 >**注意**:SyncProcess和AsyncProcess接口只需要根据算法实际情况实现一个接口即可,另一个用空方法占位(这里KWS插件为同步算法,故异步接口为空实现)。 108 109 ``` 110 #include "aie_log.h" 111 #include "aie_retcode_inner.h" 112 . 113 . 114 . 115 116 const long long KWSPlugin::GetVersion() const 117 { 118 return ALGOTYPE_VERSION_KWS; 119 } 120 121 const char *KWSPlugin::GetName() const 122 { 123 return ALGORITHM_NAME_KWS.c_str(); 124 } 125 126 const char *KWSPlugin::GetInferMode() const 127 { 128 return DEFAULT_INFER_MODE.c_str(); 129 } 130 . 131 . 132 . 133 int32_t KWSPlugin::AsyncProcess(IRequest *request, IPluginCallback *callback) 134 { 135 return RETCODE_SUCCESS; 136 } 137 ``` 138 1393. **插件SDK开发**(以唤醒词识别kws\_sdk为例) 140 141 位置://foundation/ai/engine/services/client/algorithm\_sdk/asr/keyword\_spotting 142 143 唤醒词识别SDK: 144 145 ``` 146 class KWSSdk { 147 public: 148 KWSSdk(); 149 virtual ~KWSSdk(); 150 151 /** 152 * @brief Create a new session with KWS Plugin 153 * 154 * @return Returns KWS_RETCODE_SUCCESS(0) if the operation is successful, 155 * returns a non-zero value otherwise. 156 */ 157 int32_t Create(); 158 159 /** 160 * @brief Synchronously execute keyword spotting once 161 * 162 * @param audioInput pcm data. 163 * @return Returns KWS_RETCODE_SUCCESS(0) if the operation is successful, 164 * returns a non-zero value otherwise. 165 */ 166 int32_t SyncExecute(const Array<int16_t> &audioInput); 167 168 /** 169 * @brief Asynchronously execute keyword spotting once 170 * 171 * @param audioInput pcm data. 172 * @return Returns KWS_RETCODE_SUCCESS(0) if the operation is successful, 173 * returns a non-zero value otherwise. 174 */ 175 int32_t AsyncExecute(const Array<int16_t> &audioInput); 176 177 /** 178 * @brief Set callback 179 * 180 * @param callback Callback function that will be called during the process. 181 * @return Returns KWS_RETCODE_SUCCESS(0) if the operation is successful, 182 * returns a non-zero value otherwise. 183 */ 184 int32_t SetCallback(const std::shared_ptr<KWSCallback> &callback); 185 186 /** 187 * @brief Destroy the created session with KWS Plugin 188 * 189 * @return Returns KWS_RETCODE_SUCCESS(0) if the operation is successful, 190 * returns a non-zero value otherwise. 191 */ 192 int32_t Destroy(); 193 ``` 194 195 >**注意**:SDK调用AI引擎客户端接口顺序应遵循AieClientInit-\>AieClientPrepare-\>AieClientSyncProcess/AieClientAsyncProcess-\>AieClientRelease-\>AieClientDestroy,否则调用接口会返回错误码;同时应保证各个接口都有调用到,要不然会引起内存泄漏。 196 197 198 ``` 199 int32_t KWSSdk::KWSSdkImpl::Create() 200 { 201 if (kwsHandle_ != INVALID_KWS_HANDLE) { 202 HILOGE("[KWSSdkImpl]The SDK has been created"); 203 return KWS_RETCODE_FAILURE; 204 } 205 if (InitComponents() != RETCODE_SUCCESS) { 206 HILOGE("[KWSSdkImpl]Fail to init sdk components"); 207 return KWS_RETCODE_FAILURE; 208 } 209 int32_t retCode = AieClientInit(configInfo_, clientInfo_, algorithmInfo_, nullptr); 210 if (retCode != RETCODE_SUCCESS) { 211 HILOGE("[KWSSdkImpl]AieClientInit failed. Error code[%d]", retCode); 212 return KWS_RETCODE_FAILURE; 213 } 214 if (clientInfo_.clientId == INVALID_CLIENT_ID) { 215 HILOGE("[KWSSdkImpl]Fail to allocate client id"); 216 return KWS_RETCODE_FAILURE; 217 } 218 DataInfo inputInfo = { 219 .data = nullptr, 220 .length = 0, 221 }; 222 DataInfo outputInfo = { 223 .data = nullptr, 224 .length = 0, 225 }; 226 retCode = AieClientPrepare(clientInfo_, algorithmInfo_, inputInfo, outputInfo, nullptr); 227 if (retCode != RETCODE_SUCCESS) { 228 HILOGE("[KWSSdkImpl]AieclientPrepare failed. Error code[%d]", retCode); 229 return KWS_RETCODE_FAILURE; 230 } 231 if (outputInfo.data == nullptr || outputInfo.length <= 0) { 232 HILOGE("[KWSSdkImpl]The data or length of output info is invalid"); 233 return KWS_RETCODE_FAILURE; 234 } 235 MallocPointerGuard<unsigned char> pointerGuard(outputInfo.data); 236 retCode = PluginHelper::UnSerializeHandle(outputInfo, kwsHandle_); 237 if (retCode != RETCODE_SUCCESS) { 238 HILOGE("[KWSSdkImpl]Get handle from inputInfo failed"); 239 return KWS_RETCODE_FAILURE; 240 } 241 return KWS_RETCODE_SUCCESS; 242 } 243 244 int32_t KWSSdk::KWSSdkImpl::SyncExecute(const Array<uint16_t> &audioInput) 245 { 246 intptr_t newHandle = 0; 247 Array<int32_t> kwsResult = { 248 .data = nullptr, 249 .size = 0 250 }; 251 DataInfo inputInfo = { 252 .data = nullptr, 253 .length = 0 254 }; 255 DataInfo outputInfo = { 256 .data = nullptr, 257 .length = 0 258 }; 259 int32_t retCode = PluginHelper::SerializeInputData(kwsHandle_, audioInput, inputInfo); 260 if (retCode != RETCODE_SUCCESS) { 261 HILOGE("[KWSSdkImpl]Fail to serialize input data"); 262 callback_->OnError(KWS_RETCODE_SERIALIZATION_ERROR); 263 return RETCODE_FAILURE; 264 } 265 retCode = AieClientSyncProcess(clientInfo_, algorithmInfo_, inputInfo, outputInfo); 266 if (retCode != RETCODE_SUCCESS) { 267 HILOGE("[KWSSdkImpl]AieClientSyncProcess failed. Error code[%d]", retCode); 268 callback_->OnError(KWS_RETCODE_PLUGIN_EXECUTION_ERROR); 269 return RETCODE_FAILURE; 270 } 271 if (outputInfo.data == nullptr || outputInfo.length <= 0) { 272 HILOGE("[KWSSdkImpl] The data or length of outputInfo is invalid. Error code[%d]", retCode); 273 callback_->OnError(KWS_RETCODE_NULL_PARAM); 274 return RETCODE_FAILURE; 275 } 276 MallocPointerGuard<unsigned char> pointerGuard(outputInfo.data); 277 retCode = PluginHelper::UnSerializeOutputData(outputInfo, newHandle, kwsResult); 278 if (retCode != RETCODE_SUCCESS) { 279 HILOGE("[KWSSdkImpl]UnSerializeOutputData failed. Error code[%d]", retCode); 280 callback_->OnError(KWS_RETCODE_UNSERIALIZATION_ERROR); 281 return retCode; 282 } 283 if (kwsHandle_ != newHandle) { 284 HILOGE("[KWSSdkImpl]The handle[%lld] of output data is not equal to the current handle[%lld]", 285 (long long)newHandle, (long long)kwsHandle_); 286 callback_->OnError(KWS_RETCODE_PLUGIN_SESSION_ERROR); 287 return RETCODE_FAILURE; 288 } 289 callback_->OnResult(kwsResult); 290 return RETCODE_SUCCESS; 291 } 292 293 int32_t KWSSdk::KWSSdkImpl::Destroy() 294 { 295 if (kwsHandle_ == INVALID_KWS_HANDLE) { 296 return KWS_RETCODE_SUCCESS; 297 } 298 DataInfo inputInfo = { 299 .data = nullptr, 300 .length = 0 301 }; 302 int32_t retCode = PluginHelper::SerializeHandle(kwsHandle_, inputInfo); 303 if (retCode != RETCODE_SUCCESS) { 304 HILOGE("[KWSSdkImpl]SerializeHandle failed. Error code[%d]", retCode); 305 return KWS_RETCODE_FAILURE; 306 } 307 retCode = AieClientRelease(clientInfo_, algorithmInfo_, inputInfo); 308 if (retCode != RETCODE_SUCCESS) { 309 HILOGE("[KWSSdkImpl]AieClientRelease failed. Error code[%d]", retCode); 310 return KWS_RETCODE_FAILURE; 311 } 312 retCode = AieClientDestroy(clientInfo_); 313 if (retCode != RETCODE_SUCCESS) { 314 HILOGE("[KWSSdkImpl]AieClientDestroy failed. Error code[%d]", retCode); 315 return KWS_RETCODE_FAILURE; 316 } 317 mfccProcessor_ = nullptr; 318 pcmIterator_ = nullptr; 319 callback_ = nullptr; 320 kwsHandle_ = INVALID_KWS_HANDLE; 321 return KWS_RETCODE_SUCCESS; 322 } 323 ``` 324 3254. **sample开发** [(参考唤醒词识别demo)](https://gitee.com/openharmony/applications_sample_camera/tree/master/ai) 326 327 位置://applications/sample/camera/ai/asr/keyword\_spotting 328 329 **调用Create** 330 331 ``` 332 bool KwsManager::PreparedInference() 333 { 334 if (capturer_ == nullptr) { 335 printf("[KwsManager] only load plugin after AudioCapturer ready\n"); 336 return false; 337 } 338 if (plugin_ != nullptr) { 339 printf("[KwsManager] stop created InferencePlugin at first\n"); 340 StopInference(); 341 } 342 plugin_ = std::make_shared<KWSSdk>(); 343 if (plugin_ == nullptr) { 344 printf("[KwsManager] fail to create inferencePlugin\n"); 345 return false; 346 } 347 if (plugin_->Create() != SUCCESS) { 348 printf("[KwsManager] KWSSdk fail to create.\n"); 349 return false; 350 } 351 std::shared_ptr<KWSCallback> callback = std::make_shared<MyKwsCallback>(); 352 if (callback == nullptr) { 353 printf("[KwsManager] new Callback failed.\n"); 354 return false; 355 } 356 plugin_->SetCallback(callback); 357 return true; 358 } 359 ``` 360 361 **调用SyncExecute** 362 363 ``` 364 void KwsManager::ConsumeSamples() 365 { 366 uintptr_t sampleAddr = 0; 367 size_t sampleSize = 0; 368 int32_t retCode = SUCCESS; 369 while (status_ == RUNNING) { 370 { 371 std::lock_guard<std::mutex> lock(mutex_); 372 if (cache_ == nullptr) { 373 printf("[KwsManager] cache_ is nullptr.\n"); 374 break; 375 } 376 sampleSize = cache_->GetCapturedBuffer(sampleAddr); 377 } 378 if (sampleSize == 0 || sampleAddr == 0) { 379 continue; 380 } 381 Array<int16_t> input = { 382 .data = (int16_t *)(sampleAddr), 383 .size = sampleSize >> 1 384 }; 385 { 386 std::lock_guard<std::mutex> lock(mutex_); 387 if (plugin_ == nullptr) { 388 printf("[KwsManager] cache_ is nullptr.\n"); 389 break; 390 } 391 if ((retCode = plugin_->SyncExecute(input)) != SUCCESS) { 392 printf("[KwsManager] SyncExecute KWS failed with retCode = [%d]\n", retCode); 393 continue; 394 } 395 } 396 } 397 } 398 ``` 399 400 **调用Destroy** 401 402 ``` 403 void KwsManager::StopInference() 404 { 405 printf("[KwsManager] StopInference\n"); 406 if (plugin_ != nullptr) { 407 int ret = plugin_->Destroy(); 408 if (ret != SUCCESS) { 409 printf("[KwsManager] plugin_ destroy failed.\n"); 410 } 411 plugin_ = nullptr; 412 } 413 } 414 ``` 415 416 417## 相关仓<a name="section10492183517430"></a> 418 419[AI子系统](https://gitee.com/openharmony/docs/blob/master/zh-cn/readme/AI%E4%B8%9A%E5%8A%A1%E5%AD%90%E7%B3%BB%E7%BB%9F.md) 420 421[ai_engine](https://gitee.com/openharmony/ai_engine) 422 423## 依赖仓: 424 425[build\_lite](https://gitee.com/openharmony/build_lite/blob/master/README_zh.md) 426 427[systemabilitymgr\_samgr\_lite](https://gitee.com/openharmony/systemabilitymgr_samgr_lite/blob/master/README_zh.md) 428 429[startup\_init\_lite](https://gitee.com/openharmony/startup_init_lite/blob/master/README_zh.md) 430 431## AI引擎开发导航<a name="section6808423133718"></a> 432 433[《AI插件开发指南》](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/subsystems/subsys-ai-aiframework-devguide.md)