透過 TensorFlow Lite 和 Firebase 將建議新增至應用程式 - Android 程式碼研究室

1. 總覽

歡迎來到「TensorFlow Lite 和 Firebase 的推薦功能」程式碼研究室。在本程式碼研究室中,您將瞭解如何使用 TensorFlow Lite 和 Firebase 在應用程式中部署建議模型。本程式碼研究室是以這個 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 中開啟「Start」專案。

4. 建立 Firebase 控制台專案

建立新專案

  1. 前往 Firebase 控制台
  2. 選取「新增專案」 (若為第一個專案,請選取「建立專案」)。
  3. 選取或輸入專案名稱,然後按一下「繼續」
  4. 確定「為這項專案啟用 Google Analytics」
  5. 按照 Firebase 控制台中的其餘設定步驟操作,然後按一下「建立專案」(如果您使用現有的 Google 專案,請按一下「新增 Firebase」)。

5. 新增 Firebase

  1. 在新專案的總覽畫面中,按一下 Android 圖示以啟動設定工作流程。
  2. 輸入程式碼研究室的套件名稱:com.google.firebase.codelabs.recommendations
  3. 選取「註冊應用程式」

在應用程式中加入 google-services.json 檔案

新增套件名稱並選取「註冊」後,請點選「Download google-services.json」取得 Firebase Android 設定檔,然後將 google-services.json 檔案複製到專案的 app 目錄。檔案下載完成後,您可以略過控制台中顯示的後續步驟 (已在 build-android-start 專案中完成這些步驟)。

在應用程式中新增 google-services 外掛程式

Google 服務外掛程式會使用 google-services.json 檔案,將您的應用程式設定為使用 Firebase。下列幾行內容應已新增至專案中的 build.gradle.kts 檔案中 (勾選以確認):

app/build.Grade.kts

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

build.Grade.kts

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

將專案與 Gradle 檔案同步處理

為確保應用程式能夠使用所有依附元件,請在此時將專案與 Gradle 檔案同步處理。選取「檔案」>透過 Android Studio 工具列同步處理專案與 Gradle 檔案。

6. 執行範例應用程式

既然您已將專案匯入 Android Studio,並使用 JSON 檔案設定 google-services 外掛程式,就可以開始執行應用程式了。連結 Android 裝置,然後按一下 Android Studio 工具列中的「Run」圖示 執行.png

應用程式應會在裝置上啟動。此時,您會看到執行中的應用程式,顯示一個分頁、電影清單、「喜歡的電影」分頁和「推薦」分頁。在電影清單中點按電影即可加入「喜歡」清單。完成程式碼研究室的其餘步驟後,我們就能在「推薦」分頁中產生電影推薦內容。

7. 將 Firebase Analytics 加入應用程式

在這個步驟中,您需要在應用程式中新增 Firebase Analytics,以便記錄使用者行為資料 (在本例中,使用者喜歡的電影)。這類資料會在後續步驟中匯總,用來訓練建議模型。

新增 Firebase 物料清單和數據分析依附元件

以下是將 Firebase Analytics 新增至應用程式的必要依附元件。這些項目應該已包含在 app/build.gradle.kts 檔案 (驗證) 中。

app/build.Grade.kts

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

在應用程式中設定 Firebase Analytics

LikedMoviesViewModel 包含用來儲存使用者喜歡的電影的函式。每當使用者喜歡一部新電影時,我們也想傳送分析記錄事件,以便記錄這類情況。

使用下列程式碼新增 onMovieLiked 函式,以在使用者按一下喜歡電影時登錄 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) {

    ...

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

電影加入使用者的「已按讚」名單時,請加入下列欄位和函式來記錄 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. 測試 Analytics 整合

在這個步驟中,我們會在應用程式中產生 Analytics 事件,並驗證這些事件是否傳送至 Firebase 控制台。

啟用 Analytics 偵錯記錄

Firebase 數據分析經過精心設計,可大幅提升使用者電池續航力,在裝置上批次處理事件,且偶爾只會向 Firebase 傳送事件。為了進行偵錯,我們可以停用此行為,以在事件即時查看記錄時,在 Shell 中執行下列指令。

航廈

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

確認已產生 Analytics 事件

  1. 在 Android Studio 中開啟 Logcat 視窗,檢查應用程式的記錄。
  2. 將 Logcat 篩選器設為「記錄事件」字串。
  3. 驗證「select_item」每當您在應用程式中喜歡電影時,系統就會產生數據分析事件。

此時,您已成功將 Firebase Analytics 整合至應用程式。隨著使用者使用您的應用程式及對電影表示喜歡,系統會匯總他們對這些歌曲的喜歡記錄。我們會在本程式碼研究室的其餘部分,使用這些匯總資料訓練推薦模型。您可以透過下列選用步驟,查看您在 Logcat 中看到的相同 Analytics 事件也會串流至 Firebase 控制台。您可以跳到下一頁。

選用:在 Firebase 控制台確認 Analytics 事件

  1. 前往 Firebase 控制台
  2. 選取 Analytics 下方的「DebugView」
  3. 在 Android Studio 中,選取「Run」啟動應用程式,並將一些電影加入「喜歡」清單。
  4. 在 Firebase 控制台的 DebugView 中,確認當您在應用程式中新增電影時,系統會記錄這些事件。

9. 將 Analytics 資料匯出至 BigQuery

BigQuery 是 Google Cloud 產品,可讓您檢查及處理大量資料。在這個步驟中,您將將 Firebase 控制台專案連結至 BigQuery,讓系統將應用程式產生的 Analytics 資料自動匯出至 BigQuery。

啟用 BigQuery 匯出功能

  1. 前往 Firebase 控制台
  2. 選取「Project Overview」旁邊的「設定」齒輪圖示,然後選取「專案設定」
  3. 選取「Integrations」分頁標籤。
  4. 在「BigQuery」區塊中選取「Link」或「Manage」
  5. 在「關於將 Firebase 連結至 BigQuery」步驟中,選取「下一步」。
  6. 在「設定整合」部分下方,按一下切換按鈕來啟用傳送 Google Analytics 資料的功能,然後選取「連結至 BigQuery」

您現已啟用 Firebase 控制台專案,可自動將 Firebase Analytics 事件資料傳送至 BigQuery。系統會自動執行這項程序,您不需要進行任何進一步的互動,但首次在 BigQuery 中建立數據分析資料集的匯出作業,可能不會在 24 小時內發生。建立資料集後,Firebase 會持續將新的 Analytics 事件匯出至 BigQuery,並彙整到當日資料表,並在事件資料表中將過去幾天的事件分組。

訓練建議模型需要大量資料。由於我們還沒有應用程式產生大量資料,因此我們會在下一個步驟中將範例資料集匯入 BigQuery,以便在本教學課程的後續部分中使用。

10. 使用 BigQuery 取得模型訓練資料

我們已將 Firebase 控制台連結至 BigQuery,應用程式分析事件資料會在一段時間後自動顯示在 BigQuery 控制台中。為了達成本教學課程的目的而取得一些初始資料,在這個步驟中,我們會將現有的範例資料集匯入您的 BigQuery 控制台,用來訓練建議模型。

將範例資料集匯入 BigQuery

  1. 前往 Google Cloud 控制台的 BigQuery 資訊主頁。
  2. 在選單中選取專案名稱。
  3. 在 BigQuery 左側導覽面板的底部選取專案名稱即可查看詳細資料。
  4. 選取「建立資料集」,開啟資料集建立面板。
  5. 輸入「firebase_recommendations_dataset」「資料集 ID」並選取「建立資料集」
  6. 新資料集會顯示在左選單中的專案名稱下方。請點選該服務。
  7. 選取「建立資料表」,開啟資料表建立面板。
  8. 在「Create table from」(使用下列資料建立資料表) 部分,選取「Google Cloud Storage」。
  9. 在「Select file from GCS bucket」(從 GCS 值區選取檔案) 欄位中,輸入「gs://firebase-recommendations/recommendations-test/formatted_data_filtered.txt」。
  10. 選取「JSONL」[檔案格式] 下拉式選單中。
  11. 輸入「recommendations_table」「Table name」(資料表名稱) 區段。
  12. 勾選「結構定義 > 下方的」方塊自動偵測 >結構定義和輸入參數
  13. 選取「建立資料表」

探索範例資料集

此時,您可以選擇探索結構定義,並預覽這個資料集。

  1. 選取左選單中的「firebase-recommendations-dataset」,展開內含的資料表。
  2. 選取 recommendations-table 資料表來查看資料表結構定義。
  3. 選取「預覽」即可查看這個表格包含的實際 Analytics 事件資料。

建立服務帳戶憑證

現在,我們會在 Google Cloud 控制台專案中建立服務帳戶憑證,以便在後續步驟中使用 Colab 環境存取及載入 BigQuery 資料。

  1. 請確認 Google Cloud 專案已啟用計費功能。
  2. 啟用 BigQuery 和 BigQuery Storage API。<按這裡>
  3. 前往「建立服務帳戶金鑰」頁面
  4. 在「服務帳戶」清單中,選取「新增服務帳戶」
  5. 在 [Service account name] (服務帳戶名稱) 欄位中輸入一個名稱。
  6. 從 [Role] (角色) 清單中,選取 [Project] (專案) > [Owner] (擁有者)
  7. 點選「建立」。系統會將包含金鑰的 JSON 檔案下載到電腦。

在下一個步驟中,我們會使用 Google Colab 預先處理這類資料並訓練推薦模型。

11. 預先處理資料並訓練建議模型

在這個步驟中,我們會使用 Colab 筆記本執行下列步驟:

  1. 將 BigQuery 資料匯入 Colab 筆記本
  2. 預先處理資料,以便進行模型訓練
  3. 根據數據分析資料訓練建議模型
  4. 將模型匯出為 TF lite 模型
  5. 將模型部署至 Firebase 控制台,以便我們在應用程式中使用

推出 Colab 訓練筆記本前,我們會先啟用 Firebase Model Management API,讓 Colab 將經過訓練的模型部署至 Firebase 控制台。

啟用 Firebase Model Management API

建立值區來儲存機器學習模型

在 Firebase 控制台中,前往「儲存空間」並點選「開始使用」。fbbea78f0eb3dc9f.png

按照對話方塊的指示設定值區。

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,在應用程式中建構建議功能。請注意,本程式碼研究室提及的技巧和管道可一般化,也可用於提供其他類型的建議。

涵蓋內容

  • Firebase ML
  • Firebase Analytics
  • 將數據分析事件匯出至 BigQuery
  • 預先處理數據分析事件
  • 訓練建議 TensorFlow 模型
  • 匯出模型並部署至 Firebase 控制台
  • 在應用程式中推薦電影

後續步驟

  • 在應用程式中導入 Firebase 機器學習建議。

瞭解詳情

有任何疑問嗎?

回報問題