نماینده NNAPI TensorFlow Lite

API شبکه‌های عصبی Android (NNAPI) در همه دستگاه‌های اندرویدی دارای Android 8.1 (سطح API 27) یا بالاتر در دسترس است. این شتاب را برای مدل های TensorFlow Lite در دستگاه های Android با شتاب دهنده های سخت افزاری پشتیبانی شده از جمله:

  • واحد پردازش گرافیکی (GPU)
  • پردازنده سیگنال دیجیتال (DSP)
  • واحد پردازش عصبی (NPU)

عملکرد بسته به سخت افزار خاص موجود در دستگاه متفاوت خواهد بود.

در این صفحه نحوه استفاده از نماینده NNAPI با مترجم TensorFlow Lite در جاوا و کاتلین توضیح داده شده است. برای APIهای Android C، لطفاً به مستندات Android Native Developer Kit مراجعه کنید.

نماینده NNAPI را در مدل خود امتحان کنید

واردات گرید

نماینده NNAPI بخشی از مفسر Android TensorFlow Lite است که نسخه 1.14.0 یا بالاتر منتشر شده است. با افزودن موارد زیر به فایل gradle ماژول خود می توانید آن را به پروژه خود وارد کنید:

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

راه اندازی نماینده NNAPI

قبل از اینکه مترجم TensorFlow Lite را مقداردهی کنید، کدی را برای مقداردهی اولیه نماینده NNAPI اضافه کنید.

کاتلین

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

...

جاوا

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

...

بهترین شیوه ها

قبل از استقرار عملکرد را تست کنید

عملکرد زمان اجرا به دلیل معماری مدل، اندازه، عملیات، در دسترس بودن سخت افزار و استفاده از سخت افزار زمان اجرا می تواند به طور قابل توجهی متفاوت باشد. به عنوان مثال، اگر یک برنامه به شدت از GPU برای رندر استفاده کند، شتاب NNAPI ممکن است به دلیل اختلاف منابع، عملکرد را بهبود نبخشد. توصیه می‌کنیم برای اندازه‌گیری زمان استنتاج، یک تست عملکرد ساده را با استفاده از دیباگ‌گر اجرا کنید. قبل از فعال کردن NNAPI در تولید، آزمایش را روی چندین تلفن با چیپست‌های مختلف (سازنده یا مدل‌های یک سازنده) که نماینده پایگاه کاربر شما هستند، انجام دهید.

برای توسعه دهندگان پیشرفته، TensorFlow Lite همچنین یک ابزار معیار مدل برای اندروید ارائه می دهد.

یک لیست حذف دستگاه ایجاد کنید

در تولید، ممکن است مواردی وجود داشته باشد که NNAPI مطابق انتظار عمل نکند. ما به توسعه‌دهندگان توصیه می‌کنیم فهرستی از دستگاه‌هایی که نباید از شتاب NNAPI در ترکیب با مدل‌های خاص استفاده کنند، داشته باشند. شما می توانید این لیست را بر اساس مقدار "ro.board.platform" ایجاد کنید، که می توانید با استفاده از قطعه کد زیر آن را بازیابی کنید:

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

برای توسعه دهندگان پیشرفته، این لیست را از طریق یک سیستم پیکربندی از راه دور حفظ کنید. تیم TensorFlow فعالانه در حال کار بر روی راه‌هایی برای ساده‌سازی و خودکارسازی کشف و به‌کارگیری پیکربندی بهینه NNAPI است.

کوانتیزاسیون

کوانتیزه کردن اندازه مدل را با استفاده از اعداد صحیح 8 بیتی یا شناورهای 16 بیتی به جای شناورهای 32 بیتی برای محاسبات کاهش می دهد. اندازه مدل های عدد صحیح 8 بیتی یک چهارم نسخه های شناور 32 بیتی است. شناورهای 16 بیتی نصف اندازه هستند. کوانتیزاسیون می تواند عملکرد را به طور قابل توجهی بهبود بخشد، اگرچه این فرآیند می تواند برخی از دقت مدل را کاهش دهد.

انواع مختلفی از تکنیک‌های کوانتیزه‌سازی پس از آموزش وجود دارد، اما برای حداکثر پشتیبانی و شتاب در سخت‌افزار فعلی، کوانتیزه‌سازی کامل عدد صحیح را توصیه می‌کنیم. این رویکرد هم وزن و هم عملیات را به اعداد صحیح تبدیل می کند. این فرآیند کمی سازی به یک مجموعه داده نماینده برای کار نیاز دارد.

از مدل ها و عملیات های پشتیبانی شده استفاده کنید

اگر نماینده NNAPI از برخی از ترکیبات عملیاتی یا پارامترها در یک مدل پشتیبانی نکند، فریم ورک تنها بخش‌های پشتیبانی شده از نمودار را روی شتاب‌دهنده اجرا می‌کند. بقیه روی CPU اجرا می شود که منجر به اجرای تقسیم می شود. به دلیل هزینه بالای همگام سازی CPU/شتاب دهنده، این ممکن است منجر به عملکرد کندتر نسبت به اجرای کل شبکه روی CPU به تنهایی شود.

NNAPI زمانی بهترین عملکرد را دارد که مدل‌ها فقط از عملیات پشتیبانی شده استفاده می‌کنند. مدل های زیر با NNAPI سازگار هستند:

هنگامی که مدل دارای خروجی هایی با اندازه پویا باشد، شتاب NNAPI نیز پشتیبانی نمی شود. در این صورت هشداری مانند:

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

اجرای NNAPI CPU را فعال کنید

نموداری که نمی تواند به طور کامل توسط یک شتاب دهنده پردازش شود، می تواند به اجرای CPU NNAPI برگردد. با این حال، از آنجایی که معمولاً عملکرد کمتری نسبت به مفسر TensorFlow دارد، این گزینه به طور پیش‌فرض در نمایندگی NNAPI برای Android 10 (سطح API 29) یا بالاتر غیرفعال است. برای لغو این رفتار، setUseNnapiCpu در شی NnApiDelegate.Options روی true تنظیم کنید.