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![](figures/AI引擎框架.png "AI引擎框架")
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;amp;inputInfo, DataInfo &amp;amp;outputInfo) override;
96        int32_t SetOption(int optionType, const DataInfo &amp;amp;inputInfo) override;
97        int32_t GetOption(int optionType, const DataInfo &amp;amp;inputInfo, DataInfo &amp;amp;outputInfo) override;
98        int32_t SyncProcess(IRequest *request, IResponse *&amp;amp;response) override;
99        int32_t AsyncProcess(IRequest *request, IPluginCallback*callback) override;
100        int32_t Release(bool isFullUnload, long long transactionId, const DataInfo &amp;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