השתמש בדגם TensorFlow Lite מותאם אישית באנדרואיד

אם האפליקציה שלך משתמשת במודלים מותאמים אישית של TensorFlow Lite , תוכל להשתמש ב-Firebase ML כדי לפרוס את המודלים שלך. על ידי פריסת מודלים עם Firebase, אתה יכול להקטין את גודל ההורדה הראשונית של האפליקציה שלך ולעדכן את דגמי ה-ML של האפליקציה שלך מבלי לשחרר גרסה חדשה של האפליקציה שלך. בנוסף, עם תצורה מרחוק ובדיקת A/B, אתה יכול להגיש באופן דינמי דגמים שונים לקבוצות שונות של משתמשים.

דגמי TensorFlow Lite

דגמי TensorFlow Lite הם דגמי ML המותאמים להפעלה במכשירים ניידים. כדי להשיג דגם TensorFlow Lite:

לפני שאתה מתחיל

  1. אם עדיין לא עשית זאת, הוסף את Firebase לפרויקט Android שלך .
  2. בקובץ Gradle של המודול (ברמת האפליקציה) (בדרך כלל <project>/<app-module>/build.gradle.kts או <project>/<app-module>/build.gradle ), הוסף את התלות עבור Firebase ML ספריית הורדות הדגמים עבור אנדרואיד. אנו ממליצים להשתמש ב- Firebase Android BoM כדי לשלוט בגירסאות של הספרייה.

    כמו כן, כחלק מהגדרת הורדת מודל Firebase ML, עליך להוסיף את TensorFlow Lite SDK לאפליקציה שלך.

    dependencies {
        // Import the BoM for the Firebase platform
        implementation(platform("com.google.firebase:firebase-bom:32.7.4"))
    
        // 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:24.2.3")
    // Also add the dependency for the TensorFlow Lite library and specify its version implementation("org.tensorflow:tensorflow-lite:2.3.0")
    }
    מחפש מודול ספרייה ספציפי לקוטלין? החל מאוקטובר 2023 (Firebase BoM 32.5.0) , מפתחי Kotlin ו-Java יכולים להיות תלויים במודול הספרייה הראשי (לפרטים, עיין בשאלות הנפוצות לגבי יוזמה זו ).
  3. במניפסט של האפליקציה שלך, הצהיר כי נדרשת הרשאת אינטרנט:
    <uses-permission android:name="android.permission.INTERNET" />

1. פרוס את המודל שלך

פרוס את דגמי TensorFlow המותאמים אישית שלך באמצעות קונסולת Firebase או Firebase Admin Python ו-SDKs Node.js. ראה פריסה וניהול מודלים מותאמים אישית .

לאחר שתוסיף מודל מותאם אישית לפרויקט 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 .
הדגם האחרון קבל את הדגם העדכני ביותר. אם הדגם המקומי הוא הגרסה האחרונה, מחזיר את הדגם המקומי. אחרת, הורד את הדגם העדכני ביותר. התנהגות זו תיחסם עד להורדת הגרסה העדכנית ביותר (לא מומלץ). השתמש בהתנהגות זו רק במקרים שבהם אתה זקוק במפורש לגרסה העדכנית ביותר.

עליך להשבית פונקציונליות הקשורה לדגם - לדוגמה, לאפור או להסתיר חלק מהממשק שלך - עד שתאשר שהדגם הורד.

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

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 כדי לבדוק את המודל שלך. לדוגמה:

פִּיתוֹן

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

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

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

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 מאחסן אותם בפורמט פרוטובוף רגיל באחסון מקומי.

בתיאוריה, זה אומר שכל אחד יכול להעתיק את המודל שלך. עם זאת, בפועל, רוב הדגמים הם כל כך ספציפיים ליישום ומעורפלים על ידי אופטימיזציות שהסיכון דומה לזה של מתחרים שמפרקים ומשתמשים מחדש בקוד שלך. עם זאת, עליך להיות מודע לסיכון זה לפני שאתה משתמש במודל מותאם אישית באפליקציה שלך.

ב-Android API רמה 21 (Lollipop) ואילך, הדגם מורד לספרייה שאינה נכללת בגיבוי אוטומטי .

ב-Android API רמה 20 ומעלה, הדגם יורדת לספרייה בשם com.google.firebase.ml.custom.models באחסון פנימי פרטי לאפליקציה. אם הפעלת גיבוי קבצים באמצעות BackupAgent , ייתכן שתבחר לא לכלול את הספרייה הזו.