こんにちは。研究開発部の深澤(@fufufukakaka)です。
本記事では最近面白いなと思って watch しているレコメンド系のプロジェクト RecBole を紹介いたします。また、クックパッドが展開している事業の一つであるクックパッドマートのデータを使って数多くのレコメンドモデルを試す実験も行いました。その結果も合わせて紹介します。
TL;DR:
- レコメンドモデルは作者実装に安定性がなく、またモデルをどのように評価したかも基準がバラバラで、再現性が難しいとされている(from RecSys 2019 Best Paper)
- 再現性に取り組むプロジェクトとして 2020年12月に始まった RecBole がある。 RecBole を利用することでなんと 50個以上のレコメンドモデルを大体1コマンドで試せる
- クックパッドマートでユーザに対してアイテムをレコメンドするシチュエーションを想定し実験を行った。その結果、テストデータの6000ユーザに対して2000ユーザ(三分の一)に正しい推薦を行うことができるモデルを発見できた
正しく強いレコメンドモデルを探すのは難しい
サービスの中で機械学習といえばレコメンド、といわれる機会は非常に多いかと思います。が、レコメンドは機械学習の中ではかなり特殊な問題設定です。クラス分類したり回帰したり、と様々な解き方をすることができるタスクなのがその要因です。「ユーザがこのアイテムを買ってくれる確率」を推定しても良いし「ユーザが好きなアイテムのランキング」を予測しても良い。そもそもアイテムの数が数万種類くらいある中で「このユーザはこれを買ってくれそう」を予測するのは非常に難しいです。つまり、レコメンド系は実社会サービスでの需要が高く非常に難しい問題、と言えます。
おかげでたくさんの研究が日々発表されています。それ自体は素晴らしいことです。RecSysというレコメンドのみを取り扱う国際会議も存在しています。最近ではDeep Learningを活用した研究が殆どを占めています。
ですが、この日々公開されている研究には再現性がないことが指摘されています。2019の RecSys ベストペーパーは「Are We Really Making Much Progress? A Worrying Analysis of Recent Neural Recommendation Approaches」でした。「本当にニューラルネットワーク系の手法で精度は上がっているのか?」というこの論文では衝撃の事実が明かされており
- トップ会議(KDD, SIGIR, WWW, RecSys)のDNN関連研究18本を追試した
- 18本のうち、現実的な努力を行った上で再現できたのが7本(半分以下!)
- (RecSysでの発表によると、)実装が再現できない場合は、実装を原著者らに問い合わせて1ヶ月待った
- 再現できたとしても 6/7がkNNベース(シンプルなモデル)+ハイパーパラメータ最適化に負けてしまった
- 残りの1つもDNNではない線形の手法を調整したものに負ける場合もあった
- 18本のうち、現実的な努力を行った上で再現できたのが7本(半分以下!)
(refs. https://qiita.com/smochi/items/98dbd9429c15898c5dc7 )
国際会議で「state-of-the-artだ」と主張している論文の殆どが、実際には10年以上前から存在しているシンプルな手法に負けてしまう、というサーベイ結果が出ており、非常に面白い論文でした。
この論文が示したように、レコメンドの研究は数多く発表されているものの殆どの実装に再現性がなく、また正しい比較ができていない、というのが現状です。当然ですが、論文内で提示されている GitHub リポジトリの実装は人によってまちまちです。再現実装は再利用が可能なものから環境構築自体が困難なものまで色々あります。前提としてコードを上げてくれることは非常にありがたいのですが、それぞれの手法で土台を揃えた実験を行うのはそもそもが難しい状況です。
RecBoleについて
RecBoleは中国人民大学・北京大学の研究室が共同で始めたプロジェクトのようで、去年の11月に arxiv に登場しました。今年の8月に提供しているモジュールがv1を迎えて、本格的に色々な人が利用するようになったようです。
RecBole 最大の魅力は、上述してきた再現性の難しいレコメンドモデルを統一したインタフェースで実装し、比較を容易にしているところにあります。そして実装されているモデル、適用できるデータセットの数が凄まじいです。モデルは現時点で70以上(モデルリストがすごい )、データセットは20以上のものについて即座に試せます。どれくらい即座に試せるかと言うと
pip install recbole python run_recbole.py --model=<your favorite model> --dataset_name ml-100k
これだけで、レコメンド界隈の中で最も有名なベンチマークである MovieLens-100k データセットに対して70以上のモデルを即座に(追加の設定が必要なやつもありますが)試せます。これだけのモデル・データを試すことができる環境はそうないと思われます。また70以上の収録されているモデルたちは全て PyTorch ベースで丁寧に再実装が行われており信頼性は非常に高いです。predict関数などの基本的なインタフェースは統一されており、実験のし易い環境が整えられています。
RecBole を自分たちのデータで使えるようにする
実際に RecBole を使えるようにするためにはどうするばよいのか、について簡単にまとめてみました。
- ユーザとアイテムのアクション履歴をまとめたデータを用意する
- データをコントロールするクラスを用意する
- 配布されているスクリプトを使ってデータを RecBole が読める形式に変換する
- 学習に必要な設定ファイルを用意する
- 学習スクリプトを走らせる
1. ユーザとアイテムのアクション履歴をまとめたデータを用意する
自分の使いたいデータを持ってきて、以下のようなファイルで保存しておきます。
今回はクックパッドマートを対象としてデータを作りました。interact.csv ではあるユーザがあるアイテムを購入したログが表現されています。MovieLens のような Rating (Explicit Feedback)のついていない Implicit Feedback なデータセットです。
なお、ここで紹介している user_id, item_id などはいずれもダミーとなっています。
interact.csv
user_id,item_id,timestamp(Unix timestamp) 1,1,1630461974 2,2,1630462246 3,2,1630462432
items.csv
item_id,item_name,item_category_id 1,豚バラ,9 2,にんじん,7
users.csv
user_id,feature1,feature2 1,286,130 2,491,3 3,342,32
2. データをコントロールするクラスを用意する
続いて、RecBole 内でこれらのデータを扱うためのクラスを用意します。基本的には BaseDatasetと同じインタフェースを用意して、その内部をデータに合わせて調整するような作業になります。
import os import pandas as pd from src.dataset.base_dataset import BaseDataset # https://github.com/RUCAIBox/RecSysDatasets/blob/master/conversion_tools/src/base_dataset.py をコピーして所定の場所に配置しておくclassCookpadMartDataset(BaseDataset): def__init__(self, input_path, output_path): super(CookpadMartDataset, self).__init__(input_path, output_path) self.dataset_name = "ckpd_mart"# input_path self.interact_file = os.path.join(self.input_path, "interact.csv") self.item_file = os.path.join(self.input_path, "items.csv") self.user_file = os.path.join(self.input_path, "users.csv") self.sep = ","# output_path output_files = self.get_output_files() self.output_interact_file = output_files[0] self.output_item_file = output_files[1] self.output_user_file = output_files[2] # selected feature fields# 型について -> https://recbole.io/docs/user_guide/data/atomic_files.html#format self.interact_fields = { 0: "user_id:token", 1: "item_id:token", 2: "timestamp:float", } self.item_fields = { 0: "item_id:token", 1: "item_name:token", 2: "item_category_id:token" } self.user_fields = { 0: "user_id:token", 1: "feature1:token", 2: "feature2:token", } defload_inter_data(self): return pd.read_csv(self.interact_file, delimiter=self.sep, engine="python") defload_item_data(self): return pd.read_csv(self.item_file, delimiter=self.sep, engine="python") defload_user_data(self): return pd.read_csv(self.user_file, delimiter=self.sep, engine="python")
3. 配布されているスクリプトを使ってデータを RecBole が読める形式に変換する
https://github.com/RUCAIBox/RecSysDatasets/blob/master/conversion_tools/run.py
ここで公開されているスクリプトを使って RecBole 内で利用できる形式の Atomic Files に変換します。 refs
python src/dataset/convert.py --dataset ckpd_mart \ --input_path data/mart_data --output_path dataset/ckpd_mart \ --convert_inter --convert_item --convert_user
すると ckpd_mart.inter
ckpd_mart.item
ckpd_mart.user
というファイルが所定の場所に配備されます。これでデータの準備は完了です。
4.学習に必要な設定ファイルを用意する
https://recbole.io/docs/user_guide/config_settings.html
RecBole が用意してくれている config 設定を読みながら自分のデータに合わせた設定ファイルを書いていきます。
# generalgpu_id:0use_gpu:False # GPUを使う時はTRUEにするseed:2020state: INFO reproducibility:Truedata_path:'dataset/' # 使うデータが格納されている場所checkpoint_dir:'saved/' # モデル保存先show_progress:Truesave_dataset:False # True にすればtrain, valid, test で使ったデータを保存してくれるsave_dataloaders:False# Atomic File Formatfield_separator:"\t"seq_separator:"@" # 文字列があった場合この文字で区切られる。特徴量読み込み時にバグってしまう可能性があるため、できるだけデータを事前に処理しておき絶対に出現しない保障が取れている記号を書くべき(日本語の場合)# Common FeaturesUSER_ID_FIELD: user_id ITEM_ID_FIELD: item_id RATING_FIELD:~ # implicit feedback の場合TIME_FIELD: timestamp # Selectively Loading# 使うデータだけを選んで loadしますload_col:inter:[user_id, item_id, timestamp]user:[user_id, feature1, feature2]item:[item_id, item_name, item_category_id]unused_col: # データとしては読み込むけど学習には使いたくないカラムはここで指定するinter:[timestamp]# Training and evaluation configepochs:50stopping_step:10 # 10 step valid_metric が改善しない場合は止めるtrain_batch_size:4096eval_batch_size:4096neg_sampling: # implicit feedbackなデータを扱っていて positive,negative両方のラベルが必要な手法を試す際に、negative samplingすることでデータを用意できるuniform:1eval_args:group_by: user # user 単位でアイテムを集約して評価に使う。基本的にこれ以外使うことはないorder: TO # Temporal Order。時系列順で train, valid, test を分けてくれるsplit:{'RS':[0.8,0.1,0.1]} # 80%, 10%, 10% で分けてくれるmode: full metrics:['Recall', 'MRR', 'NDCG', 'Hit', 'Precision']topk:10valid_metric: MRR@10 # この指標をtrackするmetric_decimal_place:4
5. 学習スクリプトを実行する
おまたせしました。あとは実験をするだけです。
モデルによって与えるパラメータが微妙に違ったりするので、そこを吸収する以下のようなスクリプト(run_experiment.py)を用意して
import click from recbole.quick_start import run_recbole @click.command() @click.option( "-m", "--model_name", required=True, type=str, help="Model Name(see recbole's model list)", ) @click.option( "-d", "--dataset_name", required=True, type=str, help="Dataset Name(your custom dataset name or recbole's dataset name)", ) @click.option( "-c", "--config_file_list", required=True, nargs=-1, help="config file path", ) defmain(model_name, dataset_name, config_file_list): if model_name in [ "MultiVAE", "MultiDAE", "MacridVAE", "RecVAE", "GRU4Rec", "NARM", "STAMP", "NextItNet", "TransRec", "SASRec", "BERT4Rec", "SRGNN", "GCSAN", "GRU4RecF", "FOSSIL", "SHAN", "RepeatNet", "HRM", "NPE", ]: # これらは non-sampling method# https://recbole.io/docs/user_guide/model/general/macridvae.html などを参照 parameter_dict = { "neg_sampling": None, } run_recbole( model=model_name, dataset=dataset_name, config_file_list=config_file_list, config_dict=parameter_dict, ) else: run_recbole( model=model_name, dataset=dataset_name, config_file_list=config_file_list ) if __name__ == "__main__": main()
あとは python run_experiment.py --dataset_name ckpd_mart --model_name <your favorite model> --config_files config/ckpd_mart.yml
するだけです。お疲れさまでした。
RecBole を試してみた結果
ここまで頑張って用意した土台を使って、早速 RecBole に収録されているモデルをクックパッドマートの購入履歴データ(2021年9月~10月)で試してみました。先程のスクリプトの引数を変えるだけで次々と実験を行うことができます。追加の設定ファイルが必要なものを除いて、50前後のレコメンドモデルを実験することができました。
それでは以下に結果の表を示します。モデル名と各指標、タイプ(行動データしか使わないgeneral・別の情報を使うcontext-aware、時間情報を用いるsequential)、論文名が一覧になっています。
モデル名 | recall@10 | mrr@10 | ndcg@10 | hit@10 | precision@10 | タイプ | 論文名 |
---|---|---|---|---|---|---|---|
RecVAE | 0.2754 | 0.2626 | 0.2474 | 0.314 | 0.0367 | general | RecVAE: A New Variational Autoencoder for Top-N Recommendations with Implicit Feedback |
MacridVAE | 0.2651 | 0.2488 | 0.2364 | 0.303 | 0.0347 | general | MACRo-mIcro Disentangled Variational Auto-Encoder |
NAIS | 0.2324 | 0.2452 | 0.2244 | 0.2698 | 0.0325 | general | Neural Attentive Item Similarity Model for Recommendation |
NNCF | 0.2248 | 0.1755 | 0.1767 | 0.2567 | 0.0282 | general | A Neural Collaborative Filtering Model with Interaction-based Neighborhood |
RepeatNet | 0.2725 | 0.1468 | 0.1766 | 0.2725 | 0.0272 | sequential | RepeatNet: A Repeat Aware Neural Recommendation Machine for Session-based Recommendation. |
NeuMF | 0.2344 | 0.1638 | 0.1699 | 0.268 | 0.0304 | general | Neural Collaborative Filtering |
LINE | 0.1859 | 0.1556 | 0.1529 | 0.2156 | 0.0237 | general | LINE: Large-scale Information Network Embedding |
BPR | 0.1789 | 0.1455 | 0.1442 | 0.2088 | 0.0223 | general | BPR Bayesian Personalized Ranking from Implicit Feedback |
SHAN | 0.1738 | 0.1189 | 0.132 | 0.1738 | 0.0174 | sequential | SHAN: Sequential Recommender System based on Hierarchical Attention Network. |
Item2vec | 0.121 | 0.1183 | 0.112 | 0.1372 | 0.0148 | general | Item 2 Vec-based Approach to a Recommender System |
DGCF | 0.1703 | 0.0965 | 0.1099 | 0.1931 | 0.0201 | general | Disentangled Graph Collaborative Filtering |
FFM | 0.187 | 0.0922 | 0.1096 | 0.2099 | 0.0225 | context-aware | Field-aware Factorization Machines for CTR Prediction |
FPMC | 0.151 | 0.0935 | 0.107 | 0.151 | 0.0151 | sequential | Factorizing personalized Markov chains for next-basket recommendation |
NARM | 0.1664 | 0.0847 | 0.1039 | 0.1664 | 0.0166 | sequential | Neural Attentive Session-based Recommendation |
LightGCN | 0.1549 | 0.0794 | 0.0952 | 0.1715 | 0.0174 | general | LightGCN: Simplifying and Powering Graph Convolution Network for Recommendation |
NGCF | 0.126 | 0.0823 | 0.089 | 0.1416 | 0.0148 | general | Neural Graph Collaborative Filtering |
SASRec | 0.1142 | 0.0657 | 0.0771 | 0.1142 | 0.0114 | sequential | Self-Attentive Sequential Recommendation |
HRM | 0.0992 | 0.0684 | 0.0756 | 0.0992 | 0.0099 | sequential | HRM: Learning Hierarchical Representation Model for Next Basket Recommendation. |
EASE | 0.1205 | 0.0752 | 0.0751 | 0.1559 | 0.0204 | general | Embarrassingly Shallow Autoencoders for Sparse Data |
MultiVAE | 0.1113 | 0.0681 | 0.0751 | 0.1245 | 0.0126 | general | Variational Autoencoders for Collaborative Filtering |
NPE | 0.123 | 0.0597 | 0.0744 | 0.123 | 0.0123 | sequential | NPE: Neural Personalized Embedding for Collaborative Filtering |
MultiDAE | 0.1011 | 0.0596 | 0.0671 | 0.1127 | 0.0114 | general | Variational Autoencoders for Collaborative Filtering |
SRGNN | 0.1115 | 0.0515 | 0.0654 | 0.1115 | 0.0112 | sequential | Session-based Recommendation with Graph Neural Networks |
ENMF | 0.1075 | 0.0545 | 0.0629 | 0.1261 | 0.0131 | general | Efficient Neural Matrix Factorization without Sampling for Recommendation |
DCN | 0.1085 | 0.0508 | 0.06 | 0.1255 | 0.013 | general | Deep & Cross Network for Ad Click Predictions |
FOSSIL | 0.087 | 0.0481 | 0.0572 | 0.087 | 0.0087 | sequential | FOSSIL: Fusing Similarity Models with Markov Chains for Sparse Sequential Recommendation. |
ItemKNN | 0.0649 | 0.0666 | 0.0534 | 0.094 | 0.0126 | general | Item-based top-N recommendation algorithms |
DeepFM | 0.0873 | 0.0347 | 0.0442 | 0.1029 | 0.0106 | context-aware | DeepFM: A Factorization-Machine based Neural Network for CTR Prediction |
PNN | 0.0851 | 0.0353 | 0.0441 | 0.0994 | 0.0102 | context-aware | Product-based neural networks for user response prediction |
FM | 0.0817 | 0.0325 | 0.0412 | 0.0961 | 0.0098 | context-aware | Factorization Machines |
BERT4Rec | 0.0685 | 0.0303 | 0.0391 | 0.0685 | 0.0069 | sequential | BERT4Rec: Sequential Recommendation with Bidirectional Encoder Representations from Transformer |
xDeepFM | 0.0743 | 0.0281 | 0.0371 | 0.0858 | 0.0089 | context-aware | xDeepFM: Combining Explicit and Implicit Feature Interactions for Recommender Systems |
NFM | 0.0736 | 0.0288 | 0.0369 | 0.0867 | 0.0088 | context-aware | Neural Factorization Machines for Sparse Predictive Analytics |
AutoInt | 0.0741 | 0.0275 | 0.0362 | 0.0872 | 0.0089 | context-aware | AutoInt: Automatic Feature Interaction Learning via Self-Attentive Neural Networks |
AFM | 0.0718 | 0.0284 | 0.0361 | 0.0855 | 0.0086 | context-aware | Attentional Factorization Machines: Learning the Weight of Feature Interactions via Attention Networks |
FNN | 0.0703 | 0.0274 | 0.0349 | 0.0823 | 0.0083 | context-aware | Deep Learning over Multi-field Categorical Data |
GRU4Rec | 0.0682 | 0.0247 | 0.0348 | 0.0682 | 0.0068 | sequential | Improved Recurrent Neural Networks for Session-based Recommendations |
SpectralCF | 0.0745 | 0.0238 | 0.0343 | 0.0876 | 0.0089 | general | Spectral collaborative filtering |
WideDeep | 0.0704 | 0.0261 | 0.0342 | 0.0837 | 0.0085 | context-aware | Wide & Deep Learning for Recommender Systems |
GCMC | 0.0765 | 0.0229 | 0.0341 | 0.0891 | 0.009 | general | Graph Convolutional Matrix Completion |
DMF | 0.0633 | 0.0276 | 0.034 | 0.0767 | 0.0078 | general | Deep Matrix Factorization Models for Recommender Systems |
FwFM | 0.0703 | 0.0217 | 0.0315 | 0.0823 | 0.0084 | context-aware | Field-weighted Factorization Machines for Click-Through Rate Prediction in Display Advertising |
STAMP | 0.0607 | 0.0208 | 0.03 | 0.0607 | 0.0061 | sequential | STAMP: Short-Term Attention/Memory Priority Model for Session-based Recommendation |
DSSM | 0.0582 | 0.0217 | 0.0287 | 0.0693 | 0.007 | context-aware | Learning deep structured semantic models for web search using clickthrough data |
SLIMElastic | 0.0495 | 0.0226 | 0.0263 | 0.0646 | 0.007 | general | SLIM: Sparse Linear Methods for Top-N Recommender Systems |
LR | 0.0528 | 0.0167 | 0.0231 | 0.064 | 0.0065 | context-aware | Predicting Clicks Estimating the Click-Through Rate for New Ads |
Pop | 0.0474 | 0.0136 | 0.0201 | 0.0564 | 0.0057 | general | なし |
CDAE | 0.0026 | 0.0007 | 0.001 | 0.0033 | 0.0003 | general | Collaborative Denoising Auto-Encoders for Top-N Recommender Systems |
各モデルについて、テストデータに対する以下の指標を掲載しました。 @10
は 10個レコメンドを表出した、という意味です。
- recall ... ユーザが実際に嗜好したアイテムのうち、レコメンドリストでどれくらいカバーできたかの割合
- precision ... レコメンドリストにあるアイテムのうち、ユーザが嗜好したアイテム(適合アイテム)の割合
- hits ... 正解のアイテムを一つ以上含むレコメンドリストを作成できた割合
- mrr ... mean reciprocal rank。レコメンドリストを上位から見て、最初にヒットしたアイテムの順位を逆数にしたものをスコアとする。それを平均したもの。
- ndcg ... DCG: アイテムをおすすめ順に並べた際の実際のスコアの合計値 を正規化(normalize)したもの
また、いくつかの古典的なモデルを太文字にしています。
- Pop ... popularity。人気のアイテムを表出する
- ItemKNN ... アイテム間の類似度を行動履歴から簡単な計算で定義して(コサイン類似度)、それを使って「あるユーザが過去見ていたアイテムに近いアイテムを出す」というもの。2000年代くらいから。
- BPR ... Bayesian Personalized Ranking 2009年の手法。行列分解をベイズ的なアプローチで解いてランキングを導出する。
今回試したモデルの全てがこれら3つの手法よりも後に発表され、Deep Learningを使い倒すためにGPUを何枚も用意して実績を積んでいます。当然全てのモデルが上回ってほしいところなのですが... 2019 RecSys ベストペーパーで報告された内容とほぼ同じく、古典的な手法(ItemKNNとBPR)は相当強かったです。
さて、他にもこの表からわかることがいくつかあるのでまとめてみました。
- general(ユーザとアイテムのアクション履歴のみ使う)なモデルに対して、context-aware(ユーザとアイテムのside infomationも使う)・sequential(どの順番で購入したかの順序情報を使う)モデルは総じて低い結果となりました(付加情報を駆使しているのに...)。
- RecVAEが圧倒的に強かった。これはユーザとアイテムのヒストリーを行列にした上で、 Variational Auto-Encoder というニューラルネットワークで圧縮・復元の学習を行い、ユーザとアイテムのヒストリー行列を正確に復元できるように学習したモデル(+いくつか工夫あり)です。
- わかりやすい指標である hits@10 を題材にすると、一番良かった RecVAE が 0.3(30%は正解を含んだレコメンドリストを表出できる)だったのに対して、一番下の CDAE は 0.003(0.3%しか正解を含んだレコメンドができない)というのはかなり差が大きいと感じました
- なおこの RecVAE の数字は、非常に優秀な数字です
- タスクやデータの難易度に依存するものの、機械学習に取り組み上でモデル変更のみで20ポイント以上指標に差が開くことをみることはあまり多くはない
- 推薦において、ユーザとアイテムのアクション履歴から情報を引き出すというタスクが、モデルによって得意不得意がはっきり分かれているのだと思う
- 古典手法 BPR より良かったモデルはわずか 7モデル (50弱のモデルを実験して)
さて、50弱のモデルを実験するのにかかった時間は1日でした。本来であれば作者の参照実装を見に行って、その使い方を学んで、自分の適用したいデータセットをそれに合わせた方式に前処理して、動かそうとしてみてバグにあたって... 一つのモデルを動かすのに1日かかることのほうが多いです(むしろ1日で終わらない)。
それを非常に短い時間で網羅的に実験を行うことができる環境を得られるのは非常に良いことではないでしょうか。
各レコメンドモデルの挙動の違いについて
ではこれらの結果についてもう少し踏み込んでみましょう。以下のモデルについて様々な指標を見てみます。
- BPR ... 古典的だが優秀な手法
- ItemKNN ... 古典的だが優秀な手法2
- Popularity ... 古典手法
- Item2Vec ... 商品IDを単語、同じセッションで同時に購入された商品群をcontextとみなしてword2vecを学習するモデル → 実装
- FFM ... Field-aware Factorization Machines。 context-aware モデル
- RecVAE ... 今回のチャンピオンモデル
推薦リストに一つでも正解が含まれていたユーザ数
hitsを見れば大体わかりますが、グラフにしてみました。
圧倒的に RecVAE でした。ちなみに今回のテストデータは 6000ユーザくらい。2位がBPRで古典手法でした。
過去出現したアイテムを推薦して正解している割合
レコメンドにおいて、そのユーザが過去アクションしたことがあるアイテムをどう出すか、はかなり重要です。RepeatNet というリピートに着目したモデルもあるくらい。EC系のサイトでよくあることなのですが、周期的に同じものを買っている、というのがドメインにもよりますが散見されます。マートはその例にもれず、「またあれ買って食べたい」がよく起きるサービスです。ということで、これをできるだけ取りこぼさずに推薦できると非常に良いだろうと推察できます。
ここでは割合を表示します。(過去出現したアイテムを推薦して正解している数)/(推薦が成功した数)
ここで面白いのは、RecVAE・BPRなど上位モデルの値がほとんど同じで90%以上であることです。RecVAEはたくさん推薦を成功させていますが、過去出現したことのあるアイテムを着実に当てて正解数を伸ばしていたということですね。成績の良かったモデルは取りこぼしが少なかった、と言えるかもしれません。
過去出現していないアイテムを表出して正解しているユーザ数
今度は反対に、そのユーザが一度もアクションしたことがないアイテムを表出して、しかもそれが正解だった、という数を見てみます。レコメンドに求められている新規機会創出という役割をまさに表している性能値だとも言えます。
割合にするとさっきと逆のグラフになるので、ここでは絶対数を見てみます。
200程度、と大分規模は小さくなりましたが相変わらず RecVAE は上位にいます。リピートも見逃さないし、いきなり今まで買ったことがないアイテムを買った、という人に対しても他のモデルよりは良い精度を出せています。
対してBPRはRecVAEの半分程度となっており、ここで差が開いたように思えます。
また、Item2vec は先程のリピートアイテムで推薦を成功した割合を見ると90%以上となっていました。ここでのグラフの数値を見る限り、ほとんどがリピートアイテムを当てることに特化していたようです。
レコメンドのバリエーション
次に、各レコメンドのバリエーション(coverage)を見てみます。バリエーションというのは、全アイテムを分母として、そのモデルが推薦したアイテムのユニーク数を分子とした時の値を指しています。要するに、同じ人気のアイテムばかり推薦していたら低くなります。
popularityが一番低いのは、毎回同じアイテムしか出さないため
FFM(context-aware)が低い。point-wiseな推定をするモデルであるためだと思われる
- point-wise ... Factorization Machine系は「こういう特徴を持っているユーザはこういう特徴を持っているアイテムを買うかどうか」という0,1の学習を行い、ユーザごとのアイテム購入確率を出します。その確率をソートしてレコメンドリストを生成するのですが、確率を点推定しているだけなので、順序関係などは全く気にしません。その結果、人気のアイテムの購入確率が高まりそればっかり出てくる、ということがよくあります。
- 一番カバレッジが高いのは ItemKNN、ついで Item2Vec・RecVAE と続きます
- ItemKNN ・Item2vec などアイテムの類似度を利用するモデルがいずれもバリエーション豊かな推薦を行う傾向にありました
- Deep Learning を利用するモデルは学習設定を正しくしないと over fit により出力が偏ってしまうイメージがあったのですが、RecVAE が予想に反しており驚きました
まとめ
以上、RecBole を使ってクックパッドマートでのユーザに対するアイテムレコメンドを行う設定で、内部実験を行った結果をご紹介いたしました。多種多様なレコメンドモデルを比較検討する上で非常に良い選択肢ではないかと思います。開発したレコメンドモデルに対する有用なベンチマークとなるのではないでしょうか。
今後レコメンドが必要になった際にどんなモデルを実装すればよいのかについて、今回の結果を参考にしていきたいと思います。
最後に、クックパッドでは、サービス開発や基盤開発にチャレンジする就業型インターン・そして新卒採用・中途採用を通年で受付けております。気になった方は是非ウェブサイトよりご応募ください。