Aggiungi Firebase alla tua app iOS basata su TFLite

1. Panoramica

Obiettivi

Firebase ML ti consente di distribuire il tuo modello over-the-air. Ciò ti consente di mantenere ridotte le dimensioni dell'app e di scaricare il modello ML solo quando necessario, sperimentare più modelli o aggiornare il modello ML senza dover ripubblicare l'intera app.

In questo codelab convertirai un'app iOS utilizzando un modello TFLite statico in un'app utilizzando un modello servito dinamicamente da Firebase. Imparerai come:

  1. Distribuisci i modelli TFLite su Firebase ML e accedi dalla tua app
  2. Registra le metriche relative al modello con Analytics
  3. Selezionare quale modello viene caricato tramite Remote Config
  4. Test A/B su diversi modelli

Prerequisiti

Prima di iniziare questo codelab assicurati di aver installato:

  • Xcode 11 (o successivo)
  • CocoaPods 1.9.1 (o successiva)

2. Crea un progetto della console Firebase

Aggiungi Firebase al progetto

  1. Vai alla console Firebase .
  2. Seleziona Crea nuovo progetto e dai un nome al tuo progetto "Firebase ML iOS Codelab".

3. Ottieni il progetto di esempio

Scarica il codice

Inizia clonando il progetto di esempio ed eseguendo pod update nella directory del progetto:

git clone https://github.com/FirebaseExtended/codelab-digitclassifier-ios.git
cd codelab-digitclassifier-ios
pod install --repo-update

Se non hai git installato, puoi anche scaricare il progetto di esempio dalla sua pagina GitHub o facendo clic su questo collegamento . Una volta scaricato il progetto, eseguilo in Xcode e gioca con il classificatore di cifre per avere un'idea di come funziona.

Configura Firebase

Segui la documentazione per creare un nuovo progetto Firebase. Una volta ottenuto il progetto, scarica il file GoogleService-Info.plist del progetto dalla console Firebase e trascinalo nella radice del progetto Xcode.

f06cb08d48de7e10.png

Aggiungi Firebase al tuo Podfile ed esegui l'installazione pod.

pod 'FirebaseMLModelDownloader', '9.3.0-beta'

Nel metodo didFinishLaunchingWithOptions di AppDelegate , importa Firebase nella parte superiore del file

import FirebaseCore

E aggiungi una chiamata per configurare Firebase.

FirebaseApp.configure()

Esegui nuovamente il progetto per assicurarti che l'app sia configurata correttamente e non si blocchi all'avvio.

4. Distribuisci un modello su Firebase ML

La distribuzione di un modello su Firebase ML è utile per due motivi principali:

  1. Possiamo mantenere ridotte le dimensioni di installazione dell'app e scaricare il modello solo se necessario
  2. Il modello può essere aggiornato regolarmente e con un ciclo di rilascio diverso rispetto all'intera app

Prima di poter sostituire il modello statico nella nostra app con un modello scaricato dinamicamente da Firebase, dobbiamo distribuirlo su Firebase ML. Il modello può essere distribuito tramite la console o a livello di programmazione utilizzando Firebase Admin SDK. In questo passaggio eseguiremo la distribuzione tramite la console.

Per semplificare le cose, utilizzeremo il modello TensorFlow Lite già presente nella nostra app. Innanzitutto, apri Firebase e fai clic su Machine Learning nel pannello di navigazione a sinistra. Quindi vai su "Personalizzato" e fai clic sul pulsante "Aggiungi modello".

Quando richiesto, assegna al modello un nome descrittivo come mnist_v1 e carica il file dalla directory del progetto codelab.

3c3c50e6ef12b3b.png

5. Scarica il modello da Firebase ML

Scegliere quando scaricare il modello remoto da Firebase nella tua app può essere complicato poiché i modelli TFLite possono diventare relativamente grandi. Idealmente vogliamo evitare di caricare il modello immediatamente all'avvio dell'app, poiché se il nostro modello viene utilizzato per una sola funzionalità e l'utente non utilizza mai quella funzionalità, avremo scaricato una quantità significativa di dati senza motivo. Possiamo anche impostare opzioni di download come il recupero dei modelli solo quando siamo connessi al Wi-Fi. Se vuoi assicurarti che il modello sia disponibile anche senza connessione di rete, dovresti anche raggrupparlo come parte dell'app come backup.

Per motivi di semplicità, rimuoveremo il modello in bundle predefinito e scaricheremo sempre un modello da Firebase all'avvio dell'app. In questo modo quando esegui il riconoscimento delle cifre puoi essere sicuro che l'inferenza viene eseguita con il modello fornito da Firebase.

Nella parte superiore di ModelLoader.swift , importa il modulo Firebase.

import FirebaseCore
import FirebaseMLModelDownloader

Quindi implementare il seguente metodo.

static func downloadModel(named name: String,
                          completion: @escaping (CustomModel?, DownloadError?) -> Void) {
  guard FirebaseApp.app() != nil else {
    completion(nil, .firebaseNotInitialized)
    return
  }
  guard success == nil && failure == nil else {
    completion(nil, .downloadInProgress)
    return
  }
  let conditions = ModelDownloadConditions(allowsCellularAccess: false)
  ModelDownloader.modelDownloader().getModel(name: name, downloadType: .localModelUpdateInBackground, conditions: conditions) { result in
          switch (result) {
          case .success(let customModel):
                  // Download complete.
                  // The CustomModel object contains the local path of the model file,
                  // which you can use to instantiate a TensorFlow Lite classifier.
                  return completion(customModel, nil)
          case .failure(let error):
              // Download was unsuccessful. Notify error message.
            completion(nil, .downloadFailed(underlyingError: error))
          }
  }
}

Nel viewDidLoad di ViewController.swift sostituisci la chiamata di inizializzazione DigitClassifier con il nostro nuovo metodo di download del modello.

    // Download the model from Firebase
    print("Fetching model...")
    ModelLoader.downloadModel(named: "mnist_v1") { (customModel, error) in
      guard let customModel = customModel else {
        if let error = error {
          print(error)
        }
        return
      }

      print("Model download complete")
      
      // Initialize a DigitClassifier instance
      DigitClassifier.newInstance(modelPath: customModel.path) { result in
      switch result {
        case let .success(classifier):
          self.classifier = classifier
        case .error(_):
          self.resultLabel.text = "Failed to initialize."
        }
      }
    }

Esegui nuovamente l'app. Dopo alcuni secondi, dovresti vedere un registro in Xcode che indica che il modello remoto è stato scaricato con successo. Prova a disegnare una cifra e conferma che il comportamento dell'app non è cambiato.

6. Tieni traccia del feedback e della conversione degli utenti per misurare l'accuratezza del modello

Misureremo l'accuratezza del modello monitorando il feedback degli utenti sulle previsioni del modello. Se un utente fa clic su "sì", indicherà che la previsione era accurata.

Possiamo registrare un evento Analytics per monitorare l'accuratezza del nostro modello. Innanzitutto, dobbiamo aggiungere Analytics al Podfile prima che possa essere utilizzato nel progetto:

pod 'FirebaseAnalytics'

Quindi in ViewController.swift importa Firebase nella parte superiore del file

import FirebaseAnalytics

E aggiungi la seguente riga di codice nel metodo correctButtonPressed .

Analytics.logEvent("correct_inference", parameters: nil)

Esegui nuovamente l'app e disegna una cifra. Premi il pulsante "Sì" un paio di volte per inviare un feedback sull'accuratezza dell'inferenza.

Analisi di debug

In genere, gli eventi registrati dalla tua app vengono raggruppati nell'arco di un periodo di circa un'ora e caricati insieme. Questo approccio preserva la batteria dei dispositivi degli utenti finali e riduce l'utilizzo dei dati di rete. Tuttavia, allo scopo di convalidare l'implementazione dell'analisi (e per visualizzare l'analisi nel report DebugView), puoi abilitare la modalità Debug sul tuo dispositivo di sviluppo per caricare gli eventi con un ritardo minimo.

Per abilitare la modalità Debug di Analytics sul tuo dispositivo di sviluppo, specifica il seguente argomento della riga di comando in Xcode:

-FIRDebugEnabled

Esegui nuovamente l'app e disegna una cifra. Premi il pulsante "Sì" un paio di volte per inviare un feedback sull'accuratezza dell'inferenza. Ora puoi visualizzare gli eventi del registro quasi in tempo reale tramite la visualizzazione debug nella console Firebase. Fai clic su Analytics > DebugView dalla barra di navigazione sinistra.

5276199a086721fd.png

7. Tieni traccia del tempo di inferenza con Firebase Performance

Quando testi il ​​tuo modello, le metriche delle prestazioni effettuate sui dispositivi di sviluppo non sono sufficienti per acquisire le prestazioni del modello nelle mani degli utenti, poiché è difficile stabilire su quale hardware gli utenti eseguiranno la tua app. Fortunatamente, puoi misurare le prestazioni del tuo modello sui dispositivi degli utenti con Firebase Performance per ottenere un quadro migliore delle prestazioni del tuo modello.

Per misurare il tempo necessario per eseguire l'inferenza, importa prima Firebase in DigitClassifier.swift:

import FirebasePerformance

Quindi avvia una traccia delle prestazioni nel metodo classify e interrompi la traccia una volta completata l'inferenza. Assicurati di aggiungere le seguenti righe di codice all'interno della chiusura DispatchQueue.global.async e non direttamente sotto la dichiarazione del metodo.

let inferenceTrace = Performance.startTrace(name: "tflite inference")
defer {
  inferenceTrace?.stop()
}

Se sei curioso, puoi abilitare la registrazione del debug tramite le istruzioni qui per confermare che le tracce delle prestazioni vengono registrate. Dopo un po', le tracce delle prestazioni saranno visibili anche nella Console Firebase.

8. Distribuisci un secondo modello su Firebase ML

Quando creiamo una nuova versione del tuo modello, ad esempio una con un'architettura del modello migliore o una addestrata su un set di dati più grande o aggiornato, potremmo sentirci tentati di sostituire il nostro modello attuale con la nuova versione. Tuttavia, un modello che ha ottenuto buoni risultati nei test non necessariamente ha prestazioni altrettanto buone in produzione. Pertanto, eseguiamo dei test A/B in produzione per confrontare il nostro modello originale e quello nuovo.

Abilita l'API di gestione dei modelli Firebase

In questo passaggio, abiliteremo l'API Firebase Model Management per distribuire una nuova versione del nostro modello TensorFlow Lite utilizzando il codice Python.

Crea un bucket per archiviare i tuoi modelli ML

Nella console Firebase, vai su Archiviazione e fai clic su Inizia. fbbea78f0eb3dc9f.png

Segui la finestra di dialogo per impostare il secchio.

19517c0d6d2aa14d.png

Abilita l'API Firebase ML

Vai alla pagina API Firebase ML su Google Cloud Console e fai clic su Abilita.

2414fd5cced6c984.png Seleziona l'app Classificatore cifre quando richiesto.

Ora addestreremo una nuova versione del modello utilizzando un set di dati più grande e quindi lo distribuiremo a livello di programmazione direttamente dal notebook di training utilizzando Firebase Admin SDK.

Scarica la chiave privata per l'account di servizio

Prima di poter utilizzare l'SDK Admin Firebase, dovremo creare un account di servizio. Apri il pannello Account di servizio della console Firebase facendo clic su questo collegamento e fai clic sul pulsante per creare un nuovo account di servizio per Firebase Admin SDK. Quando richiesto, fare clic sul pulsante Genera nuova chiave privata. Utilizzeremo la chiave dell'account di servizio per autenticare le nostre richieste dal notebook colab.

c3b95de1e5508516.png

Ora possiamo addestrare e implementare il nuovo modello.

  1. Apri questo taccuino di collaborazione e creane una copia nel tuo Drive.
  2. Esegui la prima cella "Addestra un modello TensorFlow Lite migliorato" facendo clic sul pulsante di riproduzione alla sua sinistra. Questa operazione addestrerà un nuovo modello e potrebbe richiedere del tempo.
  3. L'esecuzione della seconda cella creerà una richiesta di caricamento del file. Carica il file json scaricato dalla console Firebase durante la creazione del tuo account di servizio.

71e847c6a85423b3.png

  1. Esegui le ultime due celle.

Dopo aver eseguito il notebook colab, dovresti vedere un secondo modello nella console Firebase. Assicurati che il secondo modello sia denominato mnist_v2 .

c316683bb4d75d57.png

9. Selezionare un modello tramite Remote Config

Ora che abbiamo due modelli separati, aggiungeremo un parametro per selezionare quale modello scaricare in fase di esecuzione. Il valore del parametro ricevuto dal client determinerà quale modello verrà scaricato dal client. Innanzitutto, apri la console Firebase e fai clic sul pulsante Remote Config nel menu di navigazione a sinistra. Quindi, fare clic sul pulsante "Aggiungi parametro".

Assegna un nome al nuovo parametro model_name e assegnagli il valore predefinito mnist_v1 . Fare clic su Pubblica modifiche per applicare gli aggiornamenti. Inserendo il nome del modello nel parametro di configurazione remota, possiamo testare più modelli senza aggiungere un nuovo parametro per ogni modello che vogliamo testare.

Dopo aver aggiunto il parametro, dovresti vederlo nella Console:

699b3fd32acce887.png

Nel nostro codice, dovremo aggiungere un controllo durante il caricamento del modello remoto. Quando riceviamo il parametro da Remote Config, recupereremo il modello remoto con il nome corrispondente; altrimenti proveremo a caricare mnist_v1 . Prima di poter utilizzare Remote Config, dobbiamo aggiungerlo al nostro progetto specificandolo come dipendenza nel Podfile:

pod 'FirebaseRemoteConfig'

Esegui l'installazione pod e riapri il progetto Xcode. In ModelLoader.swift implementare il metodo fetchParameterizedModel .

static func fetchParameterizedModel(completion: @escaping (CustomModel?, DownloadError?) -> Void) {
  RemoteConfig.remoteConfig().fetchAndActivate { (status, error) in
    DispatchQueue.main.async {
      if let error = error {
        let compositeError = DownloadError.downloadFailed(underlyingError: error)
        completion(nil, compositeError)
        return
      }

      let modelName: String
      if let name = RemoteConfig.remoteConfig().configValue(forKey: "model_name").stringValue {
        modelName = name
      } else {
        let defaultName = "mnist_v1"
        print("Unable to fetch model name from config, falling back to default \(defaultName)")
        modelName = defaultName
      }
      downloadModel(named: modelName, completion: completion)
    }
  }
}

Infine, in ViewController.swift , sostituisci la chiamata downloadModel con il nuovo metodo che abbiamo appena implementato.

// Download the model from Firebase
print("Fetching model...")
ModelLoader.fetchParameterizedModel { (customModel, error) in
  guard let customModel = customModel else {
    if let error = error {
      print(error)
    }
    return
  }

  print("Model download complete")
  
  // Initialize a DigitClassifier instance
  DigitClassifier.newInstance(modelPath: customModel.path) { result in
  switch result {
    case let .success(classifier):
      self.classifier = classifier
    case .error(_):
      self.resultLabel.text = "Failed to initialize."
    }
  }
}

Esegui nuovamente l'app e assicurati che carichi ancora il modello correttamente.

10. Testare A/B i due modelli

Infine, possiamo utilizzare il comportamento di test A/B integrato di Firebase per vedere quale dei nostri due modelli funziona meglio. Vai ad Analisi -> Eventi nella console Firebase. Se viene visualizzato l'evento correct_inference , contrassegnalo come "Evento di conversione", in caso contrario puoi andare su Analytics -> Eventi di conversione e fare clic su "Crea un nuovo evento di conversione" e inserire correct_inference.

Ora vai su "Remote Config nella console Firebase, seleziona il pulsante "Test A/B" dal menu Altre opzioni sul parametro "nome_modello" che abbiamo appena aggiunto.

fad5ea36969d2aeb.png

Nel menu che segue, accetta il nome predefinito.

d7c006669ace6e40.png

Seleziona la tua app dal menu a discesa e modifica i criteri di targeting al 50% degli utenti attivi.

6246dd7c660b53fb.png

Se in precedenza sei riuscito a impostare l'evento correct_inference come conversione, utilizza questo evento come metrica principale da monitorare. Altrimenti, se non vuoi aspettare che l'evento venga visualizzato in Analytics, puoi aggiungere manualmente correct_inference .

1ac9c94fb3159271.png

Infine, nella schermata Varianti, imposta la variante del tuo gruppo di controllo per utilizzare mnist_v1 e il tuo gruppo Variante A per utilizzare mnist_v2 .

e4510434f8da31b6.png

Fai clic sul pulsante Rivedi nell'angolo in basso a destra.

Congratulazioni, hai creato con successo un test A/B per i tuoi due modelli separati! Il test A/B è attualmente allo stato di bozza e può essere avviato in qualsiasi momento facendo clic sul pulsante "Avvia esperimento".

Per uno sguardo più approfondito ai test A/B, consulta la documentazione sui test A/B .

11. Conclusione

In questo codelab hai imparato come sostituire una risorsa tflite raggruppata staticamente nella tua app con un modello TFLite caricato dinamicamente da Firebase. Per ulteriori informazioni su TFLite e Firebase, dai un'occhiata ad altri esempi di TFLite e alle guide introduttive di Firebase.

Hai una domanda?

Segnala problemi