如果應用程式使用自訂 TensorFlow Lite 模型,可以透過 Firebase ML 部署模型。使用 Firebase 部署模型,可減少應用程式的初始下載大小,並更新應用程式的 ML 模型,不必發布新版應用程式。此外,您也可以透過 Remote Config 和 A/B Testing,動態為不同使用者群組提供不同模型。
事前準備
MLModelDownloader程式庫僅適用於 Swift。- TensorFlow Lite 僅適用於搭載 iOS 9 以上版本的裝置。
TensorFlow Lite 模型
TensorFlow Lite 模型是經過最佳化的機器學習模型,可在行動裝置上執行。如要取得 TensorFlow Lite 模型,請按照下列步驟操作:
事前準備
如要搭配使用 TensorFlow Lite 和 Firebase,請務必使用 CocoaPods,因為 TensorFlow Lite 目前不支援使用 Swift Package Manager 安裝。如需安裝 MLModelDownloader 的操作說明,請參閱 CocoaPods 安裝指南。
安裝完成後,請匯入 Firebase 和 TensorFlowLite,以便使用。
Swift
import FirebaseMLModelDownloader
import TensorFlowLite
1. 部署模型
使用 Firebase 控制台或 Firebase Admin Python 和 Node.js SDK,部署自訂 TensorFlow 模型。請參閱「部署及管理自訂模型」。
將自訂模型新增至 Firebase 專案後,您可以使用指定的名稱在應用程式中參照模型。您隨時可以部署新的 TensorFlow Lite 模型,並呼叫 getModel() (如下所示),將新模型下載到使用者裝置上。
2. 將模型下載至裝置,並初始化 TensorFlow Lite 解譯器
如要在應用程式中使用 TensorFlow Lite 模型,請先使用 Firebase ML SDK 將最新版模型下載至裝置。如要開始下載模型,請呼叫模型下載器的 getModel() 方法,並指定您上傳模型時指派的名稱、是否一律要下載最新模型,以及允許下載的條件。
您可以選擇三種下載行為:
| 下載類型 | 說明 |
|---|---|
localModel
|
從裝置取得本機模型。
如果沒有可用的本機模型,這項功能的行為與 latestModel 類似。如果您不想檢查模型更新,請使用這個下載類型。舉例來說,您使用遠端設定擷取模型名稱,並一律以新名稱上傳模型 (建議做法)。 |
localModelUpdateInBackground
|
從裝置取得本機模型,並在背景開始更新模型。如果沒有可用的本機模型,這項功能的行為與 latestModel 類似。 |
latestModel
|
取得最新型號。如果本機模型是最新版本,則傳回本機模型。否則,請下載最新模型。這個行為會封鎖,直到下載最新版本為止 (不建議)。只有在明確需要最新版本時,才使用這項行為。 |
在確認模型已下載完畢前,您應停用模型相關功能,例如將部分 UI 設為灰色或隱藏。
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] 浮點值,您可能必須將圖片的顏色值縮放至浮點範圍,如下列範例所示:
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 ..< 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 複製到解譯器並執行:
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 格式將模型儲存在本機儲存空間。
從理論上來說,這表示任何人都能複製您的模型。不過,實際上大多數模型都經過最佳化,因此會針對特定應用程式進行混淆處理,風險與競爭對手拆解及重複使用您程式碼的風險類似。不過,在應用程式中使用自訂模型前,請務必瞭解這項風險。