TensorFlow Lite と Firebase を使用してアプリにおすすめコンテンツを追加する - Android Codelab

1. 概要

「TensorFlow Lite と Firebase によるレコメンデーション」Codelab にようこそ。この Codelab では、TensorFlow Lite と Firebase を使用してレコメンデーション モデルをアプリにデプロイする方法を学びます。この Codelab は、こちらの TensorFlow Lite のに基づいています。

おすすめを使用すると、アプリは機械学習を使用して、ユーザーごとに最も関連性の高いコンテンツをインテリジェントに提供できます。多数の他のユーザーの全体的な行動でトレーニングされたモデルを使用して、過去のユーザーの行動を考慮して、そのユーザーが今後利用したいと思うアプリのコンテンツを提案します。

このチュートリアルでは、Firebase Analytics を使用してアプリのユーザーからデータを取得し、そのデータからレコメンデーション用の ML モデルを構築して、Android アプリでそのモデルを使用して推論を実行し、レコメンデーションを取得する方法を示します。具体的には、ユーザーが過去に高く評価した映画のリストに基づき、視聴する可能性が高い映画を提案します。

学習内容

  • Firebase 向け Google アナリティクスを 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 Project] が開いたはずです。

4. Firebase コンソール プロジェクトを作成する

新しいプロジェクトを作成する

  1. Firebase コンソールに移動します。
  2. [プロジェクトを追加] を選択します(最初に選択した場合は [プロジェクトを作成] を選択します)。
  3. プロジェクト名を選択または入力して、[続行] をクリックします。
  4. [このプロジェクトで Google アナリティクスを有効にする] が有効になります。
  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.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 ファイルと同期する必要があります。[ファイル >Sync Project with Gradle Files] をクリックします。

6. スターター アプリを実行する

これで、プロジェクトを Android Studio にインポートし、JSON ファイルで google-services プラグインを設定できました。これで、アプリを初めて実行する準備ができました。Android デバイスを接続して、Android Studio ツールバーの実行アイコン(実行.png)をクリックします。

デバイスでアプリが起動するはずです。この時点でアプリケーションが正常に機能しており、映画の一覧を表示するタブ、[高く評価した映画] タブ、[おすすめ] タブが表示されています。映画のリストで映画をクリックすると、高評価リストに追加できます。Codelab の残りの手順を完了すると、[おすすめ] タブで映画のレコメンデーションを生成できるようになります。

7. アプリに Firebase 向け Google アナリティクスを追加する

このステップでは、Firebase 向け Google アナリティクスをアプリに追加して、ユーザーの行動データ(この場合は、ユーザーが好む映画)をログに記録します。このデータは、今後のステップでレコメンデーション モデルをトレーニングするために集約して使用されます。

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 向け Google アナリティクスを設定する

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())
    }
       
}

次のフィールドと関数を追加して、映画がユーザーの高評価リストに追加されたときにアナリティクス イベントをログに記録します。

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. アナリティクスとの統合をテストする

このステップでは、アプリでアナリティクス イベントを生成し、それが Firebase コンソールに送信されていることを確認します。

アナリティクスのデバッグ ロギングを有効にする

Firebase 向け Google アナリティクスは、ユーザーのバッテリー寿命を最大限に延ばすように設計されており、デバイス上のイベントをバッチ処理し、不定期に Firebase に送信するだけです。デバッグのために、この動作を無効にして、リアルタイムでログに記録されたイベントを表示するには、シェルで次のコマンドを実行します。

ターミナル

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

アナリティクス イベントが生成されていることを確認する

  1. Android Studio で [Logcat] ウィンドウを開き、アプリからのロギングを確認します。
  2. Logcat フィルタを文字列「Logging event」に設定します。
  3. "select_item" がアナリティクス イベントは、アプリで映画を高く評価するたびに生成されます。

これで、Firebase 向け Google アナリティクスがアプリに正常に統合されました。ユーザーがアプリを使用し、映画を高く評価すると、高評価が集計されて記録されます。この Codelab の残りの部分では、この集計データを使用してレコメンデーション モデルをトレーニングします。次の手順では、Logcat で表示したアナリティクス イベントと同じものを Firebase コンソールにストリーミングすることもできます。スキップして次のページに進んでもかまいません。

省略可: Firebase コンソールでアナリティクス イベントを確認する

  1. Firebase コンソールに移動します。
  2. [Analytics] で [DebugView] を選択する
  3. Android Studio で [Run] を選択してアプリを起動し、高く評価したリストに映画を追加します。
  4. Firebase コンソールの DebugView で、アプリに映画を追加したときにこれらのイベントがログに記録されていることを確認します。

9. アナリティクス データを BigQuery にエクスポートする

BigQuery は、大量のデータを調べて処理できる Google Cloud プロダクトです。このステップでは、Firebase コンソール プロジェクトを BigQuery に接続して、アプリで生成されたアナリティクス データが BigQuery に自動的にエクスポートされるようにします。

BigQuery へのエクスポートを有効にする

  1. Firebase コンソールに移動します。
  2. [Project Overview] の横にある設定の歯車アイコンを選択し、[Project settings] を選択します。
  3. [Integrations] タブを選択します。
  4. BigQuery ブロック内の [Link](または [Manage])を選択します。
  5. Firebase と BigQuery のリンクについて」のステップで [次へ] を選択します。
  6. [統合の構成] セクションで、スイッチをクリックして Google アナリティクス データの送信を有効にし、[BigQuery にリンク] を選択します。

これで、Firebase コンソール プロジェクトから Firebase Analytics イベントデータを BigQuery に自動的に送信できるようになりました。この処理はそれ以上の操作なしで自動的に行われますが、BigQuery で分析データセットを作成する最初のエクスポートは 24 時間行われない場合があります。データセットが作成されると、Firebase は新しいアナリティクス イベントを 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. [テーブルの作成元] で [Google Cloud Storage] を選択します。
  9. [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. [プレビュー] を選択すると、このテーブルに含まれている実際のアナリティクス イベントデータを確認できます。

サービス アカウントの認証情報を作成する

次に、Google Cloud コンソール プロジェクトでサービス アカウントの認証情報を作成します。この認証情報を、次のステップの Colab 環境で BigQuery データへのアクセスと読み込みに使用できます。

  1. Google Cloud プロジェクトの課金が有効になっていることを確認します。
  2. BigQuery API と BigQuery Storage API API を有効にします。<こちらをクリック>
  3. [サービス アカウント キーの作成] ページに移動します。
  4. [サービス アカウント] リストから [新しいサービス アカウント] を選択します。
  5. [サービス アカウント名] フィールドに名前を入力します。
  6. [役割] リストで、[プロジェクト] > [オーナー] を選択します。
  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 を有効にする

ML モデルを保存するバケットを作成する

Firebase コンソールで [Storage] に移動し、[使ってみる] をクリックします。fbbea78f0eb3dc9f.png

ダイアログに沿ってバケットを設定します。

19517c0d6d2aa14d.png

Firebase ML API を有効にする

Google Cloud コンソールの Firebase ML API ページに移動し、[有効にする] をクリックします。

Colab ノートブックを使用してモデルをトレーニングし、デプロイする

次のリンクを使用して Colab ノートブックを開き、以下の手順に沿って操作します。Colab ノートブックの手順を完了すると、アプリに同期できる TF Lite モデルファイルが Firebase コンソールにデプロイされます。

Colab で開く

12. アプリにモデルをダウンロードする

このステップでは、Firebase Machine Learning からトレーニングしたモデルをダウンロードするようにアプリを変更します。

Firebase ML の依存関係を追加する

アプリで Firebase ML モデルを使用するには、次の依存関係が必要です。すでに追加されているはずです(確認)。

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 アナリティクス
  • 分析イベントを BigQuery にエクスポートする
  • 分析イベントを前処理する
  • レコメンデーション TensorFlow モデルのトレーニング
  • モデルをエクスポートして Firebase コンソールにデプロイする
  • アプリで映画のレコメンデーションを提供する

次のステップ

  • Firebase ML の推奨事項をアプリに実装します。

詳細

質問がある場合

問題を報告する