BigQuery、Cloud Run、Gemma を使用して GKE のデータを分析する

このチュートリアルでは、BigQueryCloud RunGemma LLM を使用して、大規模なデータセットから分析情報を導き出す方法について説明します。このチュートリアルでは、サンプル アプリケーションを Google Kubernetes Engine(GKE)にデプロイします。サンプルアプリでは、データの保存と処理に BigQuery、リクエスト処理に Cloud Run、データの分析と受信プロンプトに基づく予測の生成に Gemma LLM を利用しています。

このチュートリアルは、クラウド プラットフォームの管理者とアーキテクトデータと AI のスペシャリストML エンジニア、MLOps(DevOps)の専門家を対象としています。このページを読む前に、KubernetesJupyter などのノートブック環境について理解しておいてください。

このチュートリアルの前提条件として、GKE の GPU で Hugging Face TGI を使用して Gemma オープンモデルを提供するチュートリアルを完了する必要があります。TGI フレームワークは、モデル サービング プロセスを容易にします。

GKE と BigQuery を選ぶ理由

BigQuery は、ペタバイト規模のデータに対するスケーラブルな分析を実現する、Platform as a Service(PaaS)のフルマネージド サーバーレス データ ウェアハウスです。BigQuery では、使い慣れた SQL と組み込みの ML を使用して、有用な分析情報を得るためのデータ分析に専念できます。

GKE の GPU で TGI を使用すると、Gemma 言語モデルをデプロイして、ユーザー インタラクションを自然言語で分析して要約できます。BigQuery を GKE と統合することで、BigQuery を使用して大量のデータセット(Google アナリティクスなど)を効率的に処理し、モデルの自然言語理解機能を使用して有意な分析情報を生成できます。

たとえば、データ サイエンティスト、アナリスト、または e コマース企業のビジネス上の意思決定者であれば、ウェブサイトやアプリでのユーザー行動を把握したいと考えるでしょう。この分析情報は、ユーザー ジャーニーを最適化してパーソナライズし、情報に基づいたビジネス上の意思決定を行い、売り上げを伸ばすために役立ちます。

このシナリオでは、BigQuery から未加工の Google アナリティクス データを取得し、Gemma モデルにフィードして、ページ訪問の概要と分析情報を自然言語で受け取ることができます。Gemma モデルは、GKE の GPU アクセラレーションを備えたスケーラブルなインフラストラクチャで実行され、ユーザー ジャーニー データを迅速に処理してパターンとトレンドを特定します。分析情報を活用して、人気のある商品の組み合わせを特定したり、購入手続きの途中で離脱するユーザーが多いポイントを特定したり、特定のランディング ページにトラフィックを誘導している成功したマーケティング キャンペーンをハイライト表示できます。

利点

このソリューションは、次のようなメリットがある効率的なワークフローを提供します。

  • BigQuery との統合: BigQuery を使用して、大規模なデータセット(このチュートリアルの Google アナリティクス データなど)を保存、処理します。これにより、モデルの分析に必要なデータをクエリして集計できます。
  • GPU アクセラレーション: GPU をサポートする GKE クラスタで Gemma モデルを実行することで、推論プロセスが高速化され、CPU ベースのプロセッサよりもはるかに高速に予測を生成できます。
  • 費用と時間を削減: オープンソースの事前トレーニング済み Gemma 言語モデルを使用することで、時間とリソースを節約でき、カスタムモデルをゼロから構築する必要がなくなります。

Gemma モデルを提供する

GKE の GPU で Hugging Face TGI を使用して Gemma オープンモデルを提供するチュートリアルに移動し、始める前にから curl を使用してモデルを操作するまでの手順に沿って、Gemma モデルが正常にデプロイされ、操作できることを確認します。

このチュートリアルでは、Gemma 2B-it モデルをデプロイします。

VPC ネットワークを設定する

リモート関数が GKE クラスタに接続できるように、us-central1 リージョンに VPC ネットワークを作成または使用します。このチュートリアルでは、Default VPC を使用します。

BigQuery データセット、リモート関数、基盤となる Cloud Run functions の関数が互換性のあるロケーションにデプロイされるようにするには、VPC ネットワークが BigQuery リモート関数と同じリージョンにある必要があります。このチュートリアルでは、リモート関数を作成しながら BigQuery DataFrames オプションを設定するときに、データセットのロケーションとして US を指定します。これは、デフォルトで Cloud Run functions の us-central1 リージョンになります。したがって、us-central1 リージョンに VPC を作成するか、そのリージョンの VPC を使用します。

ロードバランサの作成

GKE クラスタに内部ロードバランサを作成するには、次の操作を行います。

  1. 次の tgi-2b-lb-service.yaml マニフェストを作成します。

    apiVersion: v1
    kind: Service
    metadata:
    name: llm-lb-service
    annotations:
        networking.gke.io/load-balancer-type: "Internal"
    spec:
    selector:
      app: gemma-server
    type: LoadBalancer
    ports:
    - protocol: TCP
      port: 8000
      targetPort: 8000
    
  2. 新しい Cloud Shell ターミナルを開き、次のコマンドを実行してマニフェストを適用します。

    kubectl apply -f tgi-2b-lb-service.yaml
    
  3. ロードバランサの IP アドレスを取得します。この IP アドレスを取得できるようになるまで 1~2 分ほどかかることがあります。

    kubectl get service llm-lb-service --output yaml | grep ip:
    

この IP アドレスを使用して、ロードバランサの背後で実行されている gemma-server アプリケーションと通信します。

コネクタを作成する

サーバーレス VPC アクセス コネクタを使用すると、公共のインターネットを使用せずに VPC ネットワークを介してリクエストを送受信できます。詳細については、サーバーレス VPC アクセスをご覧ください。

このチュートリアルでは、VPC 内の既存のリソースとの IP アドレスの競合を回避するために、新しい専用サブネットを持つコネクタを作成します。手順については、コネクタを作成するセクションを参照して、コネクタと新しいサブネットを作成するセクションの gcloud の説明に従って操作します。

既存のサブネットを使用する場合は、既存のサブネットを使用してコネクタを作成するの手順に沿って操作します。

詳細については、コネクタのサブネットの要件をご覧ください。

ノートブックを作成する

このチュートリアルでは、Colab Enterprise ノートブックを使用して、BigQuery リモート関数を定義し、分析を実行するためのすべてのコードを実行します。

Google Cloud コンソールを使用して Colab Enterprise ノートブックを作成するには:

  1. Google Cloud コンソールで、[Colab Enterprise ノートブック] ページに移動します。

    Notebooks に移動

  2. [リージョン] メニューで [us-central1] を選択します。これは、このチュートリアルですべてのサービスを作成するリージョンと同じです。

  3. [ファイル] の横にある [ノートブックを作成] をクリックします。

新しいノートブックが [マイ ノートブック] タブに表示されます。

新しいノートブックでコードを実行するには、実行するコマンドまたはコード スニペットごとに新しいコードセルをノートブックに挿入します。

BigQuery リモート関数を作成する

BigQuery リモート関数を定義する方法の一つは、bigframes ライブラリを使用する方法です。このセクションでは、bigframes を使用して process_incoming というリモート関数を作成します。このリモート関数は、Google アナリティクスのデータを入力として受け取り、プロンプトを作成して Gemma モデルに送信し、分析を行います。

作成した Colab Enterprise ノートブックで、次の操作を行います。

  1. [+ コード] をクリックして、新しいコードセルを挿入します。
  2. 新しいコードセルに次のコードをコピーします。

    # Install the necessary packages on the notebook runtime
    %pip install --upgrade bigframes --quiet
    
    import bigframes.pandas as bpd
    import os
    import ast
    import requests
    
    # Replace the following  variables
    # Use the format ip:port
    # For example, "10.128.05:8000"
    lb_url = "LOADBALANCER_IP_ADDRESS:8000"
    
    # Set BigQuery DataFrames options
    bpd.options.bigquery.project = "PROJECT_ID"
    bpd.options.bigquery.location = "US"
    # Update the VPC connector name with the one you created
    vpc_connector_name = "VPC_CONNECTOR_NAME"
    
    # Create a remote function using bigframes
    # https://cloud.google.com/bigquery/docs/remote-functions#bigquery-dataframes
    
    @bpd.remote_function(
      dataset="ga_demo",
      name="ga_explain_example",
      bigquery_connection="bigframes-rf-conn",
      reuse=True,
      packages=["requests"],
      cloud_function_vpc_connector=VPC_CONNECTOR_NAME,
      cloud_function_service_account="default",
    )
    def process_incoming(data: str) -> str:
      ga_data = ast.literal_eval(data)
      USER_PROMPT = """
          'The following are the results from Google Analytics.
          They are reverse ranked.
          reverse_event_number 1 is the last page visited.
          reverse_event_number 2 is the second last page visited.
          You are given the following data.
          {}
          Can you summarize what was the most popular page people landed on and what page they came from?
      """.format(ga_data)
    
      url = 'http://{}/generate'.format(lb_url)
    
      myobj = {
          "inputs": USER_PROMPT,
          "temperature": 0.90,
          "top_p": 0.95,
          "max_tokens": 2048
      }
      x = requests.post(url, json=myobj)
      result = x.text
      return (result)
    
    function_name = process_incoming.bigframes_remote_function
    print (f"The function name is: {function_name}")
    
    

    次のように置き換えます。

    このチュートリアルでは、BigQuery データセットのロケーションは US に設定されています。これはデフォルトで us-central1 リージョンになります。

  3. セルを実行)をクリックします。

出力には、次のような関数名が表示されます。

The function name is: PROJECT_ID.ga_demo.ga_explain_example

ユーザーの行動を分析する

このセクションでは、次の 2 つの方法のいずれかで process_incoming リモート関数を使用して、ウェブサイト上のユーザーの行動を分析します。

  • BigQuery DataFrames を使用する
  • bq コマンドライン ツールを使用して SQL で直接クエリを実行する

BigQuery DataFrames を使用する

作成した Colab Enterprise ノートブックで BigQuery DataFrames を使用してリモート関数を実行するには:

  1. [+ コード] をクリックして、新しいコードセルを挿入します。
  2. 新しいコードセルに次のコードをコピーし、セルを実行)をクリックします。
# Generate a list of all matchups and their histories as a JSON

grouping_sql = """
with
data_table as (
 SELECT
 distinct
   user_pseudo_id,
   events.value.string_value,
   event_timestamp,
   rank() over (partition by user_pseudo_id order by event_timestamp desc) as reverse_event_number
 FROM
   `bigquery-public-data.ga4_obfuscated_sample_ecommerce.events_20210131` as events20210131,
   unnest (events20210131.event_params) as events
 where events.key = 'page_location'
 qualify reverse_event_number < 3
)
select
*,TO_JSON_STRING (data_table) as ga_history
from data_table
limit 10;

"""

ga_df = bpd.read_gbq(grouping_sql)
post_processed = ga_df.assign(results=ga_df['ga_history'].apply(process_incoming),axis=1)
post_processed.head(10)

次の出力は、クエリのサンプル結果を示しています。

user_pseudo_id string_value event_timestamp reverse_event_number ga_history results axis
0 2342103247.0307162928 https://shop.googlemerchandisestore.com/Google... 1612096237169825 2 {"user_pseudo_id":"2342103247.0307162928","str... {"generated_text":"\n 「次の項目は...
1 48976087.6959390698 https://www.googlemerchandisestore.com/ 1612056537823270 2 {"user_pseudo_id":"48976087.6959390698","strin... {"generated_text":"\n \n ```python\n imp...

bq コマンドライン ツールを使用する

bq コマンドライン ツールを使用して、SQL を使用して直接分析を実行することもできます。

作成した Colab Enterprise ノートブックで bq コマンドライン ツールを使用してリモート関数を実行するには:

  1. [+ コード] をクリックして、新しいコードセルを挿入します。
  2. 新しいコードセルに次のコードをコピーし、PROJECT_ID をプロジェクト ID に置き換えます。

    # Update with your PROJECT_ID
    
    function_name = 'PROJECT_ID.ga_demo.ga_explain_example'
    
    new_sql = """'with \
    data_table as ( \
    SELECT \
    distinct \
      user_pseudo_id, \
      events.value.string_value, \
      event_timestamp, \
      rank() over (partition by user_pseudo_id order by event_timestamp desc) as reverse_event_number \
    FROM \
      `bigquery-public-data.ga4_obfuscated_sample_ecommerce.events_20210131` as events20210131, \
      unnest (events20210131.event_params) as events \
    where events.key = "page_location" \
    qualify reverse_event_number < 3 \
    ) \
    select \
    *, `{}`(TO_JSON_STRING (data_table)) as result \
    from data_table \
    limit 10;' \
    """.format(function_name)
    
    # Run query using bq cli directly in a notebook cell
    
    !bq query --use_legacy_sql=false \
    {new_sql}
    
  3. セルを実行)をクリックします。

次の出力は、クエリのサンプル結果を示しています。

user_pseudo_id string_value event_timestamp reverse_event_number 結果
86037838.0267811614 https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Dino+Game+Tee 1612128627715585 1 {"generated_text":"回答:\n 最もアクセスされたページは https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Dino+Game+Tee でした。\n 次にアクセスされたページは、ユーザーがアクセスしてきたページです。\n\n 説明:\n\n 提供されたデータから、現在のユーザーは「Google Dino Game Tee」の商品を目的として Google のグッズストアにアクセスしたことがわかります。\n \n重要な考慮事項:\n\n* データの解釈: 以下のことは明言できません。"}
4024190.3037653934 https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Black+Cloud+Zip+Hoodie 1612085948486438 1 {"generated_text":"\n ```python\n import pandas as pd\n\n data = {'user_pseudo_id': ['4024190.3037653934', '4024190.3037653934', '4024190.3037653934'],\n 'string_value': ['https://shop.googlemerchandisestore.com"}