Mit neuronalen Netzwerken HAL 1.2 wird das Konzept der Burst-Ausführungen eingeführt. Bilderfolge Ausführungen sind Abfolge von Ausführungen desselben vorbereiteten Modells, die in eine schnelle Abfolge, z. B. wenn Sie in den Einzelbilds einer Kameraaufnahme aufeinanderfolgende Audioinhalte Proben. Mit einem Burst-Objekt können Sie eine Reihe von Burst-Ausführungen steuern und Ressourcen zwischen den Ausführungen beibehalten, wodurch die Ausführung einen geringeren Overhead hat. Burst-Objekte ermöglichen drei Optimierungen:
- Ein Burst-Objekt wird vor einer Sequenz von Ausführungen erstellt und freigegeben, wenn die Sequenz beendet ist. Aus diesem Grund kann die Lebensdauer des Bursts Ein Objekt gibt einem Fahrer an, wie lange er in einer Hochleistungsklasse bleiben soll. Bundesstaat.
- Mit einem Burst-Objekt können Ressourcen zwischen Ausführungen beibehalten werden. Beispiel: Treiber kann bei der ersten Ausführung ein Speicherobjekt zuordnen und die Zuordnung im Cache speichern. im Burst-Objekt zur Wiederverwendung in nachfolgenden Ausführungen. Alle im Cache gespeicherten Ressourcen können freigegeben werden, wenn das Burst-Objekt zerstört wird oder die NNAPI-Laufzeit das Burst-Objekt darüber informiert, dass die Ressource nicht mehr benötigt wird.
- Ein Burst-Objekt verwendet schnelle Nachrichtenwarteschlangen (FMQs) für die Kommunikation zwischen Anwendungs- und Treiberprozessen. Dies kann die Latenz verringern, da die FMQ HIDL umgeht und Daten direkt über einen atomaren zyklischen FIFO im gemeinsamen Speicher an einen anderen Prozess weitergibt. Der Verbraucherprozess weiß, dass er ein Element aus der Warteschlange entfernen und mit der Verarbeitung beginnen muss, indem er entweder die Anzahl der Elemente in der FIFO abfragt oder auf das Ereignisflag der FMQ wartet, das vom Erzeuger signalisiert wird. Dieses Ereignisflag ist ein schneller Mutex im Userspace (futex).
Eine FMQ ist eine Low-Level-Datenstruktur, die keine Lebensdauergarantien für Prozesse bietet und keinen integrierten Mechanismus zum Bestimmen hat, ob der Prozess am anderen Ende der FMQ wie erwartet ausgeführt wird. Wenn also der Produzent wenn der FMQ abbricht, könnte der Nutzer auf Daten warten, die nie ankommen. Eins Die Lösung für dieses Problem besteht darin, dass der Treiber FMQs höherem Burst-Objekt, um zu erkennen, wann die Burst-Ausführung beendet ist.
Da Burst-Ausführungen mit denselben Argumenten arbeiten und dieselben Ergebnisse wie andere Ausführungspfade zurückgeben, müssen die zugrunde liegenden FMQs dieselben Daten an die NNAPI-Diensttreiber und von diesen weitergeben. FMQs können jedoch nur
altbekannte Datentypen. Die Übertragung komplexer Daten erfolgt durch Serialisierung
und Deserialisieren verschachtelter Puffer (Vektortypen) direkt in den FMQs und verwenden
HIDL-Callback-Objekte zum Übertragen von Arbeitsspeicherpool-Handles bei Bedarf. Der Produzent
Seite der FMQ muss die Anfrage oder die Ergebnisnachrichten an den Nutzer senden.
untrennbar mit MessageQueue::writeBlocking
, wenn die Warteschlange blockiert wird, oder
indem Sie MessageQueue::write
verwenden, wenn die Warteschlange nicht blockierend ist.
Burst-Benutzeroberflächen
Die Burst-Schnittstellen für die HAL von neuronalen Netzwerken befinden sich in
hardware/interfaces/neuralnetworks/1.2/
und werden im Folgenden beschrieben. Weitere Informationen zu Burst-Schnittstellen im NDK
finden Sie unter
frameworks/ml/nn/runtime/include/NeuralNetworks.h
Typen.hal
types.hal
definiert den Datentyp, der über den FMQ gesendet wird.
FmqRequestDatum
: Ein einzelnes Element einer serialisierten Darstellung einesRequest
-Objekts für die Ausführung und einMeasureTiming
-Wert, der über die schnelle Nachrichtenwarteschlange gesendet wird.FmqResultDatum
: Ein einzelnes Element einer serialisierten Darstellung der von eine Ausführung (ErrorStatus
,OutputShapes
undTiming
), die die von der Warteschlange für schnelle Nachrichten zurückgegeben werden.
iBurstContext.hal
IBurstContext.hal
definiert das HIDL-Schnittstellenobjekt, das sich im Neural Networks-Dienst befindet.
IBurstContext
: Kontextobjekt zum Verwalten der Ressourcen eines Bursts.
IBurstCallback.hal
IBurstCallback.hal
definiert das HIDL-Schnittstellenobjekt für einen Callback, der von neuronalen Netzwerken erstellt wurde
Laufzeit und wird vom Dienst für neuronale Netzwerke verwendet, um hidl_memory
abzurufen
-Objekten, die Slot-IDs entsprechen.
- IBurstCallback: Callback-Objekt, das von einem Dienst zum Abrufen von Speicherobjekten verwendet wird.
IPreparedModel.hal
IPreparedModel.hal
wird in HAL 1.2 um eine Methode zum Erstellen eines IBurstContext
-Objekts aus einem
vorbereiteten Modell verwenden.
configureExecutionBurst
: Konfiguriert ein Burst-Objekt, mit dem mehrere Inferenzen in schneller Folge auf einem vorbereiteten Modell ausgeführt werden.
Burst-Ausführungen in einem Treiber unterstützen
Die einfachste Möglichkeit zur Unterstützung von Burst-Objekten in einem HIDL NNAPI-Dienst ist die Verwendung des
Burst-Dienstprogrammfunktion ::android::nn::ExecutionBurstServer::create
, die
gefunden in
ExecutionBurstServer.h
und verpackt in libneuralnetworks_common
und libneuralnetworks_util
statische Bibliotheken. Diese Standardfunktion hat zwei Überladungen:
- Eine Überladung akzeptiert einen Zeiger auf ein
IPreparedModel
-Objekt. Dieses die MethodeexecuteSynchronously
in einerIPreparedModel
-Objekt, um das Modell auszuführen. - Für eine Überlast wird ein anpassbares
IBurstExecutorWithCache
-Objekt akzeptiert. mit dem Ressourcen im Cache gespeichert werden können (z. B.hidl_memory
-Zuordnungen), die und bleiben über mehrere Ausführungen hinweg erhalten.
Bei jeder Überlastung wird ein IBurstContext
-Objekt zurückgegeben, das den Burst darstellt.
-Objekt), das seinen eigenen dedizierten Listener-Thread enthält und verwaltet. Dieser Thread empfängt Anfragen von der requestChannel
-FMQ, führt die Inferenz durch und gibt die Ergebnisse dann über die resultChannel
-FMQ zurück. Dieser Thread und alle anderen Ressourcen im IBurstContext
-Objekt werden automatisch freigegeben, wenn der Client des Bursts seine Referenz auf IBurstContext
verliert.
Alternativ können Sie Ihre eigene IBurstContext
-Implementierung erstellen, die
das Senden und Empfangen von Nachrichten über requestChannel
und
resultChannel
FMQs wurden an IPreparedModel::configureExecutionBurst
übergeben.
Die Burst-Hilfsfunktionen finden Sie unter ExecutionBurstServer.h
.
/**
* Create automated context to manage FMQ-based executions.
*
* This function is intended to be used by a service to automatically:
* 1) Receive data from a provided FMQ
* 2) Execute a model with the given information
* 3) Send the result to the created FMQ
*
* @param callback Callback used to retrieve memories corresponding to
* unrecognized slots.
* @param requestChannel Input FMQ channel through which the client passes the
* request to the service.
* @param resultChannel Output FMQ channel from which the client can retrieve
* the result of the execution.
* @param executorWithCache Object which maintains a local cache of the
* memory pools and executes using the cached memory pools.
* @result IBurstContext Handle to the burst context.
*/
static sp<ExecutionBurstServer> create(
const sp<IBurstCallback>& callback, const FmqRequestDescriptor& requestChannel,
const FmqResultDescriptor& resultChannel,
std::shared_ptr<IBurstExecutorWithCache> executorWithCache);
/**
* Create automated context to manage FMQ-based executions.
*
* This function is intended to be used by a service to automatically:
* 1) Receive data from a provided FMQ
* 2) Execute a model with the given information
* 3) Send the result to the created FMQ
*
* @param callback Callback used to retrieve memories corresponding to
* unrecognized slots.
* @param requestChannel Input FMQ channel through which the client passes the
* request to the service.
* @param resultChannel Output FMQ channel from which the client can retrieve
* the result of the execution.
* @param preparedModel PreparedModel that the burst object was created from.
* IPreparedModel::executeSynchronously will be used to perform the
* execution.
* @result IBurstContext Handle to the burst context.
*/
static sp<ExecutionBurstServer> create(const sp<IBurstCallback>& callback,
const FmqRequestDescriptor& requestChannel,
const FmqResultDescriptor& resultChannel,
IPreparedModel* preparedModel);
Im Folgenden finden Sie eine Referenzimplementierung einer Burst-Schnittstelle aus dem Beispieltreiber für neuronale Netze unter frameworks/ml/nn/driver/sample/SampleDriver.cpp
.
Return<void> SamplePreparedModel::configureExecutionBurst(
const sp<V1_2::IBurstCallback>& callback,
const MQDescriptorSync<V1_2::FmqRequestDatum>& requestChannel,
const MQDescriptorSync<V1_2::FmqResultDatum>& resultChannel,
configureExecutionBurst_cb cb) {
NNTRACE_FULL(NNTRACE_LAYER_DRIVER, NNTRACE_PHASE_EXECUTION,
"SampleDriver::configureExecutionBurst");
// Alternatively, the burst could be configured via:
// const sp<V1_2::IBurstContext> burst =
// ExecutionBurstServer::create(callback, requestChannel,
// resultChannel, this);
//
// However, this alternative representation does not include a memory map
// caching optimization, and adds overhead.
const std::shared_ptr<BurstExecutorWithCache> executorWithCache =
std::make_shared<BurstExecutorWithCache>(mModel, mDriver, mPoolInfos);
const sp<V1_2::IBurstContext> burst = ExecutionBurstServer::create(
callback, requestChannel, resultChannel, executorWithCache);
if (burst == nullptr) {
cb(ErrorStatus::GENERAL_FAILURE, {});
} else {
cb(ErrorStatus::NONE, burst);
}
return Void();
}