إذا كان تطبيقك يستخدم نماذج مخصّصة من TensorFlow Lite، يمكنك استخدام Firebase ML لنشر نماذجك. من خلال نشر النماذج باستخدام Firebase، يمكنك تقليل حجم التنزيل الأولي لتطبيقك وتحديث نماذج تعلُّم الآلة في تطبيقك بدون إصدار نسخة جديدة من تطبيقك. وباستخدام Remote Config وA/B Testing، يمكنك عرض نماذج مختلفة بشكل ديناميكي لمجموعات مختلفة من المستخدمين.
تم إيقافنماذج TensorFlow Lite
نماذج TensorFlow Lite هي نماذج تعلُّم آلي تم تحسينها لتنفيذها على الأجهزة الجوّالة. للحصول على نموذج TensorFlow Lite، اتّبِع الخطوات التالية:
- استخدِم نموذجًا تم إنشاؤه مسبقًا، مثل أحد نماذج TensorFlow Lite الرسمية.
- تحويل نموذج TensorFlow أو نموذج Keras أو دالة ملموسة إلى TensorFlow Lite
قبل البدء
- إذا لم يسبق لك إجراء ذلك، أضِف Firebase إلى مشروع Android.
-
في ملف 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:34.0.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متعدّدة في تطبيقك، ننصحك بشدة باستخدام 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.0")
// Also add the dependency for the TensorFlow Lite library and specify its version implementation("org.tensorflow:tensorflow-lite:2.3.0") } - في بيان تطبيقك، أدرِج أنّ الإذن INTERNET مطلوب:
<uses-permission android:name="android.permission.INTERNET" />
1. نشر النموذج
يمكنك نشر نماذج TensorFlow المخصّصة باستخدام وحدة تحكّم Firebase أو حِزم تطوير البرامج (SDK) الخاصة بلغة Python وNode.js من Firebase Admin. يُرجى الاطّلاع على نشر النماذج المخصّصة وإدارتها.
بعد إضافة نموذج مخصّص إلى مشروعك على Firebase، يمكنك الرجوع إلى النموذج في تطبيقاتك باستخدام الاسم الذي حدّدته. في أي وقت، يمكنك نشر نموذج TensorFlow Lite جديد وتنزيله على أجهزة المستخدمين من خلال استدعاء getModel()
(راجِع ما يلي).
2- تنزيل النموذج على الجهاز وتهيئة مترجم TensorFlow Lite
لاستخدام نموذج TensorFlow Lite في تطبيقك، عليك أولاً استخدام حزمة تطوير البرامج (SDK) Firebase ML لتنزيل أحدث إصدار من النموذج على الجهاز. بعد ذلك، أنشئ مثيلاً لمترجم 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 والإصدارات الأقدم، يتم تنزيل النموذج إلى دليل باسم com.google.firebase.ml.custom.models
في مساحة التخزين الداخلية الخاصة بالتطبيق. إذا فعّلت ميزة الاحتفاظ بنسخة احتياطية من الملفات باستخدام BackupAgent
،
يمكنك اختيار استبعاد هذا الدليل.