[1708.05027] Neural Factorization Machines for Sparse Predictive Analytics
みんなが好きな Factorization Machines (FM) とニューラルネットワークを組み合わせて Neural Factorization Machines (NFM) を提案する.
FM とその派生手法がいくら変数間の交互作用を表現するモデルであったとしても,しかしそれは線形モデルのままであり,表現力に乏しい,というのがモチベーション.
FM
FM は という形で予測を行う.三項目で各特徴量をで低次元表現しつつその積で交互作用を扱う,というのが FM の特徴.
NFM
NFM では として, をニューラルネットワークにすることで交互作用を考慮しつつ非線形性を表現する.
ネットワークは
- Embedding Layer
- Bi-Interaction Layer
- Hidden Layer
- Prediction Layer
の四つから構成される.三つ目は複数階層のニューラルネットワーク,四つ目はただの 1 次元に落とす操作なので前二つについて書く.
Embedding Layer
FM や NFM が扱うのはたいていスパースなので,値がある次元をそれぞれ低次元に Embedding する.例えば, D 次元の入力のうち N 個だけが値を持っているとする時,K 次元に埋め込むとすると K 次元のベクトルが N 本作られる.またこの時,各次元の値を埋め込んだベクトルに掛けることを忘れないようにする.
実装
Chainer でやった.コードはこの gist にアップロードした.
ファイルは libsvm format で入力すると動作する.ひとまず classification がやりたかったので最後に sigmoid に通している.
「埋め込みを行いつつ元の値を掛ける」という操作をどうやっていいのかわからなかったので
- 入力を「発火している特徴量の id を並べ,それ以外は -1 で padding したリスト」と「そのリストの各要素に対応する元の特徴量の値」に分ける
- 特に後者は埋め込み後に掛ける必要があるので埋め込み次元に引き伸ばす
という方針でやる.
例えば特徴量が {0: 0.1, 3: 3, 7: 1} であり,特徴量の最大次元が10であり,3次元に埋め込む場合は
raw_fv = {0: 0.1, 3: 3, 7: 1}
active_feature_ids = chainer.Variable(np.array([0, 3, 7, -1, -1, -1, -1, -1, -1, -1], dtype=np.int32))
feature_weights = chainer.Variable(np.array([[0.1, 0.1, 0.1], [3, 3, 3], [1, 1, 1], [0, 0, 0], ...], dtype=np.float32))
emb = self.EMB(active_feature_ids)
emb = emb * feature_weights
pairwise = F.square(F.sum(emb, axis=1)) - F.sum(F.square(emb), axis=1)
pairwise *= 0.5
pairwise = F.relu(self.l_pairwise_1(pairwise))
pairwise = F.relu(self.l_pairwise_2(pairwise))
pairwise = F.relu(self.l_pairwise_3(pairwise))
という感じで書いている.もっと綺麗に書く方法があると思うが書き慣れていないのでよくわかっていない.
これに加えてニューラルでない線形和の部分も chainer で推定させるために愚直にスパースな特徴ベクトルも渡している.綺麗に書きたい.
movielens のデータではそれらしく動いているのであとでちゃんと検証する.