CTRの研究ノートシリーズ王の深さモデルの前に古典的なLR、FM、FFMモデルをまとめ最初の記事、これらの古典的なモデルだけでなく、各深さのフォローアップモデルの構成要素として。カスタムKerasレイヤモデルと推定は、一つは昔の恋は新しい恋であるハハ、実装されます。エンジニアリング特性がfeature_columnリアライズを依存し、深さのモデルに従事するために、再びここでやることは比較的簡単です。ここでは完全なコードhttps://github.com/DSXiangLi/CTR
問題定義
CTRは、基本的にバイナリ分類問題で、$ X \におけるR ^ N $は、ユーザーや広告関連の機能、です\((0、1でY- \)\)各広告がクリックされたかどうかであるが、ベースモデルは、単純な物流であります回帰
\ [P(Y = 1)= \ {FRAC。1つのEXP {} {1+(W 0 + \ sum_ {I} = ^ Nw_ix_i。1)}} \]
フレームワークTF物流は、単に活性化することによって表現することができる考慮した後、我々は、コア部分が少ない簡略化している
\ [Y(X)= W_0 + \ sum_ {I = 1} ^ Nw_ix_i \]
LRモデル
2010主流CTRモデルは、プロジェクトに展開する迅速かつ簡単に、通常は強力な最も簡単なロジスティックス回帰、モデルの解釈可能です。しかし、最大の問題は、マニュアル機能の作品の多くに依存しています。
あなたは機能の組み合わせを計算する必要がある理由のプロジェクトの機能への新しい学生は不思議に思うかもしれませんか?
最初に私は単純に小さく、よりきめ細かい集計特性バイアスを考えます。因果推論と接触した後、私はそれがために、より適していると思うシンプソンのパラドックスで交絡因子バイアス、重合はすべての年齢の男性は女性よりも低かったなクリックなどのさまざまな機能、の間で一致しないことが説明するが、男性の全体的なCTR女性。このブログを読むことができます興味があるデータマイニング交絡、Collidar、調停バイアス-春のシリーズ系列の因果推論を
すなわち、エンジニアリング機能、特徴の組合せを簡素化し、参加したい場合は、我々は確かに特性の組み合わせを、以下の暴力を考えます。このモデルとも呼ばPOLY2
\ [Y(X)= W_0 + \ sum_ {i = 1} ^ N w_ix_i + \ sum_ {i = 1} ^ N \ sum_ {J = + 1} ^ NのW_ {I 、J} x_ix_j \]
しかしながら、上記の\(W_ {I、J} \) 必要学習する\(\ FRAC {N(N -1)} {2} \) パラメータ、一方高い複雑で、一方のスパース高次元の特徴が現れます大\(W_は{I、J} \) 機能サンプルを学ぶことができないモデルは、組み合わせパターン、乏しい一般モデルにおいて見出されなかった、0です。
そう複雑さ、機能の効果的な組み合わせの自動選択を低減し、モデル一般に、それは3つの連続主要な改善方向となります。
GBDT + LRモデル
2014はノック、LRのGBDT Facebookの重ね合わせで方法が提案されているモデリング機能が働くドアを。GBDT出力の確率を予測していないが、各サンプルはそれぞれのサブツリーのリーフノード0/1マトリックス上に落ちます。ビジネスを行うと、特徴の組み合わせが手動で必要なことを理解するコストを回避、ターゲットのみで効果的な機能関連の組み合わせを残したまま。
特徴の組合せに比べて、私はGBDT特徴ベクトル出力を好む、サンプル/次元削減のクラスター、ターゲットであると理解、出力は、サブツリーに属し、それぞれ対応するサンプルのいくつかの特定の基の組み合わせであります人々の種類を組み合わせます。
しかし!GBDTの一般化の問題は、まだすべてのリーフノードの選択は、トレーニングサンプルに依存しているため、存在しており、個別の機能についてGBDTより限定された効果。GBDTはまだまばらな高次元の特徴を変換する機能を通じて問題もあります。
FMモデル
2010レンドールは、一般化モデルを高めるために、計算の複雑さを低減するために因数分解マシンモデル(FM)が提案されているガイドラインを提供します
原則
特徴の暴力の組み合わせ上記FMモデル直接全体加重モーメントを解決する\(R&LT ^ {N * N}でw_ij \ \) 、重み行列解くに暗黙ベクターを形質\(R&LT ^ {N * K}にVを\ \) 、このステップは、重み行列がもはや試料中の特徴の特定の組み合わせに完全に依存しないため大幅に、モデル一般化する能力を増加させるだろうが、機能間の間接的な相関によって得ることができます。同時に、モデルのパラメータ暗黙ベクトルの数から学ぶ({n(nは\ FRAC \ -1)} {2} \) に還元される\(NK \)
\ [開始\ {ALIGN} Y (X)&= W_0 + \ sum_ {I = 1} ^ Nw_i X_I + \ sum_ {i = 1} ^ N \ sum_ {J = + 1} ^ NのW_ {I、J} x_ix_j \\&= W_0 + \ sum_ {I = 1} ^ Nw_i X_I + \ sum_
{I = 1} ^ N \ sum_ {J = + 1} ^ N <V_I、v_j> x_ix_j \\ \端{ALIGN} \] ながら以下FMトリック提案係合からプロセスの計算上の複雑さ(O(N ^ 2K)\ )\ 線形複雑に還元\(O(NK)\)
\ [{ALIGN}を開始\&\ sum_ {i = 1} ^ N \ sum_ {J = + 1} ^ N <V_I、v_j> x_ix_j \\ =&\ FRAC {1} {2}(\ sum_ { I = 1} ^ N \ sum_ {J = 1} ^ N <V_I、v_j> x_ix_j - \ sum_ {I = 1} ^ N <V_I、V_I> x_ix_i)\\ =&\ 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} ^ Kv_ {}もし^ 2x_i ^ 2)= \\&\ FRAC {1} {2} \ sum_ {F = 1} ^ K(\ sum_ {i = 1} ^ N \ sum_ {J = 1} ^ N V_ {もし} V_ {JF} x_ix_j - \ sum_ {i = 1} ^ {Nv_なら} ^ 2x_i ^ 2)= \\&\ FRAC {1} {2} \ sum_ {F = 1} ^ K((\ sum_ {I = 1} ^ N V_ {IJ} X_I)^ 2 - \ sum_ {i = 1} ^ Nv_ {もし} ^ 2x_i ^ 2)\\ =&\テキスト{square_of_sum} - \テキスト{sum_of_square} \端{ALIGN} \]
コードの実装 - カスタムKerasレイヤ
class FM_Layer(Layer):
"""
Input:
factor_dim: latent vector size
input_shape: raw feature size
activation
output:
FM layer output
"""
def __init__(self, factor_dim, activation = None, **kwargs):
self.factor_dim = factor_dim
self.activation = activations.get(activation) # if None return linear, else return function of identifier
self.InputSepc = InputSpec(ndim=2) # Specifies input layer attribute. one Inspec for each input
super(FM_Layer,self).__init__(**kwargs)
def build(self, input_shape):
"""
input:
tuple of input_shape
output:
w: linear weight
v: latent vector
b: linear Bias
func:
define all the necessary variable here
"""
assert len(input_shape) >=2
input_dim = int(input_shape[-1])
self.w = self.add_weight(name = 'w0', shape = (input_dim, 1),
initializer = 'glorot_uniform',
trainable = True)
self.b = self.add_weight(name = 'bias', shape = (1, ),
initializer = 'zeros',
trainable = True)
self.v = self.add_weight(name = 'hidden_vector', shape = (input_dim, self.factor_dim),
initializer = 'glorot_uniform',
trainable = True)
super(FM_Layer, self).build(input_shape)# set self.built=True
def call(self, x):
"""
input:
x(previous layer output)
output:
core calculation of the FM layer
func:
core calculcation of layer goes here
"""
linear_term = K.dot(x, self.w) + self.b
# Embedding之和,Embedding内积: (1, input_dim) * (input_dim, factor_dim) = (1, factor_dim)
sum_square = K.pow(K.dot(x, self.v),2)
square_sum = K.dot(K.pow(x, 2), K.pow(self.v, 2))
# (1, factor_dim) -> (1)
quad_term = K.mean( (sum_square - square_sum), axis=1, keepdims = True) #
output = self.activation((linear_term+quad_term))
return output
def compute_output_shape(self, input_shape):
# tf.keras回传input_shape是tf.dimension而不是tuple, 所以要cast成int
return (int(input_shape[0]), self.output_dim)
FMとMFの間の関係
MFが実際にFMの特殊なケースで、同じようFactorizatonマシンと行列分解が鳴ります。MFは、暗黙的なベクトルを得るために行列の因数分解によって得られるが、それだけであることを特徴マトリックスに適用されるので、2つだけの次元は、それが(USER_IDは、ITEM_ID)それらの組み合わせが一般的です。同じことは、FMは、ワンホットので、入力フィーチャの任意の数をサポートしない別個の特徴の行列を平坦化、暗黙ベクターでした。
FMと埋め込みの関係
次いで、インターワーキング機能で処理埋め込む低次元の行列にマッピングされるスパース高次元特徴語に埋め込みNLP最も一般的には、例えば、ベクトルの積に単語と単語間の類似度を表します。FMは、暗黙的にベクターは、実際にも、埋め込みフィッティング法のみ相互作用関数のベクトル内積のような限界を算出します。上記\(RにおけるX * V \ ^ {K} \) 得られた埋め込みベクトル自体です。
FFM
2015年に提案されたFFMモデルは、概念的FMに基づいてフィールドに参加しました
原則
上記FMは、重み行列Vが暗黙ベクトル内積の形態における2つの特徴の組み合わせを表現するために各特徴ベクトルに対応する暗黙で学びました。フィールド暗黙ベクトルの異なる特徴および特徴の組み合わせとFFMが異なっている必要があり提案ので、(R ^ {におけるV \ \ N * K} \) となるR ^ {におけるV \(\ N * F * K} \ ) Fは、特徴の数である場合は、フィールドに属します。次のデータ国、データ、AD_TYPEはフィールド、です\((F.を=。3)\)
二つの特徴のFM対話部分が書き換え以下であり、N-から学習すべきパラメータの数Kは、N-なる F * K. そして、それはフィッティング処理の上記トリック複雑に使用され、したがって、FMからできません\(O(NK)\)まで上昇\()O(KN ^ 2 \) 。
\ [\ sum_ {i = 1} ^ N \ sum_ {J = + 1} ^ N <V_I、v_j> x_ix_j \に&\ sum_ {i = 1} ^ N \ sum_ {J = {ALIGN}を開始\ I + 1} ^ N <V_ {I、F_J}、V_ {J、のf_i}> x_ix_j \端{ALIGN} \]
コードの実装 - カスタムmodel_fn
def model_fn(features, labels, mode, params):
"""
Field_aware factorization machine for 2 classes classification
"""
feature_columns, field_dict = build_features()
field_dim = len(np.unique(list(field_dict.values())))
input = tf.feature_column.input_layer(features, feature_columns)
input_dim = input.get_shape().as_list()[-1]
with tf.variable_scope('linear'):
init = tf.random_normal( shape = (input_dim,2) )
w = tf.get_variable('w', dtype = tf.float32, initializer = init, validate_shape = False)
b = tf.get_variable('b', shape = [2], dtype= tf.float32)
linear_term = tf.add(tf.matmul(input,w), b)
tf.summary.histogram( 'linear_term', linear_term )
with tf.variable_scope('field_aware_interaction'):
init = tf.truncated_normal(shape = (input_dim, field_dim, params['factor_dim']))
v = tf.get_variable('v', dtype = tf.float32, initializer = init, validate_shape = False)
interaction_term = tf.constant(0, dtype =tf.float32)
# iterate over all the combination of features
for i in range(input_dim):
for j in range(i+1, input_dim):
interaction_term += tf.multiply(
tf.reduce_mean(tf.multiply(v[i, field_dict[j],: ], v[j, field_dict[i],:])) ,
tf.multiply(input[:,i], input[:,j])
)
interaction_term = tf.reshape(interaction_term, [-1,1])
tf.summary.histogram('interaction_term', interaction_term)
with tf.variable_scope('output'):
y = tf.math.add(interaction_term, linear_term)
tf.summary.histogram( 'output', y )
if mode == tf.estimator.ModeKeys.PREDICT:
predictions = {
'predict_class': tf.argmax(tf.nn.softmax(y), axis=1),
'prediction_prob': tf.nn.softmax(y)
}
return tf.estimator.EstimatorSpec(mode = tf.estimator.ModeKeys.PREDICT,
predictions = predictions)
cross_entropy = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits( labels=labels, logits=y ))
if mode == tf.estimator.ModeKeys.TRAIN:
optimizer = tf.train.AdamOptimizer(learning_rate = params['learning_rate'])
train_op = optimizer.minimize(cross_entropy,
global_step = tf.train.get_global_step())
return tf.estimator.EstimatorSpec(mode, loss = cross_entropy, train_op = train_op)
else:
eval_metric_ops = {
'accuracy': tf.metrics.accuracy(labels = labels,
predictions = tf.argmax(tf.nn.softmax(y), axis=1)),
'auc': tf.metrics.auc(labels = labels ,
predictions = tf.nn.softmax(y)[:,1]),
'pr': tf.metrics.auc(labels = labels,
predictions = tf.nn.softmax(y)[:,1],
curve = 'PR')
}
return tf.estimator.EstimatorSpec(mode, loss = cross_entropy, eval_metric_ops = eval_metric_ops)
参考資料
- S. Rendle、データマイニングに関するIEEE国際会議(ICDM)の議事録で「因数分解マシン、」、頁995から1000、2010
- Yuchinフアン、龍荘、魏盛チン、CTRの予測のためのフィールドを意識した因子分解マシン。
- アリは、Google、FacebookのCTR予測モデルの時代の前に在庫の深さの調査
- LRからFFMへ:倍の深い学習のCTR予測モデルの前に道路の進化
- リコール4つのモデルの推奨システム:すべての強力なFMモデル
- 進化と比較主流モデルCTR推定
- 深FFMの原則と実践