استخدام نموذج TensorFlow Lite المخصّص على Android

إذا كان تطبيقك يستخدم نماذج مخصّصة TensorFlow Lite، يمكنك استخدام Firebase ML لنشر نماذجك. من خلال نشر النماذج باستخدام Firebase، يمكنك تقليل حجم التنزيل الأولي لتطبيقك وتعديل نماذج الذكاء الاصطناعي في تطبيقك بدون إصدار إصدار جديد من تطبيقك. وباستخدام Remote Config وA/B Testing، يمكنك عرض نماذج مختلفة بشكل ديناميكي لمجموعات مختلفة من المستخدمين.

نماذج TensorFlow Lite

نماذج TensorFlow Lite هي نماذج تعلُّم آلي تم تحسينها للتشغيل على الأجهزة الجوّالة. للحصول على نموذج 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، عليك إضافة حزمة تطوير البرامج (SDK) لنظام TensorFlow Lite إلى تطبيقك.

    dependencies {
        // Import the BoM for the Firebase platform
        implementation(platform("com.google.firebase:firebase-bom:33.7.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:25.0.1")
    // Also add the dependency for the TensorFlow Lite library and specify its version implementation("org.tensorflow:tensorflow-lite:2.3.0")
    }
    هل تبحث عن وحدة مكتبة خاصة بلغة Kotlin؟ اعتبارًا من تشرين الأول (أكتوبر) 2023 (Firebase BoM 32.5.0)، يمكن لمطوّري Kotlin وJava الاعتماد على وحدة المكتبة الرئيسية (للاطّلاع على التفاصيل، راجِع الأسئلة الشائعة حول هذه المبادرة).
  3. في بيان تطبيقك، يجب الإفصاح عن أنّ إذن INTERNET مطلوب:
    <uses-permission android:name="android.permission.INTERNET" />

1. نشر النموذج

يمكنك نشر نماذج TensorFlow المخصّصة باستخدام وحدة تحكّم Firebase أو حِزم تطوير البرامج (SDK) Firebase Admin Python وNode.js. اطّلِع على مقالة نشر النماذج المخصّصة وإدارتها.

بعد إضافة نموذج مخصّص إلى مشروعك على Firebase، يمكنك الإشارة إلى النموذج في تطبيقاتك باستخدام الاسم الذي حدّدته. يمكنك في أي وقت نشر نموذج TensorFlow Lite جديد وتنزيل النموذج الجديد على أجهزة المستخدمين من خلال الاتصال getModel() (راجِع المعلومات أدناه).

2- تنزيل النموذج على الجهاز وبدء مترجم TensorFlow Lite

لاستخدام نموذج TensorFlow Lite في تطبيقك، استخدِم أولاً حزمة Firebase ML SDK لتنزيل أحدث إصدار من النموذج على الجهاز. بعد ذلك، يمكنك إنشاء مثيل لبرنامج ترجمة 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);
        }
      }
    });

تبدأ العديد من التطبيقات مهمة التنزيل في رمز الإعداد، ولكن يمكنك انجامه في أي وقت قبل الحاجة إلى استخدام النموذج.

3- إجراء استنتاجات على بيانات الإدخال

الحصول على أشكال الإدخال والإخراج في النموذج

يأخذ مفسِّر نماذج TensorFlow Lite صفيفًا واحدًا أو أكثر من الأبعاد المتعددة كمدخل وينتج عنه صفيفًا واحدًا أو أكثر من الأبعاد المتعددة. تحتوي هذه الصفائف على قيم byte أو int أو long أو float. قبل أن تتمكّن من تمرير البيانات إلى نموذج أو استخدام نتيجته، يجب معرفة عدد الصفائف التي يستخدمها النموذج وسمات هذه الصفائف ("الشكل").

إذا كنت قد أنشأت النموذج بنفسك، أو إذا كان تنسيق الإدخال والإخراج للنموذج موثّقًا، قد تكون لديك هذه المعلومات. إذا لم تكن تعرف شكل إدخالات ومخرجات النموذج ونوع البيانات، يمكنك استخدام مفسِّر TensorFlow Lite لفحص النموذج. على سبيل المثال:

Python

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 التسلسلي العادي في مساحة التخزين على الجهاز.

من الناحية النظرية، يعني ذلك أنّه يمكن لأي شخص نسخ النموذج الخاص بك. ومع ذلك، في الممارسة، تكون معظم النماذج خاصة بالتطبيق ومموَّهة للغاية بسبب التحسينات، ما يجعل الخطر مشابهًا لخطر قيام المنافسين بتفكيك رمزك البرمجي وإعادة استخدامه. ومع ذلك، يجب أن تكون على دراية بهذا الخطر قبل استخدام نموذج مخصّص في تطبيقك.

في الإصدار 21 من واجهة برمجة التطبيقات لنظام التشغيل Android (Lollipop) والإصدارات الأحدث، يتم تنزيل النموذج إلى ملف تعريف تم استبعاده من ميزة "الاحتفاظ بنسخة احتياطية تلقائية".

في الإصدار 20 من Android API والإصدارات الأقدم، يتم تنزيل النموذج إلى دليل باسم com.google.firebase.ml.custom.models في وحدة التخزين الداخلية الخاصة بالتطبيق. إذا فعّلت ميزة "الاحتفاظ بنسخة احتياطية" من الملفات باستخدام BackupAgent، يمكنك اختيار استبعاد هذا الدليل.