אם האפליקציה שלך משתמשת במודלים מותאמים אישית של TensorFlow Lite , תוכל להשתמש ב-Firebase ML כדי לפרוס את המודלים שלך. על ידי פריסת מודלים עם Firebase, אתה יכול להקטין את גודל ההורדה הראשונית של האפליקציה שלך ולעדכן את דגמי ה-ML של האפליקציה שלך מבלי לשחרר גרסה חדשה של האפליקציה שלך. בנוסף, עם תצורה מרחוק ובדיקת A/B, אתה יכול להגיש באופן דינמי דגמים שונים לקבוצות שונות של משתמשים.
דרישות מוקדמות
- ספריית
MLModelDownloader
זמינה רק עבור Swift. - TensorFlow Lite פועל רק במכשירים המשתמשים ב-iOS 9 ואילך.
דגמי TensorFlow Lite
דגמי TensorFlow Lite הם דגמי ML המותאמים להפעלה במכשירים ניידים. כדי להשיג דגם TensorFlow Lite:
- השתמש בדגם בנוי מראש, כגון אחד מהדגמים הרשמיים של TensorFlow Lite .
- המר מודל TensorFlow, מודל Keras או פונקציית בטון ל-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 ..< 224 {
for col in 0 ..< 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(&bytes, &normalizedRed, elementSize)
inputData.append(&bytes, count: elementSize)
memcpy(&bytes, &normalizedGreen, elementSize)
inputData.append(&bytes, count: elementSize)
memcpy(&ammp;bytes, &normalizedBlue, elementSize)
inputData.append(&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 מאחסן אותם בפורמט הפרוטובוף הסטנדרטי בסידרה באחסון מקומי.
בתיאוריה, זה אומר שכל אחד יכול להעתיק את המודל שלך. עם זאת, בפועל, רוב הדגמים הם כל כך ספציפיים ליישום ומעורפלים על ידי אופטימיזציות שהסיכון דומה לזה של מתחרים שמפרקים ומשתמשים מחדש בקוד שלך. עם זאת, עליך להיות מודע לסיכון זה לפני שאתה משתמש במודל מותאם אישית באפליקציה שלך.