TFLite を利用した iOS アプリに Firebase を追加する

1。概要

目標

Firebase ML を使用すると、モデルを無線でデプロイできます。これにより、アプリのサイズを小さく保ち、必要な場合にのみ ML モデルをダウンロードしたり、複数のモデルを試したり、アプリ全体を再公開することなく ML モデルを更新したりすることができます。

このコードラボでは、静的な TFLite モデルを使用する iOS アプリを、Firebase から動的に提供されるモデルを使用するアプリに変換します。次の方法を学習します:

  1. TFLite モデルを Firebase ML にデプロイし、アプリからアクセスする
  2. Analytics を使用してモデル関連のメトリクスをログに記録する
  3. Remote Config を通じてロードされるモデルを選択します
  4. さまざまなモデルの A/B テスト

前提条件

このコードラボを開始する前に、以下がインストールされていることを確認してください。

  • Xcode 11 (またはそれ以降)
  • CocoaPods 1.9.1 (またはそれ以降)

2. Firebaseコンソールプロジェクトを作成する

Firebaseをプロジェクトに追加する

  1. Firebase コンソールに移動します。
  2. [新しいプロジェクトの作成]を選択し、プロジェクトに「Firebase ML iOS Codelab」という名前を付けます。

3. サンプルプロジェクトを入手する

コードをダウンロードする

まず、サンプル プロジェクトのクローンを作成し、プロジェクト ディレクトリでpod updateを実行します。

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

git がインストールされていない場合は、GitHub ページから、またはこのリンクをクリックしてサンプル プロジェクトをダウンロードすることもできます。プロジェクトをダウンロードしたら、それを Xcode で実行し、数字分類子を試して、その仕組みを感じてください。

Firebaseをセットアップする

ドキュメントに従って、新しい Firebase プロジェクトを作成します。プロジェクトを取得したら、プロジェクトのGoogleService-Info.plistファイルをFirebase コンソールからダウンロードし、Xcode プロジェクトのルートにドラッグします。

f06cb08d48de7e10.png

Firebase を Podfile に追加し、pod install を実行します。

pod 'FirebaseMLModelDownloader', '9.3.0-beta'

AppDelegatedidFinishLaunchingWithOptionsメソッドで、ファイルの先頭に Firebase をインポートします。

import FirebaseCore

そして、Firebase を設定するための呼び出しを追加します。

FirebaseApp.configure()

プロジェクトを再度実行して、アプリが正しく構成されており、起動時にクラッシュしないことを確認します。

4. モデルを Firebase ML にデプロイする

モデルを Firebase ML にデプロイすると、主に次の 2 つの理由で役立ちます。

  1. アプリのインストール サイズを小さく保ち、必要な場合にのみモデルをダウンロードできます。
  2. モデルは定期的に更新でき、アプリ全体とは異なるリリース サイクルで更新できます。

アプリ内の静的モデルを Firebase から動的にダウンロードしたモデルに置き換える前に、それを Firebase ML にデプロイする必要があります。モデルは、コンソール経由で、または Firebase Admin SDK を使用してプログラムでデプロイできます。このステップでは、コンソール経由でデプロイします。

物事を簡単にするために、アプリにすでに含まれている TensorFlow Lite モデルを使用します。まず、Firebase を開き、左側のナビゲーション パネルで [Machine Learning] をクリックします。次に、「カスタム」に移動し、「モデルの追加」ボタンをクリックします。

プロンプトが表示されたら、モデルにmnist_v1のようなわかりやすい名前を付け、コードラボ プロジェクト ディレクトリからファイルをアップロードします。

3c3c50e6ef12b3b.png

5. Firebase ML からモデルをダウンロードする

TFLite モデルは比較的大きくなる可能性があるため、Firebase からアプリにリモート モデルをいつダウンロードするかを選択するのは難しい場合があります。理想的には、アプリの起動時にすぐにモデルをロードすることは避けたいと考えています。モデルが 1 つの機能のみに使用され、ユーザーがその機能をまったく使用しない場合、理由もなく大量のデータがダウンロードされることになるからです。 Wi-Fi 接続時にのみモデルを取得するなどのダウンロード オプションを設定することもできます。ネットワーク接続がなくてもモデルを利用できるようにしたい場合は、バックアップとしてモデルをアプリの一部としてバンドルする必要もあります。

わかりやすくするために、デフォルトのバンドル モデルを削除し、アプリの起動時に常に Firebase からモデルをダウンロードします。こうすることで、数字認識を実行するときに、Firebase から提供されたモデルを使用して推論が実行されていることを確認できます。

ModelLoader.swiftの先頭で、Firebase モジュールをインポートします。

import FirebaseCore
import FirebaseMLModelDownloader

次に、次のメソッドを実装します。

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

ViewController.swiftviewDidLoadで、 DigitClassifier 初期化呼び出しを新しいモデル ダウンロード メソッドに置き換えます。

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

アプリを再実行します。数秒後、リモート モデルが正常にダウンロードされたことを示すログが Xcode に表示されます。数字を描いてみて、アプリの動作が変わっていないことを確認してください。

6. ユーザーのフィードバックとコンバージョンを追跡してモデルの精度を測定する

モデルの予測に関するユーザーのフィードバックを追跡することで、モデルの精度を測定します。ユーザーが「はい」をクリックすると、予測が正確であったことが示されます。

Analytics イベントをログに記録して、モデルの精度を追跡できます。まず、プロジェクトで使用する前に、Analytics を Podfile に追加する必要があります。

pod 'FirebaseAnalytics'

次にViewController.swiftで、ファイルの先頭に Firebase をインポートします

import FirebaseAnalytics

そして、 correctButtonPressedメソッドに次のコード行を追加します。

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

アプリを再度実行し、数字を描画します。 「はい」ボタンを数回押して、推論が正確であるというフィードバックを送信します。

デバッグ分析

通常、アプリによって記録されたイベントは、約 1 時間にわたってまとめられ、一緒にアップロードされます。このアプローチにより、エンド ユーザーのデバイスのバッテリーが節約され、ネットワーク データの使用量が削減されます。ただし、分析の実装を検証する目的 (および DebugView レポートで分析を表示するため) を目的として、開発デバイスでデバッグ モードを有効にして、最小限の遅延でイベントをアップロードできます。

開発デバイスで Analytics デバッグ モードを有効にするには、Xcode で次のコマンド ライン引数を指定します。

-FIRDebugEnabled

アプリを再度実行し、数字を描画します。 「はい」ボタンを数回押して、推論が正確であるというフィードバックを送信します。 Firebase コンソールのデバッグ ビューを介して、ほぼリアルタイムでログ イベントを表示できるようになりました。左側のナビゲーション バーから [Analytics] > [DebugView] をクリックします。

5276199a086721fd.png

7. Firebase Performance で推論時間を追跡する

モデルをテストする場合、ユーザーがどのハードウェアでアプリを実行するかを知るのは難しいため、開発デバイスで作成されたパフォーマンス メトリックだけでは、モデルがユーザーの手に渡ってどのように動作するかを把握するのに十分ではありません。幸いなことに、Firebase Performance を使用してユーザーのデバイスでモデルのパフォーマンスを測定し、モデルのパフォーマンスをより正確に把握できます。

推論の実行にかかる時間を測定するには、まず DigitClassifier.swift に Firebase をインポートします。

import FirebasePerformance

次に、classify メソッドでパフォーマンス トレースを開始し、推論が完了したらトレースを停止します。次のコード行を、メソッド宣言の直下ではなく、DispatchQueue.global.async クロージャー内に追加してください。

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

興味がある場合は、ここの手順に従ってデバッグ ログを有効にして、パフォーマンス トレースがログに記録されていることを確認できます。しばらくすると、パフォーマンス トレースが Firebase コンソールにも表示されるようになります。

8. 2 番目のモデルを Firebase ML にデプロイする

より優れたモデル アーキテクチャを備えたモデルや、より大規模なデータセットまたは更新されたデータセットでトレーニングされたモデルなど、モデルの新しいバージョンを思いついたとき、現在のモデルを新しいバージョンに置き換えたくなるかもしれません。ただし、テストで良好なパフォーマンスを発揮したモデルが、本番環境でも同様に良好なパフォーマンスを発揮するとは限りません。したがって、本番環境で A/B テストを実行して、元のモデルと新しいモデルを比較してみましょう。

Firebase モデル管理 API を有効にする

このステップでは、Firebase Model Management API を有効にして、Python コードを使用して TensorFlow Lite モデルの新しいバージョンをデプロイします。

ML モデルを保存するバケットを作成する

Firebase コンソールで、[ストレージ] に移動し、[開始する] をクリックします。 fbbea78f0eb3dc9f.png

ダイアログに従ってバケットを設定します。

19517c0d6d2aa14d.png

Firebase ML API を有効にする

Google Cloud Console のFirebase ML API ページに移動し、[有効にする] をクリックします。

2414fd5cced6c984.png尋ねられたら、Digit Classifier アプリを選択します。

次に、より大きなデータセットを使用して新しいバージョンのモデルをトレーニングし、Firebase Admin SDK を使用してトレーニング ノートブックからプログラムで直接デプロイします。

サービスアカウントの秘密キーをダウンロードする

Firebase Admin SDK を使用する前に、サービス アカウントを作成する必要があります。このリンクをクリックして Firebase コンソールの [サービス アカウント] パネルを開き、ボタンをクリックして Firebase Admin SDK の新しいサービス アカウントを作成します。プロンプトが表示されたら、「新しい秘密キーを生成」ボタンをクリックします。 colab ノートブックからのリクエストを認証するためにサービス アカウント キーを使用します。

c3b95de1e5508516.png

これで、新しいモデルをトレーニングしてデプロイできるようになりました。

  1. このcolab ノートブックを開いて、自分のドライブにコピーを作成します。
  2. 最初のセル「改良された TensorFlow Lite モデルのトレーニング」の左側にある再生ボタンをクリックして実行します。これにより新しいモデルがトレーニングされるため、時間がかかる場合があります。
  3. 2 番目のセルを実行すると、ファイルのアップロード プロンプトが作成されます。サービス アカウントの作成時に Firebase コンソールからダウンロードした json ファイルをアップロードします。

71e847c6a85423b3.png

  1. 最後の 2 つのセルを実行します。

colab ノートブックを実行すると、Firebase コンソールに 2 番目のモデルが表示されるはずです。 2 番目のモデルの名前がmnist_v2であることを確認します。

c316683bb4d75d57.png

9. Remote Config でモデルを選択します

2 つの別々のモデルができたので、実行時にどちらのモデルをダウンロードするかを選択するためのパラメーターを追加します。クライアントが受け取るパラメータの値によって、クライアントがダウンロードするモデルが決まります。まず、Firebase コンソールを開き、左側のナビゲーション メニューにある [Remote Config] ボタンをクリックします。次に、「パラメータの追加」ボタンをクリックします。

新しいパラメーターにmodel_nameという名前を付け、デフォルト値のmnist_v1を指定します。 「変更の公開」をクリックして更新を適用します。モデルの名前をリモート構成パラメーターに入れることで、テストしたいモデルごとに新しいパラメーターを追加することなく、複数のモデルをテストできます。

パラメータを追加すると、コンソールにパラメータが表示されます。

699b3fd32acce887.png

私たちのコードでは、リモート モデルをロードするときにチェックを追加する必要があります。 Remote Config からパラメータを受け取ると、対応する名前のリモート モデルを取得します。それ以外の場合は、 mnist_v1をロードしようとします。 Remote Config を使用する前に、Podfile で依存関係として指定してプロジェクトに追加する必要があります。

pod 'FirebaseRemoteConfig'

pod install を実行し、Xcode プロジェクトを再度開きます。 ModelLoader.swiftで、 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)
    }
  }
}

最後に、 ViewController.swiftで、 downloadModel呼び出しを実装したばかりの新しいメソッドに置き換えます。

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

アプリを再実行し、モデルが正しく読み込まれていることを確認します。

10. 2 つのモデルの A/B テスト

最後に、Firebase の組み込み A/B テスト動作を使用して、2 つのモデルのどちらのパフォーマンスが優れているかを確認できます。 Firebase コンソールで [分析] -> [イベント] に移動します。 correct_inferenceイベントが表示されている場合は、「コンバージョン イベント」としてマークします。表示されていない場合は、「分析」→「コンバージョン イベント」に移動し、「新しいコンバージョン イベントの作成」をクリックして、 correct_inference.

次に、Firebase コンソールの「Remote Config」に移動し、先ほど追加した「model_name」パラメータのその他のオプション メニューから「A/B テスト」ボタンを選択します。

fad5ea36969d2aeb.png

続くメニューでは、デフォルトの名前を受け入れます。

d7c006669ace6e40.png

ドロップダウンでアプリを選択し、ターゲティング基準をアクティブ ユーザーの 50% に変更します。

6246dd7c660b53fb.png

以前にcorrect_inferenceイベントをコンバージョンとして設定できた場合は、このイベントを追跡する主要な指標として使用します。それ以外の場合、Analytics にイベントが表示されるまで待ちたくない場合は、 correct_inference手動で追加できます。

1ac9c94fb3159271.png

最後に、[バリアント]画面で、コントロール グループのバリアントがmnist_v1を使用するように設定し、バリアント A グループがmnist_v2を使用するように設定します。

e4510434f8da31b6.png

右下隅にある「レビュー」ボタンをクリックします。

おめでとうございます。2 つの異なるモデルの A/B テストが正常に作成されました。 A/B テストは現在ドラフト状態にあり、[実験を開始] ボタンをクリックすることでいつでも開始できます。

A/B テストの詳細については、 A/B テストのドキュメントを参照してください。

11. 結論

このコードラボでは、アプリ内の静的にバンドルされた tflite アセットを、Firebase から動的にロードされた TFLite モデルに置き換える方法を学習しました。 TFLite と Firebase について詳しくは、他の TFLite サンプルと Firebase スタート ガイドをご覧ください。

質問があります?

問題を報告する