Delegasi TensorFlow Lite NNAPI

Android Neural Networks API (NNAPI) tersedia di semua perangkat Android yang menjalankan Android 8.1 (API level 27) atau lebih tinggi. Ini memberikan akselerasi untuk model TensorFlow Lite di perangkat Android dengan akselerator hardware yang didukung termasuk:

  • Unit Pemrosesan Grafis (GPU)
  • Prosesor Sinyal Digital (DSP)
  • Unit Pemrosesan Saraf (NPU)

Kinerja akan bervariasi tergantung pada perangkat keras spesifik yang tersedia pada perangkat.

Halaman ini menjelaskan cara menggunakan delegasi NNAPI dengan Interpreter TensorFlow Lite di Java dan Kotlin. Untuk API Android C, lihat dokumentasi Android Native Developer Kit .

Mencoba delegasi NNAPI pada model Anda sendiri

Impor tingkat

Delegasi NNAPI adalah bagian dari interpreter Android TensorFlow Lite, rilis 1.14.0 atau lebih tinggi. Anda dapat mengimpornya ke proyek Anda dengan menambahkan yang berikut ke file gradle modul Anda:

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

Menginisialisasi delegasi NNAPI

Tambahkan kode untuk menginisialisasi delegasi NNAPI sebelum Anda menginisialisasi penerjemah TensorFlow Lite.

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

...

Jawa

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

...

Praktik terbaik

Uji kinerja sebelum diterapkan

Kinerja runtime dapat bervariasi secara signifikan karena arsitektur model, ukuran, operasi, ketersediaan perangkat keras, dan pemanfaatan perangkat keras runtime. Misalnya, jika aplikasi banyak menggunakan GPU untuk rendering, akselerasi NNAPI mungkin tidak meningkatkan performa karena pertentangan sumber daya. Kami merekomendasikan menjalankan tes kinerja sederhana menggunakan debug logger untuk mengukur waktu inferensi. Jalankan pengujian pada beberapa ponsel dengan chipset berbeda (produsen atau model dari pabrikan yang sama) yang mewakili basis pengguna Anda sebelum mengaktifkan NNAPI dalam produksi.

Untuk pengembang tingkat lanjut, TensorFlow Lite juga menawarkan alat benchmark model untuk Android .

Buat daftar pengecualian perangkat

Dalam produksi, mungkin ada kasus di mana NNAPI tidak berfungsi seperti yang diharapkan. Kami menyarankan pengembang menyimpan daftar perangkat yang tidak boleh menggunakan akselerasi NNAPI jika dikombinasikan dengan model tertentu. Anda dapat membuat daftar ini berdasarkan nilai "ro.board.platform" , yang dapat Anda ambil menggunakan cuplikan kode berikut:

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

Untuk pengembang tingkat lanjut, pertimbangkan untuk mempertahankan daftar ini melalui sistem konfigurasi jarak jauh. Tim TensorFlow secara aktif berupaya mencari cara untuk menyederhanakan dan mengotomatisasi penemuan dan penerapan konfigurasi NNAPI yang optimal.

Kuantisasi

Kuantisasi mengurangi ukuran model dengan menggunakan bilangan bulat 8-bit atau float 16-bit, bukan float 32-bit untuk komputasi. Ukuran model integer 8-bit adalah seperempat dari versi float 32-bit; Float 16-bit berukuran setengahnya. Kuantisasi dapat meningkatkan kinerja secara signifikan meskipun prosesnya dapat mengurangi akurasi model.

Ada beberapa jenis teknik kuantisasi pasca-pelatihan yang tersedia, namun, untuk dukungan dan akselerasi maksimum pada perangkat keras saat ini, kami merekomendasikan kuantisasi bilangan bulat penuh . Pendekatan ini mengubah bobot dan operasi menjadi bilangan bulat. Proses kuantisasi ini memerlukan kumpulan data yang representatif agar dapat berfungsi.

Gunakan model dan operasi yang didukung

Jika delegasi NNAPI tidak mendukung beberapa operasi atau kombinasi parameter dalam model, kerangka kerja hanya menjalankan bagian grafik yang didukung pada akselerator. Sisanya berjalan pada CPU, yang menghasilkan eksekusi terpisah. Karena tingginya biaya sinkronisasi CPU/akselerator, hal ini dapat mengakibatkan kinerja lebih lambat dibandingkan mengeksekusi seluruh jaringan pada CPU saja.

NNAPI berkinerja terbaik ketika model hanya menggunakan operasi yang didukung . Model berikut diketahui kompatibel dengan NNAPI:

Akselerasi NNAPI juga tidak didukung ketika model berisi output berukuran dinamis. Dalam hal ini, Anda akan mendapat peringatan seperti:

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

Aktifkan implementasi CPU NNAPI

Grafik yang tidak dapat diproses sepenuhnya oleh akselerator dapat dikembalikan ke implementasi CPU NNAPI. Namun, karena performanya biasanya lebih rendah dibandingkan interpreter TensorFlow, opsi ini dinonaktifkan secara default di delegasi NNAPI untuk Android 10 (API Level 29) atau lebih tinggi. Untuk mengganti perilaku ini, setel setUseNnapiCpu ke true di objek NnApiDelegate.Options .