使用 TensorFlow Lite 和 Firebase 向您的应用添加建议 - Android Codelab

1.概览

欢迎学习“使用 TensorFlow Lite 和 Firebase 进行推荐”Codelab。在此 Codelab 中,您将学习如何使用 TensorFlow Lite 和 Firebase 将推荐模型部署到您的应用。此 Codelab 基于此 TensorFlow Lite 示例

借助推荐功能,应用可以使用机器学习技术智能地为每位用户提供最相关的内容。它们会根据过去的用户行为,使用基于大量其他用户的汇总行为训练的模型,建议用户日后可能喜欢互动的应用内容。

本教程介绍如何使用 Firebase Analytics 从应用用户处获取数据,基于这些数据构建机器学习模型,然后在 Android 应用中使用该模型进行推理和获取推荐。具体而言,我们的推荐功能会根据用户之前喜欢的电影的列表,建议用户最有可能观看哪些电影。

学习内容

  • 将 Firebase Analytics 集成到 Android 应用中,以便收集用户行为数据
  • 将这些数据导出到 Google BigQuery
  • 预处理数据并训练 TF Lite 推荐模型
  • 将 TF Lite 模型部署到 Firebase ML 并从您的应用访问该模型
  • 使用模型在设备端运行推理,以向用户提供推荐

所需条件

  • 最新版 Android Studio
  • 示例代码。
  • 一台搭载 Android 7+ 和 Google Play 服务 9.8 或更高版本的测试设备,或者搭载 Google Play 服务 9.8 或更高版本的模拟器
  • 如果使用设备,则需要一根连接线。

您打算如何使用本教程?

仅阅读教程内容 阅读并完成练习

您如何评价您构建 Android 应用的经验?

新手 中等 熟练

2. 获取示例代码

通过命令行克隆 GitHub 代码库。

$ git clone https://github.com/FirebaseExtended/codelab-contentrecommendation-android.git

3. 导入起始应用

在 Android Studio 中,从示例代码下载中选择 codelab-recommendations-android 目录 ( android_studio_folder.png) (File > Open > .../codelab-recommendations-android/start)。

现在,您应在 Android Studio 中打开启动项目。

4. 创建 Firebase 控制台项目

创建新项目

  1. 前往 Firebase 控制台
  2. 选择添加项目(如果是第一个项目,则选择创建项目)。
  3. 选择或输入项目名称,然后点击继续
  4. 请确保“为此项目启用 Google Analytics”已启用。
  5. 在 Firebase 控制台中完成剩下的设置步骤,然后点击“创建项目”(如果您使用的是现有 Google 项目,则点击“添加 Firebase”)。

5. 添加 Firebase

  1. 在新项目的概览屏幕中,点击 Android 图标以启动设置工作流。
  2. 输入此 Codelab 的软件包名称:com.google.firebase.codelabs.recommendations
  3. 选择注册应用

将 google-services.json 文件添加到您的应用中

添加软件包名称并选择“注册”后,点击下载 google-services.json 以获取 Firebase Android 配置文件,然后将 google-services.json 文件复制到项目的 app 目录中。文件下载完毕后,您可以跳过控制台中显示的后续步骤(已在 build-android-start 项目中为您完成这些步骤)。

将 google-services 插件添加到您的应用

google-services 插件使用 google-services.json 文件将应用配置为使用 Firebase。以下几行代码应已添加至项目中的 build.gradle.kts 文件中(请检查并确认):

app/build.grad.kts

plugins {
    id("com.google.gms.google-services")
}

build.grad.kts

plugins {
    id("com.google.gms.google-services") version "4.3.15" apply false
}

将您的项目与 Gradle 文件同步

为确保您的应用拥有所有依赖项,此时您应该将项目与 Gradle 文件同步。在 Android Studio 工具栏中,依次选择 File > Sync Project with Gradle Files

6. 运行起始应用

现在,您已将项目导入 Android Studio 并使用 JSON 文件配置了 google-services 插件,接下来可以首次运行应用了。连接您的 Android 设备,然后点击 Android Studio 工具栏中的 Run 图标 (执行.png)。

应用应在您的设备上启动。此时,您可以看到一个正常运行的应用,其中显示了一个包含电影列表的标签页、“赞过的电影”标签页和“推荐”标签页。您可以点击电影列表中的某部电影,将其添加到您的“赞过”列表中。完成此 Codelab 的其余步骤后,我们将能够在“建议”标签页中生成影片推荐。

7. 向应用添加 Firebase Analytics

在此步骤中,您将向应用添加 Firebase Analytics,以记录用户行为数据(在本例中,记录用户喜欢的电影)。这些数据将在未来的步骤中汇总,用于训练推荐模型。

添加 Firebase 物料清单和 Google Analytics 依赖项

以下依赖项是将 Firebase Analytics 添加到您的应用所必需的。它们应已包含在 app/build.gradle.kts 文件中(验证)。

app/build.grad.kts

implementation(platform("com.google.firebase:firebase-bom:32.0.0"))
implementation("com.google.firebase:firebase-analytics-ktx")

在应用中设置 Firebase Analytics

LikedMoviesViewModel 包含存储用户喜欢的电影的函数。每当用户顶了一部新电影,我们也会发送分析日志事件来记录该电影点赞。

使用以下代码添加 onMovieLiked 函数,以便在用户点击电影时注册分析事件。

LikedMoviesViewModel.kt

import com.google.firebase.analytics.FirebaseAnalytics
import com.google.firebase.analytics.ktx.analytics
import com.google.firebase.analytics.ktx.logEvent
import com.google.firebase.ktx.Firebase


class LikedMoviesViewModel internal constructor (application: Application) : AndroidViewModel(application) {

    ...

    fun onMovieLiked(movie: Movie) {
        movies.setLike(movie, true)
        logAnalyticsEvent(movie.id.toString())
    }
       
}

添加以下字段和函数,以便在将电影添加到用户的“赞过”列表时记录 Google Analytics 事件。

LikedMoviesViewModel.kt

import com.google.firebase.analytics.FirebaseAnalytics
import com.google.firebase.analytics.ktx.analytics
import com.google.firebase.analytics.ktx.logEvent
import com.google.firebase.ktx.Firebase


class LikedMoviesViewModel internal constructor (application: Application) : AndroidViewModel(application) {
    ...
    private val firebaseAnalytics = Firebase.analytics

    ...

    /**
     * Logs an event in Firebase Analytics that is used in aggregate to train the recommendations
     * model.
     */
    private fun logAnalyticsEvent(id: String) {
        firebaseAnalytics.logEvent(FirebaseAnalytics.Event.SELECT_ITEM) {
            param(FirebaseAnalytics.Param.ITEM_ID, id)
        }
    }

8. 测试 Google Analytics 集成

在此步骤中,我们将在应用中生成 Analytics 事件,并验证这些事件是否会发送到 Firebase 控制台。

启用 Google Analytics 调试日志记录

Firebase Analytics 旨在最大限度延长用户电池续航时间,它会在设备端对事件进行批处理,并仅在必要时将其发送到 Firebase。出于调试目的,我们可以在 shell 中运行以下命令来停用此行为,以便在实时记录事件时查看这些事件。

终端

adb shell setprop debug.firebase.analytics.app com.google.firebase.codelabs.recommendations

验证是否生成了 Google Analytics 事件

  1. 在 Android Studio 中,打开 Logcat 窗口以检查应用中的日志记录。
  2. 将 Logcat 过滤器设置为字符串“Logging event”。
  3. 确认每当您在应用中赞过一部电影时,都会发出“select_item”Google Analytics 事件。

至此,您已成功将 Firebase Analytics 集成到您的应用中。当用户使用您的应用并赞过电影时,系统会汇总记录他们的赞过内容。我们将在此 Codelab 的其余部分使用此汇总数据来训练我们的推荐模型。下一个可选步骤是,您可以看到您在 Logcat 中看到的相同 Analytics 事件也会流式传输到 Firebase 控制台。您可以随时跳转到下一页。

可选:在 Firebase 控制台中确认 Google Analytics 事件

  1. 前往 Firebase 控制台
  2. 在“Google Analytics”下方选择 DebugView
  3. 在 Android Studio 中,选择 Run 以启动应用,然后将一些电影添加到“赞过”列表。
  4. 在 Firebase 控制台的 DebugView 中,验证当您在应用中添加影片时,系统是否会记录这些事件。

9. 将 Google Analytics 数据导出到 BigQuery

BigQuery 是一款 Google Cloud 产品,可让您检查和处理大量数据。在此步骤中,您需要将 Firebase 控制台项目与 BigQuery 相关联,以便应用生成的 Analytics 数据会自动导出到 BigQuery 中。

启用 BigQuery Export

  1. 前往 Firebase 控制台
  2. 选择项目概览旁边的“设置”齿轮图标,然后选择项目设置
  3. 选择集成标签页。
  4. BigQuery 块中,选择关联(或管理)。
  5. 在“关于将 Firebase 关联到 BigQuery”步骤中选择下一步
  6. 配置集成部分下,点击开关以启用发送 Google Analytics 数据的功能,然后选择关联到 BigQuery

现在,您的 Firebase 控制台项目已启用,可以自动将 Firebase Analytics 事件数据发送到 BigQuery。系统会自动执行此操作,而无需您进一步互动,不过,在 BigQuery 中创建分析数据集的首次导出可能需要 24 小时才能完成。创建数据集后,Firebase 会不断将新的 Analytics 事件导出到当日表中,并将过去几天的事件分组到事件表中。

训练推荐模型需要大量数据。由于我们还没有生成大量数据的应用,因此在下一步中,我们将向 BigQuery 导入一个示例数据集,以便在本教程的其余部分中使用。

10. 使用 BigQuery 获取模型训练数据

现在,我们已将 Firebase 控制台关联到 BigQuery,因此我们的应用分析事件数据将在一段时间后自动显示在 BigQuery 控制台中。为了获得本教程中使用的一些初始数据,在此步骤中,我们会将现有的示例数据集导入您的 BigQuery 控制台,用于训练我们的推荐模型。

将示例数据集导入 BigQuery

  1. 前往 Google Cloud 控制台中的 BigQuery 信息中心。
  2. 在菜单中选择您的项目名称。
  3. 在 BigQuery 左侧导航栏的底部选择您的项目名称以查看详细信息。
  4. 选择创建数据集,打开数据集创建面板。
  5. 数据集 ID 中输入“firebase_recommendations_dataset”,然后选择创建数据集
  6. 新数据集将显示在左侧菜单中的项目名称下方。点击该服务。
  7. 选择创建表以打开表创建面板。
  8. 基于以下数据创建表部分,选择“Google Cloud Storage”。
  9. 从 GCS 存储分区中选择文件字段中,输入“gs://firebase-recommendations/recommendations-test/formatted_data_filtered.txt”。
  10. 文件格式下拉菜单中,选择“JSONL”。
  11. 输入“recommendations_table”(针对表名称)。
  12. 选中架构 >自动检测 >架构和输入参数
  13. 选择创建表

探索示例数据集

此时,您可以选择探索架构并预览此数据集。

  1. 在左侧菜单中选择 firebase-recommendations-dataset,展开其中包含的表。
  2. 选择 recommendations-table 表以查看表架构。
  3. 选择预览可查看此表格中包含的实际 Google Analytics 事件数据。

创建服务账号凭据

现在,我们将在 Google Cloud 控制台项目中创建服务账号凭据,以便通过以下步骤在 Colab 环境中访问和加载 BigQuery 数据。

  1. 确保您的 Google Cloud 项目已启用结算功能。
  2. 启用 BigQuery API 和 BigQuery Storage API。<点击此处>
  3. 转到“创建服务账号密钥”页面
  4. 服务账号列表中,选择新的服务账号
  5. 服务账号名称字段中,输入一个名称。
  6. 角色列表中,选择项目 > 所有者
  7. 点击创建。包含密钥的 JSON 文件就会下载到您的计算机。

在下一步中,我们将使用 Google Colab 预处理这些数据并训练推荐模型。

11. 预处理数据并训练推荐模型

在此步骤中,我们将使用 Colab 笔记本执行以下步骤:

  1. 将 BigQuery 数据导入 Colab 记事本
  2. 预处理数据,为模型训练做好准备
  3. 基于 Google Analytics 数据训练推荐模型
  4. 将模型导出为 TF Lite 模型
  5. 将模型部署到 Firebase 控制台,以便在应用中使用

在启动 Colab 训练笔记本之前,我们先启用 Firebase Model Management API,以便 Colab 将训练好的模型部署到 Firebase 控制台。

启用 Firebase Model Management API

创建存储机器学习模型的存储桶

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

按照对话框中的说明设置存储桶。

19517c0d6d2aa14d.png

启用 Firebase ML API

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

使用 Colab 笔记本训练和部署模型

使用以下链接打开 Colab 笔记本,并完成其中的步骤。完成 Colab 笔记本中的步骤后,系统会将一个 TF Lite 模型文件部署到 Firebase 控制台,以便我们将其同步到我们的应用。

在 Colab 中打开

12. 在应用中下载模型

在此步骤中,我们将修改应用,以下载我们刚刚通过 Firebase 机器学习训练的模型。

添加 Firebase ML 依赖项

若要在您的应用中使用 Firebase 机器学习模型,需要以下依赖项。应该已添加(验证)。

app/build.grade.kts

implementation("com.google.firebase:firebase-ml-modeldownloader:24.1.2")

使用 Firebase Model Manager API 下载模型

将以下代码复制到 RecommendationClient.kt 中,以设置模型下载的条件,并创建一个下载任务以将远程模型同步到我们的应用。

RecommendationClient.kt

    private fun downloadModel(modelName: String) {
        val conditions = CustomModelDownloadConditions.Builder()
            .requireWifi()
            .build()
        FirebaseModelDownloader.getInstance()
            .getModel(modelName, DownloadType.LOCAL_MODEL, conditions)
            .addOnCompleteListener {
                if (!it.isSuccessful) {
                    showToast(context, "Failed to get model file.")
                } else {
                    showToast(context, "Downloaded remote model: $modelName")
                    GlobalScope.launch { initializeInterpreter(it.result) }
                }
            }
            .addOnFailureListener {
                showToast(context, "Model download failed for recommendations, please check your connection.")
            }
    }

13. 在您的应用中集成 Tensorflow Lite 推荐模型

借助 Tensorflow Lite 运行时,您可以在应用中使用自己的模型来生成推荐。在上一步中,我们使用下载的模型文件初始化了 TFLite 解释器。在此步骤中,我们将首先加载字典和标签,以便在推理步骤中与模型搭配使用,然后添加预处理来生成模型的输入,并添加后处理来从推理中提取结果。

加载字典和标签

推荐模型用于生成候选推荐的标签列在 res/assets 文件夹的 sorted_movie_vocab.json 文件中。复制以下代码以加载这些候选项。

RecommendationClient.kt

    /** Load recommendation candidate list.  */
    private suspend fun loadCandidateList() {
        return withContext(Dispatchers.IO) {
            val collection = MovieRepository.getInstance(context).getContent()
            for (item in collection) {
                candidates[item.id] = item
            }
            Log.v(TAG, "Candidate list loaded.")
        }
    }

实现预处理

在预处理步骤中,我们会更改输入数据的形式,使其与模型预期的数据形式相匹配。在这里,如果我们尚未生成很多用户点赞,则会用占位值填充输入长度。复制以下代码:

RecommendationClient.kt

    /** Given a list of selected items, preprocess to get tflite input.  */
    @Synchronized
    private suspend fun preprocess(selectedMovies: List<Movie>): IntArray {
        return withContext(Dispatchers.Default) {
            val inputContext = IntArray(config.inputLength)
            for (i in 0 until config.inputLength) {
                if (i < selectedMovies.size) {
                    val (id) = selectedMovies[i]
                    inputContext[i] = id
                } else {
                    // Padding input.
                    inputContext[i] = config.pad
                }
            }
            inputContext
        }
    }


运行解释器以生成建议

在这里,我们使用在上一步中下载的模型对预处理输入进行推理。我们为模型设置输入和输出的类型并进行推理,以生成电影推荐。将以下代码复制到您的应用中。

RecommendationClient.kt

    /** Given a list of selected items, and returns the recommendation results.  */
    @Synchronized
    suspend fun recommend(selectedMovies: List<Movie>): List<Result> {
        return withContext(Dispatchers.Default) {
            val inputs = arrayOf<Any>(preprocess(selectedMovies))

            // Run inference.
            val outputIds = IntArray(config.outputLength)
            val confidences = FloatArray(config.outputLength)
            val outputs: MutableMap<Int, Any> = HashMap()
            outputs[config.outputIdsIndex] = outputIds
            outputs[config.outputScoresIndex] = confidences
            tflite?.let {
                it.runForMultipleInputsOutputs(inputs, outputs)
                postprocess(outputIds, confidences, selectedMovies)
            } ?: run {
                Log.e(TAG, "No tflite interpreter loaded")
                emptyList()
            }
        }
    }



实现后期处理

最后,在此步骤中,我们会对模型的输出进行后处理,选择置信度最高的结果并移除包含的值(用户已经喜欢的电影)。将以下代码复制到您的应用中。

RecommendationClient.kt

    /** Postprocess to gets results from tflite inference.  */
    @Synchronized
    private suspend fun postprocess(
        outputIds: IntArray, confidences: FloatArray, selectedMovies: List<Movie>
    ): List<Result> {
        return withContext(Dispatchers.Default) {
            val results = ArrayList<Result>()

            // Add recommendation results. Filter null or contained items.
            for (i in outputIds.indices) {
                if (results.size >= config.topK) {
                    Log.v(TAG, String.format("Selected top K: %d. Ignore the rest.", config.topK))
                    break
                }
                val id = outputIds[i]
                val item = candidates[id]
                if (item == null) {
                    Log.v(TAG, String.format("Inference output[%d]. Id: %s is null", i, id))
                    continue
                }
                if (selectedMovies.contains(item)) {
                    Log.v(TAG, String.format("Inference output[%d]. Id: %s is contained", i, id))
                    continue
                }
                val result = Result(
                    id, item,
                    confidences[i]
                )
                results.add(result)
                Log.v(TAG, String.format("Inference output[%d]. Result: %s", i, result))
            }
            results
        }
    }


测试您的应用!

重新运行您的应用。当您选择一些电影后,应用应该会自动下载新模型并开始生成推荐内容!

14. 恭喜!

您已使用 TensorFlow Lite 和 Firebase 在应用中构建了推荐功能。请注意,此 Codelab 中展示的技术和流水线可以推广到其他类型的推荐内容。

所学内容

  • Firebase ML
  • Firebase Analytics
  • 将 Google Analytics 事件导出到 BigQuery
  • 预处理分析事件
  • 训练推荐 TensorFlow 模型
  • 导出模型并部署到 Firebase 控制台
  • 在应用中提供电影推荐

后续步骤

  • 在您的应用中实现 Firebase ML 建议。

了解详情

有疑问?

报告问题