Dodaj Firebase do swojej aplikacji na iOS obsługującej TFLite

1. Przegląd

Cele

Firebase ML umożliwia wdrożenie modelu bezprzewodowo. Dzięki temu możesz zachować niewielki rozmiar aplikacji i pobierać model ML tylko w razie potrzeby, eksperymentować z wieloma modelami lub aktualizować model ML bez konieczności ponownego publikowania całej aplikacji.

Podczas tych zajęć z programowania przekonwertujesz aplikację na iOS korzystającą ze statycznego modelu TFLite na aplikację korzystającą z modelu dynamicznie udostępnianego z Firebase. Dowiesz się jak:

  1. Wdrażaj modele TFLite w Firebase ML i uzyskuj do nich dostęp ze swojej aplikacji
  2. Rejestruj metryki związane z modelem za pomocą Analytics
  3. Wybierz model, który ma zostać załadowany poprzez Zdalną konfigurację
  4. Testy A/B różnych modeli

Warunki wstępne

Przed rozpoczęciem ćwiczeń z kodowania upewnij się, że zainstalowałeś:

  • Xcode 11 (lub nowszy)
  • CocoaPods 1.9.1 (lub nowszy)

2. Utwórz projekt konsoli Firebase

Dodaj Firebase do projektu

  1. Przejdź do konsoli Firebase .
  2. Wybierz opcję Utwórz nowy projekt i nazwij swój projekt „Firebase ML iOS Codelab”.

3. Pobierz przykładowy projekt

Pobierz kod

Rozpocznij od sklonowania przykładowego projektu i uruchomienia pod update w katalogu projektu:

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

Jeśli nie masz zainstalowanego gita, możesz także pobrać przykładowy projekt ze strony GitHub lub klikając ten link . Po pobraniu projektu uruchom go w Xcode i pobaw się klasyfikatorem cyfr, aby przekonać się, jak to działa.

Skonfiguruj Firebase

Postępuj zgodnie z dokumentacją , aby utworzyć nowy projekt Firebase. Gdy już masz projekt, pobierz plik GoogleService-Info.plist swojego projektu z konsoli Firebase i przeciągnij go do katalogu głównego projektu Xcode.

f06cb08d48de7e10.png

Dodaj Firebase do swojego Podfile i uruchom instalację pod.

pod 'FirebaseMLModelDownloader', '9.3.0-beta'

W metodzie didFinishLaunchingWithOptions aplikacji AppDelegate zaimportuj Firebase na górze pliku

import FirebaseCore

I dodaj wywołanie, aby skonfigurować Firebase.

FirebaseApp.configure()

Uruchom projekt ponownie, aby upewnić się, że aplikacja jest poprawnie skonfigurowana i nie ulega awarii podczas uruchamiania.

4. Wdróż model w Firebase ML

Wdrażanie modelu w Firebase ML jest przydatne z dwóch głównych powodów:

  1. Możemy zachować niewielki rozmiar instalacji aplikacji i pobrać model tylko w razie potrzeby
  2. Model może być regularnie aktualizowany i mieć inny cykl wydawniczy niż cała aplikacja

Zanim będziemy mogli zastąpić model statyczny w naszej aplikacji modelem pobieranym dynamicznie z Firebase, musimy wdrożyć go w Firebase ML. Model można wdrożyć za pośrednictwem konsoli lub programowo przy użyciu pakietu Firebase Admin SDK. W tym kroku będziemy wdrażać za pośrednictwem konsoli.

Aby wszystko było proste, użyjemy modelu TensorFlow Lite, który jest już w naszej aplikacji. Najpierw otwórz Firebase i kliknij Uczenie maszynowe w lewym panelu nawigacyjnym. Następnie przejdź do opcji „Niestandardowy” i kliknij przycisk „Dodaj model”.

Po wyświetleniu monitu nadaj modelowi opisową nazwę, np. mnist_v1 , i prześlij plik z katalogu projektu codelab.

3c3c50e6ef12b3b.png

5. Pobierz model z Firebase ML

Wybór momentu pobrania zdalnego modelu z Firebase do aplikacji może być trudny, ponieważ modele TFLite mogą rosnąć stosunkowo duże. W idealnym przypadku chcielibyśmy uniknąć ładowania modelu natychmiast po uruchomieniu aplikacji, ponieważ jeśli nasz model będzie używany tylko do jednej funkcji, a użytkownik nigdy z niej nie skorzysta, pobierzemy znaczną ilość danych bez powodu. Możemy również ustawić opcje pobierania, takie jak pobieranie modeli tylko po podłączeniu do Wi-Fi. Jeśli chcesz mieć pewność, że model będzie dostępny nawet bez połączenia sieciowego, powinieneś również dołączyć model jako część aplikacji jako kopię zapasową.

Dla uproszczenia usuniemy domyślny model w pakiecie i zawsze pobierzemy model z Firebase po uruchomieniu aplikacji. W ten sposób podczas rozpoznawania cyfr możesz mieć pewność, że wnioskowanie działa na podstawie modelu dostarczonego z Firebase.

Na górze ModelLoader.swift zaimportuj moduł Firebase.

import FirebaseCore
import FirebaseMLModelDownloader

Następnie zaimplementuj następującą metodę.

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

W viewDidLoad pliku ViewController.swift zastąp wywołanie inicjujące DigitClassifier naszą nową metodą pobierania modelu.

    // 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."
        }
      }
    }

Uruchom ponownie aplikację. Po kilku sekundach powinieneś zobaczyć log w Xcode wskazujący, że zdalny model został pomyślnie pobrany. Spróbuj narysować cyfrę i sprawdź, czy zachowanie aplikacji się nie zmieniło.

6. Śledź opinie użytkowników i konwersję, aby mierzyć dokładność modelu

Dokładność modelu będziemy mierzyć, śledząc opinie użytkowników na temat przewidywań modelu. Jeśli użytkownik kliknie „tak”, będzie to oznaczać, że prognoza była trafna.

Możemy rejestrować zdarzenia Analytics, aby śledzić dokładność naszego modelu. Najpierw musimy dodać Analytics do Podfile, zanim będzie można go wykorzystać w projekcie:

pod 'FirebaseAnalytics'

Następnie w ViewController.swift zaimportuj Firebase na górze pliku

import FirebaseAnalytics

I dodaj następujący wiersz kodu w metodzie correctButtonPressed .

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

Uruchom aplikację ponownie i narysuj cyfrę. Naciśnij kilka razy przycisk „Tak”, aby przesłać informację zwrotną potwierdzającą, że wnioski były trafne.

Analityka debugowania

Ogólnie rzecz biorąc, zdarzenia rejestrowane przez Twoją aplikację są grupowane w okresie około jednej godziny i przesyłane razem. Takie podejście oszczędza baterię urządzeń użytkowników końcowych i zmniejsza zużycie danych w sieci. Jednakże w celu sprawdzenia poprawności implementacji analiz (oraz w celu wyświetlenia statystyk w raporcie DebugView) możesz włączyć tryb debugowania na swoim urządzeniu programistycznym, aby przesyłać zdarzenia z minimalnym opóźnieniem.

Aby włączyć tryb debugowania Analytics na urządzeniu programistycznym, określ następujący argument wiersza poleceń w Xcode:

-FIRDebugEnabled

Uruchom aplikację ponownie i narysuj cyfrę. Naciśnij kilka razy przycisk „Tak”, aby przesłać informację zwrotną potwierdzającą, że wnioski były trafne. Teraz możesz przeglądać zdarzenia w dzienniku w czasie zbliżonym do rzeczywistego, korzystając z widoku debugowania w konsoli Firebase. Kliknij Analytics > DebugView na lewym pasku nawigacyjnym.

5276199a086721fd.png

7. Śledź czas wnioskowania za pomocą Firebase Performance

Podczas testowania modelu wskaźniki wydajności wykonane na urządzeniach programistycznych nie są wystarczające, aby określić, jak model będzie działać w rękach użytkowników, ponieważ trudno jest określić, na jakim sprzęcie użytkownicy będą uruchamiać Twoją aplikację. Na szczęście możesz mierzyć wydajność swojego modelu na urządzeniach użytkowników za pomocą Firebase Performance, aby uzyskać lepszy obraz wydajności swojego modelu.

Aby zmierzyć czas potrzebny na uruchomienie wnioskowania, najpierw zaimportuj Firebase w pliku DigitClassifier.swift:

import FirebasePerformance

Następnie rozpocznij śledzenie wydajności w metodzie classify i zatrzymaj śledzenie po zakończeniu wnioskowania. Upewnij się, że dodałeś następujące wiersze kodu wewnątrz zamknięcia DispatchQueue.global.async, a nie bezpośrednio pod deklaracją metody.

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

Jeśli jesteś ciekawy, możesz włączyć rejestrowanie debugowania, korzystając z instrukcji tutaj, aby potwierdzić rejestrowanie śladów wydajności. Po chwili ślady wydajności będą widoczne również w konsoli Firebase.

8. Wdróż drugi model w Firebase ML

Tworząc nową wersję modelu, na przykład z lepszą architekturą modelu lub wyszkoloną na większym lub zaktualizowanym zbiorze danych, możemy poczuć pokusę zastąpienia naszego obecnego modelu nową wersją. Jednak model dobrze radzący sobie w testach niekoniecznie radzi sobie równie dobrze w produkcji. Dlatego wykonajmy testy A/B na produkcji, aby porównać nasz oryginalny model z nowym.

Włącz interfejs API zarządzania modelem Firebase

Na tym etapie umożliwimy interfejsowi API Firebase Model Management wdrożenie nowej wersji naszego modelu TensorFlow Lite przy użyciu kodu Python.

Utwórz zasobnik do przechowywania modeli uczenia maszynowego

W konsoli Firebase przejdź do opcji Pamięć i kliknij Rozpocznij. fbbea78f0eb3dc9f.png

Postępuj zgodnie z instrukcjami, aby skonfigurować wiadro.

19517c0d6d2aa14d.png

Włącz interfejs API Firebase ML

Przejdź do strony Firebase ML API w Google Cloud Console i kliknij Włącz.

2414fd5cced6c984.png Gdy zostaniesz o to poproszony, wybierz aplikację Digit Classifier.

Teraz przeszkolimy nową wersję modelu przy użyciu większego zestawu danych, a następnie wdrożymy go programowo bezpośrednio z notatnika szkoleniowego przy użyciu pakietu Firebase Admin SDK.

Pobierz klucz prywatny dla konta usługi

Zanim będziemy mogli korzystać z pakietu Firebase Admin SDK, musimy utworzyć konto usługi. Otwórz panel Konta usług w konsoli Firebase, klikając ten link i kliknij przycisk, aby utworzyć nowe konto usługi dla pakietu Firebase Admin SDK. Po wyświetleniu monitu kliknij przycisk Wygeneruj nowy klucz prywatny. Będziemy używać klucza konta usługi do uwierzytelniania naszych żądań z notatnika Colab.

c3b95de1e5508516.png

Teraz możemy wytrenować i wdrożyć nowy model.

  1. Otwórz ten notatnik Colab i utwórz jego kopię na swoim dysku.
  2. Uruchom pierwszą komórkę „Wytrenuj ulepszony model TensorFlow Lite”, klikając przycisk odtwarzania po lewej stronie. Spowoduje to wytrenowanie nowego modelu i może zająć trochę czasu.
  3. Uruchomienie drugiej komórki spowoduje wyświetlenie monitu o przesłanie pliku. Prześlij plik json pobrany z konsoli Firebase podczas tworzenia konta usługi.

71e847c6a85423b3.png

  1. Uruchom dwie ostatnie komórki.

Po uruchomieniu notatnika colab powinieneś zobaczyć drugi model w konsoli Firebase. Upewnij się, że drugi model ma nazwę mnist_v2 .

c316683bb4d75d57.png

9. Wybierz model poprzez Zdalną konfigurację

Teraz, gdy mamy dwa oddzielne modele, dodamy parametr umożliwiający wybranie modelu do pobrania w czasie wykonywania. Wartość parametru, którą otrzyma klient, określi, który model klient pobierze. Najpierw otwórz konsolę Firebase i kliknij przycisk Zdalna konfiguracja w lewym menu nawigacyjnym. Następnie kliknij przycisk „Dodaj parametr”.

Nazwij nowy parametr model_name i nadaj mu wartość domyślną mnist_v1 . Kliknij Opublikuj zmiany , aby zastosować aktualizacje. Umieszczając nazwę modelu w parametrze zdalnej konfiguracji, możemy przetestować wiele modeli bez dodawania nowego parametru dla każdego modelu, który chcemy przetestować.

Po dodaniu parametru powinieneś zobaczyć go w Konsoli:

699b3fd32acce887.png

W naszym kodzie będziemy musieli dodać kontrolę podczas ładowania zdalnego modelu. Kiedy otrzymamy parametr z Remote Config, pobierzemy zdalny model z odpowiednią nazwą; w przeciwnym razie spróbujemy załadować mnist_v1 . Zanim będziemy mogli użyć Remote Config, musimy dodać go do naszego projektu, określając go jako zależność w Podfile:

pod 'FirebaseRemoteConfig'

Uruchom instalację pod i ponownie otwórz projekt Xcode. W ModelLoader.swift zaimplementuj metodę 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)
    }
  }
}

Na koniec w ViewController.swift zastąp wywołanie downloadModel nową metodą, którą właśnie zaimplementowaliśmy.

// 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."
    }
  }
}

Uruchom aplikację ponownie i upewnij się, że nadal poprawnie ładuje model.

10. Test A/B obu modeli

Wreszcie możemy użyć wbudowanego w Firebase testu A/B, aby sprawdzić, który z naszych dwóch modeli działa lepiej. Przejdź do Analytics -> Zdarzenia w konsoli Firebase. Jeśli wyświetla się zdarzenie correct_inference , oznacz je jako „Zdarzenie konwersji”. Jeśli nie, możesz przejść do Analityka -> Zdarzenia konwersji i kliknąć „Utwórz nowe zdarzenie konwersji” i zapisać correct_inference.

Teraz przejdź do „Zdalnej konfiguracji” w konsoli Firebase, wybierz przycisk „Test A/B” z menu więcej opcji w właśnie dodanym parametrze „nazwa_modelu”.

fad5ea36969d2aeb.png

W następnym menu zaakceptuj domyślną nazwę.

d7c006669ace6e40.png

Wybierz swoją aplikację z menu rozwijanego i zmień kryteria kierowania na 50% aktywnych użytkowników.

6246dd7c660b53fb.png

Jeśli udało Ci się wcześniej ustawić zdarzenie correct_inference jako konwersję, użyj tego zdarzenia jako podstawowego wskaźnika do śledzenia. W przeciwnym razie, jeśli nie chcesz czekać, aż zdarzenie pojawi się w Analytics, możesz ręcznie dodać correct_inference .

1ac9c94fb3159271.png

Na koniec na ekranie Warianty ustaw wariant grupy kontrolnej na użycie mnist_v1 i grupę Wariant A na używanie mnist_v2 .

e4510434f8da31b6.png

Kliknij przycisk Recenzja w prawym dolnym rogu.

Gratulacje, pomyślnie utworzyłeś test A/B dla swoich dwóch oddzielnych modeli! Test A/B jest obecnie w wersji roboczej i można go rozpocząć w dowolnym momencie, klikając przycisk „Rozpocznij eksperyment”.

Aby bliżej przyjrzeć się testom A/B, zapoznaj się z dokumentacją testów A/B .

11. Wniosek

Podczas tych ćwiczeń z programowania nauczyłeś się, jak zastąpić statycznie powiązany zasób tflite w swojej aplikacji dynamicznie ładowanym modelem TFLite z Firebase. Aby dowiedzieć się więcej o TFLite i Firebase, zapoznaj się z innymi przykładami TFLite i przewodnikami wprowadzającymi do Firebase.

Mam pytanie?

Zgłoś problemy