O Google tem o compromisso de promover a igualdade racial para as comunidades negras. Saiba como.
Esta página foi traduzida pela API Cloud Translation.
Switch to English

Extensões de fornecedores

As extensões do fornecedor Neural Networks API (NNAPI), introduzidas no Android 10, são coleções de operações definidas pelo fornecedor e tipos de dados. Em dispositivos que executam o NN HAL 1.2 ou superior, os drivers podem fornecer operações personalizadas aceleradas por hardware, oferecendo suporte às extensões correspondentes do fornecedor. As extensões do fornecedor não modificam o comportamento das operações existentes.

As extensões do fornecedor fornecem uma alternativa mais estruturada para a operação e tipos de dados do OEM, que foram descontinuados no Android 10. Para obter mais informações, consulte Operação e tipos de dados do OEM .

Lista de permissões de uso de extensões

As extensões do fornecedor só podem ser usadas por aplicativos Android explicitamente especificados e binários nativos nas partições /product , /vendor , /odm e /data . Aplicativos e binários nativos localizados na partição /system não podem usar extensões do fornecedor.

Uma lista de aplicativos Android e binários com permissão para usar extensões de fornecedores NNAPI é armazenada em /vendor/etc/nnapi_extensions_app_allowlist . Cada linha do arquivo contém uma nova entrada. Uma entrada pode ser um caminho binário nativo prefixado com uma barra (/), por exemplo, /data/foo , ou um nome de um pacote de aplicativo Android, por exemplo, com.foo.bar .

A lista de permissões é aplicada a partir da biblioteca compartilhada de tempo de execução NNAPI. Esta biblioteca protege contra o uso acidental, mas não contra a violação deliberada por um aplicativo diretamente usando a interface HAL do driver NNAPI.

Definição de extensão de fornecedor

O fornecedor cria e mantém um arquivo de cabeçalho com a definição de extensão. Um exemplo completo de uma definição de extensão pode ser encontrado em example/fibonacci/FibonacciExtension.h .

Cada extensão deve ter um nome exclusivo que começa com o nome de domínio reverso do fornecedor.

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

O nome atua como um namespace para operações e tipos de dados. O NNAPI usa esse nome para distinguir entre as extensões do fornecedor.

Operações e tipos de dados são declarados de maneira semelhante àqueles em 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,
};

Uma operação de extensão pode usar qualquer tipo de operando, incluindo tipos de operando de não extensão e tipos de operando de outras extensões. Ao usar um tipo de operando de outra extensão, o driver deve suportar a outra extensão.

As extensões também podem declarar estruturas personalizadas para acompanhar operandos de extensão.

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

Usando extensões em clientes NNAPI

O arquivo runtime/include/NeuralNetworksExtensions.h (API C) fornece suporte à extensão de tempo de execução. Esta seção fornece uma visão geral da API C.

Para verificar se um dispositivo oferece suporte a uma extensão, use ANeuralNetworksDevice_getExtensionSupport .

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

Para construir um modelo com um operando de extensão, use ANeuralNetworksModel_getExtensionOperandType para obter o tipo de operando e chame 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);

Opcionalmente, use ANeuralNetworksModel_setOperandExtensionData para associar dados adicionais a um operando de extensão.

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

Para construir um modelo com uma operação de extensão, use ANeuralNetworksModel_getExtensionOperationType para obter o tipo de operação e chame 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);

Adicionando suporte de extensão a um driver NNAPI

Os drivers relatam extensões com suporte por meio do método IDevice::getSupportedExtensions . A lista retornada deve conter uma entrada que descreve cada extensão com suporte.

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

Dos 32 bits usados ​​para identificar tipos e operações, os bits Model::ExtensionTypeEncoding::HIGH_BITS_PREFIX são o prefixo da extensão e os bits Model::ExtensionTypeEncoding::LOW_BITS_TYPE representam o tipo ou operação da extensão.

Ao lidar com uma operação ou tipo de operando, o driver deve verificar o prefixo da extensão. Se o prefixo de extensão tiver um valor diferente de zero, a operação ou tipo de operando é um tipo de extensão. Se o valor for 0 , a operação ou tipo de operando não é um tipo de extensão.

Para mapear o prefixo para um nome de extensão, procure em model.extensionNameToPrefix . O mapeamento do prefixo para o nome da extensão é uma correspondência um-a-um (bijeção) para um determinado modelo. Valores de prefixo diferentes podem corresponder ao mesmo nome de extensão em modelos diferentes.

O driver deve validar operações de extensão e tipos de dados porque o tempo de execução NNAPI não pode validar operações de extensão e tipos de dados específicos.

Os operandos de extensão podem ter dados associados em operand.extraParams.extension , que o tempo de execução trata como um blob de dados brutos de tamanho arbitrário.

Operação OEM e tipos de dados

A NNAPI tem uma operação e tipos de dados OEM para permitir que os fabricantes de dispositivos forneçam funcionalidades personalizadas e específicas do driver. Esses tipos de operação e dados são usados ​​apenas por aplicativos OEM. A semântica da operação e dos tipos de dados do OEM são específicos do OEM e podem mudar a qualquer momento. A operação OEM e os tipos de dados são codificados usando OperationType::OEM_OPERATION , OperandType::OEM e OperandType::TENSOR_OEM_BYTE .