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

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

نماذج TensorFlow Lite

نماذج TensorFlow Lite هي نماذج ML تم تحسينها للتشغيل على الأجهزة المحمولة. للحصول على نموذج TensorFlow Lite:

قبل ان تبدأ

  1. أضف Firebase إلى مشروع Android ، إذا لم تكن قد قمت بذلك بالفعل.
  2. باستخدام Firebase Android BoM ، أعلن عن تبعية مكتبة Android لتنزيل نموذج Firebase ML في ملف Gradle (على مستوى التطبيق) (عادةً app/build.gradle ).

    أيضًا ، كجزء من إعداد أداة تنزيل نموذج Firebase ML ، تحتاج إلى إضافة TensorFlow Lite SDK إلى تطبيقك.

    Java

    dependencies {
        // Import the BoM for the Firebase platform
        implementation platform('com.google.firebase:firebase-bom:30.3.1')
    
        // Declare 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 declare 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 {
        // Declare 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:24.0.4'
    // Also declare the dependency for the TensorFlow Lite library and specify its version implementation 'org.tensorflow:tensorflow-lite:2.3.0'
    }

    Kotlin+KTX

    dependencies {
        // Import the BoM for the Firebase platform
        implementation platform('com.google.firebase:firebase-bom:30.3.1')
    
        // Declare 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-ktx'
    // Also declare 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 {
        // Declare 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-ktx:24.0.4'
    // Also declare 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" />

1. نشر النموذج الخاص بك

انشر نماذج TensorFlow المخصصة باستخدام إما وحدة تحكم Firebase أو Firebase Admin Python و Node.js SDK. راجع نشر النماذج المخصصة وإدارتها .

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

2. قم بتنزيل النموذج على الجهاز وتهيئة مترجم TensorFlow Lite

لاستخدام طراز TensorFlow Lite في تطبيقك ، استخدم أولاً Firebase ML SDK لتنزيل أحدث إصدار من النموذج على الجهاز. ثم قم بإنشاء مثيل لمترجم TensorFlow Lite مع النموذج.

لبدء تنزيل النموذج ، اتصل getModel() تنزيل النموذج ، مع تحديد الاسم الذي قمت بتعيينه للنموذج عند تحميله ، وما إذا كنت تريد دائمًا تنزيل أحدث طراز ، والشروط التي تريد بموجبها السماح بالتنزيل.

يمكنك الاختيار من بين ثلاثة سلوكيات للتنزيل:

نوع التنزيل وصف
LOCAL_MODEL احصل على النموذج المحلي من الجهاز. إذا لم يتوفر نموذج محلي ، فسيكون هذا التصرف مثل LATEST_MODEL . استخدم نوع التنزيل هذا إذا لم تكن مهتمًا بالتحقق من تحديثات الطراز. على سبيل المثال ، أنت تستخدم Remote Config لاسترداد أسماء النماذج ودائمًا ما تقوم بتحميل النماذج بأسماء جديدة (مستحسن).
LOCAL_MODEL_UPDATE_IN_BACKGROUND احصل على النموذج المحلي من الجهاز وابدأ في تحديث النموذج في الخلفية. إذا لم يتوفر نموذج محلي ، فسيكون هذا التصرف مثل LATEST_MODEL .
أحدث نموذج احصل على أحدث طراز. إذا كان النموذج المحلي هو أحدث إصدار ، يتم إرجاع النموذج المحلي. خلاف ذلك ، قم بتنزيل أحدث طراز. سيتم حظر هذا السلوك حتى يتم تنزيل أحدث إصدار (غير مستحسن). استخدم هذا السلوك فقط في الحالات التي تحتاج فيها صراحة إلى أحدث إصدار.

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

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

Kotlin+KTX

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

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

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

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

يأخذ مترجم نموذج 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'>

قم بتشغيل المترجم

بعد تحديد تنسيق إدخال وإخراج النموذج الخاص بك ، احصل على بيانات الإدخال الخاصة بك وقم بإجراء أي تحويلات على البيانات الضرورية للحصول على إدخال بالشكل الصحيح للنموذج الخاص بك.

على سبيل المثال ، إذا كان لديك نموذج تصنيف صورة مع شكل إدخال قيم الفاصلة العائمة [1224224 [1 224 224 3] ، فيمكنك إنشاء ByteBuffer إدخال من كائن Bitmap كما هو موضح في المثال التالي:

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

Kotlin+KTX

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

بعد ذلك ، قم بتخصيص ByteBuffer كبيرًا بما يكفي لاحتواء مخرجات النموذج وتمرير مخزن الإدخال المؤقت ومخزن الإخراج إلى طريقة run() لمترجم TensorFlow Lite. على سبيل المثال ، لشكل إخراج قيمته [1 1000] نقطة عائمة:

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+KTX

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

تعتمد كيفية استخدام الإخراج على النموذج الذي تستخدمه.

على سبيل المثال ، إذا كنت تقوم بالتصنيف ، كخطوة تالية ، يمكنك تعيين فهارس النتيجة إلى التسميات التي تمثلها:

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

Kotlin+KTX

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

الملحق: نموذج الأمن

بغض النظر عن كيفية إتاحة نماذج TensorFlow Lite الخاصة بك لـ Firebase ML ، يقوم Firebase ML بتخزينها بتنسيق protobuf القياسي المتسلسل في التخزين المحلي.

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

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

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