特徵組合的意義就不多多贅述了。在這裡主要介紹2種流行的特徵組合手段:FM和DCN

FM

sum_{i=1}^n sum_{j=i+1}^n langle mathbf{v}_i, mathbf{v}_j 
angle x_i x_j = frac{1}{2} sum_{f=1}^k left(left( sum_{i=1}^n v_{i, f} x_i 
ight)^2 - sum_{i=1}^n v_{i, f}^2 x_i^2 
ight)

推導: ab=frac{1}{2}[(a+b)^2-(a^2+b^2)]

舉例說明:

設 a=(2,3) , b=(1,2), 則 ab=(2,6)用上面的公式推導:

a+b=(3,5)

(a+b)^2=(9,25)

frac{1}{2}[(a+b)^2-(a^2+b^2)]=frac{1}{2}[(9-4-1=4,25-9-4=12)]=(2,6)

tesorlfow很容易實現:

def cross(self,x,share_EmbedWeights):
"""
先x的每個特徵進行embedding得到vi,然後 xi*vi ,然後再求內積
目標:[batch, n] * [n,k] =[batch,n,k]
轉化為: [n*[batch, 1]] * [n*[batch,k]] =[batch,n,k], x的每一行要轉化成一個對角矩陣
"""
n=x.shape[1].value #feature nums
k=self.k
#
embeds = []
for i in range(n):
xi = x[:,i] # shape=[batch]
vi = tf.nn.embedding_lookup(share_EmbedWeights, i) #shape=[k]
# 直接 xi*vi 報錯
# xi*v_i=[batch,1] * [1,k]=[batch,k]
embed_i = tf.expand_dims(xi,1) * tf.expand_dims(vi ,0)
embeds.append(embed_i)

embed = tf.reshape(tf.concat(embeds, 1),[-1,n,k]) # shape=[-1,n,k]
#
# sum_square 表示先sum後square. sum是axis=1,而不是axis=2
sum_square = tf.square(tf.reduce_sum(embed, axis=1))
square_sum = tf.reduce_sum(tf.square(embed), axis=1)
y_v = 0.5 * tf.reduce_sum(sum_square - square_sum, axis=1)

return y_v

DCN

核心部分是cross layer

tensorflow 實現:

def cross_layer(self,x0,x,w,b):
"""
:param x0: shape=[batch,n]
:param x: shape=[batch,n]
:param w: shape=[n]
:param b: shape=[n]
:return : shape=[batch,n]
"""
# batch = x0.shape[0].value
batch=self.batch_size
n = x0.shape[1].value # vector length
# [batch,n,1] * [batch,1,n]= [batch,n,n]
m = tf.matmul(tf.expand_dims(x0, 2), tf.expand_dims(x,1)) #[batch,n,n]
# [batch,n,n] * [batch,n,1]= [batch,n,1]
new_w=tf.reshape(tf.tile(tf.expand_dims(w,1),[batch,1]),[-1,n,1]) #[batch,n,1]
y= tf.squeeze(tf.matmul(m,new_w))+x+b
return y

FM VS DCN

X與X交叉後,是一個n x n的矩陣。 如果w也是一個n x n的矩陣,那就會維度爆炸。

FM和dcn解決辦法都是:先將每個離散變數都可以用一個embedding表示,然後做cross product。(cross product後的結果一個矩陣D。)

不同的是

  1. FM ,將矩陣D進行sum,得到一個值,加上lr的值,得到y 。 只有一階交叉。
  2. dcn,將矩陣D乘以一個w得到一個向量, 這樣就可以繼續做二階交叉、多階交叉。

推薦閱讀:

相關文章