1# AI业务子系统<a name="ZH-CN_TOPIC_0000001072614474"></a> 2 3- [简介](#section187321516154516) 4- [目录](#section571610913453) 5- [约束](#section5748426453) 6- [使用](#section6370123616447) 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 16 17## 目录<a name="section571610913453"></a> 18 19``` 20/foundation/ai/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="section6370123616447"></a> 51 521. **AI业务子系统编译** 53 54 轻量级AI引擎框架模块,代码所在路径://foundation/ai/ai_engine/services 55 56 编译指令如下: 57 58 **设置编译路径** 59 60 ``` 61 hb set -root dir(项目代码根目录) 62 ``` 63 64 **设置编译产品**(执行后用方向键和回车进行选择): 65 66 ``` 67 hb set -p 68 ``` 69 70 **执行编译**: 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/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/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 int32_t KWSSdk::KWSSdkImpl::Create() 199 { 200 if (kwsHandle_ != INVALID_KWS_HANDLE) { 201 HILOGE("[KWSSdkImpl]The SDK has been created"); 202 return KWS_RETCODE_FAILURE; 203 } 204 if (InitComponents() != RETCODE_SUCCESS) { 205 HILOGE("[KWSSdkImpl]Fail to init sdk components"); 206 return KWS_RETCODE_FAILURE; 207 } 208 int32_t retCode = AieClientInit(configInfo_, clientInfo_, algorithmInfo_, nullptr); 209 if (retCode != RETCODE_SUCCESS) { 210 HILOGE("[KWSSdkImpl]AieClientInit failed. Error code[%d]", retCode); 211 return KWS_RETCODE_FAILURE; 212 } 213 if (clientInfo_.clientId == INVALID_CLIENT_ID) { 214 HILOGE("[KWSSdkImpl]Fail to allocate client id"); 215 return KWS_RETCODE_FAILURE; 216 } 217 DataInfo inputInfo = { 218 .data = nullptr, 219 .length = 0, 220 }; 221 DataInfo outputInfo = { 222 .data = nullptr, 223 .length = 0, 224 }; 225 retCode = AieClientPrepare(clientInfo_, algorithmInfo_, inputInfo, outputInfo, nullptr); 226 if (retCode != RETCODE_SUCCESS) { 227 HILOGE("[KWSSdkImpl]AieclientPrepare failed. Error code[%d]", retCode); 228 return KWS_RETCODE_FAILURE; 229 } 230 if (outputInfo.data == nullptr || outputInfo.length <= 0) { 231 HILOGE("[KWSSdkImpl]The data or length of output info is invalid"); 232 return KWS_RETCODE_FAILURE; 233 } 234 MallocPointerGuard<unsigned char> pointerGuard(outputInfo.data); 235 retCode = PluginHelper::UnSerializeHandle(outputInfo, kwsHandle_); 236 if (retCode != RETCODE_SUCCESS) { 237 HILOGE("[KWSSdkImpl]Get handle from inputInfo failed"); 238 return KWS_RETCODE_FAILURE; 239 } 240 return KWS_RETCODE_SUCCESS; 241 } 242 243 int32_t KWSSdk::KWSSdkImpl::SyncExecute(const Array<uint16_t> &audioInput) 244 { 245 intptr_t newHandle = 0; 246 Array<int32_t> kwsResult = { 247 .data = nullptr, 248 .size = 0 249 }; 250 DataInfo inputInfo = { 251 .data = nullptr, 252 .length = 0 253 }; 254 DataInfo outputInfo = { 255 .data = nullptr, 256 .length = 0 257 }; 258 int32_t retCode = PluginHelper::SerializeInputData(kwsHandle_, audioInput, inputInfo); 259 if (retCode != RETCODE_SUCCESS) { 260 HILOGE("[KWSSdkImpl]Fail to serialize input data"); 261 callback_->OnError(KWS_RETCODE_SERIALIZATION_ERROR); 262 return RETCODE_FAILURE; 263 } 264 retCode = AieClientSyncProcess(clientInfo_, algorithmInfo_, inputInfo, outputInfo); 265 if (retCode != RETCODE_SUCCESS) { 266 HILOGE("[KWSSdkImpl]AieClientSyncProcess failed. Error code[%d]", retCode); 267 callback_->OnError(KWS_RETCODE_PLUGIN_EXECUTION_ERROR); 268 return RETCODE_FAILURE; 269 } 270 if (outputInfo.data == nullptr || outputInfo.length <= 0) { 271 HILOGE("[KWSSdkImpl] The data or length of outputInfo is invalid. Error code[%d]", retCode); 272 callback_->OnError(KWS_RETCODE_NULL_PARAM); 273 return RETCODE_FAILURE; 274 } 275 MallocPointerGuard<unsigned char> pointerGuard(outputInfo.data); 276 retCode = PluginHelper::UnSerializeOutputData(outputInfo, newHandle, kwsResult); 277 if (retCode != RETCODE_SUCCESS) { 278 HILOGE("[KWSSdkImpl]UnSerializeOutputData failed. Error code[%d]", retCode); 279 callback_->OnError(KWS_RETCODE_UNSERIALIZATION_ERROR); 280 return retCode; 281 } 282 if (kwsHandle_ != newHandle) { 283 HILOGE("[KWSSdkImpl]The handle[%lld] of output data is not equal to the current handle[%lld]", 284 (long long)newHandle, (long long)kwsHandle_); 285 callback_->OnError(KWS_RETCODE_PLUGIN_SESSION_ERROR); 286 return RETCODE_FAILURE; 287 } 288 callback_->OnResult(kwsResult); 289 return RETCODE_SUCCESS; 290 } 291 292 int32_t KWSSdk::KWSSdkImpl::Destroy() 293 { 294 if (kwsHandle_ == INVALID_KWS_HANDLE) { 295 return KWS_RETCODE_SUCCESS; 296 } 297 DataInfo inputInfo = { 298 .data = nullptr, 299 .length = 0 300 }; 301 int32_t retCode = PluginHelper::SerializeHandle(kwsHandle_, inputInfo); 302 if (retCode != RETCODE_SUCCESS) { 303 HILOGE("[KWSSdkImpl]SerializeHandle failed. Error code[%d]", retCode); 304 return KWS_RETCODE_FAILURE; 305 } 306 retCode = AieClientRelease(clientInfo_, algorithmInfo_, inputInfo); 307 if (retCode != RETCODE_SUCCESS) { 308 HILOGE("[KWSSdkImpl]AieClientRelease failed. Error code[%d]", retCode); 309 return KWS_RETCODE_FAILURE; 310 } 311 retCode = AieClientDestroy(clientInfo_); 312 if (retCode != RETCODE_SUCCESS) { 313 HILOGE("[KWSSdkImpl]AieClientDestroy failed. Error code[%d]", retCode); 314 return KWS_RETCODE_FAILURE; 315 } 316 mfccProcessor_ = nullptr; 317 pcmIterator_ = nullptr; 318 callback_ = nullptr; 319 kwsHandle_ = INVALID_KWS_HANDLE; 320 return KWS_RETCODE_SUCCESS; 321 } 322 ``` 323 3244. **sample开发**(参考唤醒词识别demo) 325 326 位置://applications/sample/camera/ai/asr/keyword\_spotting 327 328 **调用Create** 329 330 ``` 331 bool KwsManager::PreparedInference() 332 { 333 if (capturer_ == nullptr) { 334 printf("[KwsManager] only load plugin after AudioCapturer ready\n"); 335 return false; 336 } 337 if (plugin_ != nullptr) { 338 printf("[KwsManager] stop created InferencePlugin at first\n"); 339 StopInference(); 340 } 341 plugin_ = std::make_shared<KWSSdk>(); 342 if (plugin_ == nullptr) { 343 printf("[KwsManager] fail to create inferencePlugin\n"); 344 return false; 345 } 346 if (plugin_->Create() != SUCCESS) { 347 printf("[KwsManager] KWSSdk fail to create.\n"); 348 return false; 349 } 350 std::shared_ptr<KWSCallback> callback = std::make_shared<MyKwsCallback>(); 351 if (callback == nullptr) { 352 printf("[KwsManager] new Callback failed.\n"); 353 return false; 354 } 355 plugin_->SetCallback(callback); 356 return true; 357 } 358 ``` 359 360 **调用SyncExecute** 361 362 ``` 363 void KwsManager::ConsumeSamples() 364 { 365 uintptr_t sampleAddr = 0; 366 size_t sampleSize = 0; 367 int32_t retCode = SUCCESS; 368 while (status_ == RUNNING) { 369 { 370 std::lock_guard<std::mutex> lock(mutex_); 371 if (cache_ == nullptr) { 372 printf("[KwsManager] cache_ is nullptr.\n"); 373 break; 374 } 375 sampleSize = cache_->GetCapturedBuffer(sampleAddr); 376 } 377 if (sampleSize == 0 || sampleAddr == 0) { 378 continue; 379 } 380 Array<int16_t> input = { 381 .data = (int16_t *)(sampleAddr), 382 .size = sampleSize >> 1 383 }; 384 { 385 std::lock_guard<std::mutex> lock(mutex_); 386 if (plugin_ == nullptr) { 387 printf("[KwsManager] cache_ is nullptr.\n"); 388 break; 389 } 390 if ((retCode = plugin_->SyncExecute(input)) != SUCCESS) { 391 printf("[KwsManager] SyncExecute KWS failed with retCode = [%d]\n", retCode); 392 continue; 393 } 394 } 395 } 396 } 397 ``` 398 399 **调用Destroy** 400 401 ``` 402 void KwsManager::StopInference() 403 { 404 printf("[KwsManager] StopInference\n"); 405 if (plugin_ != nullptr) { 406 int ret = plugin_->Destroy(); 407 if (ret != SUCCESS) { 408 printf("[KwsManager] plugin_ destroy failed.\n"); 409 } 410 plugin_ = nullptr; 411 } 412 } 413 ``` 414 415 416## 涉及仓<a name="section10492183517430"></a> 417 418[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) 419 420**ai\_engine** 421 422依赖仓: 423 424[build\_lite](https://gitee.com/openharmony/build_lite/blob/master/README_zh.md) 425 426[distributedschedule\_samgr\_lite](https://gitee.com/openharmony/distributedschedule_samgr_lite/blob/master/README_zh.md) 427 428[startup\_init\_lite](https://gitee.com/openharmony/startup_init_lite/blob/master/README_zh.md) 429 430## AI引擎开发导航<a name="section6808423133718"></a> 431 432- [《AI插件开发指南》](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/subsystems/subsys-ai-aiframework-devguide.md) 433 434 435