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

训练新的自定义模型或 AutoML Vision Edge 模型后,您可以使用 A/B 测试来查看新模型与您已经使用的模型相比在现实条件下的表现如何。在您确认您的新模型是一种改进后,您可以轻松地向所有用户推出新模型,而无需更新应用程序。

本页展示了如何进行 A/B 测试,以评估支持假设的视觉植物搜索功能的模型的两个版本。此功能使用自定义图像标记模型来帮助用户从图像中识别植物物种。

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

1. 使您的模型远程可配置

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

因此,如果您以名称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/android/label-images-with-automl#configure-a-local-model-source
// https://firebase.google.com/docs/ml/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/android/label-images-with-automl#configure-a-local-model-source
// https://firebase.google.com/docs/ml/android/use-custom-models#configure_a_local_model

现在您的应用程序使用远程配置参数来确定要加载的模型,您只需发布新模型并将其名称分配给远程配置参数即可更改模型。此功能允许 A/B 测试将不同的模型分配给不同的用户,以便进行比较。

在继续之前,还要在模型下载代码中添加以下内容:

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 事件,您稍后将使用该事件作为实验的激活事件.激活事件是用户在被视为实验的一部分之前必须触发的事件。这可确保用户在设备完成下载自定义 ML 模型之前不会被记录在您的 A/B 测试中。

2. 确定目标指标

下一步是决定如何衡量模型的成功,并确保您的应用程序正在收集必要的数据,以根据该指标测试模型的不同版本的执行情况。

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

以假设的视觉植物搜索功能为例,假设您按照模型对每个结果的置信度的顺序向用户呈现搜索结果。了解模型准确性的一种方法是查看用户打开第一个搜索结果的频率。

为了测试哪个模型最好地实现了最大化顶部结果点击的目标,您将在用户点击结果列表中的第一项时记录一个自定义事件。

Kotlin+KTX

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

Java

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

您测试的指标最终取决于您的应用程序如何使用您的模型。

此时,您可以将应用部署到 Play 商店。您的应用将继续使用您的原始模型,但您添加的远程配置和分析代码将允许您仅使用 Firebase 控制台试验不同的模型。

3. 运行 A/B 测试实验

现在您的应用已在用户手中并正在收集分析数据,请创建一个 A/B 测试实验来测试使用新模型而不是当前模型的效果。

要创建实验:

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

    您的应用需要将每个事件至少记录一次,然后才会出现在 Firebase 控制台中。

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

  3. 创建一个新实验:

    1. 单击创建实验 > 远程配置

    2. 定位部分:

      • 从列表中选择您的应用
      • 指定您希望在实验中包含多少用户
      • 选择您开始记录的激活事件(在本例中为nondefault_model_downloaded
    3. 在“目标”部分中,从目标指标列表中选择您在上一部分中确定的目标指标(在本示例中为first_result_opened ),然后选择您要跟踪的任何其他指标,例如购买收入或无崩溃用户。

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

      • 控制组(自动创建)
      • 实验植物贴标机

      对于Control group ,创建一个plant_labeler_model参数并将其设置为plant_labeler_v1 。分配到控制组的用户将使用旧模型。 (不要将参数设置为(no change) ,因为在您的应用程序中,您正在测试您正在使用远程值。)

      对于Experimental plant labeler 变体,将plant_labeler_model参数设置为plant_labeler_v2 (假设您以该名称发布了新模型)。分配给此变体的用户将使用新模型。

    A/B 测试配置屏幕

开始实验并让它运行几天或更长时间,直到 A/B 测试宣布领导者。如果实验无法确定领导者,您可能需要将实验扩展到更多用户

4. 向所有用户推出获胜的变体

A/B 测试结果卡

在 A/B 测试收集到足够的信息来宣布领导者(在这种情况下,即最大化顶部搜索结果点击次数的变体)之后,您可以决定是否向所有用户推出获胜的变体(或其他变体)。

Firebase 控制台A/B 测试部分,打开已完成实验的详细信息视图。从此视图中,您可以查看每个变体如何根据您的目标指标和您选择的任何辅助指标执行。使用此信息,您可以决定是推出领先变体还是其他变体。

要向所有用户推出变体,请单击实验详细信息页面上的 > 推出变体。一旦这样做,所有用户的plant_labeler_model参数的值将是plant_labeler_v2

在未来的应用程序更新中,您应该将plant_labeler_model参数的默认值更改为plant_labeler_v2并更新捆绑模型(如果您使用一个)。不过,您的用户已经在使用最新型号,因此您可以在方便时将此更新作为已发布应用程序的一部分推送,例如下次进行功能更新时。