• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# AI
2
3## Introduction
4
5The AI subsystem is the part of OpenHarmony that provides native distributed AI capabilities. At the heart of the subsystem is a unified AI engine framework, which implements quick integration of AI algorithm plug-ins. The framework consists of the plug-in management, module management, and communication management modules, fulfilling lifecycle management and on-demand deployment of AI algorithms. Under this framework, AI algorithm APIs will be standardized to facilitate distributed calling of AI capabilities. In addition, unified inference APIs will be provided to adapt to different inference framework hierarchies.
6
7**Figure  1**  AI engine framework<a name="fig17296164711526"></a>
8![](figures/ai-engine-framework.png "ai-engine-framework")
9
10## Directory Structure
11
12```
13/foundation/ai/engine                        # Home directory of the AI subsystem
14├── interfaces
15│  └── kits                                  # External APIs of the AI subsystem
16└── services
17│  ├── client                                # Client module of the AI subsystem
18│  │  ├── client_executor                    # Executor of the client module
19│  │  └── communication_adapter              # Communication adaptation layer for the client module, with extension supported
20│  ├── common                                # Common tools and protocol modules of the AI subsystem
21│  │  ├── platform
22│  │  ├── protocol
23│  │  └── utils
24│  └── server                                # Server module of the AI subsystem
25│  │  ├── communication_adapter              # Communication adaptation layer for the server module, with extension supported
26│  │  ├── plugin
27│  │     ├── asr
28│  │        └── keyword_spotting             # ASR algorithm plug-in reference: keyword spotting
29│  │     └── cv
30│  │        └── image_classification         # CV algorithm plug-in reference: image classification
31│  │  ├── plugin_manager
32│  │  └── server_executor                    # Executor of the server module
33```
34
35## Constraints
36
37* **Programming language**: C/C++
38
39* **Operating system**: OpenHarmony mini- and small-system
40
41* **Others**: The System Ability Manager \(Samgr\) has been started and is running properly.
42
43## Usage
44
451.  Compile the AI subsystem.
46
47    The source code for lightweight AI framework is available at  **//foundation/ai/engine/services**.
48
49    The compilation procedure is as follows:
50
51    1. Set the compilation path.
52
53    ```
54    hb set -root dir (root dir is the root directory of the project code.)
55    ```
56
57    2. Specify the product for compilation. \(After the product list is displayed using the following command, move to the desired product with arrow keys and press  **Enter**.\)
58
59    ```
60    hb set -p
61    ```
62
63    3. Start compilation.
64
65    ```
66    hb build -f (Use this command if you want to compile the entire repository.)
67    hb build ai_engine (Use this command if you want to compile only the ai_engine module.)
68    ```
69
70    >**Note**: For details about the hb configuration, see the readme of the build\_lite subsystem.
71
722.  Develop the plug-in, with keyword spotting as an example.
73
74    Directory: //foundation/ai/engine/services/server/plugin/asr/keyword\_spotting
75
76    >**Note**: The plug-in must implement the  **IPlugin**  and  **IPluginCallback**  APIs provided by the server.
77
78    ```
79    #include "plugin/i_plugin.h
80    class KWSPlugin : public IPlugin {       // Inherits the public base class of the IPlugin API for Keywords Spotting Plugin (KWSPlugin).
81        KWSPlugin();
82        ~KWSPlugin();
83
84        const long long GetVersion() const override;
85        const char* GetName() const override;
86        const char* GetInferMode() const override;
87
88        int32_t Prepare(long long transactionId, const DataInfo &amp;amp;inputInfo, DataInfo &amp;amp;outputInfo) override;
89        int32_t SetOption(int optionType, const DataInfo &amp;amp;inputInfo) override;
90        int32_t GetOption(int optionType, const DataInfo &amp;amp;inputInfo, DataInfo &amp;amp;outputInfo) override;
91        int32_t SyncProcess(IRequest *request, IResponse *&amp;amp;response) override;
92        int32_t AsyncProcess(IRequest *request, IPluginCallback*callback) override;
93        int32_t Release(bool isFullUnload, long long transactionId, const DataInfo &amp;amp;inputInfo) override;
94        .
95        .
96        .
97    };
98    ```
99
100    >**Note**: Depending on the algorithm in use, you only need to implement the  **SyncProcess**  or  **AsyncProcess**  API. Use an empty function as a placeholder for the other API. In this example, the KWS plug-in uses the synchronous algorithm. Therefore, you need to implement  **SyncProcess**  API and use an empty function as a placeholder for the  **SyncProcess**  API.
101
102    ```
103    #include "aie_log.h"
104    #include "aie_retcode_inner.h"
105    .
106    .
107    .
108
109    const long long KWSPlugin::GetVersion() const
110    {
111        return ALGOTYPE_VERSION_KWS;
112    }
113
114    const char *KWSPlugin::GetName() const
115    {
116        return ALGORITHM_NAME_KWS.c_str();
117    }
118
119    const char *KWSPlugin::GetInferMode() const
120    {
121        return DEFAULT_INFER_MODE.c_str();
122    }
123    .
124    .
125    .
126    int32_t KWSPlugin::AsyncProcess(IRequest *request, IPluginCallback *callback)
127    {
128        return RETCODE_SUCCESS;
129    }
130    ```
131
1323.  Develop the SDK, with keyword spotting as an example.
133
134    Directory: //foundation/ai/engine/services/client/algorithm\_sdk/asr/keyword\_spotting
135
136    Keyword spotting SDK:
137
138    ```
139    class KWSSdk {
140    public:
141        KWSSdk();
142        virtual ~KWSSdk();
143
144        /**
145         * @brief Create a new session with KWS Plugin
146         *
147         * @return Returns KWS_RETCODE_SUCCESS(0) if the operation is successful,
148         *         returns a non-zero value otherwise.
149         */
150        int32_t Create();
151
152        /**
153         * @brief Synchronously execute keyword spotting once
154         *
155         * @param audioInput pcm data.
156         * @return Returns KWS_RETCODE_SUCCESS(0) if the operation is successful,
157         *         returns a non-zero value otherwise.
158         */
159        int32_t SyncExecute(const Array<int16_t> &audioInput);
160
161        /**
162         * @brief Asynchronously execute keyword spotting once
163         *
164         * @param audioInput pcm data.
165         * @return Returns KWS_RETCODE_SUCCESS(0) if the operation is successful,
166         *         returns a non-zero value otherwise.
167         */
168        int32_t AsyncExecute(const Array<int16_t> &audioInput);
169
170        /**
171         * @brief Set callback
172         *
173         * @param callback Callback function that will be called during the process.
174         * @return Returns KWS_RETCODE_SUCCESS(0) if the operation is successful,
175         *         returns a non-zero value otherwise.
176         */
177        int32_t SetCallback(const std::shared_ptr<KWSCallback> &callback);
178
179        /**
180         * @brief Destroy the created session with KWS Plugin
181         *
182         * @return Returns KWS_RETCODE_SUCCESS(0) if the operation is successful,
183         *         returns a non-zero value otherwise.
184         */
185        int32_t Destroy();
186    }
187    ```
188
189    >**Note**: The sequence for the SDK to call client APIs of the AI engine is as follows: AieClientInit -\> AieClientPrepare -\> AieClientSyncProcess/AieClientAsyncProcess -\> AieClientRelease -\> AieClientDestroy. An exception will be thrown if the call sequence is violated. In addition, all these APIs must be called. Otherwise, a memory leakage may occur.
190
191    ```
192    int32_t KWSSdk::KWSSdkImpl::Create()
193    {
194        if (kwsHandle_ != INVALID_KWS_HANDLE) {
195            HILOGE("[KWSSdkImpl]The SDK has been created");
196            return KWS_RETCODE_FAILURE;
197        }
198        if (InitComponents() != RETCODE_SUCCESS) {
199            HILOGE("[KWSSdkImpl]Fail to init sdk components");
200            return KWS_RETCODE_FAILURE;
201        }
202        int32_t retCode = AieClientInit(configInfo_, clientInfo_, algorithmInfo_, nullptr);
203        if (retCode != RETCODE_SUCCESS) {
204            HILOGE("[KWSSdkImpl]AieClientInit failed. Error code[%d]", retCode);
205            return KWS_RETCODE_FAILURE;
206        }
207        if (clientInfo_.clientId == INVALID_CLIENT_ID) {
208            HILOGE("[KWSSdkImpl]Fail to allocate client id");
209            return KWS_RETCODE_FAILURE;
210        }
211        DataInfo inputInfo = {
212            .data = nullptr,
213            .length = 0,
214        };
215        DataInfo outputInfo = {
216            .data = nullptr,
217            .length = 0,
218        };
219        retCode = AieClientPrepare(clientInfo_, algorithmInfo_, inputInfo, outputInfo, nullptr);
220        if (retCode != RETCODE_SUCCESS) {
221            HILOGE("[KWSSdkImpl]AieclientPrepare failed. Error code[%d]", retCode);
222            return KWS_RETCODE_FAILURE;
223        }
224        if (outputInfo.data == nullptr || outputInfo.length <= 0) {
225            HILOGE("[KWSSdkImpl]The data or length of output info is invalid");
226            return KWS_RETCODE_FAILURE;
227        }
228        MallocPointerGuard<unsigned char> pointerGuard(outputInfo.data);
229        retCode = PluginHelper::UnSerializeHandle(outputInfo, kwsHandle_);
230        if (retCode != RETCODE_SUCCESS) {
231            HILOGE("[KWSSdkImpl]Get handle from inputInfo failed");
232            return KWS_RETCODE_FAILURE;
233        }
234        return KWS_RETCODE_SUCCESS;
235    }
236
237    int32_t KWSSdk::KWSSdkImpl::SyncExecute(const Array<uint16_t> &audioInput)
238    {
239        intptr_t newHandle = 0;
240        Array<int32_t> kwsResult = {
241            .data = nullptr,
242            .size = 0
243        };
244        DataInfo inputInfo = {
245            .data = nullptr,
246            .length = 0
247        };
248        DataInfo outputInfo = {
249            .data = nullptr,
250            .length = 0
251        };
252        int32_t retCode = PluginHelper::SerializeInputData(kwsHandle_, audioInput, inputInfo);
253        if (retCode != RETCODE_SUCCESS) {
254            HILOGE("[KWSSdkImpl]Fail to serialize input data");
255            callback_->OnError(KWS_RETCODE_SERIALIZATION_ERROR);
256            return RETCODE_FAILURE;
257        }
258        retCode = AieClientSyncProcess(clientInfo_, algorithmInfo_, inputInfo, outputInfo);
259        if (retCode != RETCODE_SUCCESS) {
260            HILOGE("[KWSSdkImpl]AieClientSyncProcess failed. Error code[%d]", retCode);
261            callback_->OnError(KWS_RETCODE_PLUGIN_EXECUTION_ERROR);
262            return RETCODE_FAILURE;
263        }
264        if (outputInfo.data == nullptr || outputInfo.length <= 0) {
265            HILOGE("[KWSSdkImpl] The data or length of outputInfo is invalid. Error code[%d]", retCode);
266            callback_->OnError(KWS_RETCODE_NULL_PARAM);
267            return RETCODE_FAILURE;
268        }
269        MallocPointerGuard<unsigned char> pointerGuard(outputInfo.data);
270        retCode = PluginHelper::UnSerializeOutputData(outputInfo, newHandle, kwsResult);
271        if (retCode != RETCODE_SUCCESS) {
272            HILOGE("[KWSSdkImpl]UnSerializeOutputData failed. Error code[%d]", retCode);
273            callback_->OnError(KWS_RETCODE_UNSERIALIZATION_ERROR);
274            return retCode;
275        }
276        if (kwsHandle_ != newHandle) {
277            HILOGE("[KWSSdkImpl]The handle[%lld] of output data is not equal to the current handle[%lld]",
278                (long long)newHandle, (long long)kwsHandle_);
279            callback_->OnError(KWS_RETCODE_PLUGIN_SESSION_ERROR);
280            return RETCODE_FAILURE;
281        }
282        callback_->OnResult(kwsResult);
283        return RETCODE_SUCCESS;
284    }
285
286    int32_t KWSSdk::KWSSdkImpl::Destroy()
287    {
288        if (kwsHandle_ == INVALID_KWS_HANDLE) {
289            return KWS_RETCODE_SUCCESS;
290        }
291        DataInfo inputInfo = {
292            .data = nullptr,
293            .length = 0
294        };
295        int32_t retCode = PluginHelper::SerializeHandle(kwsHandle_, inputInfo);
296        if (retCode != RETCODE_SUCCESS) {
297            HILOGE("[KWSSdkImpl]SerializeHandle failed. Error code[%d]", retCode);
298            return KWS_RETCODE_FAILURE;
299        }
300        retCode = AieClientRelease(clientInfo_, algorithmInfo_, inputInfo);
301        if (retCode != RETCODE_SUCCESS) {
302            HILOGE("[KWSSdkImpl]AieClientRelease failed. Error code[%d]", retCode);
303            return KWS_RETCODE_FAILURE;
304        }
305        retCode = AieClientDestroy(clientInfo_);
306        if (retCode != RETCODE_SUCCESS) {
307            HILOGE("[KWSSdkImpl]AieClientDestroy failed. Error code[%d]", retCode);
308            return KWS_RETCODE_FAILURE;
309        }
310        mfccProcessor_ = nullptr;
311        pcmIterator_ = nullptr;
312        callback_ = nullptr;
313        kwsHandle_ = INVALID_KWS_HANDLE;
314        return KWS_RETCODE_SUCCESS;
315    }
316    ```
317
3184.  Develop a sample application.
319
320    Call the  **Create**  API.
321
322    ```
323    bool KwsManager::PreparedInference()
324    {
325        if (capturer_ == nullptr) {
326            printf("[KwsManager] only load plugin after AudioCapturer ready\n");
327            return false;
328        }
329        if (plugin_ != nullptr) {
330            printf("[KwsManager] stop created InferencePlugin at first\n");
331            StopInference();
332        }
333        plugin_ = std::make_shared<KWSSdk>();
334        if (plugin_ == nullptr) {
335            printf("[KwsManager] fail to create inferencePlugin\n");
336            return false;
337        }
338        if (plugin_->Create() != SUCCESS) {
339            printf("[KwsManager] KWSSdk fail to create.\n");
340            return false;
341        }
342        std::shared_ptr<KWSCallback> callback = std::make_shared<MyKwsCallback>();
343        if (callback == nullptr) {
344            printf("[KwsManager] new Callback failed.\n");
345            return false;
346        }
347        plugin_->SetCallback(callback);
348        return true;
349    }
350    ```
351
352    Call the  **SyncExecute**  API.
353
354    ```
355    void KwsManager::ConsumeSamples()
356    {
357        uintptr_t sampleAddr = 0;
358        size_t sampleSize = 0;
359        int32_t retCode = SUCCESS;
360        while (status_ == RUNNING) {
361            {
362                std::lock_guard<std::mutex> lock(mutex_);
363                if (cache_ == nullptr) {
364                    printf("[KwsManager] cache_ is nullptr.\n");
365                    break;
366                }
367                sampleSize = cache_->GetCapturedBuffer(sampleAddr);
368            }
369            if (sampleSize == 0 || sampleAddr == 0) {
370                continue;
371            }
372            Array<int16_t> input = {
373                .data = (int16_t *)(sampleAddr),
374                .size = sampleSize >> 1
375            };
376            {
377                std::lock_guard<std::mutex> lock(mutex_);
378                if (plugin_ == nullptr) {
379                    printf("[KwsManager] cache_ is nullptr.\n");
380                    break;
381                }
382                if ((retCode = plugin_->SyncExecute(input)) != SUCCESS) {
383                    printf("[KwsManager] SyncExecute KWS failed with retCode = [%d]\n", retCode);
384                    continue;
385                }
386            }
387        }
388    }
389    ```
390
391    Call the  **Destroy**  API.
392
393    ```
394    void KwsManager::StopInference()
395    {
396        printf("[KwsManager] StopInference\n");
397        if (plugin_ != nullptr) {
398            int ret = plugin_->Destroy();
399            if (ret != SUCCESS) {
400                printf("[KwsManager] plugin_ destroy failed.\n");
401            }
402            plugin_ = nullptr;
403        }
404    }
405    ```
406
407
408## Repositories Involved
409
410[AI subsystem](https://gitee.com/openharmony/docs/blob/master/en/readme/ai.md)
411
412[ai_engine](https://gitee.com/openharmony/ai_engine)
413
414## Dependency Repositories
415
416[build\_lite](https://gitee.com/openharmony/build_lite/blob/master/README.md)
417
418[systemabilitymgr\_samgr\_lite](https://gitee.com/openharmony/systemabilitymgr_samgr_lite/blob/master/README.md)
419
420[startup\_init\_lite](https://gitee.com/openharmony/startup_init_lite/blob/master/README.md)
421
422## Reference
423
424[AI Framework Development Guide](https://gitee.com/openharmony/docs/blob/master/en/device-dev/subsystems/subsys-ai-aiframework-devguide.md)
425
426
427