DeepFM模型介绍

场景

CTR预估是目前推荐系统的核心技术,其目标是预估用户点击推荐内容的概率,在特征工程中,二阶特征的交叉非常重要,但是人为的特征交叉及其繁琐,且需要很多领域和业务经验。FM模型具有特征自动交叉的作用,能够学到二阶特征,但是无法学习到更高阶的特征,DNN可以学习到高阶特征组合,结合FM和DNN,产生了DeepFM模型。本文简单的介绍了FM模型和DeepFM模型,并给出了一些代码案例。

FM模型

作用:将特征向量化后,利用特征向量的点积作为交叉项的权重,从而进行自动二阶交叉。
优点:泛化能力强,尤其是大规模稀疏特征场景,对于没有同时出现的特征交叉也可以学到权重。
在这里插入图片描述
本质上,MF模型是FM模型的特例,MF可以被认为是只有User ID 和Item ID这两个特征Fields的FM模型,MF将这两类特征通过矩阵分解,来达到将这两类特征embedding化表达的目的。而FM则可以看作是MF模型的进一步拓展,除了User ID和Item ID这两类特征外,很多其它类型的特征,都可以进一步融入FM模型里,它将所有这些特征转化为embedding低维向量表达,并计算任意两个特征embedding的内积,就是特征组合的权重

算法效率:
从FM的原始数学公式看,因为在进行二阶(2-order)特征组合的时候,假设有n个不同的特征,那么二阶特征组合意味着任意两个特征都要进行交叉组合,所以可以直接推论得出:FM的时间复杂度是n的平方。
二阶特征交叉公式改写后,复杂度为:kn
在这里插入图片描述

DeepFM模型

DeepFM模型包含FM和DNN两部分,FM模型可以抽取low-order特征,DNN可以抽取high-order特征。无需Wide&Deep模型人工特征工程
在这里插入图片描述
在这里插入图片描述

代码实践

特征分为两种:
onehot特征:用户属性,歌曲属性等
连续特征:用户在不通类目下的偏好,歌曲转化率等。
FM部分输入:onehot特征
DNN部分数据:concat (onehot+dense)
输入:feat_index (B x F) feat_value (B x F)
embedding 层, 对每个特征映射到k维度的embedding向量: B X F X K

 # model
self.embeddings = tf.nn.embedding_lookup(self.weights["feature_embeddings"], self.feat_index) 
feat_value = tf.reshape(self.feat_value, shape=[-1, self.field_size, 1])
self.embeddings = tf.multiply(self.embeddings, feat_value)

FM计算模块,一阶项和二阶交叉项


# ---------- first order term ----------
self.y_first_order = tf.nn.embedding_lookup(self.weights["feature_bias"], self.feat_index) # None * F * 1
self.y_first_order = tf.reduce_sum(tf.multiply(self.y_first_order, feat_value), 2)  # None * F
self.y_first_order = tf.nn.dropout(self.y_first_order, self.dropout_keep_fm[0]) # None * F
 # ---------- second order term ---------------
            # sum_square part
self.summed_features_emb = tf.reduce_sum(self.embeddings, 1)  # None * K
self.summed_features_emb_square = tf.square(self.summed_features_emb)  # None * K
 # square_sum part
self.squared_features_emb = tf.square(self.embeddings)
self.squared_sum_features_emb = tf.reduce_sum(self.squared_features_emb, 1)  # None * K

# second order
self.y_second_order = 0.5 * tf.subtract(self.summed_features_emb_square, self.squared_sum_features_emb)  # None * K
self.y_second_order = tf.nn.dropout(self.y_second_order, self.dropout_keep_fm[1])  # None * K

Deep项

# ---------- Deep component ----------
self.y_deep = tf.reshape(self.embeddings, shape=[-1, self.field_size * self.embedding_size]) # None * (F*K)
self.y_deep = tf.nn.dropout(self.y_deep, self.dropout_keep_deep[0])
for i in range(0, len(self.deep_layers)):
    self.y_deep = tf.add(tf.matmul(self.y_deep, self.weights["layer_%d" %i]), self.weights["bias_%d"%i]) # None * layer[i] * 1
    if self.batch_norm:
        self.y_deep = self.batch_norm_layer(self.y_deep, train_phase=self.train_phase, scope_bn="bn_%d" %i) # None * layer[i] * 1
    self.y_deep = self.deep_layers_activation(self.y_deep)
    self.y_deep = tf.nn.dropout(self.y_deep, self.dropout_keep_deep[1+i]) # dropout at each Deep layer

最后将Deep层和FM层的输出concat到一起,经过一层隐层+sigmod输出

# ---------- DeepFM ----------
if self.use_fm and self.use_deep:
    concat_input = tf.concat([self.y_first_order, self.y_second_order, self.y_deep], axis=1)
elif self.use_fm:
    concat_input = tf.concat([self.y_first_order, self.y_second_order], axis=1)
elif self.use_deep:
    concat_input = self.y_deep
self.out = tf.add(tf.matmul(concat_input, self.weights["concat_projection"]), self.weights["concat_bias"])
self.out = tf.nn.sigmoid(self.out)
self.loss = tf.losses.log_loss(self.label, self.out)
发布了35 篇原创文章 · 获赞 61 · 访问量 16万+

猜你喜欢

转载自blog.csdn.net/cql342624757/article/details/103939130