ベースライン的なレコメンドモデルを作るのに RecTools が便利そう
レコメンド用のツールについて
レコメンド界隈はみんなが使っている定番のライブラリというものがないように思う。例えば、自然言語処理では(色々と文句を言われることもあるが)Hugging Face が標準的に使われるようになっている。それに比べると、レコメンドはとりあえずこれ使っておけ、と言えるものが思い浮かばない。
ロジック/モデル部分中心のものであれば implicit や RecBole などポピュラーなライブラリはいくつかあるが、それに与えるデータの前処理とか結果のオフライン評価に関しては、それぞれの現場で固有のツールやライブラリが作られがちな気がしている。
大規模サービスを運営していて KPI を0.1%でも向上させることに意味があるようなテック企業を除けば、一般的な協調フィルタリングや評価指標を実装すればまずは十分だろうし、そうなると中核となるデータの処理方法も概ね共通してくる。
その割にはその辺まで含めたレコメンドシステムの構築を一通りカバーしているライブラリってないなと思っていたのだけど、最近知った RecTools はこの領域で有用なライブラリなのではないかと思ったので触ってみた。1
RecTools について
RecTools はロシアでクラウドサービスを提供している MWS という会社が開発している OSS である。ドキュメントには
RecTools is an easy-to-use Python library which makes the process of building recommendation systems easier, faster and more structured than ever before. The aim is to collect ready-to-use solutions and best practices in one place to make processes of creating your first MVP and deploying model to production as fast and easy as possible.
と書かれており、レコメンドシステムを構築するプロセス全体をカバーするようなライブラリとして作成されているのがわかる。
RecTools での学習・推論・評価パイプラインは以下のようになる。
# Interaction データの用意
# カラムが (user_id, item_id, weight, datetime) となる pandas dataframe を渡す
=
# 学習
=
# 推論
=
=
# 評価
=
=
学習には (user, item) の interaction データセットを pandas データフレーム として用意する。一部のモデルではさらに追加で特徴量を与えることもできる。
推薦モデルを作るときは生のユーザー・アイテムID(外部ID)を、0から始まる整数のID(内部ID)に変換する処理をよく実行するが、そのようなよくある前処理は全て Dataset
クラスが受け持ってくれるため自分で実装する必要がない。
また使えるモデルも ItemkNN など基本のものから、implicit や LightFM などの定番ライブラリのラッパー、SASRec や BERT4Rec などのニューラル系列推薦モデルまで基本的なものは一通り揃っており、またそれらが共通のインターフェースで使える。BPRなど単純な (user, item) interaction を学習するモデルにも、系列推薦をするモデルにも同じ形式のデータセットを与えれば学習・推論・評価ができるのは便利である。
評価指標についても基本の Recall@K や NDCG@K から、serendipity などの beyond accuracy 指標、さらにバイアス除去系のオプションまで揃っているので困ることはなさそうである。
RecTools で実務でやるような学習・推論パイプラインが組めるか?
概要は上に紹介したので、ここからは実際に実務でモデルを作るのに必要な機能があるか調べていこうと思う。
データ分割
実務でのレコメンドでは、系列推薦モデルを使っていなくても、train/test のデータ分割を時系列で行うことは多い。サービスで使う以上モデルに持たせたい能力は未来予測だからだ。RecTools では interaction データの最後の N 個を評価用に分割するための LastNSplitter
、決まった時間幅のデータを評価用に分割するための TimeRangeSplitter
が用意されており、時系列に沿った分割が簡単にできる。
以下はユーザーごとに行動を時系列で並べ、最後の一個を評価用に、それ以前を学習用に分割する例である
= # pandas -> `Dataset`
=
=
=
, ,
=
=
n_splits
を増やすことで cross validation 用に複数 fold を生成できる。
カスタム Trainer の利用
ニューラルネットワーク系のモデルは内部的には pytorch と pytorch lightning で実装されている。何も指定しなくても内部でデフォルトの Trainer インスタンスを生成してくれるが、学習の制御のためカスタマイズしたいことは多い。そのような場合は、モデルのコンストラクタに Trainer を返す関数を与える。
SASRec モデルを例とすると以下のように書ける
...
=
get_trainer
の引数は別途 get_trainer_func_kwargs
で渡す必要がある。
Early stopping やチェックポイント
これもニューラルネットワーク系のモデルの場合だが、学習時に validation セットにおけるメトリクスを監視して early stopping をしたり、途中経過をチェックポイントとして残したいことは多い。
その場合、ドキュメントの Transformer Models Advanced Training Guide にあるように、まずは毎エポック validation メトリクスを計算する callback を実装する必要がある。
Validation メトリクスを計算する callback
=
=
=
: = 0
: =
=
=
=
,
=
=
=
=
=
=
=
=
=
=
= .
+=
=
=
= 0
そしてこの callback を上の方法で Trainer に設定する
=
=
=
=
return
また validation 用のデータを作るため学習データをさらに分割する必要があるが、これは LastNSplitter
などを使わず、学習データのうちどこが validation かを表すマスクを渡すことが想定されているようである。以下は学習データのなかで各ユーザーごとに最後のアイテムを validation として使う例。
=
= == 0
return
=
以上の準備をして model.fit(ds_train)
をすれば、指定したメトリクスに基づいた early stopping が実行され、その過程のチェックポイントを残すことができる。
RecTools が向いていないこと
以上見てきたようにベースライン的なモデルであればそれなりの柔軟性を持ちつつ簡単に学習から評価まで回せそうである。一つ難点を挙げるとすれば、基本的にデータセットを pandas のデータフレームとして扱うため、一度にメモリに乗り切らないような大規模データを扱うことは向いていない。あくまで小〜中規模のデータセットに対してサクッとベースライン性能を持つレコメンドシステムを作るためのツールだと思うのが良さそうである。
Bluesky で Aki Ariga さんがコントリビュートしているのを見たことで知った。