BigQuery MLで学習してVertex AIで推論する一連の流れを追ってみよう

BigQuery MLで学習してVertex AIで推論する一連の流れを追ってみよう

おはこんハロチャオ~!何者(なにもん)なんじゃ?じょんすみすです。

BigQuery ML(以下BQML)を使って機械学習を行う方法や学習済みモデルをVertex AIと連携して利用する方法に関して、いくつかの紹介をしていました。

さて、今回はこれらを一連の流れとして整理してみることにしましょう。

BQMLの基本的な使い方

最初にBQMLを使って機械学習を行うまでの流れを確認しておきます。 BQMLを使っての機械学習はSQLで実行できます。

学習をする際は

  • CREATE MODELを使って利用するアルゴリズムや保存先、ハイパーパラメータなどを指定する
  • SELECTで学習対象となるデータ取得する

という形になります。 実際の例としては以下のようになります。

-- CREATE MODELで機械学習モデルを作る
-- 出力先の指定はテーブル名などと同様の指定方法
create or replace model `<project>.<dataset>.titanic_model`
options(
  model_type='logistic_reg', -- 利用するアルゴリズムの指定
  input_label_cols=['Survived'] -- 目的変数のカラム名を指定
) as
-- 学習に利用するデータをSELECTで取得する
-- 通常のSELECt文がそのまま利用可能
select
  Survived,
  Sex,
  Age,
  Fare,
from
  `<project>.<dataset>.titanic_train`

このモデルを使っての推論は以下のように実施します。 これによって、推論結果の数値やラベル、ラベルごとの確率値の配列などが返されます。

select 
    *
from 
    -- ML.PREDICT関数を利用
    ml.predict(
        -- 第1引数は利用するモデル
        model `<project>.<dataset>.titanic_model`,
        -- 第2引数は推論対象のデータ
        (
            select
                Sex,
                Age,
                Fare,
            from
                `<project>.<dataset>.titanic_test`
        )
    )

作成されたモデルは、テーブルなど同様に確認できます。コンソール上であれば左側にある一覧の「Models」に表示されます。 このモデルを選択することで、学習時の状況や評価に関して確認できます。

BQMLは、Explainable AI(XAI)にも対応しています。 ml.predict 関数の代わりに ml.explain_predict 関数を利用して推論を実施すると出力に以下のような項目が追加されます。

個々の項目の詳細については以下をご参照ください。

機械学習系関数とTRANSFORM句

BigQueryでは ML. で始まる関数が提供されています。 これらは、単体でも利用できますが主に機械学習での利用を想定したものとなっています。

本シリーズの先日のこの記事もML系の関数の紹介となっています。

これらの関数の中には特徴量エンジニアリングに関するものも多くあります。 例えば、 ML.IMPUTER 関数であれば欠損値の補完を行いますし ML.STANDARD_SCALER であれば正規化を行います。 このほかにもカテゴリカル変数のエンコーディングや自然言語、画像などを対象としたものもあります。

ML系の関数は基本的には対象のカラム全体やウインドウ関数として利用した際のPARTITIONを見て計算されます。 ML.IMPUTER であれば、平均値、中央値、最頻値といった値を補完対象にしますがそれらを求めるには対象とするデータ全体から算出する必要があります。 ML.STANDARD_SCALER は同様に平均と標準偏差が計算する必要があります。

機械学習で利用する際にはこの値は、学習時と同じものを推論時にも利用する必要があります。 たとえは、 正規化を行う場合、学習データの平均と標準偏差を使って推論時のデータの変換も行います。 この仕組みを実現しようと思うと、学習データの平均と標準偏差をどこかに保存しておいて、推論時にもそれを読み込んで変換するという処理が必要になります。 BQMLにおいては、このプロセスを簡略化する方法があります。ML系の関数をSELECTの中ではなくTRASFORM句として別途特徴エンジニアリングの処理を入れておくことで、この処理も含めたモデルが生成されるのです。

まずは

create or replace model `<project>.<dataset>.titanic_model_no_transform`
options(
  model_type='logistic_reg',
  input_label_cols=['Survived']
) as
select
  Survived,
  -- このように指定すると、これらで利用した値を別途持っておく必要がある
  ML.LABEL_ENCODER(Sex) over() as labeled_sex,
  ML.IMPUTER(Age, 'mean') over() as impute_age,
  ML.STANDARD_SCALER(Fare) over() as scaled_fare
from
  `<project>.<dataset>.titanic_test`
select distinct
  -- ラベルエンコードしたものと元の情報の対応関係
  Sex,
  ML.LABEL_ENCODER(Sex) over() as labeled_sex
from
  `<project>.<dataset>.titanic_test`
--
select
  -- 計算するのに必要な値
  avg(Age) as mean_age,
  avg(Fare) as mean_fare,
  stddev(Fare) as sd_fare
from
  `<project>.<dataset>.titanic_test`

その後、推論時にはこの値を使って計算する必要があります。

select 
    *
from 
    ml.predict(
        model `<project>.<dataset>.titanic_model_no_transform`,
        (
            select
                -- ラベル名に対応する値を入れている
                case when Sex = 'female' then 1 else 2 end as labeled_sex,
                if(Age is null, <Ageの平均値>, Age) as impute_age,
                (Fare - <Fareの平均値>) / <Fareの標準偏差> as scaled_fare
            from
                `<project>.<dataset>.titanic_test`
        )
    )

ここで便利に使えるのがTRANSFORM句です。TRANSFORM句を使えば、学習時も推論時もSELECTの結果に対して同じ処理を適用してくれるようになります。

create or replace model `<project>.<dataset>.titanic_model_transform`
transform(
  Survived,
  ML.LABEL_ENCODER(Sex) over() as labeled_sex,
  ML.IMPUTER(Age, 'mean') over() as impute_age,
  ML.ROBUST_SCALER(Fare) over() as scaled_fare,
)
options(
  model_type='logistic_reg',
  input_label_cols=['Survived'],
) as
select
  Survived,
  Sex,
  Age,
  Fare
from
  `<project>.<dataset>.titanic_test`

これに対して、SELECTの結果が同じであればいいので推論は以下のように実施できます。

select 
    *
from 
    ml.predict(
        model `<project>.<dataset>.titanic_model_transform`,
        (
            select
                Sex,
                Age,
                Fare
            from
                `<project>.<dataset>.titanic_test`
        )
    )

別途計算に利用する値を保持しておく必要も無いので楽ですね。

Vertex AIと連携して使う

SQLだけで機械学習ができる便利なBQMLですが、推論時にも入植データがBigQuery内にあることが前提となるため、バッチ推論しかできません。

機械学習の利用シーンとして、ユーザからリクエストに応じてリアルタイムに推論結果を返したい場合があります。 一方、機械学習に関する全般的な機能を提供するVertex AIではそういった推論用エンドポイントを立てる仕組みが提供されています。 Vertex AIをそのまま利用しようとすると、コードの実装や動かすためのコンテナの用意など事前に準備すことも多くなります。

そこで、BQMLで作成したモデルをVertex AIで利用できるようにすれば、後はエンドポイントを立てるだけで簡単にリアルタイム推論を実現できそうです。 BQMLではそれを簡単に実現する方法があります。

以下のようにオプションを一つ追加するだけです。

create or replace model `<project>.<dataset>.titanic_model_transform`
transform(
  Survived,
  ML.LABEL_ENCODER(Sex) over() as labeled_sex,
  ML.IMPUTER(Age, 'mean') over() as impute_age,
  ML.ROBUST_SCALER(Fare) over() as scaled_fare,
)
options(
  model_type='logistic_reg',
  input_label_cols=['Survived'],
  -- オプションでこの項目を追加することでVertex AIのModel Registryと連携される
  model_registry="vertex_ai"
) as
select
  Survived,
  Sex,
  Age,
  Fare
from
  `<project>.<dataset>.titanic_model_transform`

Vertex AIには様々な機能がありますが、今回知っておく必要があるのは以下の3つです。

  • Trainingジョブ
  • Model Regstry
  • Online prediction

Trainingジョブはその名の通り、学習を行う機能を提供します。 先ほどのBQMLでいうとCREATE MODELで実行する処理に相当します。 どのような処理を動かすかを記述したプログラムのコード、それを動かすためのコンテナをあらかじめ用意しておきます。 それに対して、実行時にオプションとCloud StorageやBigQueryからデータを入力として受け取って学習処理をします。

推論時には、推論を実行するコードと学習済みモデル、それを動かすコンテナを用意してエンドポイントを立てます。 推論エンドポイントはHTTPリクエストで1件1件に対する推論を行います。

モデルはTrainingジョブなどで作成したものを利用する必要があるためこの2つはセットでの流れとなっています。 ただし、モデルは必ずしもVertex AIで作成したものである必要はありません。 推論エンドポイントを立てるのに必要な要素さえ揃っていればいいのです。

そこで登場するのがModel Registryです。 これは、推論エンドポイントを立てるのに必要な要素をまとめて管理しておくためのものです。 Trainingジョブの出力ともなっていますが、外部から持ち込んだモデルも含めてエンドポイントを立てるのに必要な要素を管理しておくための仕組みになっています。 TrainingジョブがCloud Storage出力した学習済みモデルや外部からアップロードしたモデルとそれを動かすコンテナをセットで管理しています。

さて、BQMLとの連携に話を戻すと、OPTIONSにて model_registry="vertex_ai" を指定することでBQMLで作成したモデルをVertex AIのModel Regstryにも登録しているとわけです。

これで、モデルをVertex AIで利用する準備が整いました。

エンドポイントを立てて推論を実施する

エンドポイントを立てて推論をしてみます。 今回は、コンソール上から実施してみます。

表示された設定で「Endpoint name」に任意の値を入力します。

続いての「Model Settings」の前半です。 今回はエンドポイントに複数モデルをぶら下げる設定はしないため、Machine typeのみを指定して他はそのままで問題ありません。

後半として、LoggingとExplainability optionsというものがあり〼。これらはそれぞれ、ログ出力に関する設定とXAIの機能を利用するかの設定となりますので、必要に応じて設定してください。

最後はModel Monitoringに関する設定です。 こちらはスキューやドリフトといった特徴量が時間経過などに伴って学習時から変化していないかを検出するための仕組みとなりますが、今回は利用しないためオフのままにしておきます。

エンドポイントのStatusがアクティブになればデプロイ完了です。 コンソール上からテストしてみましょう。

JSON requestに以下のようなデータを入力して「PREDICT」を選択する右側に推論結果が表示されます。

この際BQMLにてTRANSFORM句で実施していた処理も含まれていることが確認できます。 以前は、TRANSFORM句を含むモデルには対応していませんでしたが現在ではこの処理も含めて実施可能となっています。

そのため、BigQueryに生データが蓄積されていれば、都度リクエストとして与えられる情報と一致して、処理を共通化しやすくなります。

(Optional)エンドポイントの削除

モデルをデプロイしているエンドポイントは立て続けておくと課金が発生します。 そのため、必要ない場合は削除しておくことをお勧めします。 その際、エンドポイントへのモデルの紐づけ解除 → エンドポイントの削除の順で行う必要があります。

メニューのOnline predictionから作成したモデルを選択します。

エンドポイントに紐づくモデルの一覧が表示されるので、右側のメニューを展開して「Undeploy model from endpoint」を選択して紐づけを解除します。

その後、戻ってエンドポイント自体を削除します。

おわりに

今回は、BQMLに関してモデル作成から推論までのやり方と、Vertex AIを使ってリアルタイム推論できるようになるまでの流れを確認しました。

今回は、エンドポイントデプロイは手動で行いましたが新しいモデルのデプロイをトリガーにして自動化すれば、SQLのみで一通りのことができる環境が整いますし、Model Monitoringと合わせてモデル再作しのSQLを自動実行するなども考えられますね。