モデルの 2 つのバージョン間で A/B テストを実施する

新しいカスタムモデルや AutoML Vision Edge モデルをトレーニングしたら、A/B Testing を使用して、すでに使用しているモデルと新しいモデルを比較し、新しいモデルが現実的な条件においてどれだけ適切に動作するかを確認できます。新しいモデルの性能が向上していることを確認したら、アプリをアップデートすることなく、すべてのユーザーに新しいモデルを簡単にロールアウトできます。

このページでは、A/B テストを実施して、架空の植物画像検索機能を提供する 2 つのバージョンのモデルを評価する方法について説明します。この機能では、カスタムの画像ラベル付けモデルを使用して、植物の画像からその種類を特定します。

新しい植物ラベル付けモデル plant_labeler_v2 を公開したばかりで、このモデルと現在のモデル plant_labeler_v1 を比較するテストを実施するとします。以下の手順では、テストをセットアップして実行する方法、ならびに結果に応じてアクションを実行する方法を示します。

1. モデルをリモートで構成可能にする

モデルの A/B テストを実施するための最初のステップはアプリの変更です。Remote Config パラメータを使用するようにアプリを変更し、使用するモデルをこのパラメータで決定します。まず、このパラメータのデフォルト値として、アプリがすでに使用しているモデルを設定します。リモートで構成可能なパラメータによってモデル名を制御できるため、アプリのアップデートをユーザーに push する必要なく、さまざまなモデルに変更してテストできます。

現在のモデルを plant_labeler_v1 という名前で公開している場合は、次の例のように、アプリ初期化コードで plant_labeler_model パラメータのデフォルト値として plant_labeler_v1 を設定します。

Kotlin+KTX

val remoteConfig = FirebaseRemoteConfig.getInstance()

val remoteConfigDefaults = HashMap<String, Any>()
remoteConfigDefaults["plant_labeler_model"] = "plant_labeler_v1"
Tasks.await(remoteConfig.setDefaultsAsync(remoteConfigDefaults))

remoteConfig.fetchAndActivate().addOnSuccessListener { success ->
    if (success) {
      // Okay to get remote values.
      // ...
    }
}

Java

final FirebaseRemoteConfig remoteConfig = FirebaseRemoteConfig.getInstance();

Map<String, Object> remoteConfigDefaults = new HashMap<>();
remoteConfigDefaults.put("plant_labeler_model", "plant_labeler_v1");
Tasks.await(remoteConfig.setDefaultsAsync(remoteConfigDefaults));

remoteConfig.fetchAndActivate().addOnSuccessListener(
        new OnSuccessListener<Boolean>() {
            @Override
            public void onSuccess(Boolean success) {
                if (success) {
                  // Okay to get remote values.
                  // ...
                }
            }
        });

次に、モデル設定コードを変更して、plant_labeler_model パラメータで指定されたモデルを読み込むようにします。

Kotlin+KTX

val rcValue = remoteConfig.getValue("plant_labeler_model")
val remoteModelName = rcValue.asString()

// ...

val remoteModel = FirebaseRemoteModel.Builder(remoteModelName)
        .enableModelUpdates(true)
        .setInitialDownloadConditions(initialConditions)
        .setUpdatesDownloadConditions(updateConditions)
        .build()
FirebaseModelManager.getInstance().registerRemoteModel(remoteModel)

// Optionally configure a local model:
// https://firebase.google.com/docs/ml-kit/android/label-images-with-automl#configure-a-local-model-source
// https://firebase.google.com/docs/ml-kit/android/use-custom-models#configure_a_local_model

Java

FirebaseRemoteConfigValue rcValue = remoteConfig.getValue("plant_labeler_model");
String remoteModelName = rcValue.asString();

// ...

FirebaseRemoteModel remoteModel = new FirebaseRemoteModel.Builder(remoteModelName)
        .enableModelUpdates(true)
        .setInitialDownloadConditions(initialConditions)
        .setUpdatesDownloadConditions(updateConditions)
        .build();
FirebaseModelManager.getInstance().registerRemoteModel(remoteModel);

// Optionally configure a local model:
// https://firebase.google.com/docs/ml-kit/android/label-images-with-automl#configure-a-local-model-source
// https://firebase.google.com/docs/ml-kit/android/use-custom-models#configure_a_local_model

アプリが読み込むモデルを決定する際に Remote Config パラメータを使用するようになったので、新しいモデルを公開し、その名前を Remote Config パラメータに割り当てるだけでモデルを変更できます。この機能により、A/B Testing は異なるユーザーに異なるモデルを割り当ててモデルを比較できます。

続行する前に、モデルのダウンロード コードに次の処理を追加します。

Kotlin+KTX

FirebaseModelManager.getInstance().downloadRemoteModelIfNeeded(remoteModel)
    .addOnSuccessListener {
        // If the model downloaded was specified by a remote parameter, log an
        // event, which will be our experiment's activation event.
        if (rcValue.source == FirebaseRemoteConfig.VALUE_SOURCE_REMOTE) {
            FirebaseAnalytics.getInstance(this).logEvent("nondefault_model_downloaded", null)
        }
    }

Java

FirebaseModelManager.getInstance().downloadRemoteModelIfNeeded(remoteModel)
        .addOnSuccessListener(new OnSuccessListener<Void>() {
            @Override
            public void onSuccess(Void aVoid) {
                // If the model downloaded was specified by a remote parameter, log an
                // event, which will be our experiment's activation event.
                if (rcValue.getSource() == FirebaseRemoteConfig.VALUE_SOURCE_REMOTE) {
                    FirebaseAnalytics.getInstance(YourActivity.this)
                            .logEvent("nondefault_model_downloaded", null);
                }
            }
        });

上記のコードはカスタム アナリティクス イベントをロギングします。このイベントは、後でテストのアクティベーション イベントとして使用されます。アクティベーション イベントとは、ユーザーがテストの参加者としてみなされる条件としてあらかじめトリガーする必要があるイベントです。これにより、ユーザーのデバイスが ML Kit カスタムモデルのダウンロードを完了するまで、そのユーザーが A/B テストに記録されないようにします。

2. 目標指標を決定する

次のステップでは、モデルの成功をどのように測定するかを決定します。また、その指標に従って、モデルのさまざまなバージョンの効果をテストするのに必要なデータをアプリが収集できるようにします。

A/B Testing には、収益、日々のエンゲージメント、ユーザー維持率など、いくつかの組み込み指標があります。これらの指標は、異なる UX フローのテストや、パラメータを微調整する際に役立ちますが、モデルやユースケースを評価する際には役に立たない場合があります。このような場合は、代わりにカスタムのアナリティクス イベントのために最適化を試みます。

たとえば、前に述べた架空の植物画像検索機能を使用して、各結果に含まれるモデルの信頼度の順序で検索結果をユーザーに表示するとします。モデルの精度に関する知見を得る方法の一つとして、ユーザーが最初の検索結果を開いた頻度を調べるという方法が考えられます。

検索結果のクリック数を最大化するという目標が、どちらのモデルによって達成されたかをテストするには、ユーザーが結果リストの最初の項目をタップするたびにカスタム イベントをロギングします。

Kotlin+KTX

FirebaseAnalytics.getInstance(this).logEvent("first_result_opened", null)

Java

FirebaseAnalytics.getInstance(YourActivity.this).logEvent("first_result_opened", null);

テストの指標は、最終的にはアプリがモデルをどのように使用するかによって異なります。

この時点で、Play ストアにアプリをデプロイできます。アプリは引き続き元のモデルを使用しますが、追加した Remote Config とアナリティクスのコードを利用することによって、Firebase コンソールのみを使用してさまざまなモデルをテストできます。

3. A/B Testing テストの実施

これで、アプリがユーザーのデバイスでアナリティクス データを収集するようになりました。現在のモデルではなく新しいモデルを使用してその効果をテストする A/B Testing のテストを作成します。

テストを作成するには:

  1. Firebase コンソールの [イベント] ページで、適切なアナリティクス イベント(アクティベーション イベントと目標指標)がロギングされていることを確認します。

    アプリがイベントを 1 回以上ロギングするまでは、そのイベントは Firebase コンソールに表示されません。

  2. Firebase コンソールで [A/B Testing] セクションを開きます。

  3. 新しいテストを作成します。

    1. [テストを作成] > [Remote Config] をクリックします。

    2. [ターゲット設定] セクションで次の操作を行います。

      • リストからアプリを選択します。
      • テストに含めるユーザー数を指定します。
      • ロギング開始のアクティベーション イベントを選択します(この例では nondefault_model_downloaded)。
    3. [目標] セクションで、前のセクションで指定した目標指標(この例では first_result_opened)を目標指標のリストから選択します。また、追跡したいその他の指標(購入による収益、クラッシュの影響を受けていないユーザーなど)を選択します。

    4. [バリアント] セクションで、次の 2 つのバリアントを定義します。

      • コントロール グループ(自動的に作成)
      • Experimental plant labeler

      コントロール グループでは、plant_labeler_model パラメータを作成し、それに plant_labeler_v1 を設定します。コントロール グループに割り当てられたユーザーは、古いモデルを使用します(アプリではリモート値を使用してテストしているため、パラメータを (no change) に設定しないでください)。

      Experimental plant labeler バリアントでは、plant_labeler_model パラメータに plant_labeler_v2 を設定します(新しいモデルをこの名前で公開していると仮定します)。このバリアントに割り当てられたユーザーは、新しいモデルを使用します。

テストを開始し、A/B Testing で最良のバリアントが判別するまで数日間テストを続けます。最良のバリアントを判別できない場合は、より多くのユーザーにテストを拡大する必要があります。

4. 最良のバリアントをすべてのユーザーにロールアウトする

A/B Testing で十分な情報が収集され、最良のバリアント(ここでは検索結果のクリック数が最も多いバリアント)が判別したら、そのバリアント(あるいは別のバリアント)をすべてのユーザーにロールアウトするかどうかを決定できます。

Firebase コンソールの [A/B Testing] セクションで、完了したテストの詳細ビューを開きます。ここには、選択した目標指標とその他の二次的指標について、各バリアントのパフォーマンスが表示されます。この情報を使って、最良のバリアントをロールアウトするか、または他のバリアントをロールアウトするかを決定できます。

バリアントをすべてのユーザーにロールアウトするには、テストの詳細ページで、 > [バリアントを展開] をクリックします。この操作を行うと、すべてのユーザーの plant_labeler_model パラメータの値が plant_labeler_v2 になります。

新しいモデルを使用する場合は、将来のアプリのアップデートで plant_labeler_model パラメータのデフォルト値を plant_labeler_v2 に変更し、バンドルするモデルを更新する必要があります。ただし、ユーザーはすでに新しいモデルを使用しているため、いつでも都合の良いタイミングで(次回の機能更新など)、このアップデートを公開アプリの一部として push できます。