Ekstensi vendor

Ekstensi vendor Neural Networks API (NNAPI), diperkenalkan di Android 10, kumpulan operasi yang ditentukan vendor dan tipe data. Di perangkat yang menjalankan NN HAL 1.2 atau lebih tinggi, {i>driver<i} dapat menyediakan operasi khusus yang dipercepat perangkat keras dengan yang mendukung ekstensi vendor yang sesuai. Ekstensi vendor tidak mengubah perilaku operasi yang ada.

Ekstensi vendor memberikan alternatif yang lebih terstruktur untuk operasi OEM dan tipe data yang tidak digunakan lagi di Android 10. Untuk mengetahui informasi selengkapnya, lihat Jenis data dan operasi OEM.

Daftar yang diizinkan untuk penggunaan ekstensi

Ekstensi vendor hanya dapat digunakan oleh aplikasi Android dan biner native yang ditentukan secara eksplisit di partisi /product, /vendor, /odm, dan /data. Aplikasi dan biner native yang berada di partisi /system tidak dapat menggunakan ekstensi vendor.

Daftar aplikasi dan biner Android yang diizinkan untuk menggunakan ekstensi vendor NNAPI adalah disimpan di /vendor/etc/nnapi_extensions_app_allowlist. Setiap baris file berisi entri baru. Entri dapat berupa jalur biner native yang diawali dengan garis miring (/), misalnya, /data/foo, atau nama paket aplikasi Android, misalnya com.foo.bar.

Daftar yang diizinkan diterapkan dari library bersama runtime NNAPI. Library ini melindungi dari penggunaan yang tidak disengaja tetapi tidak dari pengelakan yang disengaja dengan aplikasi secara langsung menggunakan antarmuka HAL driver NNAPI.

Definisi ekstensi vendor

Vendor membuat dan mengelola file header dengan definisi ekstensi. J contoh lengkap dari definisi ekstensi dapat ditemukan di example/fibonacci/FibonacciExtension.h

Setiap ekstensi harus memiliki nama unik yang dimulai dengan nama domain terbalik vendor.

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

Nama berfungsi sebagai namespace untuk operasi dan jenis data. NNAPI menggunakan ini untuk membedakan di antara ekstensi vendor.

Operasi dan jenis data dideklarasikan dengan cara yang mirip dengan yang ada di 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,
};

Operasi ekstensi dapat menggunakan jenis operand apa pun, termasuk jenis operand non-ekstensi dan jenis operand dari ekstensi lain. Saat menggunakan jenis operand dari ekstensi lainnya, {i>driver<i} harus mendukung ekstensi lainnya.

Ekstensi juga dapat mendeklarasikan struktur kustom untuk menyertai operand ekstensi.

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

Menggunakan ekstensi di klien NNAPI

File runtime/include/NeuralNetworksExtensions.h (C API) memberikan dukungan ekstensi runtime. Bagian ini menyediakan tentang ringkasan API C.

Untuk memeriksa apakah perangkat mendukung ekstensi, gunakan ANeuralNetworksDevice_getExtensionSupport.

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

Untuk mem-build model dengan operand ekstensi, gunakan ANeuralNetworksModel_getExtensionOperandType untuk mendapatkan jenis operand dan panggil 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);

Secara opsional, gunakan ANeuralNetworksModel_setOperandExtensionData untuk mengaitkan data tambahan dengan operand ekstensi.

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

Untuk mem-build model dengan operasi ekstensi, gunakan ANeuralNetworksModel_getExtensionOperationType untuk mendapatkan jenis operasi dan panggil 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);

Menambahkan dukungan ekstensi ke driver NNAPI

Driver melaporkan ekstensi yang didukung melalui metode IDevice::getSupportedExtensions. Daftar yang ditampilkan harus berisi entri yang menjelaskan setiap ekstensi yang didukung.

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

Dari 32 bit yang digunakan untuk mengidentifikasi jenis dan operasi, bit Model::ExtensionTypeEncoding::HIGH_BITS_PREFIX tinggi adalah awalan ekstensi dan bit Model::ExtensionTypeEncoding::LOW_BITS_TYPE rendah mewakili jenis atau operasi ekstensi.

Saat menangani jenis operasi atau operand, driver harus memeriksa awalan ekstensi. Jika awalan ekstensi memiliki nilai bukan nol, operasi atau operand adalah jenis ekstensi. Jika nilainya 0, jenis operasi atau operand bukan jenis ekstensi.

Untuk memetakan awalan ke nama ekstensi, cari di model.extensionNameToPrefix Pemetaan dari awalan ke nama ekstensi adalah korespondensi satu-ke-satu (bijection) untuk model tertentu. Nilai awalan yang berbeda mungkin sesuai dengan nama ekstensi yang sama dalam model yang berbeda.

Driver harus memvalidasi operasi ekstensi dan jenis data karena runtime NNAPI tidak dapat memvalidasi operasi ekstensi dan jenis data tertentu.

Operand ekstensi dapat memiliki data terkait di operand.extraParams.extension, yang diperlakukan runtime sebagai blob data mentah dengan ukuran arbitrer.

Operasi dan jenis data OEM

NNAPI memiliki operasi OEM dan jenis data OEM yang memungkinkan produsen perangkat untuk menyediakan fungsi khusus bagi {i>driver<i}. Jenis data dan operasi ini hanya digunakan oleh aplikasi OEM. Semantik operasi OEM dan jenis data bersifat khusus OEM dan dapat berubah kapan saja. Jenis data dan operasi OEM dienkode menggunakan OperationType::OEM_OPERATION, OperandType::OEM, dan OperandType::TENSOR_OEM_BYTE.