将 Firebase 添加到 TFLite 支持的 iOS 应用程序

1. 概述

目标

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 项目。获得项目后,从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 添加到 Podfile 中,然后才能在项目中使用:

pod 'FirebaseAnalytics'

然后在ViewController.swift中文件顶部导入 Firebase

import FirebaseAnalytics

并在correctButtonPressed方法中添加以下代码行。

Analytics.logEvent("correct_inference", parameters: nil)

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

调试分析

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

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

-FIRDebugEnabled

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

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 笔记本的请求。

c3b95de1e5508516.png

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

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

71e847c6a85423b3.png

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

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

c316683bb4d75d57.png

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

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

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

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

699b3fd32acce887.png

在我们的代码中,我们需要在加载远程模型时添加检查。当我们收到远程配置的参数时,我们将获取具有相应名称的远程模型;否则我们将尝试加载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 控制台中的“分析”->“事件”。如果显示了correct_inference事件,请将其标记为“转化事件”,如果没有,您可以转到“分析”->“转化事件”,然后单击“创建新的转化事件”并输入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 中,您学习了如何使用 Firebase 动态加载的 TFLite 模型替换应用中静态捆绑的 tflite 资源。要了解有关 TFLite 和 Firebase 的更多信息,请查看其他 TFLite 示例和 Firebase 入门指南。

有一个问题?

报告问题