استفاده از مدل سفارشی TensorFlow Lite در Android

اگر برنامه‌تان از مدل‌های سفارشی TensorFlow Lite استفاده می‌کند، می‌توانید از Firebase ML برای استقرار مدل‌هایتان استفاده کنید. با استفاده از مدل‌ها با Firebase، می‌توانید اندازه بارگیری اولیه برنامه‌تان را کاهش دهید و مدل‌های یادگیری ماشین برنامه‌تان را بدون انتشار نسخه جدید برنامه به‌روز کنید. و با Remote Config و A/B Testing، می‌توانید به‌طور پویا مدل‌های مختلف را به مجموعه‌های مختلف کاربران ارائه دهید.

مدل‌های TensorFlow Lite

مدل‌های TensorFlow Lite مدل‌های ML هستند که برای اجرا در دستگاه‌های همراه بهینه‌سازی شده‌اند. برای دریافت مدل TensorFlow Lite:

قبل از شروع

  1. اگر قبلاً این کار را نکرده‌اید، ‫Firebase را به پروژه Android خود اضافه کنید.
  2. در فایل Gradle واحد (سطح برنامه) (معمولاً <project>/<app-module>/build.gradle.kts یا <project>/<app-module>/build.gradle)، وابستگی کتابخانه بارگیری‌کننده مدل Firebase ML برای Android را اضافه کنید. توصیه می‌کنیم از Firebase Android BoM برای کنترل نسخه‌بندی کتابخانه استفاده کنید.

    همچنین، به‌عنوان بخشی از راه‌اندازی بارگیری‌کننده مدل Firebase ML، باید «کیت توسعه نرم‌افزار TensorFlow Lite» را به برنامه‌تان اضافه کنید.

    dependencies {
        // Import the BoM for the Firebase platform
        implementation(platform("com.google.firebase:firebase-bom:34.19.0"))
    
        // Add the dependency for the Firebase ML model downloader library
        // When using the BoM, you don't specify versions in Firebase library dependencies
        implementation("com.google.firebase:firebase-ml-modeldownloader")
    // Also add the dependency for the TensorFlow Lite library and specify its version implementation("org.tensorflow:tensorflow-lite:2.3.0")
    }

    بااستفاده از Firebase Android BoM، برنامه شما همیشه از نسخه‌های سازگار کتابخانه‌های Firebase Android استفاده خواهد کرد.

    (جایگزین)  افزودن وابستگی‌های کتابخانه Firebase بدون استفاده از BoM

    اگر انتخاب کنید که از Firebase BoM استفاده نکنید، باید نسخه هر کتابخانه Firebase را در خط وابستگی آن مشخص کنید.

    توجه داشته باشید که اگر از چند کتابخانه Firebase در برنامه‌تان استفاده می‌کنید، قویاً توصیه می‌کنیم از BoM برای مدیریت نسخه‌های کتابخانه استفاده کنید، که تضمین می‌کند همه نسخه‌ها سازگار باشند.

    dependencies {
        // Add the dependency for the Firebase ML model downloader library
        // When NOT using the BoM, you must specify versions in Firebase library dependencies
        implementation("com.google.firebase:firebase-ml-modeldownloader:26.1.1")
    // Also add the dependency for the TensorFlow Lite library and specify its version implementation("org.tensorflow:tensorflow-lite:2.3.0")
    }
  3. در مانیفست برنامه‌تان، اعلام کنید که اجازه INTERNET الزامی است:
    <uses-permission android:name="android.permission.INTERNET" />

۱. مدلتان را مستقر کنید

مدل‌های TensorFlow سفارشی‌تان را بااستفاده از کنسول Firebase یا کیت‌های توسعه نرم‌افزار Firebase Admin Python و Node.js مستقر کنید. استقرار و مدیریت مدل‌های سفارشی را ببینید.

پس‌از افزودن مدل سفارشی به پروژه Firebase، می‌توانید بااستفاده از نامی که مشخص کرده‌اید به مدل در برنامه‌هایتان ارجاع دهید. هرزمان بخواهید می‌توانید مدل جدید TensorFlow Lite را پیاده‌سازی کنید و با فراخوانی getModel() (به زیر مراجعه کنید)، مدل جدید را در دستگاه‌های کاربران بارگیری کنید.

۲. مدل را در دستگاه بارگیری کنید و مفسر TensorFlow Lite را مقداردهی اولیه کنید

برای استفاده از مدل TensorFlow Lite در برنامه‌تان، ابتدا از Firebase ML کیت توسعه نرم‌افزار برای بارگیری جدیدترین نسخه مدل در دستگاه استفاده کنید. سپس، یک مترجم TensorFlow Lite با مدل نمونه‌سازی کنید.

برای شروع بارگیری مدل، روش getModel() بارگیری‌کننده مدل را فراخوانی کنید، نامی را که هنگام بارگذاری مدل به آن اختصاص دادید مشخص کنید، و مشخص کنید آیا می‌خواهید همیشه جدیدترین مدل بارگیری شود و تحت چه شرایطی می‌خواهید بارگیری مجاز باشد.

می‌توانید از بین سه رفتار بارگیری انتخاب کنید:

نوع بارگیری شرح
LOCAL_MODEL مدل محلی را از دستگاه دریافت کنید. اگر مدل محلی دردسترس نباشد، این مانند LATEST_MODEL عمل می‌کند. اگر علاقه‌ای به بررسی به‌روزرسانی‌های مدل ندارید، از این نوع بارگیری استفاده کنید. برای مثال، از «پیکربندی از دور» برای بازیابی نام‌های مدل استفاده می‌کنید و همیشه مدل‌ها را تحت نام‌های جدید بارگذاری می‌کنید (توصیه می‌شود).
LOCAL_MODEL_UPDATE_IN_BACKGROUND مدل محلی را از دستگاه دریافت کنید و به‌روزرسانی مدل را در پس‌زمینه شروع کنید. اگر مدل محلی دردسترس نباشد، این مانند LATEST_MODEL عمل می‌کند.
LATEST_MODEL جدیدترین مدل را دریافت کنید. اگر مدل محلی جدیدترین نسخه باشد، مدل محلی را برمی‌گرداند. درغیراین‌صورت، جدیدترین مدل را بارگیری کنید. این رفتار تا زمانی که جدیدترین نسخه بارگیری شود مسدود خواهد شد (توصیه نمی‌شود). فقط در مواردی که صریحاً به جدیدترین نسخه نیاز دارید از این رفتار استفاده کنید.

تا زمانی که تأیید کنید مدل بارگیری شده است، باید عملکرد مربوط به مدل را غیرفعال کنید—برای مثال، بخشی از رابط کاربری خود را خاکستری کنید یا پنهان کنید.

Kotlin

val conditions = CustomModelDownloadConditions.Builder()
        .requireWifi()  // Also possible: .requireCharging() and .requireDeviceIdle()
        .build()
FirebaseModelDownloader.getInstance()
        .getModel("your_model", DownloadType.LOCAL_MODEL_UPDATE_IN_BACKGROUND,
            conditions)
        .addOnSuccessListener { model: CustomModel? ->
            // Download complete. Depending on your app, you could enable the ML
            // feature, or switch from the local model to the remote model, etc.

            // The CustomModel object contains the local path of the model file,
            // which you can use to instantiate a TensorFlow Lite interpreter.
            val modelFile = model?.file
            if (modelFile != null) {
                interpreter = Interpreter(modelFile)
            }
        }

Java

CustomModelDownloadConditions conditions = new CustomModelDownloadConditions.Builder()
    .requireWifi()  // Also possible: .requireCharging() and .requireDeviceIdle()
    .build();
FirebaseModelDownloader.getInstance()
    .getModel("your_model", DownloadType.LOCAL_MODEL_UPDATE_IN_BACKGROUND, conditions)
    .addOnSuccessListener(new OnSuccessListener<CustomModel>() {
      @Override
      public void onSuccess(CustomModel model) {
        // Download complete. Depending on your app, you could enable the ML
        // feature, or switch from the local model to the remote model, etc.

        // The CustomModel object contains the local path of the model file,
        // which you can use to instantiate a TensorFlow Lite interpreter.
        File modelFile = model.getFile();
        if (modelFile != null) {
            interpreter = new Interpreter(modelFile);
        }
      }
    });

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

۳. انجام استنباط روی داده‌های ورودی

دریافت شکل‌های ورودی و خروجی مدل

تفسیرگر مدل TensorFlow Lite یک یا چند آرایه چندبعدی را به‌عنوان ورودی می‌گیرد و به‌عنوان خروجی تولید می‌کند. این آرایه‌ها حاوی مقادیر byte،‏ int،‏ long، یا float هستند. قبل‌از اینکه بتوانید داده‌ها را به مدل منتقل کنید یا از نتیجه آن استفاده کنید، باید تعداد و ابعاد («شکل») آرایه‌هایی را که مدل شما استفاده می‌کند بدانید.

اگر خودتان مدل را ساخته‌اید، یا اگر قالب ورودی و برونداد مدل مستند شده است، ممکن است ازقبل این اطلاعات را داشته باشید. اگر شکل و نوع داده ورودی و خروجی مدل خود را نمی‌دانید، می‌توانید از مفسر TensorFlow Lite برای بررسی مدل خود استفاده کنید. برای مثال:

پایتون

import tensorflow as tf

interpreter = tf.lite.Interpreter(model_path="your_model.tflite")
interpreter.allocate_tensors()

# Print input shape and type
inputs = interpreter.get_input_details()
print('{} input(s):'.format(len(inputs)))
for i in range(0, len(inputs)):
    print('{} {}'.format(inputs[i]['shape'], inputs[i]['dtype']))

# Print output shape and type
outputs = interpreter.get_output_details()
print('\n{} output(s):'.format(len(outputs)))
for i in range(0, len(outputs)):
    print('{} {}'.format(outputs[i]['shape'], outputs[i]['dtype']))

برونداد نمونه:

1 input(s):
[  1 224 224   3] <class 'numpy.float32'>

1 output(s):
[1 1000] <class 'numpy.float32'>

اجرای مترجم

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

برای مثال، اگر مدل طبقه‌بندی تصویری با شکل ورودی [1 224 224 3] مقدار ممیز شناور دارید، می‌توانید ورودی ByteBuffer را از شیء Bitmap همان‌طور که در مثال زیر نشان داده شده است تولید کنید:

Kotlin

val bitmap = Bitmap.createScaledBitmap(yourInputImage, 224, 224, true)
val input = ByteBuffer.allocateDirect(224*224*3*4).order(ByteOrder.nativeOrder())
for (y in 0 until 224) {
    for (x in 0 until 224) {
        val px = bitmap.getPixel(x, y)

        // Get channel values from the pixel value.
        val r = Color.red(px)
        val g = Color.green(px)
        val b = Color.blue(px)

        // Normalize channel values to [-1.0, 1.0]. This requirement depends on the model.
        // For example, some models might require values to be normalized to the range
        // [0.0, 1.0] instead.
        val rf = (r - 127) / 255f
        val gf = (g - 127) / 255f
        val bf = (b - 127) / 255f

        input.putFloat(rf)
        input.putFloat(gf)
        input.putFloat(bf)
    }
}

Java

Bitmap bitmap = Bitmap.createScaledBitmap(yourInputImage, 224, 224, true);
ByteBuffer input = ByteBuffer.allocateDirect(224 * 224 * 3 * 4).order(ByteOrder.nativeOrder());
for (int y = 0; y < 224; y++) {
    for (int x = 0; x < 224; x++) {
        int px = bitmap.getPixel(x, y);

        // Get channel values from the pixel value.
        int r = Color.red(px);
        int g = Color.green(px);
        int b = Color.blue(px);

        // Normalize channel values to [-1.0, 1.0]. This requirement depends
        // on the model. For example, some models might require values to be
        // normalized to the range [0.0, 1.0] instead.
        float rf = (r - 127) / 255.0f;
        float gf = (g - 127) / 255.0f;
        float bf = (b - 127) / 255.0f;

        input.putFloat(rf);
        input.putFloat(gf);
        input.putFloat(bf);
    }
}

سپس، ByteBuffer را که برای نگهداری برونداد مدل به‌اندازه کافی بزرگ باشد تخصیص دهید و بافر ورودی و بافر برونداد را به روش run() مفسر TensorFlow Lite منتقل کنید. برای مثال، برای شکل برونداد [1 1000] مقدار ممیز شناور:

Kotlin

val bufferSize = 1000 * java.lang.Float.SIZE / java.lang.Byte.SIZE
val modelOutput = ByteBuffer.allocateDirect(bufferSize).order(ByteOrder.nativeOrder())
interpreter?.run(input, modelOutput)

Java

int bufferSize = 1000 * java.lang.Float.SIZE / java.lang.Byte.SIZE;
ByteBuffer modelOutput = ByteBuffer.allocateDirect(bufferSize).order(ByteOrder.nativeOrder());
interpreter.run(input, modelOutput);

نحوه استفاده از برونداد به مدلی که استفاده می‌کنید بستگی دارد.

برای مثال، اگر طبقه‌بندی انجام می‌دهید، به‌عنوان گام بعدی می‌توانید شاخص‌های نتیجه را به برچسب‌هایی که نشان می‌دهند نگاشت کنید:

Kotlin

modelOutput.rewind()
val probabilities = modelOutput.asFloatBuffer()
try {
    val reader = BufferedReader(
            InputStreamReader(assets.open("custom_labels.txt")))
    for (i in probabilities.capacity()) {
        val label: String = reader.readLine()
        val probability = probabilities.get(i)
        println("$label: $probability")
    }
} catch (e: IOException) {
    // File not found?
}

Java

modelOutput.rewind();
FloatBuffer probabilities = modelOutput.asFloatBuffer();
try {
    BufferedReader reader = new BufferedReader(
            new InputStreamReader(getAssets().open("custom_labels.txt")));
    for (int i = 0; i < probabilities.capacity(); i++) {
        String label = reader.readLine();
        float probability = probabilities.get(i);
        Log.i(TAG, String.format("%s: %1.4f", label, probability));
    }
} catch (IOException e) {
    // File not found?
}

پیوست: امنیت مدل

صرف‌نظر از اینکه چگونه مدل‌های TensorFlow Lite خود را دردسترس Firebase ML قرار می‌دهید، Firebase ML آن‌ها را در قالب استاندارد protobuf سریال‌سازی‌شده در حافظه محلی ذخیره می‌کند.

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

در Android API سطح ۲۱ (Lollipop) و جدیدتر، مدل در دایرکتوری‌ای بارگیری می‌شود که از پشتیبان‌گیری خودکار مستثنا است.

در سطح میانای برنامه‌سازی کاربردی Android 20 و قدیمی‌تر، مدل در دایرکتوری‌ای به‌نام com.google.firebase.ml.custom.models در حافظه داخلی خصوصی برنامه بارگیری می‌شود. اگر پشتیبان‌گیری فایل را بااستفاده از BackupAgent فعال کرده‌اید، می‌توانید انتخاب کنید که این دایرکتوری را مستثنا کنید.