✉️

RecBole を使った推薦システムの実装とRecVAEの概要

2023/09/07に公開

はじめに

RecBoleはMIT licenseで公開されているOSSで、81種[1]の推薦アルゴリズムが実装されているPython(PyTorch)のライブラリである。主に研究の文脈で、各アルゴリズムの再現性を確認するために開発されており、実装されているアルゴリズムの一覧は、「Model Introduction¶」にて確認できる。

この記事では、「General Recommendation」に分類される一般的な推薦アルゴリズムの使用方法と、その中で比較的高性能な推薦が行えるDNNベースのモデルであるRecVAE[2]について紹介する。私自身は推薦アルゴリズムが専門ではないため、推薦アルゴリズム自体や、RecBole開発の背景、その他のアルゴリズムの外観については以下の記事を参考にされたい。

RecBoleの使い方

独自のデータセットの利用

推薦アルゴリズムの評価でよく利用されるデータセットが準備されており、Dataset Listにて、データセットの一覧を確認することができる。実応用の場合、独自のデータセットで学習・評価したい場合も多いため、独自データセットの利用方法について紹介する。

独自のデータセットを利用する方法はいくつかあるが、「Running New Dataset」で紹介されている通り、Atomic Filesという形式でデータセットを作成するのが最も単純な実装だと思われる。利用するモデルによって必要なファイルは異なるが、「General Recommendation」では「.inter」ファイルが必須となる。ここでは、「test」というデータセットを作成する場合を紹介する。

以下のようなtsvファイル(以下の例では入力可能文字に制限があるため、スペース文字にて代用している。)を「test.inter」として保存する。「.inter」は、userとitemの関係を記述するデータで、通常user_id、item_id、任意の追加情報から構成される。関係はインタラクションとも呼ばれ、アイテムの購入や評価など、データセットに応じて異なる意味を持つ。先頭行にはフィールド名が名称とデータ型の組みとして記載されているが、フィールドの名称は任意でよく、実際にアルゴリズムで利用するuser_id/item_idとはconfig.yamlでマッピングする。利用できるデータ型は、先ほどのAtomic Filesのページで確認できる。

user_id:token item_id:token rating:float timestamp:float
1             1193          5            978300760
1             661           3            978302109

user_id/item_idに追加の情報を設定したい場合は、それぞれ「test.user」と「test.item」という名称のtsvファイルを作成し、「test.inter」と同様に記載すれば良い。

これらのファイルは以下のようなディレクトリ構成で保存する必要がある。「dataset」がデータセットの一覧を格納するディレクトリで、その配下に個々のデータセットのディレクトリを作成する。データセットのディレクトリとファイルの名称は、データセットの名称(例の場合はtest)とする必要がある点に注意されたい。

/任意のディレクトリパス/dataset/test/
├── test.inter
├── test.item
└── test.user

評価実験

RecBoleでは、評価実験用のrun_recboleというユーティリティを提供している。PythonやCLIから利用できるが、ここではPythonから利用する方法を紹介する。この節の内容は「Quick Start: General Recommendation」を補足しつつ紹介したものである。

まずは、「config.yaml」を作成する。ここでは、独自データセットのディレクトリパスの設定や、General Recommendationで利用するデータセットのどのフィールドをuser_id/item_idとして利用するか、各推薦アルゴリズム固有の設定(ハイパーパラメータ)、実験の設定を記載する。実験の際は複数のconfigファイルを指定できるので、アルゴリズム固有の設定と共通の設定でファイルを分割しても良いが、名前空間が競合しない範囲においては、単一のファイルにまとめても良い。

# 独自データセットのディレクトリ指定
data_path: /データセットを格納したディレクトリへのパス/dataset

# General Recommendationにおけるデータセットの設定
USER_ID_FIELD: user_id
ITEM_ID_FIELD: item_id
load_col:
    inter: [user_id, item_id]

# model config
embedding_size: 64

# Training and evaluation config
epochs: 500
train_batch_size: 4096
eval_batch_size: 4096
train_neg_sample_args:
    distribution: uniform
    sample_num: 1
    alpha: 1.0
    dynamic: False
    candidate_num: 0
eval_args:
    group_by: user
    order: RO
    split: {'RS': [0.8,0.1,0.1]}
    mode: full
metrics: ['Recall', 'MRR', 'NDCG', 'Hit', 'Precision']
topk: 10
valid_metric: MRR@10
metric_decimal_place: 4

ここでは、BPE(Bayesian Personalized Ranking)を利用する場合の設定を記載しており、モデル固有の設定はリファレンスの各ページで確認できる。実験に関する設定は「Training Settings」と「Evaluation Settings」を参照されたい。

設定ファイルが作成できたら、run_recbole関数に、使用する推薦アルゴリズムの名称、datasetの名称(ここではtest)、設定ファイルのパスを引数として渡すだけで実験ができる。

from recbole.quick_start import run_recbole

result = run_recbole(model='BPR',
                     dataset='test',
		     config_file_list=['config.yaml'])
print(result['test_result'])

Pythonファイルを実行すると、実行ログの後に以下の様なテスト結果が出力される。

OrderedDict([('recall@10', 0.1554), ('mrr@10', 0.129), ('ndcg@10', 0.1175), ('hit@10', 0.2109), ('precision@10', 0.0289)])

モデルの推論結果を得る

評価実験の結果から良さそうなモデルが定まると、そのモデルの推論結果を得たい。推薦アルゴリズムは、「AbstractRecommender」を継承しており、「full_sort_predict」や「predict」メソッドで推論結果を得ることができる[3]。「full_sort_predict」は全てのitemのスコアを返却し、「predict」は指定されたitemのスコアを返却する。これらのメソッドには「Interaction」クラスのオブジェクトを渡す必要がある。ここでは、あるユーザに対するすべてのアイテムのスコアを計算する例を示す。

from recbole.config import Config
from recbole.data import create_dataset, data_preparation
from recbole.model.general_recommender import BPR
from recbole.trainer import Trainer
from recbole.data.interaction import Interaction
from recbole.quick_start import load_data_and_model
import torch


# 推論用のモデル新たに学習する場合
config = Config(model='BPR',
                dataset='test',
		config_file_list=['config_prod.yaml'])
dataset = create_dataset(config)
train_data, _, _ = data_preparation(config, dataset)
model = BPR(config, train_data.dataset).to(config['device'])
trainer = Trainer(config, model)
trainer.fit(train_data)
model = trainer.model

# 学習済みのモデルをロードする場合
# config, model, dataset, train_data, valid_data, test_data = load_data_and_model(
#     model_file='モデルファイルのパス',
# )

# test.userに記載したuser_id
user_id = '123'

input_interaction = Interaction(
	{
	    "user_id": torch.tensor(dataset.token2id(dataset.uid_field, [user_id])),
	}
)
item_scores = model.full_sort_predict(input_interaction).tolist()
item_ids = dataset.id2token(dataset.iid_field, range(len(results)))

RecBoleの推薦アルゴリズムでは「.inter」で指定されたuser_id/token_idを、連続するリストのindexにマッピングして利用しているため、indexとしてのidと「.inter」上でのidを必要に応じて変換する必要がある。変換には、「token2id」と「id2token」メソッドが容易されており、第一引数に「uid_field」か「iid_field」を指定することで、user/itemのどちらのマッピングを解決したいかを指定できる。

RecVAEについて

冒頭で紹介した記事では、RecVAEが高い精度であったことを報告している。私自身で作成したデータセットにおいても、RecVAEが高い精度であったたため、この記事の残りの部分では、RecVAEの動作原理の概要について解説する。詳細は、「AutoEncoder系の手法でTop-N推薦まとめ」を参考にされたい。

RecVAE(Recommender VAE)は、Mult-VAE[4]のEncoderの構造や事前分布等を改善した手法である。また、Mult-VAEは、CDAE(Collaborative Denoising Auto-Encoders)[5]AutoEncoderをVAE(Variational AutoEncoder)変更したものである。従って、CDAEの構造とVAEについての理解があれば、RecVAEのイメージは理解することができる。

CDAEについて

CDAE(Collaborative Denoising Auto-Encoders)は、下図の様なAutoEncoderをノイズを加えたデータで学習させたモデルである。


引用図: Wu et al.,"Collaborative Denoising Auto-Encoders for Top-N Recommender Systems
", 2016

AutoEncoderとは、入出力層よりも少ないボトルネック層と呼ばれる中間層を持つネットワークを、入力層と出力層を近づける様に学習を行う教師なし学習手法である。推論システムであるCDAEでは、ユーザuとアイテムiのインタラクションの履歴y_{u i}に、一部の値を0に置き換えるノイズを加えた\~y_{u i}を入力とし、y_{u i}を出力としてAutoEncoderの学習を行う。この様に、モデルがノイズ除去(Denoising)を学習することで、ユーザとインタラクションが無いアイテムのインタラクションの確率を予測することができるため、推論システムとして利用することができる。
またCDAEでは、ユーザ固有のベクトルを(図中のUser Node)を中間層に足し合わせることで、性能向上を行なっている。

VAEについて

VAE(Variational AutoEncoder, 変分オートエンコーダー)は、中間層を標準正規分布に従う確率変数としてモデル化することで、頑健性を向上させ、ある種の構造化された中間表現を獲得する手法である。詳しくは「【数分解説】VAE : データの生成分布を学習し、潜在変数に応じて滑らかに変化する出力が欲しい Variational Auto Encoder」や「VAE (Variational Autoencoder, 変分オートエンコーダ)」を参照されたい。

単純にAutoEncoderの中間層を標準正規分布からサンプルされるベクトルに変換すると、誤差逆伝播法による効率的なパラメータ推定ができないため、Reparametrization Trickという手法が提案さている。VAEのエンコーダーは、平均\bm{\mu}と分散\bm{\Sigma}を表す表現のエンコードを行い、標準正規分布から生成された乱数\bm{\epsilon}を用いて、中間層を\bm{z} = \bm{\mu} + \bm{\epsilon} \cdot \bm{\Sigma}の様に表現する。このままではエンコードされた結果が平均と分散を表現するとは限らないため、VAEでは、ELBO(Evidence Lower Bound)と呼ばれる再構成誤差を最大化すると同時に、標準正規分布と潜在変数の分布とのKLダイバージェンスを最小化する。


引用図: 「【数分解説】VAE : データの生成分布を学習し、潜在変数に応じて滑らかに変化する出力が欲しい Variational Auto Encoder

おわりに

RecBoleは様々な推論モデルの比較検討を容易に実現できるライブラリであり、新たに推論システムを構築する際は有力な選択肢だと思う。プロダクションでRecBoleを利用しないにしても、比較的最新の手法を含めた実験が容易に実現できるため、独自実装を行うモデルの取捨選択に有益である。

私自身は推論タスクに触れるのが10年ぶりくらいだったので、協調フィルタリング時代のモデルで知識が止まっており、VAEの様なDNNベースの推薦システムの基本原理を理解することができて面白かった。

脚注
  1. 2023/08/25時点 ↩︎

  2. Shenbin et al., "RecVAE: a New Variational Autoencoder for Top-N Recommendations with Implicit Feedback", 2020 ↩︎

  3. 一部のアルゴリズムではfull_sort_predictが実装されていない場合があった ↩︎

  4. Liang et al., "Variational Autoencoders for Collaborative Filtering", 2018 ↩︎

  5. Wu et al.,"Collaborative Denoising Auto-Encoders for Top-N Recommender Systems
    ", 2016
    ↩︎

Discussion