Utiliser un modèle TensorFlow Lite personnalisé sur les plates-formes Apple

Si votre application utilise des TensorFlow Lite, vous pouvez utiliser Firebase ML pour déployer vos modèles. Par déployer des modèles avec Firebase, vous pouvez réduire la taille de téléchargement initiale votre application et mettre à jour ses modèles de ML sans publier de nouvelle version votre application. De plus, avec Remote Config et A/B Testing, vous pouvez dynamiquement peuvent servir des modèles différents pour différents ensembles d'utilisateurs.

Prérequis

  • La bibliothèque MLModelDownloader n'est disponible que pour Swift.
  • TensorFlow Lite ne s'exécute que sur les appareils équipés d'iOS 9 ou version ultérieure.

Modèles TensorFlow Lite

Les modèles TensorFlow Lite sont des modèles de ML optimisés pour s'exécuter sur des appareils mobiles. Pour obtenir un modèle TensorFlow Lite, procédez comme suit:

Avant de commencer

Pour utiliser TensorFlowLite avec Firebase, vous devez utiliser CocoaPods en tant que TensorFlowLite n'est actuellement pas compatible avec l'installation avec le gestionnaire de packages Swift. Consultez le le guide d'installation de CocoaPods pour des instructions pour installer MLModelDownloader.

Une fois ces outils installés, importez Firebase et TensorFlowLite pour pouvoir les utiliser.

Swift

import FirebaseMLModelDownloader
import TensorFlowLite

1. Déployer le modèle

Déployez vos modèles TensorFlow personnalisés à l'aide de la console Firebase ou les SDK Firebase Admin Python et Node.js. Voir Déployer et gérer des modèles personnalisés

Après avoir ajouté un modèle personnalisé à votre projet Firebase, vous pouvez référencer le dans vos applications en utilisant le nom spécifié. Vous pouvez déployer à tout moment un nouveau modèle TensorFlow Lite et le télécharger appareils par appelez getModel() (voir ci-dessous).

2. Télécharger le modèle sur l'appareil et initialiser un interpréteur TensorFlow Lite

Pour utiliser votre modèle TensorFlow Lite dans votre application, commencez par utiliser le SDK Firebase ML pour télécharger la dernière version du modèle sur l'appareil.

Pour lancer le téléchargement du modèle, appelez la méthode getModel() de l'outil de téléchargement de modèles. en spécifiant le nom que vous avez attribué au modèle lors de son importation, télécharger systématiquement le modèle le plus récent, ainsi que les conditions dans lesquelles vous si vous souhaitez autoriser le téléchargement.

Vous avez le choix entre trois comportements de téléchargement:

Type de téléchargement Description
localModel Récupérez le modèle local de l'appareil. Si aucun modèle local n'est disponible, le comportement est identique à celui de latestModel. Utiliser ceci de téléchargement si vous n'êtes pas intéressé par des mises à jour du modèle. Par exemple, vous utilisez Remote Config pour récupérer les noms de modèles, et vous importez toujours des modèles sous de nouveaux noms (recommandé).
localModelUpdateInBackground Obtenez le modèle local à partir de l'appareil et commencez à le mettre à jour en arrière-plan. Si aucun modèle local n'est disponible, le comportement est identique à celui de latestModel.
latestModel Téléchargez le dernier modèle. Si le modèle local est la dernière version, renvoie la valeur du modèle de ML. Sinon, téléchargez la dernière version du modèle de ML. Ce comportement sera bloqué jusqu'à ce que la dernière version est téléchargée (pas recommandé). Utilisez ce comportement uniquement dans dans les cas où vous avez explicitement besoin version.

Vous devez désactiver les fonctionnalités liées aux modèles, par exemple, les options grisées ou masquer une partie de l'interface utilisateur jusqu'à ce que vous confirmiez que le modèle a été téléchargé.

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)
        }
}

De nombreuses applications lancent la tâche de téléchargement dans leur code d'initialisation, mais vous pouvez avant de devoir utiliser le modèle.

3. Effectuer une inférence sur des données d'entrée

Obtenir les formes d'entrée et de sortie de votre modèle

L'interpréteur de modèle TensorFlow Lite prend en entrée et produit en sortie un ou plusieurs tableaux multidimensionnels. Ces tableaux contiennent byte, int, long ou float valeurs. Avant de pouvoir transmettre des données à un modèle ou utiliser son résultat, vous devez savoir le nombre et les dimensions ("forme") des tableaux utilisés par le modèle ;

Si vous avez créé le modèle vous-même, ou si le format d'entrée et de sortie du modèle est documentées, vous disposez peut-être déjà de ces informations. Si vous ne connaissez pas le et le type de données des entrées et sorties de votre modèle, vous pouvez utiliser Interpréteur TensorFlow Lite pour inspecter votre modèle. Exemple :

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']))

Exemple de résultat :

1 input(s):
[  1 224 224   3] <class 'numpy.float32'>

1 output(s):
[1 1000] <class 'numpy.float32'>

Exécuter l'interpréteur

Une fois que vous avez déterminé le format des entrées et des sorties de votre modèle, obtenez les données d'entrée et effectuer toutes les transformations nécessaires sur les données une entrée dont la forme est adaptée à votre modèle.

Par exemple, si votre modèle traite des images et possède des dimensions d'entrée de [1, 224, 224, 3] valeurs à virgule flottante, vous devrez peut-être effectuer un scaling les valeurs de couleur de l'image dans une plage à virgule flottante, comme dans l'exemple suivant:

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 ..&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)
  }
}

Ensuite, copiez votre entrée NSData dans l'interpréteur et exécutez-la:

Swift

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

Vous pouvez obtenir la sortie du modèle en appelant la méthode output(at:) de l'interpréteur. La manière dont vous utilisez la sortie dépend du modèle que vous utilisez.

Par exemple, si vous effectuez une classification, vous pourriez mappez les index du résultat aux étiquettes qu'ils représentent:

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])")
}

Annexe: Sécurité du modèle

Quelle que soit la manière dont vous mettez vos modèles TensorFlow Lite à la disposition de Firebase ML, Firebase ML les stocke au format protobuf sérialisé standard dans l'espace de stockage local.

En théorie, cela signifie que n'importe qui peut copier votre modèle. Toutefois, Dans la pratique, la plupart des modèles sont tellement spécifiques à une application et obscurcis par des optimisations dont le risque est similaire à celui des concurrents en démontrant et en réutilisant votre code. Toutefois, vous devez être conscient de ce risque avant d'utiliser un modèle personnalisé dans votre application.