推奨システムシリーズ(A):FM理論と実践

なぜ

お勧めの地域では、多くの場合、カテゴリの特性を組み合わせることがあります。しかし、一般的な組み合わせで2つの問題があります。

  • ワンホット機能した後スパース性の高い、次元の呪い。
  • 一般的な線形モデルは、機能間の関係を考慮していません。\(Y = W_0 + \ sum_ {i = 1} ^ {n}はw_ix_i \)

FM(因数分解マシン)が特徴の組み合わせの過程で遭遇した上記のような問題は、効率的なソリューションを提案しているためです。[1]

1.特性との関係

まず、一般的な線形モデルの特性との関係は、二次多項式モデルに書き換えることができる確立し、第二の問題を解決します。ここだけ高次の多項式を議論していない二次を議論します。
\ [Y = W_0 + \ sum_ {i = 1} ^ nw_ix_i + \ sum_ {i = 1} ^ {N-1} \ sum_ {J = + 1} ^ nw_ {IJ} x_ix_jの\タグ{1} \]

2.パラメータは、定量化します

上記の式を使用すると、検討する必要があるパラメータを解決する方法です。ワンホット後の機能の多くは、スパース度の高い問題を示すため、上記式\(x_ix_jの\)はゼロ値の大きな数を生成します。パラメータ学習が十分ではなく、直接の結果\(W_ {ijは} \)のトレーニングを介して取得することはできません。説明:オーダー\(X-x_ix_j = \) 次いで(\ \ FRAC {\部分{Y}} {\部分W_ {{}}}、X = \のIJ) なぜなら\(X-0 = \)そう\ (W_} ^ {新規新しいW_の{IJ} = {} ^ {オールドのIJ} +オールドの{\ Xアルファ= W_}} ^ {IJ} {\) 勾配0パラメータを更新することができません。

:このような状況の根本的な原因は、ということですあまりにもスパースます。私たちは、このようなことを、方法を見つけることを期待\(W_ {ijは} \)スパース解決機能の影響を受けません。

マトリックス分解各特徴のために、インスピレーション\(X_I \)補助ベクトル(暗黙ベクター)を導入する\(V_I =(V_ {I1}、V_ {I2}、\ cdots、V_ {IKを})\)次に使用\(V_iV_j ^ T \)\(W_ {ijは} \)解決されます。すなわち、以下の仮定である:\({W_のIJ} \約V_iV_j ^ T \)

ベクターの導入の隠れたメリットがあります

  1. 二次用語の元の量からパラメータは\(\ FRAC {N(N -1)} {2} \) 減少\(KN \)

  2. そこ元のパラメータの間には関係はありませんが、今の暗黙のベクトルを通じて関係を構築することができます。以前のように\(W_ {IJ} \)\(W_ {IK} \)の独立したが、今$ W_ {IJ} = \ langle V_I、V_j \ rangle、W_ {IK} = \ langle V_I、V_K \ rangle ある2つの共通の$ \(V_I \) つまり、全て含ん\(x_ix_j \)機能の非ゼロの組み合わせ(の存在\(J \ NEQ I \)そう\(x_ix_j \ NEQ 0 \))サンプルを暗黙ベクター研究するために使用することができる\(V_I \)大部分のデータスパースによる衝撃を回避し、。[2]

今、式(1)に書き換えられることができる:
\ [Y = W 0 + \ sum_ {I = 1} ^ nw_ix_i + \ sum_ {I = 1} ^ {N - 1} \ sum_ {J = I + 1} ^ N- \ langle V_I、v_j \ rangle x_ix_j \タグ
{2} \] 2次項の背後式(2)を解決する方法に焦点を当てます。

最初理解対称の上三角行列を設定する行列加算\を(M \):\
。[M = \(左\ m_Low {行列} {}開始11&12 m_Low {}&\&cdots \\ {1N}であるm_Low m_Low {21}&M_ {22} - \ cdots&M_ {1N} \\ \ vdots&\ vdots&\ ddots&\ vdots \\ M_ {N1}&M_ {N2}&\ cdots&M_ {NN} \\ \端{行列} \右)
_ {N×n個} \] 、\ m_Low JIの(m_Low} = {IJ} {\)

カム要素は、そのようにする(\)を\、すなわち、\(\ sum_ {I = 1} ^ {N - 1} \ sum_ {Jは=私は+ 1} ^ {N-} m_Low {のIJ}が\を=) 次に、\(M \)に等しいすべての要素で\(A + TR * 2(M)\)、\ (TR(M)\)行列のトレースです。
\ [\ Sum_ {i = 1 } ^ n個の\ sum_ {J = 1} ^ nm_ {IJ} = 2 * \ sum_ {i = 1} ^ {N-1} \ sum_ {J = + 1} ^ { N} M_ {IJ} + \
sum_ {i = 1} ^ {n}はM_ {II} \] 利用可能な、
\ [A = \ sum_ {I = 1} ^ {N - 1} \ sum_ {J = I +1} ^ {n}はM_ { IJ} = \ FRAC {1} {2} * \左\ {\ sum_ {i = 1} ^ n個の\ sum_ {J = 1} ^ nm_ {IJ} - \ sum_ { I = 1} ^ {n}は
M_は{II}右\ \} \] この前提では、式(2)2次の項を導出することができます。
\ [\開始{整列}&\ sum_ {i = 1} ^ {N-1} \ sum_ {J = + 1} ^ n個の\ langle V_I、V_j \ rangle x_ix_j \ notag \\ = {}&\ FRAC {1} {2} * \左\ {\ sum_ {i = 1} ^ {N} \ sum_ {J =} ^ {N}の\ langle V_I、V_j \ rangle x_ix_j- \ sum_ {i = 1} ^ {N}の\ langle V_I、V_I \ rangle x_ix_i右\ \} \ notag \\ = {}&\ FRAC {1} {2} * \左\ {\ sum_ {i = 1} ^ {N} \ sum_ { J = 1} ^ {N} \ sum_ {F = 1} ^ {K} V_ {}もしV_ {JF} x_ix_j- \ sum_ {i = 1} ^ {N} \ sum_ {F = 1} ^ {K } V_ {もし} V_ {もし} x_ix_i \右\} \ notag \\ = {}&\ FRAC {1} {2} * \ sum_ {F = 1} ^ {K} \左\ {\ sum_ {I = 1} ^ {N} \ sum_ {J = 1} ^ {n}はV_ {もし} x_iv_ {JF} x_j- \ sum_ {i = 1} ^ {n}はV_ {もし} ^ {2} X_ {I } ^ 2右\ \} \ notag \\ = {}&\ FRAC {1} {2} * \ sum_ {F = 1} ^ {K} \左\ {\左(\ sum_ {i = 1} ^ {N} V_ {もし} X_I \右)\左(\ sum_ {J = 1} ^ {n}はV_ {JF} X - jが\右) - \ sum_ {i = 1} ^ {n}はV_ {もし} ^左{2} X_ {I} ^ 2右\ \} \ notag \\ = {}&\ FRAC {1} {2} * \ sum_ {F = 1} ^ {K} \左\ {\(\ sum_ {i = 1} ^ {n}はV_ {もし} X_I \右)^ {2} - 右\ sum_ {i = 1} ^ {n}はV_ {もし} ^ {2} X_ {I} ^ 2 \ \ } \ notag \\ \端{\タグ{3} \]}整列
(2)(3)を得ることができる結合:
\ [\開始{左=整列} Y = {}&W 0 + \ sum_ ^ nw_ix_i + \ sum_ {I = 1} ^ {N - 1} \ sum_ {J {I = 1です。} = I + 1} ^ n個の\ langle V_I、v_j \ rangle x_ix_j \ notag \\ = {}&W_0 + \ sum_ {i = 1} ^ nw_ix_i + \ FRAC {1} {2} * \ sum_ {F = 1} ^ {K} \左\ {\左(\ sum_ {i = 1} ^ {n}はV_ {}もしX_I \右)^ {2} - \ sum_ {i = 1} ^ {n}はV_ {}もし^ {2} X_ {I} ^
2 \右\} \ notag \\ \エンド{揃える} \タグ{4} \] この時点で、我々はモデル式を取得したいです。

なぜ式(2)式のように書き換えられるべきである(4)、算出された書き換え前ため\(Y \)複雑である\(O(KN ^ 2)\) 計算の複雑さをすることが書き換えられる(\ O(KN)\) モデルの推論速度を向上させます。

どうやって

これまでのところ、我々は唯一のモデルが出てきた定義して、どのようにそれを解決するには?パラメータ勾配降下の最も一般的な方法を解決するために使用することができ、パラメータを以下の勾配モデルの計算式:

パラメータがある場合\(W 0 \) \(\ FRACは{\部分{Y}} {\部分}} = {0 1 \ W)

パラメータがある場合、\(W_i \)場合、\(\ FRAC {\部分{Y}} {\部分}} = {W_i X_I \)

パラメータがされた場合(V_ {なら} \)\、高次の項のみが計算されたパラメータをモデルに焦点を当てる必要がある(V_ {なら} \)\残り独立パラメータの勾配が一定とみなすことができます。
\ [\ {整列}開始\ FRAC {\部分{Y}} {\部分{V_ {もし}}} = {}&\左部分{\ FRAC {1} {2} \左\ {\(\ sum_ {i = 1} ^ {N } V_ {もし} X_I \右)^ {2} -右\ sum_ {i = 1} ^ {n}はV_ {もし} ^ {2} X_ {I} ^ 2 \ \ }} / \部分{V_ { }}もし\ notag \\ = {}&\ FRAC {1} {2} * \左\ {\ FRAC {\部分{\左\ {\ sum_ {i = 1} ^ {N} V_ {もし} X_I \右\} ^ 2}} {\部分{V_ {}}}もし- \のFRAC {\部分{\左\ {\ sum_ {i = 1} ^ {n}はV_ { もし} ^ {2} X_ {
I} ^ 2右\ \}}} {\部分{V_ {右\}}}もし\} \ notag \\ \端{}整列\タグ{5} \] ここで:
\ [\ FRAC {\部分{ \左\ {\ sum_ {i = 1} ^ {n}はV_ {}もし^ {2} X_ {I} ^ 2 \右\}}} {\部分{V_ {もし}}} = 2x_ {I}
^ 2v_ {もし} \タグ{6} \] オーダー\(\ラムダ= \ sum_ 1 = {I}} ^ {N-V_} {IF X_I \。)、その後:
\ [\ \ {整列}開始 FRACを{\部分{\左\ {\ sum_ {i = 1} ^ {n}はV_ {}もしX_I \右\} ^ 2}} {\部分{V_ {もし}} } = {}&\ FRAC { \部分{\ラムダ^ 2}} {\部分{V_ {もし}}} \ notag \\ = {}&\ FRAC {\部分{\ラムダ^ 2}} {\部分{\ラムダ}} \ FRAC { \部分{\ラムダ}} {\部分{V_ {もし}}} \ notag \\ = {}&2 \ラムダ* \ FRAC {\部分{\ sum_ {i = 1} ^ {n}はV_ {もし} X_I}} {\部分{V_ {もし}}} \ notag \\ = {}&2 \ラムダ* X_I \ notag \\ = {}&2 * X_I * \ sum_ {J = 1} ^ {n}はV_
{JF} X - jが\ notag \\ \端{整列} \タグ{7} \] 式(5-7)を組み合わせることで、得ることができる:
\ [\ FRAC {\部分} {Y} {\部分{V_ {}もし
}} = \ ^ V_ \ \] X_I sum_ {J = 1} {N} {JF} X - jが、X_ {I} ^ 2v_ {もし}タグ{8} 要するに、最終モデル次のようにグラデーション表現パラメータは、次のとおりです。
; \ [\ = \ {ケース} 1を開始し、&\テキスト\シータ\テキストがW_0 {ある} {もし} {{\シータ}部分\} \ FRAC {\部分{Y}を} {式}開始 \\ X_I、&\テキスト\シータ\テキスト{ある} w_i {もし}。\\ X_I \ sum_ {J = 1} ^ {n}はV_ {JF} X - jが、X_ {I} ^ 2v_ {場合}、&\テキスト{なら} \シータ\テキスト{ある} V_ {なら}。\端{ケース} \端{式} \ notag \]

1.パフォーマンス分析

上記のセクション、時間複雑FM予報から\(O(KN)\) トレーニングの複雑勾配パラメータ式に基づく解析、\(\ sum_ 1} = {J} ^ {N-V_ JF} {X_ {J} \)\が(私は\)にかかわらず、最初のパラメータの更新することができますすべての\(\ sum_ {J = 1 } ^ {n}はV_ {JF} X_ {J} \) 複雑さ、計算される\(O(KN)\)の両方の時間複雑さのすべてのパラメータ、後続の更新ある\(O(1)\)パラメータの量、(1 + N - + KN \。)\同様に、最終的なトレーニング時間複雑\(O(KN)\) ここで\(n-は\)特徴の数であります\ (K \)隠されたベクトルの次元の数。

FMトレーニングと予測の時間複雑です\(O(KN)\) 非常に効率的なモデルです。

メリット[1]:

合計では、私たちの提案FMの利点は次のとおりです。

1)FMSがSVMのは失敗非常にまばらなデータの下にパラメータ推定を可能にします。

2)FMSが線形複雑度を持っている、原初に最適化することができ、SVMのようなサポートベクトルに依存しないでください。私たちは、のFMトレーニングインスタンスの100百万のネットフリックスのような大規模なデータセットに拡張することを示しています。

3)FMSが任意の実数値の特徴ベクトルを操作することができ、一般的な予測因子です。これとは対照的に、他の最先端の因数分解モデルは非常に制限された入力データにのみ動作します。私達はちょうど、入力データの特徴ベクトルを定義することによって、のFMが偏っMF、SVD ++、実務対応報告またはFPMCのような最先端のモデルを模倣することができることを示します。

欠点[6]。

  1. 唯一の二次クロスオーバー機能することができ、まだ我々が特徴の作品を横断する必要があります。

2.理論と実践

FMを適用することができる両方の回帰タスクにも分類タスクに適用することができます。唯一式の第2分類タスク(2)最外入れ、として\(シグモイド\)分析タスクに機能を派生回帰に基づいて行われます。

同じモデルの最終的な損失関数を使用することができ、このような回帰タスクとして多くの形態をとることができます\は(MSE \) 分類タスクを使用することができます\(クロスエントロピー\)のようにと。

それが知られているが、それは補助ベクトルを導入することによって計算することができますが、機能とどのように補助ベクトル\(X_I \)は、他の言葉で、連絡先を確立するために、どのように\(X_I \)補助ベクトル\(V_I \) FM、内ニューラルネットワーク使って\(X_I \)\を(埋め込むこと\)補助ベクトル、得られたとして\を(\こと埋め込み)ベクトルセットがあることに対応する低次元の密な特徴を特徴付けるとみなすことができます他の下流の作業への応用。

本明細書で使用する場合、\(MovieLens 100Kデータセット\) [3]実験入力特徴セットとしてユーザ番号、フィルムの数、映画の歴史のためのユーザの評価である\(ラベル\)

以下を達成するために特定のコード:

# -*- coding:utf-8 -*-
import pandas as pd
import numpy as np
from scipy.sparse import csr
from itertools import count
from collections import defaultdict
import tensorflow as tf


def vectorize_dic(dic, label2index=None, hold_num=None):
  
    if label2index == None:
        d = count(0)
        label2index = defaultdict(lambda: next(d))  # 数值映射表

    sample_num = len(list(dic.values())[0])  # 样本数
    feat_num = len(list(dic.keys()))  # 特征数
    total_value_num = sample_num * feat_num

    col_ix = np.empty(total_value_num, dtype=int)

    i = 0
    for k, lis in dic.items():
        col_ix[i::feat_num] = [label2index[str(k) + str(el)] for el in lis]
        i += 1

    row_ix = np.repeat(np.arange(sample_num), feat_num)
    data = np.ones(total_value_num)

    if hold_num is None:
        hold_num = len(label2index)

    left_data_index = np.where(col_ix < hold_num)  # 为了剔除不在train set中出现的test set数据

    return csr.csr_matrix(
        (data[left_data_index], (row_ix[left_data_index], col_ix[left_data_index])),
        shape=(sample_num, hold_num)), label2index

def batcher(X_, y_, batch_size=-1):

    assert X_.shape[0] == len(y_)

    n_samples = X_.shape[0]
    if batch_size == -1:
        batch_size = n_samples
    if batch_size < 1:
        raise ValueError('Parameter batch_size={} is unsupported'.format(batch_size))

    for i in range(0, n_samples, batch_size):
        upper_bound = min(i + batch_size, n_samples)
        ret_x = X_[i:upper_bound]
        ret_y = y_[i:upper_bound]
        yield(ret_x, ret_y)

def load_dataset():
    cols = ['user', 'item', 'rating', 'timestamp']
    train = pd.read_csv('data/ua.base', delimiter='\t', names=cols)
    test = pd.read_csv('data/ua.test', delimiter='\t', names=cols)

    x_train, label2index = vectorize_dic({'users': train.user.values, 'items': train.item.values})
    x_test, label2index = vectorize_dic({'users': test.user.values, 'items': test.item.values}, label2index, x_train.shape[1])

    y_train = train.rating.values
    y_test = test.rating.values

    x_train = x_train.todense()
    x_test = x_test.todense()

    return x_train, x_test, y_train, y_test

x_train, x_test, y_train, y_test = load_dataset()

print("x_train shape: ", x_train.shape)
print("x_test shape: ", x_test.shape)
print("y_train shape: ", y_train.shape)
print("y_test shape: ", y_test.shape)

vec_dim = 10
batch_size = 1000
epochs = 10
learning_rate = 0.001
sample_num, feat_num = x_train.shape

x = tf.placeholder(tf.float32, shape=[None, feat_num], name="input_x")
y = tf.placeholder(tf.float32, shape=[None,1], name="ground_truth")

w0 = tf.get_variable(name="bias", shape=(1), dtype=tf.float32)
W = tf.get_variable(name="linear_w", shape=(feat_num), dtype=tf.float32)
V = tf.get_variable(name="interaction_w", shape=(feat_num, vec_dim), dtype=tf.float32)

linear_part = w0 + tf.reduce_sum(tf.multiply(x, W), axis=1, keep_dims=True)
interaction_part = 0.5 * tf.reduce_sum(tf.square(tf.matmul(x, V)) - tf.matmul(tf.square(x), tf.square(V)), axis=1, keep_dims=True)
y_hat = linear_part + interaction_part
loss = tf.reduce_mean(tf.square(y - y_hat))
train_op = tf.train.AdamOptimizer(learning_rate).minimize(loss)

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    for e in range(epochs):
        step = 0
        print("epoch:{}".format(e))
        for batch_x, batch_y in batcher(x_train, y_train, batch_size):
            sess.run(train_op, feed_dict={x:batch_x, y:batch_y.reshape(-1, 1)})
            step += 1
            if step % 10 == 0:
                for val_x, val_y in batcher(x_test, y_test):
                    train_loss = sess.run(loss, feed_dict={x:batch_x, y:batch_y.reshape(-1, 1)})
                    val_loss = sess.run(loss, feed_dict={x:val_x, y:val_y.reshape(-1, 1)})
                    print("batch train_mse={}, val_mse={}".format(train_loss, val_loss))

    for val_x, val_y in batcher(x_test, y_test):
        val_loss = sess.run(loss, feed_dict={x: val_x, y: val_y.reshape(-1, 1)})
        print("test set rmse = {}".format(np.sqrt(val_loss)))

結果:

epoch:0
batch train_mse=19.54930305480957, val_mse=19.687997817993164
batch train_mse=16.957233428955078, val_mse=19.531404495239258
batch train_mse=18.544944763183594, val_mse=19.376962661743164
batch train_mse=18.870519638061523, val_mse=19.222412109375
batch train_mse=18.769777297973633, val_mse=19.070764541625977
batch train_mse=19.383392333984375, val_mse=18.915040969848633
batch train_mse=17.26403045654297, val_mse=18.75937843322754
batch train_mse=17.652183532714844, val_mse=18.6033935546875
batch train_mse=18.331804275512695, val_mse=18.447608947753906
......
epoch:9
batch train_mse=1.394300103187561, val_mse=1.4516444206237793
batch train_mse=1.2031371593475342, val_mse=1.4285767078399658
batch train_mse=1.1761484146118164, val_mse=1.4077649116516113
batch train_mse=1.134848952293396, val_mse=1.3872103691101074
batch train_mse=1.2191411256790161, val_mse=1.3692644834518433
batch train_mse=1.572729468345642, val_mse=1.3509554862976074
batch train_mse=1.3323310613632202, val_mse=1.3339732885360718
batch train_mse=1.1601723432540894, val_mse=1.3183823823928833
batch train_mse=1.2751621007919312, val_mse=1.3023829460144043
test set rmse = 1.1405380964279175

参照

おすすめ

転載: www.cnblogs.com/yinzm/p/11619829.html