見出し画像

性格診断を使ったユーザレコメンド機能を作ってみた REALITY Advent Calendar 2023

さて7日目の記事になりましたが REALITY Advent Calendar 2023 は楽しんでいただけていますでしょうか!まだまだ続きますよー!

どうもサーバエンジニアのうすぎぬです。今回はGoogle CloudのVertex AIを使ってユーザレコメンド機能を検証する記事になります!
なお、今回の開発合宿はチームで臨みましてクライアント実装をメタルおじさんにお願いしました!

※ 本記事の内容は将来のREALITYアプリへの新規機能追加を示唆するものではありません。

概要

突然ですが、REALITYアプリの「あなたへのおすすめ」機能はご存知でしょうか。「あなたへのおすすめ」機能は配信一覧画面のフォロータブの下の方や、ユーザ検索画面の下の方に表示されています。まあこの機能自体は他SNSにもよくある機能でして、ここから新しい推しや友達を見つけることができますね。

REALITYのユーザレコメンド(あなたへのおすすめ)にはソーシャルグラフベースでのレコメンドロジックが実装され「友達の友達」が優先して表示される仕組みになっています(共通のフォロワーが表示されていることからも分かると思います)。つまりは、存在は認知しているがまだフォローしていない人だったり友達の配信によくコラボしてる人だったりがレコメンドされやすい構造になっています。

このロジックには、友達伝いにソーシャルグラフを広げやすいメリットがある一方で、全く別のコミュニティとの出会いが少なくなる構造になるデメリットがありますね。全く別のコミュニティの友達を見つけやすくするためにはソーシャルグラフ以外でのアプローチのユーザレコメンドロジックが必要そうです。

というわけで「今回は全く別のコミュニティとのつながりを増やそう」をテーマにユーザレコメンドシステムを作ってみようと思います。なんとなく今回は「趣味が似ている」「社会的属性が似ている」あたりでレコメンドできると楽しそうだと思ったので、それを目標にチャレンジします。

また、個人的に機械学習の勉強がしたかったので、機械学習によるレコメンド機能を作ってみることにしました。

機能概観

今回は開発合宿期間中に実装を完了する必要があることから、できるだけ薄い実装で実現する必要があります。それを念頭に置いて以下のシステムを作ることにしました。

  • 「趣味」や「社会的属性」といったラベル情報を収集するための性格診断機能を作成する

  • 性格診断のユーザ回答をもとにクラスタリングモデルを作成し、性格診断の結果からユーザをニアリアルタイムでクラスタリングする

性格診断の結果が近い人をレコメンドすることで、結果的に属性が近いユーザを抽出してレコメンドできそうという算段です。

システム構成

次は、システムを満たすために必要になる具体的なシステム構成を考えます。「性格診断機能」と「機械学習(ML)によるレコメンドシステム」があれば必要最低限の目標は実現できそうです。

大まかには以下の構成でレコメンド機能の作成に臨みます。

  • 性格診断機能

    • 性格診断機能の実装(クライアント)

    • 性格診断回答の保存のためのAPIの作成(サーバ)

  • レコメンドシステム

    • BigQuery MLによるML Model生成

    • Vertex AIによるML Modelのserving

    • API ServerからのVertex AI APIの利用

実際に作った機能紹介

性格診断機能

こちらはNativeでのクライアント実装が必要で、メタルおじさんにお願いしました。性格診断の質問に答える画面だけだと味気なかったので、他アプリなどを参考に性格診断の前後にストーリーを入れてもらいました。

性格診断までの流れは以下のとおりです。

① 配信リストの友達を探すタブ(今回作成)から診断を開始する
② ストーリーが流れる
③ 性格診断のための質問に答える
④ ストーリーが流れる

友達を探すタブのバナーやストーリー、性格診断のコンテンツはChatGPTに作ってもらいました。AIすごい。性格診断のコンテンツはチューニングするとレコメンドの質がより良くなりそうなので、そこに時間をかけるのも楽しそうですね。

※ 本記事の内容は将来のREALITYアプリへの新規機能追加を示唆するものではありません(2回目)。

BigQuery MLによるML Model生成

ここについては多くの人が記事にしており、それらを参考にさせていただきました。特に今回はクラスタリングモデルを利用しておりまして、こちらの記事にて分かりやすく説明いただいていました。感謝!

また、今回はBigQuery MLで作成したML ModelをVertex AIのModel Registryで管理しました。ML Model作成のクエリにVertex AI用のOPTIONを追加することで作成したML Modelが自動でModel Registryに登録されます。大変便利!

最終的なクエリはこんな感じです。

CREATE OR REPLACE MODEL
  sample.hoge_recommend_engine -- Modelの名前
OPTIONS(
    model_registry="vertex_ai", -- Vertex AIのModel Registryに登録
    vertex_ai_model_id='your_model_id', -- Vertex AI上でのModelのID
    model_type='kmeans',
    num_clusters=4,
    standardize_features = TRUE) AS
SELECT * FROM `your-project.sample.your_table`

こちらをBigQueryで実行するだけでVertex AI上にML Modelが作成されます。元データは頑張って作りました(合宿なので許して)。仮に実際にアプリに性格診断機能が入れば、ユーザ回答が元データとして蓄積される設計です。

Vertex AIによるML Modelのserving

BigQuery MLがVertex AIのModel RegistryにML Modelを登録してくれた様子がこちらです。さらに「エンドポイントにデプロイ」するとML Modelによるクラスタリング予測がWebAPIとして利用可能になります。ここがワンステップぽちぽちで完了するの便利すぎますね。Vertex AIすごい。

「エンドポイントにデプロイ」後はオンライン予測のページにデプロイしたエンドポイントが出現します。curlでリクエストするときのサンプルも教えてくれてありがたいです。

API ServerからのVertex AI APIの利用

GolangからのVertex AI APIの利用にはこちらのaiplatform moduleを利用しました。

いくつか躓きポイントはありましたが、以下のコードでVertex AI APIを利用できました。

package hoge

import (
	"fmt"

	aiplatform "cloud.google.com/go/aiplatform/apiv1beta1"
	aiplatformpb "cloud.google.com/go/aiplatform/apiv1beta1/aiplatformpb"
	"golang.org/x/net/context"
	"google.golang.org/api/option"
	"google.golang.org/protobuf/types/known/structpb"
)

func Prediction(params []uint) (*structpb.Value_StructValue, error) {
	// create instance
	instance, err := structpb.NewValue(map[string]interface{}{
		"column1": params[0],
		"column2": params[1],
		"column3": params[2],
		// ...
	})
	if err != nil {
		return nil, fmt.Errorf("failed to create instance. err:%s", err.Error())
	}

	// create prediction client
	ctx := context.Background()
	c, err := aiplatform.NewPredictionClient(
		ctx,
		option.WithEndpoint(fmt.Sprintf("%s-aiplatform.googleapis.com:443", "yourLocation")),
	)
	if err != nil {
		return nil, fmt.Errorf("failed to create prediction client. err:%s", err.Error())
	}
	defer c.Close()

	// exec prediction
	req := &aiplatformpb.PredictRequest{
		Endpoint:  fmt.Sprintf("projects/%s/locations/%s/endpoints/%s", "yourProject", "yourLocation", "yourEndpoint"),
		Instances: []*structpb.Value{instance},
		// See https://pkg.go.dev/google.golang.org/genproto/googleapis/cloud/aiplatform/v1#PredictRequest.
	}
	res, err := c.Predict(ctx, req)
	if err != nil {
		return nil, fmt.Errorf("failed to predict. err:%s", err.Error())
	}
	if len(res.Predictions) == 0 {
		return nil, fmt.Errorf("failed to predict. response value is empty.")
	}

	// parse response
	pbResult, ok := res.Predictions[0].Kind.(*structpb.Value_StructValue)
	if !ok {
		return nil, fmt.Errorf("failed to parse response.")
	}

	return pbResult, nil
}

今回試した範囲ではレイテンシは350 ~ 750 msec程度に収まっていて、意外と軽量に使えるもんやな〜と感心しました。

感想

開発合宿の二日間を使って、性格診断からユーザレコメンドシステムを作りました。個人的に開発合宿では、普段の業務中にはなかなかできないであろう技術領域にチャレンジしたく、その意味ではVertex AIを利用した技術検証を完遂できてよかったです(何より楽しかった)。Vertex AIはGoogle Cloud Nextでも多くのセッションで紹介され、他にも魅力的なサービスが多く存在します。来年もこの領域で開発合宿にチャレンジしたいと思っています。

明日の予告

明日はやまださんによる「ルームにJUKEBOXが欲しい!」です!
お楽しみに!JUKEBOX欲しい!