Artımlı yürütmeler ve hızlı mesaj sıraları

Neural Networks HAL 1.2, toplu yürütme kavramını sunar. Patlama yürütmeleri, aynı hazırlanmış modelin hızlı bir şekilde gerçekleşen bir dizi yürütmesidir. Örneğin, kamera yakalama kareleri veya ardışık ses örnekleri üzerinde çalışanlar. Patlama nesnesi, bir dizi patlama yürütmesini kontrol etmek ve yürütmeler arasında kaynakları korumak için kullanılır. Bu sayede yürütmeler daha düşük ek yüke sahip olabilir. Patlatma nesneleri üç optimizasyonu etkinleştirir:

  1. Patlama nesnesi, bir yürütme dizisinden önce oluşturulur ve dizi sona erdiğinde serbest bırakılır. Bu nedenle, patlama nesnesi ipuçlarının ömrü, sürücüye ne kadar süreyle yüksek performans durumunda kalması gerektiğini gösterir.
  2. Patlama nesnesi, yürütmeler arasındaki kaynakları koruyabilir. Örneğin, bir sürücü ilk yürütmede bir bellek nesnesini eşleyebilir ve sonraki yürütmelerde yeniden kullanmak üzere patlama nesnesinde eşlemeyi önbelleğe alabilir. Patlama nesnesi yok edildiğinde veya NNAPI çalışma zamanı, patlama nesnesine kaynağın artık gerekli olmadığını bildirdiğinde önbelleğe alınmış tüm kaynaklar serbest bırakılabilir.
  3. Patlama nesnesi, uygulama ve sürücü süreçleri arasında iletişim kurmak için hızlı mesaj kuyruklarını (FMQ) kullanır. Bu, FMQ'nun HIDL'yi atlayıp verileri paylaşılan bellekteki atomik dairesel FIFO aracılığıyla doğrudan başka bir işleme iletmesi nedeniyle gecikmeyi azaltabilir. Tüketici süreci, FIFO'daki öğe sayısını yoklayarak veya üretici tarafından sinyali verilen FMQ'nun etkinlik işaretini bekleyerek bir öğeyi kuyruktan çıkarma ve işlemeye başlama konusunda bilgi sahibidir. Bu etkinlik işareti, hızlı bir kullanıcı alanı karşılıklı dışlama kilididir (futex).

FMQ, süreçler arasında kullanım ömrü garantisi sunmayan ve FMQ'nun diğer ucundaki sürecin beklendiği gibi çalışıp çalışmadığını belirlemek için yerleşik bir mekanizmaya sahip olmayan düşük seviyeli bir veri yapısıdır. Dolayısıyla, FMQ'nun üreticisi ölürse tüketici, hiçbir zaman gelmeyecek verileri beklemek zorunda kalabilir. Bu sorunun bir çözümü, sürücünün FMQ'ları daha üst düzey burst nesnesiyle ilişkilendirerek burst yürütmenin ne zaman sona erdiğini algılamasıdır.

Toplu yürütmeler aynı bağımsız değişkenler üzerinde çalıştığından ve diğer yürütme yollarıyla aynı sonuçları döndürdüğünden, temel FMQ'lar aynı verileri NNAPI hizmet sürücülerine ve sürücülerden geçirmelidir. Ancak FMQ'lar yalnızca basit veri türlerini aktarabilir. Karmaşık verilerin aktarımı, iç içe yerleştirilmiş arabelleklerin (vektör türleri) doğrudan FMQ'larda serileştirilmesi ve seri durumdan çıkarılmasıyla ve bellek havuzu tutamaçlarını gerektiğinde aktarmak için HIDL geri çağırma nesnelerinin kullanılmasıyla gerçekleştirilir. FMQ'nun üretici tarafı, istek veya sonuç mesajlarını tüketiciye atomik olarak göndermelidir. Bu işlem, kuyruk engelliyorsa MessageQueue::writeBlocking kullanılarak, engellemiyorsa MessageQueue::write kullanılarak yapılmalıdır.

Seri arayüzler

Neural Networks HAL'nin patlama arayüzleri hardware/interfaces/neuralnetworks/1.2/ içinde bulunur ve aşağıda açıklanmıştır. NDK katmanındaki burst arayüzleri hakkında daha fazla bilgi için frameworks/ml/nn/runtime/include/NeuralNetworks.h başlıklı makaleye göz atın.

types.hal

types.hal FMQ üzerinden gönderilen veri türünü tanımlar.

  • FmqRequestDatum: Bir Request yürütme nesnesinin ve hızlı mesaj kuyruğuna gönderilen bir MeasureTiming değerinin serileştirilmiş gösteriminin tek bir öğesi.
  • FmqResultDatum: Yürütmeden (ErrorStatus, OutputShapes ve Timing) döndürülen değerlerin seri hale getirilmiş gösteriminin tek bir öğesidir. Bu öğe, hızlı mesaj sırası üzerinden döndürülür.

IBurstContext.hal

IBurstContext.hal Neural Networks hizmetinde bulunan HIDL arayüz nesnesini tanımlar.

  • IBurstContext: Bir patlamanın kaynaklarını yönetmek için kullanılan bağlam nesnesi.

IBurstCallback.hal

IBurstCallback.hal Neural Networks çalışma zamanı tarafından oluşturulan bir geri çağırma için HIDL arayüz nesnesini tanımlar ve Neural Networks hizmeti tarafından yuva tanımlayıcılarına karşılık gelen hidl_memory nesnelerini almak için kullanılır.

  • IBurstCallback: Bir hizmetin bellek nesnelerini almak için kullandığı geri çağırma nesnesi.

IPreparedModel.hal

IPreparedModel.hal HAL 1.2'de, hazırlanmış bir modelden IBurstContext nesnesi oluşturma yöntemiyle genişletilmiştir.

  • configureExecutionBurst: Hazırlanan bir modelde hızlı bir şekilde birden fazla çıkarım yürütmek için kullanılan bir patlama nesnesi yapılandırır.

Sürücüde toplu yürütme desteği

HIDL NNAPI hizmetinde patlama nesnelerini desteklemenin en basit yolu, ::android::nn::ExecutionBurstServer::create patlama yardımcı işlevini kullanmaktır. Bu işlev, ExecutionBurstServer.h içinde bulunur ve libneuralnetworks_common ile libneuralnetworks_util statik kitaplıklarında paketlenir. Bu fabrika işlevinin iki aşırı yüklemesi vardır:

  • Bir aşırı yükleme, IPreparedModel nesnesinin işaretçisini kabul eder. Bu yardımcı işlev, modeli yürütmek için IPreparedModel nesnesinde executeSynchronously yöntemini kullanır.
  • Bir aşırı yükleme, özelleştirilebilir bir IBurstExecutorWithCache nesnesini kabul eder. Bu nesne, birden fazla yürütme boyunca kalıcı olan kaynakları (ör. hidl_memory eşlemeleri) önbelleğe almak için kullanılabilir.

Her aşırı yükleme, kendi özel dinleyici iş parçacığını içeren ve yöneten bir IBurstContext nesnesi (bu nesne, patlama nesnesini temsil eder) döndürür. Bu iş parçacığı, requestChannel FMQ'dan istek alır, çıkarım işlemini gerçekleştirir ve sonuçları resultChannel FMQ üzerinden döndürür. Bu iş parçacığı ve IBurstContext nesnesinde bulunan diğer tüm kaynaklar, patlamanın istemcisi IBurstContext referansını kaybettiğinde otomatik olarak serbest bırakılır.

Alternatif olarak, IBurstContext'nın kendi uygulamanızı oluşturabilirsiniz. Bu uygulama, requestChannel üzerinden ve IPreparedModel::configureExecutionBurst'a iletilen resultChannel FMQ'lar aracılığıyla mesaj gönderme ve alma işlemlerini anlar.

Seri çekim yardımcı işlevleri ExecutionBurstServer.h bölümünde bulunur.

/**
 * 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);

Aşağıda, frameworks/ml/nn/driver/sample/SampleDriver.cpp adresindeki Neural Networks örnek sürücüsünde bulunan bir burst arayüzünün referans uygulaması verilmiştir.

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();
}