将 Firebase 添加到基于 TFLite 的 iOS 应用中

一、概述

目标

Firebase ML 使您能够无线部署模型。这使您可以保持较小的应用程序大小并仅在需要时下载 ML 模型、试验多个模型或更新您的 ML 模型而无需重新发布整个应用程序。

在此 Codelab 中,您会将使用静态 TFLite 模型的 iOS 应用程序转换为使用从 Firebase 动态提供的模型的应用程序。你将学到如何:

  1. 将 TFLite 模型部署到 Firebase ML 并从您的应用访问它们
  2. 使用 Analytics 记录与模型相关的指标
  3. 选择通过 Remote Config 加载哪个模型
  4. A/B 测试不同的模型

先决条件

在开始此 Codelab 之前,请确保您已安装:

  • 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文件并将其拖到 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 非常有用,主要有两个原因:

  1. 我们可以保持应用程序安装较小,只在需要时下载模型
  2. 该模型可以定期更新,并且具有与整个应用程序不同的发布周期

在我们用从 Firebase 动态下载的模型替换我们应用程序中的静态模型之前,我们需要将它部署到 Firebase ML。该模型可以通过控制台部署,也可以使用 Firebase Admin SDK 以编程方式部署。在此步骤中,我们将通过控制台进行部署。

为简单起见,我们将使用应用程序中已有的 TensorFlow Lite 模型。首先,打开 Firebase 并单击左侧导航面板中的机器学习。然后导航到“自定义”并单击“添加模型”按钮。

出现提示时,为模型指定一个描述性名称,例如mnist_v1 ,然后从 Codelab 项目目录上传文件。

3c3c50e6ef12b3b.png

5. 从 Firebase ML 下载模型

选择何时将远程模型从 Firebase 下载到您的应用程序可能会很棘手,因为 TFLite 模型可能会变得相对较大。理想情况下,我们希望避免在应用程序启动时立即加载模型,因为如果我们的模型仅用于一个功能而用户从未使用该功能,我们将无缘无故地下载大量数据。我们还可以设置下载选项,例如仅在连接到 wifi 时获取模型。如果要确保模型即使在没有网络连接的情况下也可用,您还应该将模型捆绑为应用程序的一部分作为备份。

为了简单起见,我们将删除默认的捆绑模型,并在应用启动时始终从 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)

再次运行应用程序并绘制一个数字。按几次“是”按钮以发送推断准确的反馈。

调试分析

通常,您的应用程序记录的事件会在大约一小时的时间内集中在一起并一起上传。这种方法可以节省最终用户设备的电池电量并减少网络数据使用量。但是,为了验证您的分析实施(以及为了在 DebugView 报告中查看您的分析),您可以在您的开发设备上启用调试模式,以便以最小的延迟上传事件。

要在您的开发设备上启用 Analytics 调试模式,请在 Xcode 中指定以下命令行参数:

-FIRDebugEnabled

再次运行应用程序并绘制一个数字。按几次“是”按钮以发送推断准确的反馈。现在,您可以通过 Firebase 控制台中的调试视图近乎实时地查看日志事件。单击左侧导航栏中的 Analytics > DebugView。

5276199a086721fd.png

7. 使用 Firebase Performance 跟踪推理时间

在测试您的模型时,在开发设备上制定的性能指标不足以捕捉模型在用户手中的表现,因为很难判断用户将在哪些硬件上运行您的应用程序。幸运的是,您可以使用 Firebase Performance 测量模型在用户设备上的性能,以更好地了解模型的性能。

要测量运行推理所需的时间,首先在 DigitClassifier.swift 中导入 Firebase:

import FirebasePerformance

然后在分类方法中启动性能跟踪,并在推理完成时停止跟踪。确保在 DispatchQueue.global.async 闭包中添加以下代码行,而不是直接在方法声明下方。

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

如果您好奇,您可以通过此处的说明启用调试日志记录,以确认您的性能跟踪已被记录。一段时间后,性能跟踪也将在 Firebase 控制台中可见。

8. 将第二个模型部署到 Firebase ML

当提出模型的新版本时,例如具有更好模型架构的模型或在更大或更新的数据集上训练的模型,我们可能会想用新版本替换我们当前的模型。但是,在测试中表现良好的模型在生产中不一定表现得同样好。因此,让我们在生产中进行 A/B 测试,以比较我们的原始模型和新模型。

启用 Firebase 模型管理 API

在此步骤中,我们将启用 Firebase 模型管理 API,以使用 Python 代码部署新版本的 TensorFlow Lite 模型。

创建存储桶来存储您的 ML 模型

在您的 Firebase 控制台中,转到存储并单击开始。 fbbea78f0eb3dc9f.png

按照对话设置您的存储桶。

19517c0d6d2aa14d.png

启用 Firebase ML API

转到 Google Cloud Console 上的Firebase ML API 页面,然后单击启用。

2414fd5cced6c984.png询问时选择数字分类器应用程序。

现在我们将使用更大的数据集训练模型的新版本,然后我们将使用 Firebase Admin SDK 直接从训练笔记本以编程方式部署它。

下载服务帐户的私钥

在使用 Firebase Admin SDK 之前,我们需要创建一个服务帐户。单击此链接打开 Firebase 控制台的服务帐户面板,然后单击按钮为 Firebase Admin SDK 创建一个新的服务帐户。出现提示时,单击“生成新私钥”按钮。我们将使用服务帐户密钥来验证来自 colab notebook 的请求。

c3b95de1e5508516.png

现在我们可以训练和部署新模型了。

  1. 打开这个colab notebook ,在你自己的 Drive 下复制一份。
  2. 通过单击左侧的播放按钮运行第一个单元格“Train an improved TensorFlow Lite model”。这将训练一个新模型,可能需要一些时间。
  3. 运行第二个单元将创建一个文件上传提示。上传您在创建服务帐户时从 Firebase 控制台下载的 json 文件。

71e847c6a85423b3.png

  1. 运行最后两个单元格。

运行 colab notebook 后,您应该会在 Firebase 控制台中看到第二个模型。确保第二个模型命名为mnist_v2

c316683bb4d75d57.png

9.通过远程配置选择模型

现在我们有两个独立的模型,我们将添加一个参数来选择在运行时下载哪个模型。客户端收到的参数值将决定客户端下载哪个模型。首先,打开 Firebase 控制台并单击左侧导航菜单中的远程配置按钮。然后,单击“添加参数”按钮。

将新参数命名为model_name并为其指定默认值mnist_v1 。单击发布更改以应用更新。通过将模型名称放在远程配置参数中,我们可以测试多个模型,而无需为每个要测试的模型添加新参数。

添加参数后,您应该在控制台中看到它:

699b3fd32acce887.png

在我们的代码中,我们需要在加载远程模型时添加一个检查。当我们从 Remote Config 接收到参数时,我们将获取具有相应名称的远程模型;否则我们将尝试加载mnist_v1 。在我们可以使用远程配置之前,我们必须通过在 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. A/B 测试两个模型

最后,我们可以使用 Firebase 的内置 A/B 测试行为来查看我们的两个模型中哪个模型表现更好。转到 Firebase 控制台中的 Analytics -> Events。如果显示了correct_inference事件,将其标记为“Conversion event”,如果没有,您可以转到 Analytics -> Conversion Events 并单击“Create a New Conversion Event”并放下correct_inference.

现在转到 Firebase 控制台中的“远程配置”,从我们刚刚添加的“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

单击右下角的审阅按钮。

恭喜,您已成功为两个独立的模型创建 A/B 测试! A/B 测试目前处于草稿状态,可以随时点击“开始实验”按钮开始。

要详细了解 A/B 测试,请查看A/B 测试文档

11.结论

在此 Codelab 中,您学习了如何将应用中静态捆绑的 tflite 资产替换为来自 Firebase 的动态加载的 TFLite 模型。要了解有关 TFLite 和 Firebase 的更多信息,请查看其他 TFLite 示例和 Firebase 入门指南。

有一个问题?

报告问题