Firebase 将于 5 月 10 日重返 Google I/O 大会!立即报名

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

يمكنك استخدام ML Kit لإجراء الاستدلال على الجهاز باستخدام نموذج TensorFlow Lite .

تتطلب واجهة برمجة التطبيقات هذه Android SDK المستوى 16 (Jelly Bean) أو أحدث.

قبل ان تبدأ

  1. أضف Firebase إلى مشروع Android ، إذا لم تكن قد قمت بذلك بالفعل.
  2. أضف تبعيات مكتبات ML Kit Android إلى ملف Gradle (على مستوى التطبيق) للوحدة النمطية (عادةً app/build.gradle ):
    apply plugin: 'com.android.application'
    apply plugin: 'com.google.gms.google-services'
    
    dependencies {
      // ...
    
      implementation 'com.google.firebase:firebase-ml-model-interpreter:22.0.3'
    }
    
  3. قم بتحويل نموذج TensorFlow الذي تريد استخدامه إلى تنسيق TensorFlow Lite. راجع TOCO: محول تحسين TensorFlow Lite .

قم باستضافة نموذجك أو تجميعه

قبل أن تتمكن من استخدام نموذج TensorFlow Lite للاستدلال في تطبيقك ، يجب أن تجعل النموذج متاحًا لـ ML Kit. يمكن لـ ML Kit استخدام نماذج TensorFlow Lite المستضافة عن بُعد باستخدام Firebase أو المجمعة مع البرنامج الثنائي للتطبيق أو كليهما.

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

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

من خلال تجميع نموذجك مع تطبيقك ، يمكنك التأكد من استمرار عمل ميزات ML في تطبيقك عندما لا يكون النموذج المستضاف في Firebase متاحًا.

النماذج المضيفة على Firebase

لاستضافة نموذج TensorFlow Lite الخاص بك على Firebase:

  1. في قسم ML Kit بوحدة تحكم Firebase ، انقر على علامة التبويب " مخصص ".
  2. انقر فوق إضافة نموذج مخصص (أو إضافة نموذج آخر ).
  3. حدد اسمًا سيتم استخدامه لتعريف نموذجك في مشروع Firebase الخاص بك ، ثم قم بتحميل ملف نموذج TensorFlow Lite (عادةً ما ينتهي .tflite أو .lite ).
  4. في بيان التطبيق الخاص بك ، أعلن أن إذن الإنترنت مطلوب:
    <uses-permission android:name="android.permission.INTERNET" />
    

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

تجميع النماذج مع التطبيق

لتجميع نموذج TensorFlow Lite الخاص بك مع تطبيقك ، انسخ ملف النموذج (ينتهي عادةً .tflite أو .lite ) إلى assets/ مجلد التطبيق الخاص بك. (قد تحتاج إلى إنشاء المجلد أولاً بالنقر بزر الماوس الأيمن فوق app/ المجلد ، ثم النقر فوق جديد> مجلد> مجلد الأصول .)

بعد ذلك ، أضف ما يلي إلى ملف build.gradle الخاص بتطبيقك للتأكد من أن Gradle لا يضغط النماذج عند إنشاء التطبيق:

android {

    // ...

    aaptOptions {
        noCompress "tflite"  // Your model's file extension: "tflite", "lite", etc.
    }
}

سيتم تضمين ملف النموذج في حزمة التطبيق وسيكون متاحًا لـ ML Kit كأصل خام.

قم بتحميل النموذج

لاستخدام نموذج TensorFlow Lite في تطبيقك ، قم أولاً بتهيئة ML Kit مع المواقع التي يتوفر فيها نموذجك: عن بُعد باستخدام Firebase أو في التخزين المحلي أو كليهما. إذا حددت نموذجًا محليًا وبعيدًا ، فيمكنك استخدام النموذج البعيد إذا كان متاحًا ، والعودة إلى النموذج المخزن محليًا إذا لم يكن النموذج البعيد متاحًا.

هيئ نموذجًا مستضافًا على Firebase

إذا استضفت نموذجك باستخدام Firebase ، فأنشئ كائن FirebaseCustomRemoteModel ، مع تحديد الاسم الذي عينته للنموذج عند تحميله:

Java

FirebaseCustomRemoteModel remoteModel =
        new FirebaseCustomRemoteModel.Builder("your_model").build();

Kotlin+KTX

val remoteModel = FirebaseCustomRemoteModel.Builder("your_model").build()

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

Java

FirebaseModelDownloadConditions conditions = new FirebaseModelDownloadConditions.Builder()
        .requireWifi()
        .build();
FirebaseModelManager.getInstance().download(remoteModel, conditions)
        .addOnCompleteListener(new OnCompleteListener<Void>() {
            @Override
            public void onComplete(@NonNull Task<Void> task) {
                // Success.
            }
        });

Kotlin+KTX

val conditions = FirebaseModelDownloadConditions.Builder()
    .requireWifi()
    .build()
FirebaseModelManager.getInstance().download(remoteModel, conditions)
    .addOnCompleteListener {
        // Success.
    }

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

تكوين نموذج محلي

إذا جمعت النموذج مع تطبيقك ، فأنشئ كائن FirebaseCustomLocalModel ، مع تحديد اسم ملف نموذج TensorFlow Lite:

Java

FirebaseCustomLocalModel localModel = new FirebaseCustomLocalModel.Builder()
        .setAssetFilePath("your_model.tflite")
        .build();

Kotlin+KTX

val localModel = FirebaseCustomLocalModel.Builder()
    .setAssetFilePath("your_model.tflite")
    .build()

قم بإنشاء مترجم من النموذج الخاص بك

بعد تكوين مصادر النموذج ، قم بإنشاء كائن FirebaseModelInterpreter من أحدها.

إذا كان لديك نموذج مجمع محليًا فقط ، فما عليك سوى إنشاء مترجم فوري من كائن FirebaseCustomLocalModel :

Java

FirebaseModelInterpreter interpreter;
try {
    FirebaseModelInterpreterOptions options =
            new FirebaseModelInterpreterOptions.Builder(localModel).build();
    interpreter = FirebaseModelInterpreter.getInstance(options);
} catch (FirebaseMLException e) {
    // ...
}

Kotlin+KTX

val options = FirebaseModelInterpreterOptions.Builder(localModel).build()
val interpreter = FirebaseModelInterpreter.getInstance(options)

إذا كان لديك نموذج مستضاف عن بُعد ، فسيتعين عليك التحقق من تنزيله قبل تشغيله. يمكنك التحقق من حالة مهمة تنزيل النموذج باستخدام طريقة isModelDownloaded() الخاصة بمدير النموذج.

على الرغم من أنه يتعين عليك تأكيد ذلك فقط قبل تشغيل المترجم الفوري ، إذا كان لديك نموذج مستضاف عن بُعد ونموذج مجمع محليًا ، فقد يكون من المنطقي إجراء هذا الفحص عند إنشاء مثيل مترجم النموذج: قم بإنشاء مترجم فوري من النموذج البعيد إذا تم تنزيله ، ومن النموذج المحلي بخلاف ذلك.

Java

FirebaseModelManager.getInstance().isModelDownloaded(remoteModel)
        .addOnSuccessListener(new OnSuccessListener<Boolean>() {
            @Override
            public void onSuccess(Boolean isDownloaded) {
                FirebaseModelInterpreterOptions options;
                if (isDownloaded) {
                    options = new FirebaseModelInterpreterOptions.Builder(remoteModel).build();
                } else {
                    options = new FirebaseModelInterpreterOptions.Builder(localModel).build();
                }
                FirebaseModelInterpreter interpreter = FirebaseModelInterpreter.getInstance(options);
                // ...
            }
        });

Kotlin+KTX

FirebaseModelManager.getInstance().isModelDownloaded(remoteModel)
    .addOnSuccessListener { isDownloaded -> 
    val options =
        if (isDownloaded) {
            FirebaseModelInterpreterOptions.Builder(remoteModel).build()
        } else {
            FirebaseModelInterpreterOptions.Builder(localModel).build()
        }
    val interpreter = FirebaseModelInterpreter.getInstance(options)
}

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

Java

FirebaseModelManager.getInstance().download(remoteModel, conditions)
        .addOnSuccessListener(new OnSuccessListener<Void>() {
            @Override
            public void onSuccess(Void v) {
              // Download complete. Depending on your app, you could enable
              // the ML feature, or switch from the local model to the remote
              // model, etc.
            }
        });

Kotlin+KTX

FirebaseModelManager.getInstance().download(remoteModel, conditions)
    .addOnCompleteListener {
        // Download complete. Depending on your app, you could enable the ML
        // feature, or switch from the local model to the remote model, etc.
    }

حدد مدخلات ومخرجات النموذج

بعد ذلك ، قم بتكوين تنسيقات المدخلات والمخرجات لمترجم النموذج.

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

إذا كنت لا تعرف شكل ونوع البيانات لإدخال وإخراج النموذج الخاص بك ، يمكنك استخدام مترجم TensorFlow Lite Python لفحص النموذج الخاص بك. علي سبيل المثال:

import tensorflow as tf

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

# Print input shape and type
print(interpreter.get_input_details()[0]['shape'])  # Example: [1 224 224 3]
print(interpreter.get_input_details()[0]['dtype'])  # Example: <class 'numpy.float32'>

# Print output shape and type
print(interpreter.get_output_details()[0]['shape'])  # Example: [1 1000]
print(interpreter.get_output_details()[0]['dtype'])  # Example: <class 'numpy.float32'>

بعد تحديد تنسيق إدخال وإخراج النموذج ، يمكنك تكوين مترجم نموذج التطبيق الخاص بك عن طريق إنشاء كائن FirebaseModelInputOutputOptions .

على سبيل المثال ، قد يأخذ نموذج تصنيف صورة النقطة العائمة كمدخلات مصفوفة N x224x224x3 من القيم float ، والتي تمثل دفعة من الصور ثلاثية القنوات (RGB) N 224x224 ، وينتج كإخراج قائمة من 1000 قيمة float ، كل منها يمثل احتمالية أن تكون الصورة عضوًا في إحدى الفئات 1000 التي يتوقعها النموذج.

بالنسبة لمثل هذا النموذج ، يمكنك تكوين مدخلات ومخرجات مترجم النموذج كما هو موضح أدناه:

Java

FirebaseModelInputOutputOptions inputOutputOptions =
        new FirebaseModelInputOutputOptions.Builder()
                .setInputFormat(0, FirebaseModelDataType.FLOAT32, new int[]{1, 224, 224, 3})
                .setOutputFormat(0, FirebaseModelDataType.FLOAT32, new int[]{1, 5})
                .build();

Kotlin+KTX

val inputOutputOptions = FirebaseModelInputOutputOptions.Builder()
        .setInputFormat(0, FirebaseModelDataType.FLOAT32, intArrayOf(1, 224, 224, 3))
        .setOutputFormat(0, FirebaseModelDataType.FLOAT32, intArrayOf(1, 5))
        .build()

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

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

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

Java

Bitmap bitmap = getYourInputImage();
bitmap = Bitmap.createScaledBitmap(bitmap, 224, 224, true);

int batchNum = 0;
float[][][][] input = new float[1][224][224][3];
for (int x = 0; x < 224; x++) {
    for (int y = 0; y < 224; y++) {
        int pixel = bitmap.getPixel(x, y);
        // Normalize channel values to [-1.0, 1.0]. This requirement varies by
        // model. For example, some models might require values to be normalized
        // to the range [0.0, 1.0] instead.
        input[batchNum][x][y][0] = (Color.red(pixel) - 127) / 128.0f;
        input[batchNum][x][y][1] = (Color.green(pixel) - 127) / 128.0f;
        input[batchNum][x][y][2] = (Color.blue(pixel) - 127) / 128.0f;
    }
}

Kotlin+KTX

val bitmap = Bitmap.createScaledBitmap(yourInputImage, 224, 224, true)

val batchNum = 0
val input = Array(1) { Array(224) { Array(224) { FloatArray(3) } } }
for (x in 0..223) {
    for (y in 0..223) {
        val pixel = bitmap.getPixel(x, y)
        // Normalize channel values to [-1.0, 1.0]. This requirement varies by
        // model. For example, some models might require values to be normalized
        // to the range [0.0, 1.0] instead.
        input[batchNum][x][y][0] = (Color.red(pixel) - 127) / 255.0f
        input[batchNum][x][y][1] = (Color.green(pixel) - 127) / 255.0f
        input[batchNum][x][y][2] = (Color.blue(pixel) - 127) / 255.0f
    }
}

بعد ذلك ، قم بإنشاء كائن FirebaseModelInputs ببيانات الإدخال الخاصة بك ، وقم بتمريره ومواصفات إدخال وإخراج النموذج إلى أسلوب run مترجم النموذج :

Java

FirebaseModelInputs inputs = new FirebaseModelInputs.Builder()
        .add(input)  // add() as many input arrays as your model requires
        .build();
firebaseInterpreter.run(inputs, inputOutputOptions)
        .addOnSuccessListener(
                new OnSuccessListener<FirebaseModelOutputs>() {
                    @Override
                    public void onSuccess(FirebaseModelOutputs result) {
                        // ...
                    }
                })
        .addOnFailureListener(
                new OnFailureListener() {
                    @Override
                    public void onFailure(@NonNull Exception e) {
                        // Task failed with an exception
                        // ...
                    }
                });

Kotlin+KTX

val inputs = FirebaseModelInputs.Builder()
        .add(input) // add() as many input arrays as your model requires
        .build()
firebaseInterpreter.run(inputs, inputOutputOptions)
        .addOnSuccessListener { result ->
            // ...
        }
        .addOnFailureListener { e ->
            // Task failed with an exception
            // ...
        }

إذا نجحت المكالمة ، يمكنك الحصول على الإخراج عن طريق استدعاء طريقة getOutput() للكائن الذي يتم تمريره إلى مستمع النجاح. علي سبيل المثال:

Java

float[][] output = result.getOutput(0);
float[] probabilities = output[0];

Kotlin+KTX

val output = result.getOutput<Array<FloatArray>>(0)
val probabilities = output[0]

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

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

Java

BufferedReader reader = new BufferedReader(
        new InputStreamReader(getAssets().open("retrained_labels.txt")));
for (int i = 0; i < probabilities.length; i++) {
    String label = reader.readLine();
    Log.i("MLKit", String.format("%s: %1.4f", label, probabilities[i]));
}

Kotlin+KTX

val reader = BufferedReader(
        InputStreamReader(assets.open("retrained_labels.txt")))
for (i in probabilities.indices) {
    val label = reader.readLine()
    Log.i("MLKit", String.format("%s: %1.4f", label, probabilities[i]))
}

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

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

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

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

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