공급업체 확장 프로그램

Android 10에 도입된 Neural Networks API(NNAPI) 공급업체 확장 프로그램에는 공급업체에서 정의한 연산 및 데이터 유형이 모여 있습니다. NN HAL 1.2 이상을 실행하는 기기에서는 드라이버가 해당하는 공급업체 확장 프로그램을 지원하여 맞춤 하드웨어로 가속화된 연산을 제공할 수 있습니다. 공급업체 확장 프로그램은 기존 연산의 동작을 수정하지 않습니다.

공급업체 확장 프로그램은 Android 10에서 지원 중단된 OEM 연산 및 데이터 유형에 대한 좀 더 구조화된 대안을 제공합니다. 자세한 내용은 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이 아닌 값이 있으면 연산 또는 피연산자 유형이 확장 프로그램 유형이 됩니다. 값이 0인 경우에는 연산 또는 피연산자 유형이 확장 프로그램 유형이 아닙니다.

접두사를 확장 프로그램 이름에 매핑하려면 model.extensionNameToPrefix에서 접두사를 검색합니다. 접두사에서 확장 프로그램 이름으로 이어지는 매핑은 주어진 모델에 대한 일대일 대응관계(bijection)입니다. 여러 접두사 값이 다른 모델의 동일한 확장 프로그램 이름과 일치할 수 있습니다.

드라이버가 확장 프로그램 연산과 데이터 유형을 확인해야 하는 이유는 NNAPI 런타임으로 특정 확장 프로그램 연산과 데이터 유형을 확인할 수 없기 때문입니다.

확장 프로그램 피연산자는 operand.extraParams.extension에 관련 데이터가 있을 수 있으며, 이는 런타임에 의해 임의의 크기의 원시 데이터 blob로 간주됩니다.

OEM 연산 및 데이터 유형

NNAPI에는 기기 제조업체에서 드라이버와 관련된 맞춤 기능을 제공할 수 있게 해주는 OEM 연산 및 OEM 데이터 유형이 포함되어 있습니다. 이러한 연산 및 데이터 유형은 OEM 애플리케이션에 의해서만 사용됩니다. OEM 연산과 데이터 유형의 의미 체계는 OEM과 관련이 있으며 언제든지 변경될 수 있습니다. OEM 연산과 데이터 유형은 OperationType::OEM_OPERATION, OperandType::OEMOperandType::TENSOR_OEM_BYTE를 사용하여 인코딩됩니다.