将 Firebase 添加到由 TFLite 提供支持的 iOS 应用

1.概览

目标

Firebase ML 使您能够通过无线方式部署模型。这样,您就可以将应用体量变小,并且仅在需要时下载机器学习模型、对多个模型进行实验或更新机器学习模型,而不必重新发布整个应用。

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

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

前提条件

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

  • Xcode 11(或更高版本)
  • CocoaPods 1.9.1(或更高版本)

2. 创建 Firebase 控制台项目

将 Firebase 添加到项目中

  1. 前往 Firebase 控制台
  2. 选择 Create New Project,然后将您的项目命名为“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 项目。获取项目后,从 Firebase 控制台下载项目的 GoogleService-Info.plist 文件,并将其拖动到 Xcode 项目的根目录中。

f06cb08d48de7e10

将 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

5. 从 Firebase ML 下载模型

选择何时从 Firebase 将远程模型下载到您的应用可能很棘手,因为 TFLite 模型可能会变得相对较大。理想情况下,我们希望避免在应用启动时立即加载模型,因为如果我们的模型只用于一项特征,而用户从未使用该功能,那么我们将无故下载大量数据。我们还可以设置下载选项,例如仅在连接到 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 小时内集中成批,并一起上传。此方法可节省最终用户并减少网络流量消耗不过,为了验证您的 Google Analytics 实现情况(并且为了在 DebugView 报告中查看您的分析数据),您可以在开发设备上启用调试模式,从而以最短延迟时间上传事件。

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

-FIRDebugEnabled

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

5276199a086721fd.png

7. 使用 Firebase 性能跟踪推理时间

测试模型时,在开发设备上生成的性能指标不足以捕获模型在用户操作中的表现因为很难判断用户将在什么硬件上运行您的应用。幸运的是,你可以根据设备与 Firebase 性能,以更好地了解模型的性能。

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

import FirebasePerformance

然后,在 classify 方法中开始跟踪性能,并在推理完成时停止跟踪。请确保在 DispatchQueue.global.async 闭包内添加以下代码行,而不是在方法声明的正下方。

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

如果您有兴趣,可以按照此处的说明启用调试日志记录,以确认系统是否正在记录您的性能跟踪记录。一段时间后,您也可以在 Firebase 控制台中看到性能跟踪记录。

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

在为模型提出新版本时,比如具有更好的模型架构的版本或者使用更大或更新的数据集进行训练的模型时,我们可能会想用新版本替换当前模型。不过,在测试中表现良好的模型未必在生产环境中同样表现良好。因此,我们在生产环境中进行 A/B 测试,以比较原始模型和新模型。

启用 Firebase Model Management API

在此步骤中,我们将启用 Firebase Model Management API,以便使用 Python 代码部署新版 TensorFlow Lite 模型。

创建存储分区来存储机器学习模型

在 Firebase 控制台中,转到 Storage,然后点击“开始使用”。fbbea78f0eb3dc9f

按照对话框设置存储分区。

19517c0d6d2aa14d.png

启用 Firebase ML API

前往 Google Cloud 控制台的 Firebase ML API 页面,然后点击“启用”。

2414fd5cced6c984在系统提示时,选择 Digit Classifier 应用。

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

下载服务账号的私钥

我们需要先创建一个服务账号,然后才能使用 Firebase Admin SDK。点击此链接打开 Firebase 控制台的“服务账号”面板,然后点击按钮以便为 Firebase Admin SDK 创建新的服务账号。出现提示时,点击 生成新的私钥 按钮。我们将使用服务账号密钥对来自 Colab 笔记本的请求进行身份验证。

c3b95de1e5508516

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

  1. 打开此 Colab 笔记本,并在您自己的云端硬盘下创建一份副本。
  2. 运行第一个单元“训练改进的 TensorFlow Lite 模型”方法是点击该画面左侧的“播放”按钮这将训练新模型,可能需要一些时间。
  3. 运行第二个单元格会创建文件上传提示。上传您在创建服务账号时从 Firebase 控制台下载的 json 文件。

71e847c6a85423b3

  1. 运行最后两个单元。

运行 Colab 笔记本后,您应该会在 Firebase 控制台中看到第二个模型。确保第二个模型的名称为 mnist_v2

c316683bb4d75d57

9. 通过 Remote Config 选择模型

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

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

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

699b3fd32acce887

在代码中,我们需要在加载远程模型时添加一个检查。当我们从 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. 对两种模型进行 A/B 测试

最后,我们可以使用 Firebase 内置的 A/B Testing 行为来了解两个模型中哪个效果更好。转到 Google Analytics->Firebase 控制台中的事件。如果显示 correct_inference 事件,请将其标记为“转化事件”。如果未显示,您可以前往 Google Analytics->转化事件,然后点击“创建新的转化事件”然后放下correct_inference.

现在,前往 Firebase 控制台中的“Remote Config”,选择“A/B 测试”“model_name”上“更多选项”菜单中的按钮参数。

fad5ea36969d2aeb

在随后显示的菜单中,接受默认名称。

d7c006669ace6e40.png

从下拉菜单中选择您的应用,然后将定位条件更改为活跃用户的 50%。

6246dd7c660b53fb

如果您能够之前将 correct_inference 事件设置为转化,请将此事件用作主要指标进行跟踪。或者,如果您不想等待事件显示在 Google Analytics 中,可以手动添加 correct_inference

1ac9c94fb3159271

最后,在“变体”屏幕上,将对照组变体设置为使用“mnist_v1”,将变体 A 组设置为使用“mnist_v2”。

e4510434f8da31b6

点击右下角的“查看”按钮。

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

如需详细了解 A/B 测试,请参阅 A/B 测试文档

11. 总结

在此 Codelab 中,您学习了如何将应用中静态捆绑的 tflite 资源替换为 Firebase 中动态加载的 TFLite 模型。如需详细了解 TFLite 和 Firebase,请查看其他 TFLite 示例和 Firebase 入门指南。

有疑问?

报告问题