Rozszerzenia dostawcy interfejsu Neural Networks API (NNAPI), wprowadzone w Androidzie 10, to zbiory operacji i typów danych zdefiniowanych przez dostawcę. Na urządzeniach z NNHAL w wersji 1.2 lub nowszej sterowniki mogą zapewniać niestandardowe operacje przyspieszone sprzętowo, obsługując odpowiednie rozszerzenia dostawców. Rozszerzenia dostawców nie modyfikują zachowanie istniejących operacji.
Rozszerzenia dostawcy stanowią bardziej uporządkowaną alternatywę dla operacji OEM i typów danych, które zostały wycofane w Androidzie 10. Więcej informacji: Operacje OEM i typy danych.
Lista dozwolonych rozszerzeń
Rozszerzenia dostawców mogą być używane tylko przez wyraźnie określone aplikacje na Androida
natywne pliki binarne na partycjach /product
, /vendor
, /odm
i /data
.
Aplikacje i natywne pliki binarne znajdujące się na partycji /system
nie mogą używać rozszerzeń dostawców.
Lista aplikacji i plików binarnych na Androida, które mogą korzystać z rozszerzeń dostawcy NNAPI, jest przechowywana w /vendor/etc/nnapi_extensions_app_allowlist
. Każdy wiersz w pliku
zawiera nowy wpis. Element może być ścieżką do pliku binarnego z prefiksem ukośnika (/), np. /data/foo
, lub nazwą pakietu aplikacji na Androida, np. com.foo.bar
.
Lista dozwolonych jest wymuszana przez bibliotekę współdzieloną NNAPI. Ta biblioteka chroni przed przypadkowym użyciem, ale nie przed celowym obejściem zabezpieczeń przez aplikację bezpośrednio za pomocą interfejsu HAL sterownika NNAPI.
Definicja rozszerzenia dostawcy
Dostawca tworzy i utrzymuje plik nagłówka z definicją rozszerzenia. O
pełny przykład definicji rozszerzenia można znaleźć w
example/fibonacci/FibonacciExtension.h
Każde rozszerzenie musi mieć unikalną nazwę, która zaczyna się od odwrotnej nazwy domeny od dostawcy.
const char EXAMPLE_EXTENSION_NAME[] = "com.example.my_extension";
Nazwa działa jako przestrzeń nazw dla operacji i typów danych. NNAPI używa tej nazwy do rozróżniania rozszerzeń dostawców.
Operacje i typy danych są deklarowane w sposób podobny do tych w
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,
};
Operacja rozszerzenia może używać dowolnego typu operandu, w tym operandu bez rozszerzenia i typy operandów z innych rozszerzeń. W przypadku użycia typu operandu z argumentu z innego rozszerzenia, sterownik musi je obsługiwać.
Rozszerzenia mogą też deklarować niestandardowe struktury, które będą towarzyszyć operatorom rozszerzeń.
/**
* Quantization parameters for {@link EXAMPLE_TENSOR}.
*/
typedef struct ExampleTensorParams {
double scale;
int64_t zeroPoint;
} ExampleTensorParams;
Korzystanie z rozszerzeń w klientach NNAPI
runtime/include/NeuralNetworksExtensions.h
(C API) zapewnia obsługę rozszerzenia środowiska wykonawczego. Ta sekcja zawiera omówienie interfejsu C API.
Aby sprawdzić, czy urządzenie obsługuje rozszerzenie, użyj ANeuralNetworksDevice_getExtensionSupport
.
bool isExtensionSupported;
CHECK_EQ(ANeuralNetworksDevice_getExtensionSupport(device, EXAMPLE_EXTENSION_NAME,
&isExtensionSupported),
ANEURALNETWORKS_NO_ERROR);
if (isExtensionSupported) {
// The device supports the extension.
...
}
Aby utworzyć model z operandem rozszerzenia, użyj funkcji ANeuralNetworksModel_getExtensionOperandType
, aby uzyskać typ operandu, a następnie wywołaj funkcję 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);
Opcjonalnie możesz użyć parametru ANeuralNetworksModel_setOperandExtensionData
, aby powiązać dodatkowe dane z operandem rozszerzenia.
ExampleTensorParams params{
.scale = 0.5,
.zeroPoint = 128,
};
CHECK_EQ(ANeuralNetworksModel_setOperandExtensionData(model, operandIndex, ¶ms, sizeof(params)),
ANEURALNETWORKS_NO_ERROR);
Aby utworzyć model z operacją rozszerzenia, użyj funkcji ANeuralNetworksModel_getExtensionOperationType
, aby uzyskać typ operacji, a potem wywołaj funkcję 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);
Dodawanie obsługi rozszerzenia do sterownika NNAPI
Sterowniki zgłaszają obsługiwane rozszerzenia za pomocą metody IDevice::getSupportedExtensions
. Zwrócona lista musi zawierać wpis opisujący każdą obsługiwaną listę
.
Extension {
.name = EXAMPLE_EXTENSION_NAME,
.operandTypes = {
{
.type = EXAMPLE_SCALAR,
.isTensor = false,
.byteSize = 8,
},
{
.type = EXAMPLE_TENSOR,
.isTensor = true,
.byteSize = 8,
},
},
}
Z 32 bitów używanych do identyfikowania typów i operacji najwyższe
Model::ExtensionTypeEncoding::HIGH_BITS_PREFIX
bity to rozszerzenie
prefiks, a najniższe
Model::ExtensionTypeEncoding::LOW_BITS_TYPE
bity reprezentują typ lub operację rozszerzenia.
Podczas obsługi operacji lub typu operandu sterownik musi sprawdzić rozszerzenie
. Jeśli prefiks rozszerzenia ma wartość różną od 0, typ operacji lub operand jest typem rozszerzenia. Jeśli wartość to 0
, jest to typ operacji lub argumentu.
Nie jest typem rozszerzenia.
Aby zmapować prefiks na nazwę rozszerzenia, wyszukaj go w
model.extensionNameToPrefix
Mapowanie z prefiksu na nazwę rozszerzenia jest korespondencją „jeden do jednego”.
(bijekcjom) danego modelu. Różne wartości prefiksów mogą odpowiadać
z tą samą nazwą rozszerzenia w różnych modelach.
Sterownik musi zweryfikować operacje rozszerzenia i typy danych, ponieważ NNAPI środowisko wykonawcze nie może sprawdzać konkretnych operacji rozszerzeń ani typów danych.
Operandy rozszerzeń mogą mieć powiązane dane w operand.extraParams.extension
, które środowisko wykonawcze traktuje jako surowy blok danych o dowolnym rozmiarze.
Działania i typy danych OEM
NNAPI ma placówkę OEM i typy danych OEM, które pozwalają na
producentów urządzeń, by udostępnić im niestandardowe funkcje dostosowane do konkretnych sterowników. Te
operacji i typów danych
są używane tylko przez aplikacje OEM. Semantyka operacji OEM i typów danych zależy od producenta OEM i może się w dowolnym momencie zmienić. OEM
operacji i typów danych są kodowane za pomocą OperationType::OEM_OPERATION
,
OperandType::OEM
i OperandType::TENSOR_OEM_BYTE
.