NNAPI-Anbietererweiterungen (Neural Networks API), die im Android 10 Sammlungen von anbieterdefinierten Vorgängen und Datentypen. Auf Geräten mit NN HAL 1.2 oder höher können Treiber benutzerdefinierte hardwarebeschleunigte Operationen durch entsprechende Anbietererweiterungen unterstützt. Durch die Anbietererweiterungen ändert sich vorhandenen Vorgängen.
Diese Erweiterungen sind eine strukturiertere Alternative zum OEM-Betrieb und Datentypen, die in Android 10 eingestellt wurden. Weitere Informationen finden Sie unter OEM-Betrieb und -Datentypen.
Zulassungsliste für die Nutzung von Erweiterungen
Anbietererweiterungen können nur von explizit angegebenen Android-Apps und
native Binärdateien in den Partitionen /product
, /vendor
, /odm
und /data
.
Apps und native Binärdateien, die sich in der Partition /system
befinden, können den Anbieter nicht verwenden
Erweiterungen.
Eine Liste der Android-Apps und -Binärprogramme, die NNAPI-Anbietererweiterungen verwenden dürfen, ist
gespeichert in /vendor/etc/nnapi_extensions_app_allowlist
. Jede Zeile der Datei
enthält einen neuen Eintrag. Ein Eintrag kann ein nativer Binärpfad mit dem Präfix
einen Schrägstrich (/), z. B. /data/foo
oder der Name eines Android-App-Pakets für
Beispiel: com.foo.bar
.
Die Zulassungsliste wird von der gemeinsam genutzten NNAPI-Laufzeitbibliothek erzwungen. Diese Bibliothek vor versehentlicher Nutzung, aber nicht vor absichtlicher Umgehung durch über die HAL-Schnittstelle des NNAPI-Treibers eine Anwendung erstellen.
Definition der Anbietererweiterung
Der Anbieter erstellt und verwaltet eine Headerdatei mit der Definition der Erweiterung. A
Ein vollständiges Beispiel für eine Erweiterungsdefinition finden Sie unter
example/fibonacci/FibonacciExtension.h
Jede Erweiterung muss einen eindeutigen Namen haben, der mit dem umgekehrten Domainnamen beginnt des Zulieferunternehmens.
const char EXAMPLE_EXTENSION_NAME[] = "com.example.my_extension";
Der Name dient als Namespace für Vorgänge und Datentypen. Die NNAPI verwendet diese Namen, um zwischen den Anbietererweiterungen zu unterscheiden.
Vorgänge und Datentypen werden ähnlich wie die in
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,
};
Für einen Erweiterungsvorgang kann jeder Operandtyp verwendet werden, einschließlich Nichterweiterungs-Operanden und Operandtypen von anderen Erweiterungen. Wenn Sie einen Operandentyp aus eine andere Erweiterung haben, muss der Treiber die andere Erweiterung unterstützen.
Erweiterungen können auch benutzerdefinierte Strukturen deklarieren, die zu Erweiterungsoperanden gehören.
/**
* Quantization parameters for {@link EXAMPLE_TENSOR}.
*/
typedef struct ExampleTensorParams {
double scale;
int64_t zeroPoint;
} ExampleTensorParams;
Erweiterungen in NNAPI-Clients verwenden
Die
runtime/include/NeuralNetworksExtensions.h
(C API) unterstützt Laufzeiterweiterung. Dieser Abschnitt enthält eine
Übersicht über die C API.
Wenn Sie prüfen möchten, ob ein Gerät eine Erweiterung unterstützt, verwenden Sie
ANeuralNetworksDevice_getExtensionSupport
bool isExtensionSupported;
CHECK_EQ(ANeuralNetworksDevice_getExtensionSupport(device, EXAMPLE_EXTENSION_NAME,
&isExtensionSupported),
ANEURALNETWORKS_NO_ERROR);
if (isExtensionSupported) {
// The device supports the extension.
...
}
Um ein Modell mit einem Erweiterungsoperanden zu erstellen, verwenden Sie
ANeuralNetworksModel_getExtensionOperandType
um den Operandentyp zu erhalten und
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);
Optional:
ANeuralNetworksModel_setOperandExtensionData
, um zusätzliche Daten mit einem Erweiterungsoperanden zu verknüpfen.
ExampleTensorParams params{
.scale = 0.5,
.zeroPoint = 128,
};
CHECK_EQ(ANeuralNetworksModel_setOperandExtensionData(model, operandIndex, ¶ms, sizeof(params)),
ANEURALNETWORKS_NO_ERROR);
Um ein Modell mit einem Erweiterungsvorgang zu erstellen, verwenden Sie
ANeuralNetworksModel_getExtensionOperationType
um den Vorgangstyp zu erhalten und
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);
Erweiterungsunterstützung zu einem NNAPI-Treiber hinzufügen
Treiber melden unterstützte Erweiterungen über das
IDevice::getSupportedExtensions
. Die zurückgegebene Liste muss einen Eintrag enthalten, der alle unterstützten
.
Extension {
.name = EXAMPLE_EXTENSION_NAME,
.operandTypes = {
{
.type = EXAMPLE_SCALAR,
.isTensor = false,
.byteSize = 8,
},
{
.type = EXAMPLE_TENSOR,
.isTensor = true,
.byteSize = 8,
},
},
}
Von den 32 Bits, die zum Identifizieren von Typen und Vorgängen verwendet werden, ist die hohe
Model::ExtensionTypeEncoding::HIGH_BITS_PREFIX
Bits ist die Erweiterung
Präfix und der niedrige
Model::ExtensionTypeEncoding::LOW_BITS_TYPE
Bits stehen für den Typ oder Vorgang
der Erweiterung.
Bei der Verarbeitung eines Vorgangs- oder Operandentyps muss der Treiber die Erweiterung überprüfen.
. Wenn das Erweiterungspräfix einen Wert ungleich null hat, wird die Operation oder der Operand
Typ ist ein Erweiterungstyp. Wenn der Wert 0
ist, ist der Operation- oder Operandentyp
ist kein Erweiterungstyp.
Wenn Sie das Präfix einem Erweiterungsnamen zuordnen möchten, suchen Sie es unter
model.extensionNameToPrefix
Die Zuordnung vom Präfix zum Erweiterungsnamen erfolgt 1:1-Übereinstimmung
(Bijektion) für ein bestimmtes Modell. Unterschiedliche Präfixwerte können dem
Erweiterungsnamen in verschiedenen Modellen.
Der Treiber muss Erweiterungsvorgänge und Datentypen validieren, da die NNAPI Laufzeit bestimmte Erweiterungsvorgänge und Datentypen nicht validieren kann.
Erweiterungsoperanden können zugehörige Daten haben in
operand.extraParams.extension
,
die die Laufzeit als Rohdaten-Blob
beliebiger Größe behandelt.
OEM-Betrieb und Datentypen
NNAPI bietet einen OEM-Betrieb und OEM-Datentypen,
Geräteherstellern zur Bereitstellung benutzerdefinierter, treiberspezifischer Funktionen. Diese
Vorgang und Datentypen werden nur von OEM-Anwendungen verwendet. Die Semantik von OEM
Betriebs- und Datentypen sind OEM-spezifisch und können sich jederzeit ändern. Der OEM
Vorgang und Datentypen werden mit OperationType::OEM_OPERATION
,
OperandType::OEM
und OperandType::TENSOR_OEM_BYTE
.