对模型的两个版本进行 A/B 测试

在您训练新的自定义模型或 AutoML Vision Edge 模型后,您可以使用 A/B Testing 来查看新模型与现有模型相比在实际情况下的效果。在确认新模型的确有所改进后,您可以轻松向所有用户发布新模型,而无需更新应用。

本页面介绍了如何进行 A/B 测试,以评估提供假想的植物图片搜索功能的两个模型版本。此功能使用自定义图片标签模型,帮助用户根据植物的图片来识别植物种类。

假设您刚刚发布了一个新的植物标签模型 plant_labeler_v2,想要运行一个实验,将新模型与名为 plant_labeler_v1 的当前模型进行比较。下面的步骤展示了如何设置实验、运行实验以及根据结果采取措施。

1. 将模型设置为支持远程配置

对模型进行 A/B 测试的第一步是修改您的应用,以使用 Remote Config 参数来确定应用采用的模型。最初,您需要将此参数的默认值设置为应用已经在使用的模型,但由于模型名称是由可远程配置的参数进行控制,因此您可以更改和试验不同的模型,而无需每次向您的用户推送应用更新。

所以,如果您以名称 plant_labeler_v1 发布当前模型,则应在应用初始化代码中将 plant_labeler_v1 设置为 plant_labeler_model 参数的默认值,如以下示例所示:

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

上面的代码记录了您稍后将用作实验的激活事件的自定义 Analytics 事件。激活事件是指用户在被视为参与实验之前必须触发的事件。这可确保用户在其设备下载完自定义机器学习套件模型之前不会被记录在 A/B 测试中。

2. 确定目标指标

下一步是决定如何衡量模型的成效,并确保您的应用正在收集根据该目标指标测试模型不同版本的表现效果所必需的数据。

A/B Testing 有几个内置指标,包括收入、日常互动和用户留存率。这些指标通常对测试不同的用户体验流程或微调参数很有用,但对评估您的模型和用例也许没有意义。在这种情况下,您可以改为尝试针对一个自定义 Analytics 事件进行优化。

以假想的植物图片搜索功能为例,假设您按照每个结果中模型的置信度排序向用户显示搜索结果。了解模型准确率的一种方式是查看用户打开首条搜索结果的频率。

为了测试哪个模型在实现“获得最高的首条结果点击率”这一目标时的表现最佳,每次用户点按结果列表中的第一项,您就记录一次自定义事件。

Kotlin+KTX

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

Java

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

您测试的指标最终取决于您的应用使用模型的方式。

此时,您可以将应用部署到 Play 商店。您的应用将继续使用原始模型,但您添加的 Remote Config 和 Analytics 代码可让您仅使用 Firebase 控制台来实验不同的模型。

3. 运行 A/B Testing 实验

现在您的应用已被用户使用并正在收集分析数据,接下来,创建一个 A/B Testing 实验以测试使用新模型代替当前模型的效果。

创建实验的步骤如下:

  1. Firebase 控制台的事件页面上,确认您正在记录相关 Analytics 事件:激活事件和目标指标。

    您的应用至少需记录一次上述每一种事件,之后相应事件才会显示在 Firebase 控制台中。

  2. Firebase 控制台中,打开 A/B Testing 部分。

  3. 创建新实验:

    1. 依次点击创建实验 > Remote Config

    2. 定位部分:

      • 从列表中选择您的应用
      • 指定您想要纳入实验中的用户数量
      • 选择您开始记录的激活事件(在此示例中为 nondefault_model_downloaded
    3. 目标部分,从目标指标列表中选择您在上一部分确定的目标指标(在此示例中为 first_result_opened),然后选择您要跟踪的任何其他指标,例如销售收入或未遇到崩溃问题的用户数。

    4. 变体部分,定义两个变体:

      • 对照组(自动创建)
      • 实验性植物标记器

      对于对照组,创建一个 plant_labeler_model 参数并将其设置为 plant_labeler_v1。分配给对照组的用户将使用旧模型。(请不要将该参数设置为 (no change),因为在您的应用中,您要测试的是使用远程值的情况。)

      对于实验性植物标记器变体,将 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 并对捆绑模型进行更新(如果使用捆绑模型)。不过,您的用户已经在使用最新模型,因此您可以在方便的时候将此更新作为已发布应用的一部分推送,例如在下一次更新功能时推送。