TensorFlow Lite NNAPI temsilcisi

Android Neural Networks API (NNAPI), Android 8.1 (API düzeyi 27) veya üzerini çalıştıran tüm Android cihazlarda mevcuttur. Aşağıdakiler dahil desteklenen donanım hızlandırıcılara sahip Android cihazlarda TensorFlow Lite modelleri için hızlandırma sağlar:

  • Grafik İşlem Birimi (GPU)
  • Dijital Sinyal İşlemcisi (DSP)
  • Sinir İşleme Birimi (NPU)

Performans, cihazda bulunan spesifik donanıma bağlı olarak değişecektir.

Bu sayfada NNAPI temsilcisinin Java ve Kotlin'de TensorFlow Lite Interpreter ile nasıl kullanılacağı açıklanmaktadır. Android C API'leri için lütfen Android Yerel Geliştirici Seti belgelerine bakın.

NNAPI temsilcisini kendi modelinizde denemek

Gradle'ı içe aktarma

NNAPI temsilcisi, TensorFlow Lite Android yorumlayıcısının bir parçasıdır, sürüm 1.14.0 veya üzeridir. Aşağıdakileri modül gradle dosyanıza ekleyerek projenize aktarabilirsiniz:

dependencies {
   implementation 'org.tensorflow:tensorflow-lite:+'
}

NNAPI temsilcisini başlatma

TensorFlow Lite yorumlayıcısını başlatmadan önce NNAPI temsilcisini başlatmak için kodu ekleyin.

kotlin

import android.content.res.AssetManager
import org.tensorflow.lite.Interpreter
import org.tensorflow.lite.nnapi.NnApiDelegate
import java.io.FileInputStream
import java.io.IOException
import java.nio.MappedByteBuffer
import java.nio.channels.FileChannel
...

val options = Interpreter.Options()
var nnApiDelegate: NnApiDelegate? = null
// Initialize interpreter with NNAPI delegate for Android Pie or above
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
    nnApiDelegate = NnApiDelegate()
    options.addDelegate(nnApiDelegate)
}
val assetManager = assets

// Initialize TFLite interpreter
val tfLite: Interpreter
try {
    tfLite = Interpreter(loadModelFile(assetManager, "model.tflite"), options)
} catch (e: Exception) {
    throw RuntimeException(e)
}

// Run inference
// ...

// Unload delegate
tfLite.close()
nnApiDelegate?.close()

...

@Throws(IOException::class)
private fun loadModelFile(assetManager: AssetManager, modelFilename: String): MappedByteBuffer {
    val fileDescriptor = assetManager.openFd(modelFilename)
    val inputStream = FileInputStream(fileDescriptor.fileDescriptor)
    val fileChannel = inputStream.channel
    val startOffset = fileDescriptor.startOffset
    val declaredLength = fileDescriptor.declaredLength
    return fileChannel.map(FileChannel.MapMode.READ_ONLY, startOffset, declaredLength)
}

...

java

import android.content.res.AssetManager;
import org.tensorflow.lite.Interpreter;
import org.tensorflow.lite.nnapi.NnApiDelegate;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
...

Interpreter.Options options = (new Interpreter.Options());
NnApiDelegate nnApiDelegate = null;
// Initialize interpreter with NNAPI delegate for Android Pie or above
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
    nnApiDelegate = new NnApiDelegate();
    options.addDelegate(nnApiDelegate);
}

AssetManager assetManager = getAssets();
// Initialize TFLite interpreter
try {
    tfLite = new Interpreter(loadModelFile(assetManager, "model.tflite"), options);
} catch (Exception e) {
    throw new RuntimeException(e);
}

// Run inference
// ...

// Unload delegate
tfLite.close();
if(null != nnApiDelegate) {
    nnApiDelegate.close();
}

...

private MappedByteBuffer loadModelFile(AssetManager assetManager, String modelFilename) throws IOException {
    AssetFileDescriptor fileDescriptor = assetManager.openFd(modelFilename);
    FileInputStream inputStream = new FileInputStream(fileDescriptor.getFileDescriptor());
    FileChannel fileChannel = inputStream.getChannel();
    long startOffset = fileDescriptor.getStartOffset();
    long declaredLength = fileDescriptor.getDeclaredLength();
    return fileChannel.map(FileChannel.MapMode.READ_ONLY, startOffset, declaredLength);
}

...

En iyi uygulamalar

Dağıtımdan önce performansı test edin

Çalışma zamanı performansı, model mimarisi, boyut, işlemler, donanım kullanılabilirliği ve çalışma zamanı donanım kullanımına bağlı olarak önemli ölçüde değişiklik gösterebilir. Örneğin, bir uygulama oluşturma için GPU'yu yoğun bir şekilde kullanıyorsa, NNAPI hızlandırması kaynak çekişmesi nedeniyle performansı iyileştirmeyebilir. Çıkarım süresini ölçmek için hata ayıklama günlükçüsünü kullanarak basit bir performans testi yapmanızı öneririz. NNAPI'yi üretimde etkinleştirmeden önce testi, kullanıcı tabanınızı temsil eden farklı yonga setlerine (üretici veya aynı üreticinin modelleri) sahip birkaç telefonda çalıştırın.

TensorFlow Lite, ileri düzey geliştiriciler için Android için bir model kıyaslama aracı da sunar.

Cihaz hariç tutma listesi oluşturma

Üretimde NNAPI'nin beklendiği gibi performans göstermediği durumlar olabilir. Geliştiricilerin NNAPI hızlandırmasını belirli modellerle birlikte kullanmaması gereken cihazların bir listesini tutmasını öneririz. Bu listeyi, aşağıdaki kod parçacığını kullanarak alabileceğiniz "ro.board.platform" değerine göre oluşturabilirsiniz:

String boardPlatform = "";

try {
    Process sysProcess =
        new ProcessBuilder("/system/bin/getprop", "ro.board.platform").
        redirectErrorStream(true).start();

    BufferedReader reader = new BufferedReader
        (new InputStreamReader(sysProcess.getInputStream()));
    String currentLine = null;

    while ((currentLine=reader.readLine()) != null){
        boardPlatform = line;
    }
    sysProcess.destroy();
} catch (IOException e) {}

Log.d("Board Platform", boardPlatform);

İleri düzey geliştiriciler için bu listeyi uzaktan yapılandırma sistemi aracılığıyla tutmayı düşünün. TensorFlow ekibi, optimum NNAPI yapılandırmasını keşfetmeyi ve uygulamayı basitleştirmenin ve otomatikleştirmenin yolları üzerinde aktif olarak çalışıyor.

Niceleme

Niceleme, hesaplama için 32 bitlik kayan noktalar yerine 8 bitlik tamsayılar veya 16 bitlik kayan noktalar kullanarak model boyutunu azaltır. 8 bitlik tamsayı model boyutları, 32 bitlik kayan sürümlerin dörtte biri kadardır; 16 bitlik kayan noktalar boyutun yarısı kadardır. Niceleme performansı önemli ölçüde artırabilir, ancak süreç bazı model doğruluğundan ödün verebilir.

Eğitim sonrası niceleme tekniklerinin birden çok türü mevcuttur, ancak mevcut donanımda maksimum destek ve hızlandırma için tam tamsayı nicelemeyi öneriyoruz. Bu yaklaşım hem ağırlığı hem de işlemleri tam sayılara dönüştürür. Bu niceleme işleminin çalışması temsili bir veri kümesi gerektirir.

Desteklenen modelleri ve işlemleri kullanın

NNAPI temsilcisi bir modeldeki bazı işlemleri veya parametre birleşimlerini desteklemiyorsa çerçeve, hızlandırıcıdaki grafiğin yalnızca desteklenen kısımlarını çalıştırır. Geri kalanı CPU üzerinde çalışır ve bu da bölünmüş yürütmeyle sonuçlanır. CPU/hızlandırıcı senkronizasyonunun yüksek maliyeti nedeniyle bu, tüm ağın yalnızca CPU üzerinde yürütülmesinden daha düşük performansla sonuçlanabilir.

NNAPI, modeller yalnızca desteklenen işlemleri kullandığında en iyi performansı gösterir. Aşağıdaki modellerin NNAPI ile uyumlu olduğu bilinmektedir:

Model dinamik olarak boyutlandırılmış çıkışlar içerdiğinde NNAPI hızlandırması da desteklenmez. Bu durumda şöyle bir uyarı alırsınız:

ERROR: Attempting to use a delegate that only supports static-sized tensors \
with a graph that has dynamic-sized tensors.

NNAPI CPU uygulamasını etkinleştir

Bir hızlandırıcı tarafından tamamen işlenemeyen bir grafik, NNAPI CPU uygulamasına geri dönebilir. Ancak bu genellikle TensorFlow yorumlayıcısından daha düşük performanslı olduğundan, bu seçenek Android 10 (API Düzeyi 29) veya üzeri için NNAPI temsilcisinde varsayılan olarak devre dışıdır. Bu davranışı geçersiz kılmak için NnApiDelegate.Options nesnesinde setUseNnapiCpu true olarak ayarlayın.