يمكنك استخدام أدوات تعلُّم الآلة لإجراء استنتاج على الجهاز باستخدام TensorFlow Lite.
وتتطلّب واجهة برمجة التطبيقات هذه المستوى 16 من حزمة تطوير البرامج (SDK) لنظام التشغيل Android (Jelly Bean) أو إصدارًا أحدث.
قبل البدء
- إذا لم تكن قد فعلت ذلك بالفعل، إضافة Firebase إلى مشروع Android
- إضافة الموارد التابعة لمكتبات 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' }
- حوِّل نموذج TensorFlow الذي تريد استخدامه إلى تنسيق TensorFlow Lite. عرض TOCO: TensorFlow Lite Adapter.
استضافة النموذج أو تجميعه
قبل أن تتمكّن من استخدام نموذج TensorFlow Lite للاستنتاج في تطبيقك، عليك إتاحة النموذج لأداة تعلّم الآلة. يمكن لـ ML Kit استخدام TensorFlow Lite نماذج مستضافة عن بُعد باستخدام Firebase، أو مرفقة مع البرنامج الثنائي للتطبيق، أو كليهما.
من خلال استضافة نموذج على Firebase، يمكنك تعديل النموذج بدون إطلاق إصدار جديد من التطبيق، ويمكنك استخدام Remote Config وA/B Testing لإجراء ما يلي: تعرض نماذج مختلفة ديناميكيًا لمجموعات مختلفة من المستخدمين.
إذا اخترت توفير النموذج من خلال استضافته باستخدام Firebase فقط، وليس حزمة التطبيق مع التطبيق، يمكنك تقليل حجم التنزيل الأولي لتطبيقك. ومع ذلك، يُرجى الأخذ في الاعتبار أنه إذا لم يتم إدراج النموذج مع تطبيقك، لن تتوفّر الوظائف المتعلّقة بالطراز إلى أن ينزِّل تطبيقك لأول مرة.
يمكنك ضمان ميزات تعلُّم الآلة في تطبيقك من خلال دمج نموذجك مع تطبيقك. لا يزال يعمل في حال عدم توفُّر النموذج المستضاف على Firebase.
نماذج المضيف على Firebase
لاستضافة نموذج TensorFlow Lite على Firebase، اتّبِع الخطوات التالية:
- في قسم حزمة تعلّم الآلة في وحدة تحكّم Firebase، انقر على علامة التبويب مخصّص.
- انقر على إضافة نموذج مخصّص (أو إضافة نموذج آخر).
- حدِّد اسمًا سيتم استخدامه لتحديد نموذجك في Firebase.
ثم تحميل ملف نموذج TensorFlow Lite (الذي ينتهي عادةً بـ
.tflite
أو.lite
). - في بيان تطبيقك، عليك الإشارة إلى أنّه يجب الحصول على إذن INTERNET:
<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.
}
}
سيتم تضمين ملف النموذج في حزمة التطبيق وسيكون متاحًا في حزمة تعلّم الآلة. كمادة عرض أولية
تحميل النموذج
لاستخدام نموذج TensorFlow Lite في تطبيقك، عليك أولاً ضبط حزمة تعلّم الآلة باستخدام المواقع التي يتوفر فيها نموذجك: استخدام 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
. يجب
اضبط حزمة تعلّم الآلة باستخدام عدد وأبعاد ("شكل") الصفائف
استخدامات النموذج.
إذا كنت لا تعرف شكل ونوع البيانات لمدخلات النموذج ومخرجاته، يمكنك استخدام مترجم 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
.
على سبيل المثال، قد يتخذ نموذج تصنيف الصور ذات النقطة العائمة كمدخل
مصفوفة Nx224x224x3 مكونة من float
قيمة، تمثل مجموعة من
N صور ثلاثية القنوات (RGB) مقاس 224×224، ويتم إنتاج قائمة بالإخراج
1, 000 قيمة 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()
إجراء استنتاج على بيانات الإدخال
وأخيرًا، للاستنتاج باستخدام النموذج والحصول على البيانات المدخلة وتنفيذ أي عمليات تحويل في البيانات ضرورية للحصول على صفيف إدخال الشكل الصحيح لنموذجك.فعلى سبيل المثال، إذا كان لديك نموذج تصنيف صور به شكل إدخال
[1 224 224 3] قيم النقطة العائمة، يمكنك إنشاء صفيف إدخال من
كائن Bitmap
كما هو موضَّح في المثال التالي:
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 القياسي القياسي في التخزين المحلي.
ومن الناحية النظرية، يعني هذا أنه بإمكان أي شخص نسخ نموذجك. ومع ذلك، عمليًا، تكون معظم النماذج خاصة بالتطبيقات ومشوَّشة بواسطة تتشابه المخاطر مع تلك الخاصة بالمنافسين الذين يقومون بتفكيكها إعادة استخدام التعليمات البرمجية. ومع ذلك، يجب أن تكون على دراية بهذه الخطر قبل استخدام نموذج مخصص في تطبيقك.
في المستوى 21 من واجهة برمجة تطبيقات Android (Lollipop) والإصدارات الأحدث، يتم تنزيل النموذج إلى الدليل استبعاده من ميزة الاحتفاظ بنسخة احتياطية تلقائيًا.
في المستوى 20 من واجهة برمجة تطبيقات Android والإصدارات الأقدم، يتم تنزيل النموذج إلى دليل.
باسم com.google.firebase.ml.custom.models
في خصوصية التطبيق
وحدة التخزين الداخلية. في حال تفعيل الاحتفاظ بنسخة احتياطية من الملفات باستخدام BackupAgent
،
يمكنك اختيار استبعاد هذا الدليل.