HiAI Foundation開發平臺,加速端側AI應用的智慧革命

HarmonyOS_SDK發表於2024-07-03

如果您是一名開發者,正在尋找一種高效、靈活且易於使用的端側AI開發框架,那麼HarmonyOS SDKHiAI Foundation服務(HiAI Foundation Kit)就是您的理想選擇。

作為一款AI開發框架,HiAI Foundation不僅提供強大的NPU計算能力和豐富的開發工具,還提供完善的技術支援和社群資源,幫助您快速構建高質量的AI應用程式。以影像分類這種常見的AI應用為例,使用HiAI Foundation可以幫助開發者們快速實現高效的影像分類應用。HiAI Foundation面向自定義AI演算法的開發者們,可以靈活地支援自有的演算法,給應用帶來更好的效能功耗收益。

功能演示

image

如果開發者對實現方式感興趣,可以下載Demo體驗,基於具體的應用場景最佳化。Demo支援載入離線模型,對圖片中的物體進行分類。

影像分類開發步驟

1.建立專案

本章以Caffe SqueezeNet模型整合為例,說明App整合操作過程。

2.配置專案NAPI

編譯HAP時,NAPI層的so需要編譯依賴NDK中的libneural_network_core.so和libhiai_foundation.so。

3.標頭檔案引用

按需引用標頭檔案。

#include "neural_network_runtime/neural_network_core.h"
#include "hiai_foundation/hiai_options.h"

4.編寫CMakeLists.txt

CMakeLists.txt中的關鍵程式碼如下:

include_directories(${HMOS_SDK_NATIVE}/sysroot/usr/lib)
FIND_LIBRARY(hiai_foundation-lib hiai_foundation)
add_library(entry SHARED Classification.cpp HIAIModelManager.cpp)
target_link_libraries(entry PUBLIC libace_napi.z.so
    libhilog_ndk.z.so
    librawfile.z.so
    ${hiai_foundation-lib}
    libneural_network_core.so
    )

5.整合模型

模型的載入、編譯和推理主要是在native層實現,應用層主要作為資料傳遞和展示作用。

模型推理之前需要對輸入資料進行預處理以匹配模型的輸入,同樣對於模型的輸出也需要做處理獲取自己期望的結果。另外SDK中提供了設定模型編譯和執行時的配置介面,開發者可根據實際需求選擇使用介面。

本節闡述同步模式下單模型的使用,從流程上分別闡述每個步驟在應用層和Native層的實現和呼叫,介面請參見API參考。

6.預置模型

為了讓App執行時能夠讀取到模型檔案和處理推理結果,需要先把離線模型和模型對應的結果標籤檔案預置到工程的"entry/src/main/resources/rawfile"目錄中。

本示例所使用的離線模型轉換和生成可參考Caffe模型轉換,當前支援Caffe 1.0版本。

命令列中的引數說明請參見OMG引數,轉換命令:

./omg --model xxx.prototxt --weight yyy.caffemodel --framework 0 --
output ./modelname

轉換示例:

./omg --model deploy.prototxt --weight squeezenet_v1.1.caffemodel --framework
0 --output ./squeezenet

當看到OMG generate offline model success時,則說明轉換成功,會在當前目錄下生成squeezenet.om。

7.載入離線模型

在App應用建立時載入模型和讀取結果標籤檔案。

1)呼叫NAPI層的"LoadModel"函式,讀取模型的buffer。

2)把模型buffer傳遞給HIAIModelManager類的"HIAIModelManager::LoadModelFromBuffer"介面,該介面呼叫

OH_NNCompilation_ConstructWithOfflineModelBuffer建立模型的編譯例項。

3)獲取並設定模型的deviceID。

size_t deviceID = 0;
const size_t *allDevicesID = nullptr;
uint32_t deviceCount = 0;
OH_NN_ReturnCode ret = OH_NNDevice_GetAllDevicesID(&allDevicesID, &deviceCount);
if (ret != OH_NN_SUCCESS || allDevicesID == nullptr) {
    OH_LOG_ERROR(LOG_APP, "OH_NNDevice_GetAllDevicesID failed");
    return OH_NN_FAILED;
}
for (uint32_t i = 0; i < deviceCount; i++) {
    const char *name = nullptr;
    ret = OH_NNDevice_GetName(allDevicesID[i], &name);
    if (ret != OH_NN_SUCCESS || name == nullptr) {
        OH_LOG_ERROR(LOG_APP, "OH_NNDevice_GetName failed");
        return OH_NN_FAILED;
    }
    if (std::string(name) == "HIAI_F") {
        deviceID = allDevicesID[i];
        break;
    }
}
// modelData和modelSize為模型的記憶體地址和大小
OH_NNCompilation *compilation = OH_NNCompilation_ConstructWithOfflineModelBuffer(modelData, modelSize); 
ret = OH_NNCompilation_SetDevice(compilation, deviceID); 
if (ret != OH_NN_SUCCESS) {
    OH_LOG_ERROR(LOG_APP, "OH_NNCompilation_SetDevice failed");
    return OH_NN_FAILED;
}

4)呼叫OH_NNCompilation_Build,執行模型編譯。

5)呼叫OH_NNExecutor_Construct,建立模型執行器。

6)呼叫OH_NNCompilation_Destroy,釋放模型編譯例項。

上述流程可參見Demo中"entry/src/main/cpp/Classification.cpp"檔案中的"LoadModel"函式和"entry/src/main/cpp/HiAiModelManager.cpp"中的"HIAIModelManager::LoadModelFromBuffer"函式。

8.準備輸入輸出

1)準備輸入輸出

2)處理模型的輸入,例如示例中模型的輸入為13227*227格式Float型別的資料,需要把輸入的圖片轉成該格式後傳遞到NAPI層。

3)建立模型的輸入和輸出Tensor,並把應用層傳遞的資料填充到輸入的Tensor中。

// 建立輸入資料
size_t inputCount = 0;
std::vector<NN_Tensor*> inputTensors;
OH_NN_ReturnCode ret = OH_NNExecutor_GetInputCount(executor, &inputCount); 
if (ret != OH_NN_SUCCESS || inputCount != inputData.size()) { // inputData為開發者構造的輸入資料
    OH_LOG_ERROR(LOG_APP, "OH_NNExecutor_GetInputCount failed, size mismatch");
    return OH_NN_FAILED;
}
for (size_t i = 0; i < inputCount; ++i) {
    NN_TensorDesc *tensorDesc = OH_NNExecutor_CreateInputTensorDesc(executor, i); 
    NN_Tensor *tensor = OH_NNTensor_Create(deviceID, tensorDesc); // deviceID的獲取方式可參考"載入離線模型"的步驟3
    if (tensor != nullptr) {
        inputTensors.push_back(tensor);
    }
    OH_NNTensorDesc_Destroy(&tensorDesc);
}
if (inputTensors.size() != inputCount) {
    OH_LOG_ERROR(LOG_APP, "input size mismatch");
    DestroyTensors(inputTensors); // DestroyTensors為釋放tensor記憶體操作函式
    return OH_NN_FAILED;
}
// 初始化輸入資料
for (size_t i = 0; i < inputTensors.size(); ++i) {
    void *data = OH_NNTensor_GetDataBuffer(inputTensors[i]);
    size_t dataSize = 0;
    OH_NNTensor_GetSize(inputTensors[i], &dataSize);
    if (data == nullptr || dataSize != inputData[i].size()) { // inputData為模型的輸入資料
        OH_LOG_ERROR(LOG_APP, "invalid data or dataSize");
        return OH_NN_FAILED;
    }
    memcpy(data, inputData[i].data(), inputData[i].size()); // inputData為模型的輸入資料
}
// 建立輸出資料,與輸入資料的建立方式類似
size_t outputCount = 0;
std::vector<NN_Tensor*> outputTensors;
ret = OH_NNExecutor_GetOutputCount(executor, &outputCount); 
if (ret != OH_NN_SUCCESS) {
    OH_LOG_ERROR(LOG_APP, "OH_NNExecutor_GetOutputCount failed");
    DestroyTensors(inputTensors); // DestroyTensors為釋放tensor記憶體操作函式
    return OH_NN_FAILED;
}
for (size_t i = 0; i < outputCount; i++) {
    NN_TensorDesc *tensorDesc = OH_NNExecutor_CreateOutputTensorDesc(executor, i); 
    NN_Tensor *tensor = OH_NNTensor_Create(deviceID, tensorDesc); // deviceID的獲取方式可參考"載入離線模型"的步驟3
    if (tensor != nullptr) {
        outputTensors.push_back(tensor);
    }
    OH_NNTensorDesc_Destroy(&tensorDesc);
}
if (outputTensors.size() != outputCount) {
    DestroyTensors(inputTensors); // DestroyTensors為釋放tensor記憶體操作函式
    DestroyTensors(outputTensors); // DestroyTensors為釋放tensor記憶體操作函式
    OH_LOG_ERROR(LOG_APP, "output size mismatch");
    return OH_NN_FAILED;
}

上述流程可參見Demo中"entry/src/main/cpp/Classification.cpp"檔案中的"InitIOTensors"函式和"entry/src/main/cpp/HiAiModelManager.cpp"中的"HIAIModelManager::InitIOTensors"函式。

9.同步推理離線模型

呼叫OH_NNExecutor_RunSync,完成模型的同步推理。

可參見Demo中"entry/src/main/cpp/Classification.cpp"檔案中的"RunModel"函式和"entry/src/main/cpp/HiAiModelManager.cpp"中的"HIAIModelManager::RunModel"函式。

說明:如果不更換模型,則首次編譯載入完成後可多次推理,即一次編譯載入,多次推理。

10.模型輸出後處理

1)呼叫OH_NNTensor_GetDataBuffer,獲取輸出的Tensor,在輸出Tensor中會得到模型的輸出資料。

2)對輸出資料進行相應的處理可得到期望的結果。

3)例如本示例demo中模型的輸出是1000個label的機率,期望得到這1000個結果中機率最大的三個標籤。

4)銷燬例項。

呼叫OH_NNExecutor_Destroy,銷燬建立的模型執行器例項。

呼叫OH_NNTensor_Destroy,銷燬建立的輸入輸出Tensor。

上述流程可參見Demo中"entry/src/main/cpp/Classification.cpp"檔案中的"GetResult"、"UnloadModel"函式和"entry/src/main/cpp/HiAiModelManager.cpp"中的"HIAIModelManager::GetResult"、"HIAIModelManager::UnloadModel"函式。

瞭解更多詳情>>

訪問HiAI Foundation服務聯盟官網

獲取HiAI Foundation服務開發指導文件

相關文章