השתמש במודל TensorFlow Lite להסקת ערכת ML באנדרואיד

אתה יכול להשתמש ML קיט לבצע על-התקן היסק עם לייט TensorFlow מודל.

API זה דורש אנדרואיד SDK ברמה 16 (Jelly Bean) ואילך.

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

  1. אם לא עשית זאת עדיין, להוסיף Firebase לפרויקט Android שלך .
  2. מוסיפים את התלות עבור ספריות אנדרואיד קיט ML למודול שלך (ברמת האפליקציה) קובץ 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 .

אירח או צרר את הדגם שלך

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

על ידי אירוח דגם ב- Firebase, תוכל לעדכן את הדגם מבלי לשחרר גרסת אפליקציה חדשה, ותוכל להשתמש ב- Config Remote וב- A/B Testing כדי לשרת באופן דינמי מודלים שונים לקבוצות משתמשים שונות.

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

על ידי צירוף המודל שלך עם האפליקציה שלך, תוכל לוודא שתכונות ה- ML של האפליקציה שלך עדיין פועלות כאשר המודל המתארח ב- Firebase אינו זמין.

דגמי מארח ב- Firebase

לארח את דגם TensorFlow Lite שלך ​​ב- Firebase:

  1. במקטע ערכת ML של קונסולת Firebase , לחץ על הכרטיסייה המותאמת אישית.
  2. לחץ להוסיף מודל מותאם אישית (או להוסיף דגם נוסף).
  3. ציין שם כי ישמש לזיהוי המודל שלך בפרויקט Firebase שלך, ואז להעלות את הקובץ מודל לייט TensorFlow (בדרך כלל עם סיומת .tflite או .lite ).
  4. בשנת למניפסט של האפליקציה, להצהיר כי רשות לאינטרנט נדרש:
    <uses-permission android:name="android.permission.INTERNET" />
    

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

צרור דגמים עם אפליקציה

כדי לקבץ מודל לייט TensorFlow שלך עם האפליקציה שלך, להעתיק את קובץ המודל (בדרך כלל עם סיומת .tflite או .lite ) כדי באפליקציה assets/ התיקייה. (ייתכן שיהיה עליך ליצור את התיקייה הראשונה על ידי לחיצה ימנית על app/ תיקייה, ולאחר מכן לחיצה על New> Folder> נכסים תיקיה.)

ואז, להוסיף את הדברים הבאים של האפליקציה שלך build.gradle הקובץ כדי לוודא Gradle לא לדחוס את הדגמים כאשר בונים את האפליקציה:

android {

    // ...

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

קובץ הדגם ייכלל בחבילת האפליקציות וזמין ל- ML Kit כנכס גולמי.

טען את הדגם

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

הגדר מודל המתארח ב- Firebase

אם אתה מתארח המודל שלך עם Firebase, ליצור FirebaseCustomRemoteModel אובייקט, המפרטת את השם שהקצית המודל כאשר שהעלית אותו:

ג'אווה

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

קוטלין+KTX

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

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

ג'אווה

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

קוטלין+KTX

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

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

הגדר מודל מקומי

אם אתה ארוזות המודל עם האפליקציה שלך, ליצור FirebaseCustomLocalModel אובייקט, המפרט את שם הקובץ של המודל לייט TensorFlow:

ג'אווה

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

קוטלין+KTX

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

צור מתורגמן מהדגם שלך

לאחר שהגדרת מקורות המודל שלך, ליצור FirebaseModelInterpreter חפץ מאחד מהם.

אם יש לך רק מודל מקומי ארוז, פשוט ליצור מתורגמן מן שלך FirebaseCustomLocalModel אובייקט:

ג'אווה

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

קוטלין+KTX

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

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

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

ג'אווה

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);
                // ...
            }
        });

קוטלין+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() שיטה:

ג'אווה

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

קוטלין+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 עם המספר והמידות ("צורה") של המערכים שבהם הדגם שלך משתמש.

אם אינך יודע את צורת וסוג הנתונים של הקלט והפלט של הדגם שלך, תוכל להשתמש במתורגמן 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 ערכים, המייצג קבוצה של N 224x224 שלושה ערוצים (RGB) תמונות, ותוצרת כפלט רשימה של 1000 float ערכים, וכל עמודה מייצגת את סביר שהתמונה היא חברה באחת מ -1000 הקטגוריות שהמודל מנבא.

עבור דגם כזה, היית מגדיר את הקלט והפלט של מתורגמן המודל כפי שמוצג להלן:

ג'אווה

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

קוטלין+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 האובייקט כפי שמוצג בדוגמה הבאה:

ג'אווה

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

קוטלין+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 השיטה:

ג'אווה

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
                        // ...
                    }
                });

קוטלין+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() השיטה של האובייקט כי הוא עבר אל מאזין ההצלחה. לדוגמה:

ג'אווה

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

קוטלין+KTX

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

אופן השימוש בפלט תלוי בדגם שבו אתה משתמש.

לדוגמה, אם אתה מבצע סיווג, כשלב הבא, תוכל למפות את אינדקס התוצאה לתוויות שהם מייצגים:

ג'אווה

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

קוטלין+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 באחסון מקומי.

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

ב API אנדרואיד ברמה 21 (Lollipop) ומעלה, המודל שהורדו לספרייה כי הוא נכלל גיבוי אוטומטי .

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