אם האפליקציה שלכם משתמשת במודלים מותאמים אישית של 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 כלי להורדת מודלים, צריך להוסיף את TensorFlow Lite SDK לאפליקציה.
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 כדי לנהל את גרסאות הספריות, וכך לוודא שכל הגרסאות תואמות.
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 או באמצעות Firebase Admin Python ו-Node.js SDKs. איך פורסים ומנהלים מודלים בהתאמה אישית
אחרי שמוסיפים מודל בהתאמה אישית לפרויקט Firebase, אפשר להפנות למודל באפליקציות באמצעות השם שצוין. בכל שלב אפשר לפרוס מודל חדש של TensorFlow Lite ולהוריד את המודל החדש למכשירים של המשתמשים באמצעות קריאה ל-getModel()
(ראו בהמשך).
2. הורדת המודל למכשיר ואתחול של מתורגמן TensorFlow Lite
כדי להשתמש במודל TensorFlow Lite באפליקציה, קודם צריך להשתמש ב-Firebase ML SDK כדי להוריד את הגרסה האחרונה של המודל למכשיר. לאחר מכן, יוצרים מופע של מתורגמן TensorFlow Lite עם המודל.כדי להתחיל את ההורדה של המודל, קוראים לשיטה getModel()
של כלי ההורדה של המודל, מציינים את השם שהקציתם למודל כשמעלים אותו, אם אתם רוצים להוריד תמיד את המודל העדכני ביותר ואת התנאים שבהם אתם רוצים לאפשר הורדה.
אפשר לבחור מבין שלוש אפשרויות להורדה:
סוג ההורדה | תיאור |
---|---|
LOCAL_MODEL | קבלת המודל המקומי מהמכשיר.
אם אין מודל מקומי זמין, ההתנהגות של LATEST_MODEL תהיה כמו של LATEST_MODEL . משתמשים בסוג ההורדה הזה אם לא רוצים לבדוק אם יש עדכונים למודל. לדוגמה, אתם משתמשים ב-Remote Config כדי לאחזר שמות של מודלים, ואתם תמיד מעלים מודלים עם שמות חדשים (מומלץ). |
LOCAL_MODEL_UPDATE_IN_BACKGROUND | מקבלים את המודל המקומי מהמכשיר ומתחילים לעדכן את המודל ברקע.
אם אין מודל מקומי זמין, ההתנהגות של LATEST_MODEL תהיה כמו של 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]
ערכים מסוג floating-point, תוכלו ליצור קלט 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 סטנדרטי בספרייה המקומית.
תיאורטית, המשמעות היא שכל אחד יכול להעתיק את המודל שלכם. עם זאת, בפועל, רוב המודלים הם ספציפיים לאפליקציה ומוסתרים על ידי אופטימיזציות, כך שהסיכון דומה לסיכון שמתחרים יפרקו את הקוד שלכם וישתמשו בו מחדש. עם זאת, חשוב להיות מודעים לסיכון הזה לפני שמשתמשים במודל מותאם אישית באפליקציה.
ב-Android API ברמה 21 (Lollipop) ואילך, המודל מורד לספרייה שלא נכללת בגיבוי האוטומטי.
ב-Android API ברמה 20 ומטה, המודל מוריד לספרייה בשם com.google.firebase.ml.custom.models
באחסון הפנימי הפרטי של האפליקציה. אם הפעלתם גיבוי של קבצים באמצעות BackupAgent
,
אולי תרצו להחריג את הספרייה הזו.