ส่วนขยายของผู้ให้บริการ

ส่วนขยายของผู้ให้บริการ Neural Networks API (NNAPI) ซึ่งเปิดตัวใน Android 10 เป็นชุดการดำเนินการและประเภทข้อมูลที่ผู้ให้บริการกำหนด ในอุปกรณ์ที่ใช้ NN HAL 1.2 ขึ้นไป ไดรเวอร์สามารถให้การดำเนินการที่เร่งด้วยฮาร์ดแวร์ที่กำหนดเองได้โดย รองรับส่วนขยายของผู้ให้บริการที่เกี่ยวข้อง ส่วนขยายของผู้ให้บริการจะไม่แก้ไขลักษณะการทำงานของการดำเนินการที่มีอยู่

ส่วนขยายของผู้ให้บริการเป็นทางเลือกที่มีโครงสร้างมากขึ้นแทนการดำเนินการและ ประเภทข้อมูลของ OEM ซึ่งเลิกใช้งานใน Android 10 ดูข้อมูลเพิ่มเติมได้ที่ การดำเนินการและประเภทข้อมูลของ OEM

รายการที่อนุญาตสำหรับการใช้งานส่วนขยาย

ส่วนขยายของผู้ให้บริการจะใช้ได้เฉพาะกับแอป Android และไบนารีเนทีฟที่ระบุอย่างชัดแจ้งในพาร์ติชัน /product, /vendor, /odm และ /data แอปและไบนารีแบบเนทีฟที่อยู่ในพาร์ติชัน /system จะใช้ส่วนขยายของผู้ให้บริการไม่ได้

ระบบจะจัดเก็บรายการแอปและไบนารี Android ที่ได้รับอนุญาตให้ใช้ส่วนขยายของผู้ให้บริการ NNAPI ไว้ใน /vendor/etc/nnapi_extensions_app_allowlist แต่ละบรรทัดของไฟล์ จะมีรายการใหม่ รายการอาจเป็นเส้นทางไบนารีแบบเนทีฟที่มีคำนำหน้าเป็น เครื่องหมายทับ (/) เช่น /data/foo หรือชื่อแพ็กเกจแอป Android เช่น com.foo.bar

ระบบจะบังคับใช้รายการที่อนุญาตจากไลบรารีที่ใช้ร่วมกันของรันไทม์ NNAPI ไลบรารีนี้ ป้องกันการใช้งานโดยไม่ตั้งใจ แต่ไม่ได้ป้องกันการหลบเลี่ยงโดยเจตนาโดย แอปที่ใช้อินเทอร์เฟซ HAL ของไดรเวอร์ NNAPI โดยตรง

คำจำกัดความของส่วนขยายผู้ให้บริการ

ผู้ให้บริการสร้างและดูแลไฟล์ส่วนหัวที่มีคำจำกัดความของส่วนขยาย ดูตัวอย่างคำจำกัดความของส่วนขยายที่สมบูรณ์ได้ใน 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_OPERATION, OperandType::OEM และ OperandType::TENSOR_OEM_BYTE