Neural Collaborative Filtering (WWW 2017) 読んだ & Chainer で実装した
Neural Collaborative Filtering (pdf)
概要
タスクは user と item について評価しているか (1) していないか (0) の情報 (implicit feedback) から未知の user と item の評価を予測する,商品推薦において非常に古典的なもの.
一般的には協調フィルタリングや行列分解を行なうが,この論文では Neural Collaborative Filtering (NCF) を提案している.
手法
人の user と 個の item について,評価/購入しているかしていないかのデータ が与えられているとする.
NCF ではこの を行列分解と多層パーセプトロンの二つを同時に推定することで学習する.
行列分解
入力である の行列を となるように 次元の行列 に分解する.
NCF
行列分解と多層パーセプトロンとを同時に学習する.わかりやすく各処理での次元数を書く.
Chainer による実装
はじめてまともに Chainer を書いた.簡単でいい.
とりあえずは二層で,宣言時にユーザ数,アイテム数,行列分解の次元数,ニューラルネットの層の数を指定する.
学習時には user と item ,それらを one-hot encoding したベクトル user_vec/item_vec ,およびラベルを与える.
movielens で実験したところ,素の行列分解よりは精度が高そうな感じがした. ensemble に近い内容だからではないのという気持ちも少しある.
import numpy as np import chainer from chainer import functions as F from chainer import links as L from chainer import Variable class NCF(chainer.Chain): def __init__(self, n_user, n_item, n_mf_dim, n_dim_1, n_dim_2): self.n_user = n_user self.n_item = n_item self.n_mf_dim = n_mf_dim self.n_dim_1 = n_dim_1 self.n_dim_2 = n_dim_2 self._layers = { 'MFQ': L.EmbedID(self.n_user, self.n_mf_dim), 'MFP': L.EmbedID(self.n_item, self.n_mf_dim), 'l1': L.Linear(self.n_user + self.n_item, self.n_dim_1), 'l2': L.Linear(self.n_dim_1, self.n_dim_2), 'l_out': L.Linear(self.n_dim_2 + self.n_mf_dim, 1) } super(NCF, self).__init__(**self._layers) for param in self.params(): param.data[...] = np.random.uniform(-0.1, 0.1, param.data.shape) def predict(self, u, i, user_vec, item_vec): # train neural net input_vec = F.concat((user_vec, item_vec), axis = 1) h = F.relu(self.l1(input_vec)) h = F.relu(self.l2(h)) # matrix factorization mf_p_u = self.MFQ(u) mf_q_i = self.MFP(i) # concat matrix factorization h = F.concat((h, mf_p_u * mf_q_i), axis = 1) h = self.l_out(h) return F.sigmoid(h) def __call__(self, u, i, user_vec, item_vec, y): pred = self.predict(u, i, user_vec, item_vec) loss = F.sigmoid_cross_entropy(pred, y.reshape(len(y), 1)) chainer.report({'loss': loss}, self) return loss