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

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

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

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

דגמי TensorFlow Lite

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

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

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

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

מָהִיר

import FirebaseMLModelDownloader
import TensorFlowLite

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

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

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

2. הורד את הדגם למכשיר ואתחל מתורגמן TensorFlow Lite

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

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

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

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

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

מָהִיר

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

פִּיתוֹן

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

מָהִיר

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 הקלט שלך למתורגמן והפעל אותו:

מָהִיר

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

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

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

מָהִיר

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

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