O Google tem o compromisso de promover a igualdade racial para as comunidades negras. Saiba como.

Extensões de fornecedores

As extensões do fornecedor da 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 NN HAL 1.2 ou superior, os drivers podem fornecer operações personalizadas aceleradas por hardware, oferecendo suporte a extensões de fornecedores correspondentes. As extensões do fornecedor não modificam o comportamento das operações existentes.

Extensões vendedor fornecer uma alternativa mais estruturada para operação e tipos de dados OEM, que foram preteridos no Android 10. Para mais informações, consulte tipos de operação e dados de OEM .

Lista de permissões de uso de extensões

Extensões vendedor só pode ser usado por aplicativos Android explicitamente especificadas e binários nativos sobre o /product , /vendor , /odm , e /data partições. Aplicativos e binários nativos localizados no /system partição não pode usar extensões vendedor.

A lista de aplicativos Android e binários permissão para usar extensões vendedor NNAPI é armazenado em /vendor/etc/nnapi_extensions_app_allowlist . Cada linha do arquivo contém uma nova entrada. Uma entrada pode ser um caminho nativo binário que é prefixado com uma barra (/), por exemplo, /data/foo , ou um nome de um pacote de aplicação 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 fraude 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 de uma definição completa 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 forma semelhante aos de 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 runtime/include/NeuralNetworksExtensions.h (C API) arquivo fornece suporte a extensão de tempo de execução. Esta seção fornece uma visão geral da API C.

Para verificar se um dispositivo suporta uma extensão, o uso 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 extensão, uso ANeuralNetworksModel_getExtensionOperandType para obter o tipo de operando e chamada 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, usar ANeuralNetworksModel_setOperandExtensionData de dados adicionais associados com uma extensão operando.

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, o uso ANeuralNetworksModel_getExtensionOperationType para obter o tipo de operação e chamada 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

Drivers relatam extensões suportadas através do IDevice::getSupportedExtensions método. 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 utilizado para identificar os tipos e operações, a alta Model::ExtensionTypeEncoding::HIGH_BITS_PREFIX bits é o prefixo extensão e o baixo Model::ExtensionTypeEncoding::LOW_BITS_TYPE os bits representa o tipo de operação ou 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 operando não é um tipo de extensão.

Para mapear o prefixo para um nome de extensão, procurá-lo 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.

Operandos de extensão pode ter associado dados em operand.extraParams.extension , que os mimos de tempo de execução como uma mancha de tamanho arbitrário de dados em bruto.

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 do OEM e os tipos de dados são específicos do OEM e podem mudar a qualquer momento. Os tipos de operação e dados de OEM são codificados utilizando OperationType::OEM_OPERATION , OperandType::OEM , e OperandType::TENSOR_OEM_BYTE .