Se la tua app utilizza modelli TensorFlow Lite, puoi utilizzare Firebase ML per eseguire il deployment dei modelli. Di eseguendo il deployment di modelli con Firebase, puoi ridurre le dimensioni l'app e aggiorna i modelli ML dell'app senza rilasciare una nuova versione la tua app. Inoltre, con Remote Config e A/B Testing, puoi eseguire dinamicamente per distribuire modelli diversi a insiemi di utenti differenti.
Prerequisiti
- La raccolta
MLModelDownloader
è disponibile solo per Swift. - TensorFlow Lite funziona solo sui dispositivi che utilizzano iOS 9 e versioni successive.
Modelli TensorFlow Lite
I modelli TensorFlow Lite sono modelli di ML ottimizzati per l'esecuzione sui dispositivi mobili dispositivi mobili. Per ottenere un modello TensorFlow Lite:
- Utilizza un modello predefinito, ad esempio uno dei modelli TensorFlow Lite ufficiali.
- Converti un modello TensorFlow, un modello Keras o una funzione concreta a TensorFlow Lite.
Prima di iniziare
Per utilizzare TensorFlowLite con Firebase, devi utilizzare CocoaPods perché TensorFlowLite attualmente non supporta l'installazione con Swift Package Manager. Consulta la
guida all'installazione di CocoaPods per
istruzioni su come installare MLModelDownloader
.
Dopo l'installazione, importa Firebase e TensorFlowLite per utilizzarli.
Swift
import FirebaseMLModelDownloader
import TensorFlowLite
1. Esegui il deployment del modello
Esegui il deployment dei tuoi modelli TensorFlow personalizzati utilizzando la console Firebase oppure gli SDK Firebase Admin e Node.js. Consulta Distribuire e gestire modelli personalizzati.
Dopo aver aggiunto un modello personalizzato al tuo progetto Firebase, puoi fare riferimento alla
tuo modello nelle tue app utilizzando il nome specificato. Puoi eseguire il deployment in qualsiasi momento
un nuovo modello TensorFlow Lite e scaricarlo sul sito web degli utenti dispositivi per
chiamata al numero getModel()
(vedi sotto).
2. Scarica il modello sul dispositivo e inizializza un interprete TensorFlow Lite
Per utilizzare il modello TensorFlow Lite nella tua app, usa prima l'SDK Firebase ML per scaricare l'ultima versione del modello sul dispositivo.Per avviare il download del modello, chiama il metodo getModel()
del downloader del modello,
specificando il nome assegnato al modello al momento del caricamento, se
vuoi scaricare sempre il modello più recente e le condizioni in cui
vuoi consentire il download.
Puoi scegliere fra tre tipi di comportamento di download:
Tipo di download | Descrizione |
---|---|
localModel
|
Recupera il modello locale dal dispositivo.
Se non è disponibile alcun modello locale,
si comporta come latestModel . Usa questa
tipo di download se non ti interessa
controllare la disponibilità di aggiornamenti del modello. Ad esempio:
stai utilizzando Remote Config per recuperare
dei modelli, ma i modelli vengono sempre caricati
con nuovi nomi (consigliato). |
localModelUpdateInBackground
|
Recupera il modello locale dal dispositivo e
iniziare ad aggiornare il modello in background.
Se non è disponibile alcun modello locale,
si comporta come latestModel . |
latestModel
|
Scarica il modello più recente. Se il modello locale è all'ultima versione, restituisce il token un modello di machine learning. Altrimenti, scarica l'ultima versione un modello di machine learning. Questo comportamento bloccherà fino a quando viene scaricata l'ultima versione (non consigliato). Utilizza questo comportamento solo in nei casi in cui è necessaria esplicitamente la versione completamente gestita. |
Devi disattivare le funzionalità correlate al modello, ad esempio disattivare o nascondere parte dell'interfaccia utente, finché non confermi che il modello è stato scaricato.
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)
}
}
Molte app avviano l'attività di download nel codice di inizializzazione, ma puoi farlo quindi in qualsiasi momento prima di dover usare il modello.
3. Esegui l'inferenza sui dati di input
Ottenere le forme di input e output del modello
L'interprete di modelli TensorFlow Lite prende come input e lo produce come output
uno o più array multidimensionali. Questi array contengono
byte
, int
, long
o float
e i relativi valori. Prima di poter passare i dati a un modello o utilizzare il suo risultato, devi conoscere
il numero e le dimensioni ("forma") degli array utilizzati dal modello.
Se il modello è stato creato da te o se il formato di input e output del modello è potrebbero essere già state documentate, potresti già avere queste informazioni. Se non conosci la forma e il tipo di dati di input e output del modello, puoi utilizzare Interprete TensorFlow Lite per ispezionare il modello. Ad esempio:
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']))
Output di esempio:
1 input(s): [ 1 224 224 3] <class 'numpy.float32'> 1 output(s): [1 1000] <class 'numpy.float32'>
Esegui l'interprete
Dopo aver determinato il formato di input e output del modello, ottieni il di input ed eseguire le trasformazioni necessarie per ottenere un input della forma giusta per il tuo modello.Ad esempio, se il tuo modello elabora immagini e ha dimensioni di input di valori di tipo [1, 224, 224, 3]
a virgola mobile, potresti dover scalare i valori di colore dell'immagine a un intervallo a virgola mobile come nell'esempio seguente:
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)
}
}
Quindi, copia il tuo input NSData
nell'interprete ed eseguilo:
Swift
try interpreter.allocateTensors()
try interpreter.copy(inputData, toInputAt: 0)
try interpreter.invoke()
Puoi ottenere l'output del modello chiamando il metodo output(at:)
dell'interprete.
Il modo in cui utilizzi l'output dipende dal modello utilizzato.
Ad esempio, se esegui la classificazione, come passaggio successivo, mappa gli indici del risultato alle etichette che rappresentano:
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])")
}
Appendice: Sicurezza del modello
Indipendentemente da come rendi disponibili i tuoi modelli TensorFlow Lite Firebase ML, Firebase ML li archivia nel formato protobuf serializzato standard in archiviazione locale.
In teoria, ciò significa che chiunque può copiare il tuo modello. Tuttavia, in pratica, la maggior parte dei modelli è così specifica per l'applicazione e offuscata dalle ottimizzazioni che il rischio è simile a quello dei concorrenti che smontano e riutilizzano il codice. Tuttavia, è necessario essere consapevoli di questo rischio prima di utilizzare un modello personalizzato nella tua app.