LightGCNを用いた推薦候補集合の生成 | Wantedly Engineer Blog
こんにちは。ウォンテッドリーでデータサイエンティストをしている角川(@nogawanogawa)です。この記事では、Graph Neural Network(GNN)のアルゴリズムの1つであるL...
https://www.wantedly.com/companies/wantedly/post_articles/1029285
こんにちは。ウォンテッドリーでデータサイエンティストをしている角川(@nogawanogawa)です。
以前のブログにて、LightGCNを用いた推薦候補集合生成を試してみました。
LightGCNではuser-itemの二部グラフを前提にしており、user-item間のインタラクションが複数種類ある(マルチビヘイビア)場合を考慮できていません。そこで今回の記事では、LightGCNをマルチビヘイビア向けに拡張したMB-CGCN を試してみた事例についてご紹介します。
マルチビヘイビア推薦
MB-CGCN
実装
実験
まとめ
ECサイトを例に考えると、ユーザー (user) と商品 (item) 間の関係は最終的な購入以外にもいくつか種類があることがわかります。実際には、
など、user-item間のインタラクションには購入以外にも複数存在することがわかります。
一方で、多くの基本的な推薦ではインタラクションは1種類を想定している場合が多くなっています。グラフニューラルネットワーク(GNN)でモデリングする際にも、基本的にはインタラクションをuser nodeとitem nodeの間の単一のrelationとしてモデリングすることが多くなっています。以前ご紹介したLightGCNの推薦アルゴリズムでもインタラクションが1種類の二部グラフが想定されており、このようなインタラクションが1種類を想定した推薦モデルで複数種類のインタラクションを考える場合にはなんらかの拡張が必要になります。
LightGCNをマルチビヘイビアに対応させる研究の1つに、WWW'23にて"Multi-Behavior Recommendation with Cascading Graph Convolution Networks"という論文で MB-CGCNが発表されています。
他にもLightGCNをマルチビヘイビアに拡張する手法はいくつか提案されているのですが(参考1, 参考2)、モデル構造が過度に複雑になったり、マルチタスク学習が必要になったりしており、私がサーベイした中ではこちらの手法がシンプルにマルチビヘイビアに拡張した手法だと感じたので今回はこちらを取り上げようと思います。
MB-CGCNは複数種類のインタラクションを連鎖反応としてモデル化し、LightGCNをマルチビヘイビアに対応するように拡張したモデルです。
"Multi-Behavior Recommendation with Cascading Graph Convolution Networks"より引用
MB-CGCNではインタラクションの種類ごとに別々にLightGCNで埋め込みを作成します。このとき、インタラクションには順序性を想定しており、前のLightGCNで学習された埋め込みは特徴量変換処理を経て次のLightGCNの入力特徴量として利用されます。
特徴量変換処理は論文によると前段の出力のノイズを軽減する効果を意図して変換行列をかけ合わせることで実現しています。
最後に各インタラクションの出力はuser, itemそれぞれについて加算し、得られたEmbeddingの内積によって最終的な購入が発生するかどうかの予測値を得ています。このようにして、LightGCNを使いつつuser-item間の複数のインタラクションを考慮しつつ、最終的な購入予測に活用しています。
学習から推論まで以前作成したデータセットを用いて実装してみます。こちらの疑似データセットを作る際に、インタラクションを1種類しか作成していなかったので、今回はクリックしたログを擬似的に作成して実装しています。
モデルについては下記のように定義しており、LightGCNの出力を組み合わせています。(今回は2種類のインタラクションを想定して実装しています)
class MBCGCN(nn.Module):
def __init__(self, num_nodes, embedding_dim=64, num_layers=2):
super(MBCGCN, self).__init__()
self.num_nodes = num_nodes
self.embedding_dim = embedding_dim
# Behavior 1 (Click) - LightGCN
self.lightgcn_b1 = LightGCN(
num_nodes=num_nodes,
embedding_dim=embedding_dim,
num_layers=num_layers
)
# Behavior 2 (Rating) - LightGCN
self.lightgcn_b2 = LightGCN(
num_nodes=num_nodes,
embedding_dim=embedding_dim,
num_layers=num_layers
)
# Transformation matrices from B1 to B2
self.W_transform = nn.Linear(embedding_dim, embedding_dim, bias=False)
# Initialize transformation matrix
nn.init.xavier_uniform_(self.W_transform.weight)
def forward(self, edge_index_b1, edge_index_b2, edge_label_index):
"""
Forward pass with cascading behaviors.
Args:
edge_index_b1: Edge index for behavior 1 (click)
edge_index_b2: Edge index for behavior 2 (rating)
edge_label_index: Edge pairs to compute scores for
Returns:
Prediction scores for edge_label_index pairs
"""
# Behavior 1: Get embeddings from click graph
emb_b1 = self.lightgcn_b1.get_embedding(edge_index_b1)
# Transform B1 embeddings for cascade
emb_b1_transformed = self.W_transform(emb_b1)
# Inject transformed B1 embeddings into B2's initial embeddings
# Temporarily modify B2's embedding
original_embedding = self.lightgcn_b2.embedding.weight.data.clone()
self.lightgcn_b2.embedding.weight.data = original_embedding + emb_b1_transformed.detach()
# Behavior 2: Get embeddings from rating graph with cascaded input
emb_b2 = self.lightgcn_b2.get_embedding(edge_index_b2)
# Restore original embedding
self.lightgcn_b2.embedding.weight.data = original_embedding
# Final embedding: Sum of both behaviors
emb_final = emb_b1 + emb_b2
# Compute prediction scores
src = emb_final[edge_label_index[0]]
dst = emb_final[edge_label_index[1]]
return (src * dst).sum(dim=-1)
Lossについては、論文中でBPR Lossを使用しているとの記述があったのでそちらで学習するようにしています。
def recommendation_loss(self, pos_rank, neg_rank, lambda_reg=1e-4):
"""
BPR loss with L2 regularization.
"""
# BPR loss
loss = -F.logsigmoid(pos_rank - neg_rank).mean()
# L2 regularization on transformation matrix
reg_loss = lambda_reg * torch.sum(self.W_transform.weight ** 2)
return loss + reg_lossその他、今回作成したサンプルノートブックもこちらに公開していますので、ご興味ある方がいらっしゃいましたら御覧ください。
今回も社内のデータセットを使用して、実際に利用できそうか確認してみます。性能については以前ご紹介したLightGCNと比較してみようと思います。今回はユーザーと募集間に応募が発生するかを予測することを目的とし、ユーザーと募集間の複数のインタラクションを学習に使用してMB-CGCNで予測してみようと思います。
前回同様Recallで性能比較することとし、LightGCNからの向上率で確認しようと思います。結果は下記の表のようになりました。
今回の実験結果ではLightGCNをマルチビヘイビアへ拡張することで、シンプルなLightGCNからさらに改善できることが確認できました。
今回はLightGCNをマルチビヘイビアへ対応できるよう拡張したMB-CGCNについてご紹介しました。実サービスではuser-item間のインタラクションには最終的なコンバージョン以外にも存在することは容易に想像がつきますが、それをモデルに組み込むのはなかなか骨が折れます。こうした行動をうまくモデルに反映させることで性能向上が期待できることがわかり、勉強になりました。
ウォンテッドリーでは、ユーザーにとってより良い推薦を届けるために日々開発を行っています。ユーザーファーストの推薦システムを作ることに興味があるという方は、下の募集の「話を聞きに行きたい」ボタンから気軽に話を聞きに来ていただけるとうれしいです!