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

1. 總覽

歡迎參加「使用 TensorFlow Lite 和 Firebase 進行推薦」程式碼研究室。在本程式碼研究室中,您將瞭解如何使用 TensorFlow Lite 和 Firebase,將建議模型部署至應用程式。本程式碼研究室以這個 TensorFlow Lite 範例為基礎。

應用程式可透過建議功能,運用機器學習技術,為每位使用者放送最相關的內容。系統會考量過去的使用者行為,並運用以大量其他使用者匯總行為訓練的模型,建議使用者未來可能感興趣的應用程式內容。

本教學課程說明如何使用 Firebase Analytics 取得應用程式使用者的資料、根據這些資料建構機器學習模型以提供建議,然後在 Android 應用程式中使用該模型執行推論並取得建議。具體來說,我們會根據使用者先前喜歡的電影清單,推薦他們最有可能觀看的電影。

課程內容

  • 在 Android 應用程式中整合 Firebase Analytics,收集使用者行為資料
  • 將該資料匯出至 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. 輸入程式碼研究室的套件名稱: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.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 工具列中,依序選取「File」>「Sync Project with Gradle Files」

6. 執行範例應用程式

將專案匯入 Android Studio 並使用 JSON 檔案設定 google-services 外掛程式後,即可首次執行應用程式。連線至 Android 裝置,然後按一下 Android Studio 工具列中的「Run」 ( execute.png)。

應用程式應會在裝置上啟動。此時,您會看到一個運作中的應用程式,其中包含顯示電影清單的分頁、顯示喜愛電影的分頁,以及顯示推薦內容的分頁。只要按一下電影清單中的電影,即可將其加入「喜歡」清單。完成本程式碼研究室的其餘步驟後,我們就能在「建議」分頁中產生電影建議。

7. 在應用程式中新增 Firebase Analytics

在這個步驟中,您會在應用程式中加入 Firebase Analytics,記錄使用者行為資料 (在本例中,是指使用者喜歡的電影)。在後續步驟中,系統會彙整這些資料,用於訓練建議模型。

新增 Firebase Bill of Materials 和 Analytics 依附元件

如要將 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 Analytics 的設計宗旨是盡量延長使用者裝置的電池續航力,因此會批次處理裝置上的事件,並只偶爾傳送至 Firebase。為了進行偵錯,我們可以停用這項行為,在 Shell 中執行下列指令,即可即時查看記錄的事件。

航廈

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

確認是否已產生 Analytics 事件

  1. 在 Android Studio 中開啟 Logcat 視窗,檢查應用程式的記錄。
  2. 將 Logcat 篩選器設為「Logging event」字串。
  3. 確認每次在應用程式中對電影按讚時,系統都會發出「select_item」Analytics 事件。

到目前為止,您已成功將 Firebase Analytics 整合至應用程式。使用者使用應用程式並喜歡電影時,系統會記錄他們喜歡的電影。在本程式碼研究室的其餘部分,我們會使用這項匯總資料訓練建議模型。以下為選用步驟,可讓您在 Firebase 控制台中,看到與 Logcat 中相同的 Analytics 事件串流。請直接跳到下一頁。

選用:在 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 Export

  1. 前往 Firebase 控制台
  2. 選取「專案總覽」旁的「設定」齒輪圖示,然後選取「專案設定」
  3. 選取「整合」分頁標籤。
  4. 在「BigQuery」方塊中選取「連結」 (或「管理」)。
  5. 在「瞭解如何將 Firebase 連結至 BigQuery」步驟中,選取「下一步」
  6. 在「設定整合」部分下方,按一下切換鈕,啟用傳送 Google Analytics 資料的功能,然後選取「連結至 BigQuery」

您已啟用 Firebase 控制台專案,可自動將 Firebase Analytics 事件資料傳送至 BigQuery。系統會自動執行這項操作,不需要任何進一步互動,但首次匯出作業 (在 BigQuery 中建立 Analytics 資料集) 可能需要 24 小時。建立資料集後,Firebase 會持續將新的 Analytics 事件匯出至 BigQuery 的當日資料表,並將過去幾天的事件歸入事件資料表。

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

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

Firebase 主控台已連結至 BigQuery,因此過一段時間後,應用程式的 Analytics 事件資料就會自動顯示在 BigQuery 主控台中。為了取得本教學課程的初始資料,我們將在本步驟中,將現有的範例資料集匯入 BigQuery 控制台,用於訓練建議模型。

將範例資料集匯入 BigQuery

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

探索範例資料集

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

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

建立服務帳戶憑證

接下來,我們會在 Google Cloud 控制台專案中建立服務帳戶憑證,以便在下個步驟中,於 Colab 環境存取及載入 BigQuery 資料。

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

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

11. 預先處理資料並訓練推薦模型

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

  1. 將 BigQuery 資料匯入 Colab 筆記本
  2. 預先處理資料,準備用於模型訓練
  3. 根據 Analytics 資料訓練建議模型
  4. 將模型匯出為 TF Lite 模型
  5. 將模型部署至 Firebase 控制台,以便在應用程式中使用

在啟動 Colab 訓練筆記本之前,請先啟用 Firebase Model Management API,這樣 Colab 才能將訓練好的模型部署到 Firebase 控制台。

啟用 Firebase Model Management API

建立 bucket 來儲存機器學習模型

在 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
  • 將 Analytics 事件匯出至 BigQuery
  • 預先處理 Analytics 事件
  • 訓練建議事項 TensorFlow 模型
  • 匯出模型並部署至 Firebase 控制台
  • 在應用程式中提供電影推薦

後續步驟

  • 在應用程式中導入 Firebase ML 建議。

瞭解詳情

有任何疑問嗎?

回報問題