BigQuery MLでVertex AIの基盤モデルPaLM2を呼び出して感情分析してみた

記事タイトルとURLをコピーする

G-gen 又吉です。当記事では、BigQuery ML から Vertex AI の基盤モデルを呼び出して感情分析を行う方法を解説します。

Use Generative AI from BigQuery

前提知識

Generative AI Support on Vertex AI

先日 Vertex AI でも Generative AI がサポートされました。Generative AI モデル (基盤モデル) の裏側は PaLM 2 が利用されており、多言語、推論、コーディング機能が強化された最先端の大規模言語モデル (LLM) です。

Vertex AI の Generative AI サポートについての詳細は以下の記事をご参照下さい。

blog.g-gen.co.jp

リモートモデル

リモートモデル とは、Vertex AI エンドポイントまたはリモートサービスタイプを BigQuery から呼び出すことができる機能です。

リモートサービスタイプでは、2023 年 7 月現在、以下のサービスをサポートしています。

尚、2023 年 7 月現在、 リモートモデルはプレビュー機能となっています。

ML.GENERATE_TEXT 関数

概要

ML.GENERATE_TEXT 関数 とは、リモートモデル (Vertex AI の text-bison の基盤モデル) と組み合わせることで、BigQuery に保存されているテキストに対して自然言語生成タスクを実行できます。

言語タスクには、以下の例が挙げられます。

  • 分類
  • 感情分析
  • エンティティの抽出
  • 抽出的な質問への回答
  • 要約
  • テキストを別のスタイルで書き直す
  • 広告コピーの生成
  • コンセプトのアイデア出し

尚、2023 年 7 月現在、 ML.GENERATE_TEXT 関数はプレビュー機能となっています。

引数

ML.GENERATE_TEXT 関数の引数には、Vertex AI の基盤モデル (言語) でモデルに送信できるTop-K や Top-P、Temperature 等のパラメータ値と同等の引数を設定できます。

パラメータ値がどのような役割なのかは、以下のブログにも記載しているのでご参照下さい。

参考:パラメータ値

また、flatten_json_output という引数は、flatten_json_output が TRUE の場合、JSON 形式のレスポンスに含まれる LLM の出力結果と 安全属性の信頼スコアリング の出力結果を個別の列で出力する引数です。

参考:Arguments

出力

出力は、flatten_json_output が TRUE の時と FALSE のときで出力される列名が変わってきます。デフォルトで FALSE となります。

No flatten_json_output 出力される列名 説明
1 FALSE ml_generate_text_result 基盤モデルからの JSON レスポンス。基盤モデルにより生成されたテキストは content の中に含まれ、安全属性の信頼スコアリングは safetyAttributes に含まれる。
2 FALSE ml_generate_text_status 対応する行の API 応答ステータス。操作が成功した場合、この値は空になる。
3 TRUE ml_generate_text_llm_result 基盤モデルから返される生成されたテキスト。
4 TRUE ml_generate_text_rai_result 基盤モデルから返される安全属性の信頼スコアリング。
5 TRUE or FALSE ml_generate_text_status 対応する行の API 応答ステータス。操作が成功した場合、この値は空になる。

クォータと制限

ML.GENERATE_TEXT 関数は、以下のような制限が適用されています。

  • 1 分あたりの Vertex AI API へのリクエスト数 : デフォルト 60
  • ジョブあたりの行数 : 10,000
  • 同時実行ジョブの数 : 1

特に、1 回のジョブ実行あたり 10,000 行の制限があるので、行数が多い場合は少し工夫が必要になります。

参考:BigQuery - Quotas and limits - Cloud AI service functions

参考:Vertex AI - Quotas and limits - Request quotas

概要

使用するデータ

使用するデータは BigQuery の一般公開データセット上にある IMDB(Internet Movie Database) のデータセットを使用します。

IMDB とは、映画やテレビ番組等のコンテンツに関連する情報を集めたオンラインデータベースで、キャスト、制作スタッフ、作品の概要、評価、ファンや批評家のレビューなどが含まれており、今回はその中から reviews テーブルを使用します。

reviews テーブルには、「(映画の) レビュー」「(正解の) ラベル」「映画 ID」「映画 URL」等が含まれています。

reviews テーブルのプレビュー

今回やること

Vertex AI の基盤モデルを BigQuery のリモートモデルとして設定します。そして、そのリモートモデルと BigQuery ML を用いて「(映画の) レビュー」をインプットに、そのレビュー内容が Positive なのか Negative なのかを判断する感情分析タスクを基盤モデルに実行させていきます。

また、「(正解の) ラベル」も含まれるため、最後に 簡易的な精度も算出してみます。

プロンプト設計

プロンプトとは、言語モデルへ送るリクエストのことです。このプロンプト設計が良ければ、基盤モデルからより良い回答を得られます。

今回、映画のレビューをもとに Positive な内容なのか Negative な内容なのかを判定してほしいため、プロンプトには以下の文章を入力してモデルに対しリクエストを送ります。

Classify the sentiment of this review as Positive or Negative?
Review: {映画レビュー内容}
Sentiment:

後述の 実行 部分で、SQL を用いて {映画のレビュー内容} 部分に実際のテキストを入力していきます。

参考:感情分析プロンプト

精度結果

先に結果から申し上げますと、英語で書かれた「(映画の) レビュー」に対し、基盤モデルで感情分析を行った結果、合計 10 回試行した平均の正解率は脅威の 94.3% となりました。

以降に、準備の手順や結果をまとめております。

準備

API の有効化

以下のコマンドを実行し、使用する API を有効化します。

gcloud services enable bigqueryconnection.googleapis.com \
    aiplatform.googleapis.com

データセットの作成

以下のコマンドを実行し、データセットを作成します。

PROJECT_ID={プロジェクト ID を入力}
DATASET_ID={データセット ID を入力}

bq --location=US mk \
    --dataset \
    ${PROJECT_ID}:${DATASET_ID}

Connection の作成

以下のコマンドを実行し、Connection を作成します。

CONNECTION_ID={任意の Connection ID を入力}

bq mk --connection \
    --location=US \
     --project_id=${PROJECT_ID} \
    --connection_type=CLOUD_RESOURCE ${CONNECTION_ID}

Connection リソースを作成すると、自動的に一意のサービスアカウントが生成され、Connection にひも付きます。

以下のコマンドを実行し、サービスアカウントが生成されたか確認します。

bq show --connection ${PROJECT_ID}.us.${CONNECTION_ID}

以下のような出力がでるので、後続作業で利用するためサービスアカウント ID をコピーしておきます。

                 name                   friendlyName   description    Last modified         type        hasCredential                                            properties                                           
 ------------------------------------- -------------- ------------- ----------------- ---------------- --------------- ---------------------------------------------------------------------------------------------- 
  1234556789.{Connection ID}                                17 Jul 13:43:53   CLOUD_RESOURCE   False           {"serviceAccountId": "bqcx-{Project Number}-xxxx@gcp-sa-bigquery-condel.iam.gserviceaccount.com"}  

サービスアカウントに権限付与

以下のコマンドを実行し、先程 Connection 作成時に自動で生成されたサービスアカウントに対し、プロジェクトリソースの Vertex AI ユーザー ロールを付与します。

SERVICE_ACCOUNT_ID={先程コピーしたサービスアカウント ID}

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
    --member="serviceAccount:${SERVICE_ACCOUNT_ID}" \
    --role="roles/aiplatform.user"

リモートモデルの作成

以下のコマンドを BigQuery のクエリエディタで実行し、リモートモデルを作成します。尚、変数は置き換えて下さい。

  • DATASET_ID : 先ほど作成したデータセット ID
  • MODEL_NAME : 任意のモデル名
  • CONNECTION_ID : 先ほど作成した Connection ID
CREATE OR REPLACE MODEL ${DATASET_ID}.${MODEL_NAME}
  REMOTE WITH CONNECTION `us.${CONNECTION_ID}`
  OPTIONS (remote_service_type = 'CLOUD_AI_LARGE_LANGUAGE_MODEL_V1');

実行

感情分析を実行

以下のコマンドを BigQuery のクエリエディタで実行し、5 件の映画レビューについて感情分析を行います。尚、変数は置き換えて下さい。

SELECT
  ml_generate_text_llm_result,
  CAST(JSON_EXTRACT_SCALAR(ml_generate_text_rai_result, '$.blocked') AS BOOL) AS is_safety_filter_blocked,
  * EXCEPT (ml_generate_text_llm_result,
    ml_generate_text_rai_result)
FROM
  ML.GENERATE_TEXT( MODEL `${DATASET_ID}.${MODEL_NAME}`,
    (
    SELECT
      CONCAT( 'Classify the sentiment of this review as Positive or Negative? \n Review: ', review, '\n Sentiment:' ) AS prompt,
      *
    FROM
      `bigquery-public-data.imdb.reviews`
    LIMIT
      5),
    STRUCT( 0.2 AS temperature,
      100 AS max_output_tokens,
      TRUE AS flatten_json_output ))

出力結果は以下のとおりです。2 ~4 行目のレコードは、モデルのレスポンスが安全しきい値を超えた (is_safety_filter_blocked が true ) ため、基盤モデル からの出力 (ml_generate_text_llm_result )が自動的にブロックされています。尚、このような安全フィルターを削除したい場合は、Google のアカウントチームに問い合わせる必要があります。

参考:安全しきい値 (Safety thresholds)

結果出力画面

評価

前提条件

今回使用している IMDB データセットの reviews テーブルは、映画レビューとともに、その映画レビューが Psitive な内容なのか Negative な内容なのかを表す正解ラベルも付与されています。したがって、基盤モデルからの出力と正解ラベルを比較することで正解率 (Accuracy) を求めていきたいと思います。

元データが 100,000 件あるため、すべてのレコードを対象とすると処理にかなり時間を要します。そこで今回は、label カラムが Positive から 50 件、Negative から 50 件を抽出したサンプルデータで正解率を求めていきます。尚、安全フィルターに該当するデータは基盤モデルからの出力がないため SQL 中で除外いたします。

実行

以下のコマンドを BigQuery のクエリエディタで実行し、 正解率を求めてみます。尚、変数は置き換えて下さい。

WITH
  positive AS (
  SELECT
    *,
    ROW_NUMBER() OVER (ORDER BY RAND()) AS row_num
  FROM
    `bigquery-public-data.imdb.reviews`
  WHERE
    label = "Positive" ),
  negative AS (
  SELECT
    *,
    ROW_NUMBER() OVER (ORDER BY RAND()) AS row_num
  FROM
    `bigquery-public-data.imdb.reviews`
  WHERE
    label = "Negative" ),
  sample_data AS (
  SELECT
    *
  FROM
    positive
  WHERE
    row_num <= 50
  UNION ALL
  SELECT
    *
  FROM
    negative
  WHERE
    row_num <= 50 )
SELECT
  COUNTIF(ml_generate_text_llm_result = label) AS correct_answer_number,
  COUNT(label) AS total_number,
  COUNTIF(ml_generate_text_llm_result = label) / COUNT(label) AS accuracy
FROM
  ML.GENERATE_TEXT( MODEL `${DATASET_ID}.${MODEL_NAME}`,
    (
    SELECT
      CONCAT( 'Classify the sentiment of this review as Positive or Negative? \n Review: ', review, '\n Sentiment:' ) AS prompt,
      *
    FROM
      sample_data ),
    STRUCT( 0.2 AS temperature,
      100 AS max_output_tokens,
      TRUE AS flatten_json_output ))
WHERE
  CAST(JSON_EXTRACT_SCALAR(ml_generate_text_rai_result, '$.blocked') AS BOOL) = FALSE

出力結果は以下のとおりです。

出力結果画面

10 回試行し平均値を求めてみると以下のとおりです。

10回試行後の結果まとめ

正解率の平均値は、94.3 % となりました。

又吉 佑樹(記事一覧)

クラウドソリューション部

はいさい、沖縄出身のクラウドエンジニア!

セールスからエンジニアへ転身。Google Cloud 全 11 資格保有。Google Cloud Champion Innovator (AI/ML)。Google Cloud Partner Top Engineer 2024。Google Cloud 公式ユーザー会 Jagu'e'r でエバンジェリストとして活動中。好きな分野は AI/ML。