供應商額外資訊

Android 10 中推出的 Neural Networks API (NNAPI) 供應商擴充功能是廠商定義的作業和資料類型集合。在搭載 NN HAL 1.2 以上版本的裝置上,驅動程式可支援對應的廠商擴充功能,來提供自訂的硬體加速作業。供應商擴充功能不會修改現有作業的行為。

供應商擴充功能可為原始設備製造商 (OEM) 作業和資料類型提供更結構化的替代方案,但這些擴充功能已在 Android 10 中淘汰。詳情請參閱「原始設備製造商 (OEM) 作業和資料類型」。

擴充功能用量許可清單

供應商擴充功能只能由明確指定的 Android 應用程式和 /product/vendor/odm/data 分區上的原生二進位檔使用。位於 /system 分區的應用程式和原生二進位檔無法使用廠商擴充功能。

系統會將可使用 NNAPI 供應商擴充功能的 Android 應用程式和二進位檔清單儲存在 /vendor/etc/nnapi_extensions_app_allowlist 中。檔案的每一行都包含一個新項目。項目可以是前置字串為斜線 (/) 的原生二進位檔路徑,例如 /data/foo,或 Android 應用程式套件的名稱,例如 com.foo.bar

系統會強制執行 NNAPI 執行階段共用資料庫的許可清單。這個程式庫可防止意外使用,但可防止應用程式直接使用 NNAPI 驅動程式 HAL 介面規避蓄意規避。

供應商擴充功能定義

供應商會建立並維護包含擴充功能定義的標頭檔案。example/fibonacci/FibonacciExtension.h 提供擴充功能定義的完整範例。

每個擴充功能的名稱都必須以供應商的反向網域名稱做為開頭。

const char EXAMPLE_EXTENSION_NAME[] = "com.example.my_extension";

這個名稱可做為作業和資料類型的命名空間。NNAPI 使用此名稱來區分廠商延伸模組。

宣告作業和資料類型的方式與 runtime/include/NeuralNetworks.h 中的宣告方式類似。

enum {
    /**
     * A custom scalar type.
     */
    EXAMPLE_SCALAR = 0,

    /**
     * A custom tensor type.
     *
     * Attached to this tensor is {@link ExampleTensorParams}.
     */
    EXAMPLE_TENSOR = 1,
};

enum {
    /**
     * Computes example function.
     *
     * Inputs:
     * * 0: A scalar of {@link EXAMPLE_SCALAR}.
     *
     * Outputs:
     * * 0: A tensor of {@link EXAMPLE_TENSOR}.
     */
    EXAMPLE_FUNCTION = 0,
};

擴充功能作業可使用任何運算元類型,包括非擴充功能運算元類型,以及來自其他擴充功能的運算元類型。使用其他擴充功能的運算元類型時,驅動程式必須支援其他擴充功能。

擴充功能也可以為隨附的擴充功能運算元宣告自訂結構。

/**
 * Quantization parameters for {@link EXAMPLE_TENSOR}.
 */
typedef struct ExampleTensorParams {
    double scale;
    int64_t zeroPoint;
} ExampleTensorParams;

在 NNAPI 用戶端中使用擴充功能

runtime/include/NeuralNetworksExtensions.h (C API) 檔案提供執行階段擴充功能支援。本節提供 C API 總覽。

如要確認裝置是否支援擴充功能,請使用 ANeuralNetworksDevice_getExtensionSupport

bool isExtensionSupported;
CHECK_EQ(ANeuralNetworksDevice_getExtensionSupport(device, EXAMPLE_EXTENSION_NAME,
                                                   &isExtensionSupported),
         ANEURALNETWORKS_NO_ERROR);
if (isExtensionSupported) {
    // The device supports the extension.
    ...
}

如要建構具有擴充運算元的模型,請使用 ANeuralNetworksModel_getExtensionOperandType 取得運算元類型並呼叫 ANeuralNetworksModel_addOperand

int32_t type;
CHECK_EQ(ANeuralNetworksModel_getExtensionOperandType(model, EXAMPLE_EXTENSION_NAME, EXAMPLE_TENSOR, &type),
         ANEURALNETWORKS_NO_ERROR);
ANeuralNetworksOperandType operandType{
        .type = type,
        .dimensionCount = dimensionCount,
        .dimensions = dimensions,
};
CHECK_EQ(ANeuralNetworksModel_addOperand(model, &operandType), ANEURALNETWORKS_NO_ERROR);

您也可以選擇使用 ANeuralNetworksModel_setOperandExtensionData 將其他資料與擴充運算元建立關聯。

ExampleTensorParams params{
        .scale = 0.5,
        .zeroPoint = 128,
};
CHECK_EQ(ANeuralNetworksModel_setOperandExtensionData(model, operandIndex, &params, sizeof(params)),
         ANEURALNETWORKS_NO_ERROR);

如要建構具有擴充功能作業的模型,請使用 ANeuralNetworksModel_getExtensionOperationType 取得作業類型,並呼叫 ANeuralNetworksModel_addOperation

ANeuralNetworksOperationType type;
CHECK_EQ(ANeuralNetworksModel_getExtensionOperationType(model, EXAMPLE_EXTENSION_NAME, EXAMPLE_FUNCTION,
                                                        &type),
         ANEURALNETWORKS_NO_ERROR);
CHECK_EQ(ANeuralNetworksModel_addOperation(model, type, inputCount, inputs, outputCount, outputs),
         ANEURALNETWORKS_NO_ERROR);

為 NNAPI 驅動程式新增擴充功能支援

驅動程式會透過 IDevice::getSupportedExtensions 方法回報支援的擴充功能。傳回的清單必須包含說明每個支援的副檔名的項目。

Extension {
    .name = EXAMPLE_EXTENSION_NAME,
    .operandTypes = {
        {
            .type = EXAMPLE_SCALAR,
            .isTensor = false,
            .byteSize = 8,
        },
        {
            .type = EXAMPLE_TENSOR,
            .isTensor = true,
            .byteSize = 8,
        },
    },
}

在用於識別類型和作業的 32 位元中,較高的 Model::ExtensionTypeEncoding::HIGH_BITS_PREFIX 位元是擴充的前置字串,低的 Model::ExtensionTypeEncoding::LOW_BITS_TYPE 位元則代表擴充功能的類型或作業。

處理作業或運算元類型時,驅動程式必須檢查擴充功能前置字串。如果擴充內容前置字串的值不是零,則作業或運算元類型就會是擴充功能類型。如果值為 0,則表示作業或運算元類型不是擴充功能類型。

如要將前置字串對應至擴充功能名稱,請在 model.extensionNameToPrefix 中查詢。從前置字串與擴充功能名稱的對應,是指定模型的一對一通訊 (單注)。不同的前置字串值可能會在不同模型中對應至相同的擴充功能名稱。

驅動程式必須驗證擴充功能作業和資料類型,因為 NNAPI 執行階段無法驗證特定擴充功能作業和資料類型。

擴充功能運算元可在 operand.extraParams.extension 中有相關資料,而執行階段會將其視為任意大小的原始資料 blob。

原始設備製造商 (OEM) 作業和資料類型

NNAPI 具有 OEM 作業和 OEM 資料類型,可讓裝置製造商提供自訂的驅動程式專屬功能。這些作業和資料類型僅供原始設備製造商 (OEM) 應用程式使用。原始設備製造商 (OEM) 作業和資料類型的語意僅適用於原始設備製造商 (OEM),且隨時可能變更。原始設備製造商 (OEM) 作業和資料類型使用 OperationType::OEM_OPERATIONOperandType::OEMOperandType::TENSOR_OEM_BYTE 編碼。