از یک مدل سفارشی TensorFlow Lite در اندروید استفاده کنید

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

مدل‌های TensorFlow Lite

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

قبل از اینکه شروع کنی

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

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

    dependencies {
        // Import the BoM for the Firebase platform
        implementation(platform("com.google.firebase:firebase-bom:34.5.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 استفاده خواهد کرد.

    (جایگزین) اضافه کردن وابستگی‌های کتابخانه 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.0.1")
    // Also add the dependency for the TensorFlow Lite library and specify its version implementation("org.tensorflow:tensorflow-lite:2.3.0")
    }
  3. در فایل مانیفست برنامه خود، اعلام کنید که مجوز اینترنت مورد نیاز است:
    <uses-permission android:name="android.permission.INTERNET" />

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

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

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

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

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

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

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

نوع دانلود توضیحات
مدل محلی مدل محلی را از دستگاه دریافت کنید. اگر هیچ مدل محلی در دسترس نباشد، این تابع مانند LATEST_MODEL عمل می‌کند. اگر علاقه‌ای به بررسی به‌روزرسانی‌های مدل ندارید، از این نوع دانلود استفاده کنید. به عنوان مثال، شما از Remote Config برای بازیابی نام مدل‌ها استفاده می‌کنید و همیشه مدل‌ها را با نام‌های جدید آپلود می‌کنید (توصیه می‌شود).
به‌روزرسانی مدل محلی در پس‌زمینه مدل محلی را از دستگاه دریافت کن و در پس‌زمینه شروع به به‌روزرسانی مدل کن. اگر هیچ مدل محلی در دسترس نباشد، این تابع مانند 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 در حافظه محلی ذخیره می‌کند.

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

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

در اندروید API سطح ۲۰ و بالاتر، مدل در دایرکتوری به نام com.google.firebase.ml.custom.models در حافظه داخلی app-private دانلود می‌شود. اگر پشتیبان‌گیری از فایل را با استفاده از BackupAgent فعال کرده باشید، می‌توانید این دایرکتوری را مستثنی کنید.