Wenn in Ihrer App benutzerdefinierte TensorFlow Lite-Modelle verwendet werden, können Sie Firebase ML verwenden, um Ihre Modelle bereitzustellen. Wenn Sie Modelle mit Firebase bereitstellen, können Sie die anfängliche Downloadgröße Ihrer App verringern und die ML-Modelle Ihrer App aktualisieren, ohne eine neue Version Ihrer App zu veröffentlichen. Mit Remote Config und A/B Testing können Sie verschiedenen Nutzergruppen dynamisch unterschiedliche Modelle bereitstellen.
Vorbereitung
- Die
MLModelDownloader-Bibliothek ist nur für Swift verfügbar. - TensorFlow Lite kann nur auf Geräten mit iOS 9 und höher ausgeführt werden.
TensorFlow Lite-Modelle
TensorFlow Lite-Modelle sind ML-Modelle, die für die Ausführung auf Mobilgeräten optimiert sind. So erhalten Sie ein TensorFlow Lite-Modell:
- Verwenden Sie ein vordefiniertes Modell, z. B. eines der offiziellen TensorFlow Lite-Modelle.
- TensorFlow-Modell, Keras-Modell oder konkrete Funktion in TensorFlow Lite konvertieren
Hinweis
Wenn Sie TensorFlowLite mit Firebase verwenden möchten, müssen Sie CocoaPods verwenden, da TensorFlowLite derzeit keine Installation mit Swift Package Manager unterstützt. Eine Anleitung zum Installieren von MLModelDownloader finden Sie im Installationsleitfaden für CocoaPods.
Nach der Installation müssen Sie Firebase und TensorFlow Lite importieren, um sie verwenden zu können.
Swift
import FirebaseMLModelDownloader
import TensorFlowLite
1. Modell bereitstellen
Sie können Ihre benutzerdefinierten TensorFlow-Modelle entweder über die Firebase-Konsole oder die Firebase Admin SDKs für Python und Node.js bereitstellen. Weitere Informationen finden Sie unter Benutzerdefinierte Modelle bereitstellen und verwalten.
Nachdem Sie Ihrem Firebase-Projekt ein benutzerdefiniertes Modell hinzugefügt haben, können Sie in Ihren Apps anhand des von Ihnen angegebenen Namens auf das Modell verweisen. Sie können jederzeit ein neues TensorFlow Lite-Modell bereitstellen und das neue Modell auf die Geräte der Nutzer herunterladen, indem Sie getModel() aufrufen (siehe unten).
2. Modell auf das Gerät herunterladen und einen TensorFlow Lite-Interpreter initialisieren
Wenn Sie Ihr TensorFlow Lite-Modell in Ihrer App verwenden möchten, müssen Sie zuerst das Firebase ML SDK verwenden, um die neueste Version des Modells auf das Gerät herunterzuladen.Rufen Sie zum Starten des Modell-Downloads die getModel()-Methode des Modell-Downloaders auf. Geben Sie dabei den Namen an, den Sie dem Modell beim Hochladen zugewiesen haben, ob Sie immer das neueste Modell herunterladen möchten, und die Bedingungen, unter denen Sie den Download zulassen möchten.
Sie können zwischen drei Download-Verhaltensweisen wählen:
| Downloadtyp | Beschreibung |
|---|---|
localModel
|
Das lokale Modell vom Gerät abrufen.
Wenn kein lokales Modell verfügbar ist, verhält sich die Funktion wie latestModel. Verwenden Sie diesen Downloadtyp, wenn Sie nicht nach Modellupdates suchen möchten. Sie verwenden beispielsweise Remote Config, um Modellnamen abzurufen, und laden Modelle immer unter neuen Namen hoch (empfohlen). |
localModelUpdateInBackground
|
Das lokale Modell vom Gerät abrufen und das Modell im Hintergrund aktualisieren
Wenn kein lokales Modell verfügbar ist, verhält sich die Funktion wie latestModel. |
latestModel
|
Aktuelles Modell erhalten Wenn das lokale Modell die aktuelle Version ist, wird das lokale Modell zurückgegeben. Laden Sie andernfalls das aktuelle Modell herunter. Dieses Verhalten wird blockiert, bis die neueste Version heruntergeladen wurde (nicht empfohlen). Verwenden Sie dieses Verhalten nur, wenn Sie ausdrücklich die neueste Version benötigen. |
Sie sollten modellbezogene Funktionen deaktivieren, z. B. einen Teil der Benutzeroberfläche ausblenden oder ausgrauen, bis Sie bestätigen, dass das Modell heruntergeladen wurde.
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)
}
}
Bei vielen Apps wird der Downloadvorgang im Initialisierungscode gestartet. Sie können dies jedoch jederzeit tun, bevor Sie das Modell verwenden müssen.
3. Inferenz für Eingabedaten durchführen
Eingabe- und Ausgabeshapes des Modells abrufen
Der TensorFlow Lite-Modellinterpreter verwendet ein oder mehrere mehrdimensionale Arrays als Eingabe und gibt sie als Ausgabe zurück. Diese Arrays enthalten entweder die Werte byte, int, long oder float. Bevor Sie Daten an ein Modell übergeben oder dessen Ergebnis verwenden können, müssen Sie die Anzahl und die Dimensionen („Form“) der Arrays kennen, die Ihr Modell verwendet.
Wenn Sie das Modell selbst erstellt haben oder das Ein- und Ausgabeformat des Modells dokumentiert ist, haben Sie diese Informationen möglicherweise bereits. Wenn Sie die Form und den Datentyp der Ein- und Ausgabe Ihres Modells nicht kennen, können Sie den TensorFlow Lite-Interpreter verwenden, um Ihr Modell zu untersuchen. Beispiel:
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']))
Beispielausgabe:
1 input(s): [ 1 224 224 3] <class 'numpy.float32'> 1 output(s): [1 1000] <class 'numpy.float32'>
Interpreter ausführen
Nachdem Sie das Format der Ein- und Ausgabe Ihres Modells festgelegt haben, müssen Sie die Eingabedaten abrufen und alle Transformationen durchführen, die erforderlich sind, um eine Eingabe mit der richtigen Form für Ihr Modell zu erhalten.Wenn Ihr Modell beispielsweise Bilder verarbeitet und die Eingabedimensionen Ihres Modells [1, 224, 224, 3] Gleitkommawerte sind, müssen Sie die Farbwerte des Bildes möglicherweise auf einen Gleitkomma-Bereich skalieren, wie im folgenden Beispiel:
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)
}
}
Kopieren Sie dann Ihre Eingabe NSData in den Interpreter und führen Sie sie aus:
Swift
try interpreter.allocateTensors()
try interpreter.copy(inputData, toInputAt: 0)
try interpreter.invoke()
Sie können die Ausgabe des Modells abrufen, indem Sie die Methode output(at:) des Interpreters aufrufen.
Wie Sie die Ausgabe verwenden, hängt vom verwendeten Modell ab.
Wenn Sie beispielsweise eine Klassifizierung durchführen, können Sie als Nächstes die Indexe des Ergebnisses den Labels zuordnen, die sie repräsentieren:
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])")
}
Anhang: Modellsicherheit
Unabhängig davon, wie Sie Ihre TensorFlow Lite-Modelle für Firebase ML verfügbar machen, speichert Firebase ML sie im standardmäßigen serialisierten Protobuf-Format im lokalen Speicher.
Theoretisch bedeutet das, dass jeder Ihr Modell kopieren kann. In der Praxis sind die meisten Modelle jedoch so anwendungsspezifisch und durch Optimierungen verschleiert, dass das Risiko ähnlich hoch ist wie das Risiko, dass Wettbewerber Ihren Code disassemblieren und wiederverwenden. Sie sollten sich dieses Risikos jedoch bewusst sein, bevor Sie ein benutzerdefiniertes Modell in Ihrer App verwenden.