שימוש במודל TensorFlow Lite בהתאמה אישית בפלטפורמות של Apple

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

דרישות מוקדמות

  • הספרייה MLModelDownloader זמינה רק ב-Swift.
  • TensorFlow Lite פועל רק במכשירים עם מערכת ההפעלה iOS 9 ואילך.

דגמים של TensorFlow Lite

מודלים של TensorFlow Lite הם מודלים של למידת מכונה שעברו אופטימיזציה לצורך הפעלה במכשירים ניידים. כדי לקבל מודל TensorFlow Lite:

לפני שמתחילים

כדי להשתמש ב-TensorFlowLite עם Firebase, צריך להשתמש ב-CocoaPods בתור TensorFlowLite כרגע לא תומכת בהתקנה עם Swift Package Manager. לצפייה מדריך ההתקנה של CocoaPods עבור הוראות להתקנה של MLModelDownloader.

לאחר ההתקנה, מייבאים את Firebase ואת TensorFlowLite כדי להשתמש בהם.

Swift

import FirebaseMLModelDownloader
import TensorFlowLite

1. פריסת המודל

פורסים מודלים מותאמים אישית של TensorFlow באמצעות המסוף Firebase או את ערכות ה-SDK של Firebase Admin עבור Python ו-Node.js. צפייה פריסה וניהול של מודלים בהתאמה אישית.

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

2. צריך להוריד את המודל למכשיר ולהפעיל תרגום של TensorFlow Lite

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

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

אתם יכולים לבחור מבין שלוש התנהגויות של הורדות:

סוג הורדה תיאור
localModel מוצאים את הדגם המקומי מהמכשיר. אם אין מודל מקומי זמין, מתנהגת כמו latestModel. שימוש בטיוטה הזו סוג ההורדה, אם לא היית רוצה להשתמש בו. בדיקה אם יש עדכוני מודל. לדוגמה, אתם משתמשים ב'הגדרת תצורה מרחוק' כדי לאחזר שמות של מודלים ואתה תמיד מעלה מודלים בשמות חדשים (מומלץ).
localModelUpdateInBackground מקבלים את הדגם המקומי מהמכשיר מתחילים לעדכן את המודל ברקע. אם אין מודל מקומי זמין, מתנהגת כמו latestModel.
latestModel מקבלים את המודל העדכני ביותר. אם המודל המקומי הוא את הגרסה העדכנית ביותר, מחזירה את הערך מודל טרנספורמר. אחרת, צריך להוריד את הגרסה העדכנית ביותר מודל טרנספורמר. התנהגות זו תיחסם עד מתבצעת הורדה של הגרסה האחרונה (לא ). מומלץ להשתמש בהתנהגות הזו רק במקרים שבהם אתם זקוקים באופן מפורש לגרסה העדכנית ביותר.

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

Swift

let conditions = ModelDownloadConditions(allowsCellularAccess: false)
ModelDownloader.modelDownloader()
    .getModel(name: "your_model",
              downloadType: .localModelUpdateInBackground,
              conditions: conditions) { result in
        switch (result) {
        case .success(let customModel):
            do {
                // 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.
                let interpreter = try Interpreter(modelPath: customModel.path)
            } catch {
                // Error. Bad model file?
            }
        case .failure(let error):
            // Download was unsuccessful. Don't enable ML features.
            print(error)
        }
}

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

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), יכול להיות שיהיה צורך לשנות את קנה המידה את ערכי הצבעים של התמונה בטווח של נקודה צפה (floating-point) כמו בדוגמה הבאה:

Swift

let image: CGImage = // Your input image
guard let context = CGContext(
  data: nil,
  width: image.width, height: image.height,
  bitsPerComponent: 8, bytesPerRow: image.width * 4,
  space: CGColorSpaceCreateDeviceRGB(),
  bitmapInfo: CGImageAlphaInfo.noneSkipFirst.rawValue
) else {
  return false
}

context.draw(image, in: CGRect(x: 0, y: 0, width: image.width, height: image.height))
guard let imageData = context.data else { return false }

var inputData = Data()
for row in 0 ..&lt; 224 {
  for col in 0 ..&lt; 224 {
    let offset = 4 * (row * context.width + col)
    // (Ignore offset 0, the unused alpha channel)
    let red = imageData.load(fromByteOffset: offset+1, as: UInt8.self)
    let green = imageData.load(fromByteOffset: offset+2, as: UInt8.self)
    let blue = imageData.load(fromByteOffset: offset+3, as: UInt8.self)

    // Normalize channel values to [0.0, 1.0]. This requirement varies
    // by model. For example, some models might require values to be
    // normalized to the range [-1.0, 1.0] instead, and others might
    // require fixed-point values or the original bytes.
    var normalizedRed = Float32(red) / 255.0
    var normalizedGreen = Float32(green) / 255.0
    var normalizedBlue = Float32(blue) / 255.0

    // Append normalized values to Data object in RGB order.
    let elementSize = MemoryLayout.size(ofValue: normalizedRed)
    var bytes = [UInt8](repeating: 0, count: elementSize)
    memcpy(&amp;bytes, &amp;normalizedRed, elementSize)
    inputData.append(&amp;bytes, count: elementSize)
    memcpy(&amp;bytes, &amp;normalizedGreen, elementSize)
    inputData.append(&amp;bytes, count: elementSize)
    memcpy(&ammp;bytes, &amp;normalizedBlue, elementSize)
    inputData.append(&amp;bytes, count: elementSize)
  }
}

לאחר מכן, מעתיקים את הקלט NSData למפענח ומריצים אותו:

Swift

try interpreter.allocateTensors()
try interpreter.copy(inputData, toInputAt: 0)
try interpreter.invoke()

כדי לקבל את הפלט של המודל, אפשר להפעיל את השיטה output(at:) של המתרגם. אופן השימוש בפלט משתנה בהתאם למודל שבו משתמשים.

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

Swift

let output = try interpreter.output(at: 0)
let probabilities =
        UnsafeMutableBufferPointer<Float32>.allocate(capacity: 1000)
output.data.copyBytes(to: probabilities)

guard let labelPath = Bundle.main.path(forResource: "retrained_labels", ofType: "txt") else { return }
let fileContents = try? String(contentsOfFile: labelPath)
guard let labels = fileContents?.components(separatedBy: "\n") else { return }

for i in labels.indices {
    print("\(labels[i]): \(probabilities[i])")
}

נספח: אבטחת המודל

בלי קשר לאופן שבו המודלים של TensorFlow Lite יהיו זמינים Firebase ML, Firebase ML מאחסן אותם בפורמט Protobuf סריאלי סטנדרטי ב אחסון מקומי.

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