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 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 196 >**注意**:SDK调用AI引擎客户端接口顺序应遵循AieClientInit-\>AieClientPrepare-\>AieClientSyncProcess/AieClientAsyncProcess-\>AieClientRelease-\>AieClientDestroy,否则调用接口会返回错误码;同时应保证各个接口都有调用到,要不然会引起内存泄漏。 197 198 199 ``` 200 int32_t KWSSdk::KWSSdkImpl::Create() 201 { 202 if (kwsHandle_ != INVALID_KWS_HANDLE) { 203 HILOGE("[KWSSdkImpl]The SDK has been created"); 204 return KWS_RETCODE_FAILURE; 205 } 206 if (InitComponents() != RETCODE_SUCCESS) { 207 HILOGE("[KWSSdkImpl]Fail to init sdk components"); 208 return KWS_RETCODE_FAILURE; 209 } 210 int32_t retCode = AieClientInit(configInfo_, clientInfo_, algorithmInfo_, nullptr); 211 if (retCode != RETCODE_SUCCESS) { 212 HILOGE("[KWSSdkImpl]AieClientInit failed. Error code[%d]", retCode); 213 return KWS_RETCODE_FAILURE; 214 } 215 if (clientInfo_.clientId == INVALID_CLIENT_ID) { 216 HILOGE("[KWSSdkImpl]Fail to allocate client id"); 217 return KWS_RETCODE_FAILURE; 218 } 219 DataInfo inputInfo = { 220 .data = nullptr, 221 .length = 0, 222 }; 223 DataInfo outputInfo = { 224 .data = nullptr, 225 .length = 0, 226 }; 227 retCode = AieClientPrepare(clientInfo_, algorithmInfo_, inputInfo, outputInfo, nullptr); 228 if (retCode != RETCODE_SUCCESS) { 229 HILOGE("[KWSSdkImpl]AieclientPrepare failed. Error code[%d]", retCode); 230 return KWS_RETCODE_FAILURE; 231 } 232 if (outputInfo.data == nullptr || outputInfo.length <= 0) { 233 HILOGE("[KWSSdkImpl]The data or length of output info is invalid"); 234 return KWS_RETCODE_FAILURE; 235 } 236 MallocPointerGuard<unsigned char> pointerGuard(outputInfo.data); 237 retCode = PluginHelper::UnSerializeHandle(outputInfo, kwsHandle_); 238 if (retCode != RETCODE_SUCCESS) { 239 HILOGE("[KWSSdkImpl]Get handle from inputInfo failed"); 240 return KWS_RETCODE_FAILURE; 241 } 242 return KWS_RETCODE_SUCCESS; 243 } 244 245 int32_t KWSSdk::KWSSdkImpl::SyncExecute(const Array<uint16_t> &audioInput) 246 { 247 intptr_t newHandle = 0; 248 Array<int32_t> kwsResult = { 249 .data = nullptr, 250 .size = 0 251 }; 252 DataInfo inputInfo = { 253 .data = nullptr, 254 .length = 0 255 }; 256 DataInfo outputInfo = { 257 .data = nullptr, 258 .length = 0 259 }; 260 int32_t retCode = PluginHelper::SerializeInputData(kwsHandle_, audioInput, inputInfo); 261 if (retCode != RETCODE_SUCCESS) { 262 HILOGE("[KWSSdkImpl]Fail to serialize input data"); 263 callback_->OnError(KWS_RETCODE_SERIALIZATION_ERROR); 264 return RETCODE_FAILURE; 265 } 266 retCode = AieClientSyncProcess(clientInfo_, algorithmInfo_, inputInfo, outputInfo); 267 if (retCode != RETCODE_SUCCESS) { 268 HILOGE("[KWSSdkImpl]AieClientSyncProcess failed. Error code[%d]", retCode); 269 callback_->OnError(KWS_RETCODE_PLUGIN_EXECUTION_ERROR); 270 return RETCODE_FAILURE; 271 } 272 if (outputInfo.data == nullptr || outputInfo.length <= 0) { 273 HILOGE("[KWSSdkImpl] The data or length of outputInfo is invalid. Error code[%d]", retCode); 274 callback_->OnError(KWS_RETCODE_NULL_PARAM); 275 return RETCODE_FAILURE; 276 } 277 MallocPointerGuard<unsigned char> pointerGuard(outputInfo.data); 278 retCode = PluginHelper::UnSerializeOutputData(outputInfo, newHandle, kwsResult); 279 if (retCode != RETCODE_SUCCESS) { 280 HILOGE("[KWSSdkImpl]UnSerializeOutputData failed. Error code[%d]", retCode); 281 callback_->OnError(KWS_RETCODE_UNSERIALIZATION_ERROR); 282 return retCode; 283 } 284 if (kwsHandle_ != newHandle) { 285 HILOGE("[KWSSdkImpl]The handle[%lld] of output data is not equal to the current handle[%lld]", 286 (long long)newHandle, (long long)kwsHandle_); 287 callback_->OnError(KWS_RETCODE_PLUGIN_SESSION_ERROR); 288 return RETCODE_FAILURE; 289 } 290 callback_->OnResult(kwsResult); 291 return RETCODE_SUCCESS; 292 } 293 294 int32_t KWSSdk::KWSSdkImpl::Destroy() 295 { 296 if (kwsHandle_ == INVALID_KWS_HANDLE) { 297 return KWS_RETCODE_SUCCESS; 298 } 299 DataInfo inputInfo = { 300 .data = nullptr, 301 .length = 0 302 }; 303 int32_t retCode = PluginHelper::SerializeHandle(kwsHandle_, inputInfo); 304 if (retCode != RETCODE_SUCCESS) { 305 HILOGE("[KWSSdkImpl]SerializeHandle failed. Error code[%d]", retCode); 306 return KWS_RETCODE_FAILURE; 307 } 308 retCode = AieClientRelease(clientInfo_, algorithmInfo_, inputInfo); 309 if (retCode != RETCODE_SUCCESS) { 310 HILOGE("[KWSSdkImpl]AieClientRelease failed. Error code[%d]", retCode); 311 return KWS_RETCODE_FAILURE; 312 } 313 retCode = AieClientDestroy(clientInfo_); 314 if (retCode != RETCODE_SUCCESS) { 315 HILOGE("[KWSSdkImpl]AieClientDestroy failed. Error code[%d]", retCode); 316 return KWS_RETCODE_FAILURE; 317 } 318 mfccProcessor_ = nullptr; 319 pcmIterator_ = nullptr; 320 callback_ = nullptr; 321 kwsHandle_ = INVALID_KWS_HANDLE; 322 return KWS_RETCODE_SUCCESS; 323 } 324 ``` 325 3264. **sample开发** 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](https://gitee.com/openharmony/ai_engine) 421 422## 依赖仓: 423 424[build\_lite](https://gitee.com/openharmony/build_lite/blob/master/README_zh.md) 425 426[systemabilitymgr\_samgr\_lite](https://gitee.com/openharmony/systemabilitymgr_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)