Wykonywanie serii i szybkie kolejki wiadomości

Neural Networks HAL 1.2 zawiera koncepcję wykonań burstowych. Seria to sekwencja wykonań tego samego przygotowanego modelu, które występują w szybkiej sekwencyjności, np. w ramach kadrów nagrywanych kamerą lub kolejny dźwięk przykłady. Obiekt burst służy do sterowania zestawem wykonań burst zachowuj zasoby pomiędzy uruchomieniami, dzięki czemu wykonań mają nadmiarowe. W przypadku obiektów serii można włączyć 3 optymalizacje:

  1. Obiekt burstowy jest tworzony przed sekwencją wykonań i zostaje zwolniony po zakończeniu sekwencji. Z tego względu czas trwania wybuchu wskazówki dotyczące obiektów, przekazane do sterownika, jak długo ma ono pozostawać w wysokiej wydajności stanu.
  2. Obiekt burstowy może zachowywać zasoby między uruchomieniami. Na przykład plik sterownik może zmapować obiekt pamięci przy pierwszym uruchomieniu i buforować mapowanie w obiekcie burst do ponownego wykorzystania w kolejnych wykonaniach. Dowolny zasób z pamięci podręcznej może zostać zwolniona, gdy obiekt burst zostanie zniszczony lub gdy interfejs NNAPI środowisko wykonawcze powiadamia obiekt Burst, że zasób nie jest już wymagany.
  3. Obiekt serii używa funkcji szybkie kolejki wiadomości (FMQ) do komunikacji między procesami aplikacji i sterownika. Może to spowodować zmniejsza opóźnienie, ponieważ FMQ omija HIDL i przekazuje dane bezpośrednio przez atomowy okrągły proces FIFO we wspólnej pamięci. że proces konsumenta musi usunąć element z kolejki i rozpocząć przetwarzanie ankietowanie liczby pierwiastków w FIFO lub oczekiwanie na zdarzenie FMQ flaga, co jest sygnalizowane przez producenta. Ta flaga zdarzenia jest szybka mutex w przestrzeni użytkownika (futex).

FMQ to niskopoziomowa struktura danych, która nie daje żadnych bezterminowych gwarancji procesów i nie ma wbudowanego mechanizmu określającego, czy dany proces drugi koniec FMQ działa zgodnie z oczekiwaniami. W związku z tym, jeśli producent dla FMQ umrze, konsument może utknąć w oczekiwaniu na dane, które nigdy nie zostaną dostarczone. Jedna Rozwiązaniem tego problemu jest powiązanie przez kierowcę FMQ z obiektu burst wyższego poziomu w celu wykrycia zakończenia wykonywania serii.

Ponieważ wykonania burstowe działają na tych samych argumentach i zwracają to samo jak w innych ścieżkach wykonania, bazowe wskaźniki FMQ muszą przekazywać te same dane do i sterowników usługi NNAPI. FMQ mogą jednak przesyłać tylko i nie tylko. Przenoszenie złożonych danych odbywa się przez serializację deserializacji zagnieżdżonych buforów (typów wektorów) bezpośrednio w FMQ; Obiekty wywołania zwrotnego HIDL do przesyłania uchwytów puli pamięci na żądanie. Producent strony FMQ muszą wysyłać do konsumenta komunikaty o żądaniach lub wynikach atomowo przy użyciu funkcji MessageQueue::writeBlocking, jeśli kolejka jest blokowana; używając metody MessageQueue::write, jeśli kolejka nie jest blokowana.

Interfejsy serii

Interfejsy burst dla HAL sieci neuronowych znajdują się w: hardware/interfaces/neuralnetworks/1.2/ i zostały opisane poniżej. Więcej informacji o interfejsach burst w pakiecie NDK patrz frameworks/ml/nn/runtime/include/NeuralNetworks.h

type.hal

types.hal określa typ danych wysyłanych przez FMQ.

  • FmqRequestDatum: Pojedynczy element serializowanej reprezentacji wykonania Request i wartość MeasureTiming, która jest wysyłana przez szybką wiadomość kolejkę.
  • FmqResultDatum: Pojedynczy element zserializowanej reprezentacji wartości zwracanych z wykonania (ErrorStatus, OutputShapes i Timing), które jest w ramach szybkiej kolejki komunikatów.

IBurstContext.hal

IBurstContext.hal określa obiekt interfejsu HIDL, który funkcjonuje w usłudze sieci neuronowych.

  • IBurstContext: Obiekt kontekstu do zarządzania zasobami serii.

IBurstCallback.hal

IBurstCallback.hal określa obiekt interfejsu HIDL dla wywołania zwrotnego utworzonego przez sieci neuronowe w czasie działania i jest używany przez usługę sieci neuronowych do pobierania danych hidl_memory odpowiadających identyfikatorami przedziałów.

  • IBurstCallback: Obiekt wywołania zwrotnego używany przez usługę do pobierania obiektów pamięci.

IPreparedModel.hal

IPreparedModel.hal jest rozszerzany w HAL 1.2 o metodę tworzenia obiektu IBurstContext na podstawie gotowy model.

  • configureExecutionBurst: Konfiguruje obiekt burst używany do wykonywania wielu wnioskowania na przygotowanej bazie które można szybko po sobie osiągnąć.

Obsługa wykonań burst w sterowniku

Najprostszym sposobem obsługi obiektów burst w usłudze HIDL NNAPI jest użycie burst funkcji użytkowej ::android::nn::ExecutionBurstServer::create, która jest znaleziono w ExecutionBurstServer.h. i spakowane w libneuralnetworks_common i libneuralnetworks_util bibliotek statycznych. Ta funkcja fabryczna ma 2 przeciążenia:

  • Jedno przeciążenie akceptuje wskaźnik do obiektu IPreparedModel. Ten funkcja użytkowa korzysta z metody executeSynchronously w funkcji IPreparedModel obiekt do wykonania modelu.
  • Jedno przeciążenie akceptuje konfigurowalny obiekt IBurstExecutorWithCache, która może być używana do buforowania zasobów (np. mapowań hidl_memory), które pozostają aktywne w wielu uruchomieniach.

Każde przeciążenie zwraca obiekt IBurstContext (który reprezentuje serię obiekt), który zawiera własny wątek detektora dedykowanego detektora i nim zarządza. Ten wątek odbiera żądania z FMQ requestChannel, przeprowadza wnioskowanie, a następnie zwraca wyniki za pośrednictwem funkcji FMQ resultChannel. Ten i wszystkie inne zasoby zawarte w obiekcie IBurstContext są automatycznie zwalniane gdy klient serii utraci odwołanie do IBurstContext.

Możesz też utworzyć własną implementację tagu IBurstContext, która wie, jak wysyłać i odbierać wiadomości przez requestChannel oraz Do IPreparedModel::configureExecutionBurst przekazano resultChannel FMQ.

Funkcje burstowe znajdują się w 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);

Poniżej znajduje się referencyjna implementacja interfejsu burst, który znajduje się w Przykładowy sterownik sieci neuronowych ma 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();
}