DeepFM算法原理&实现
💵

DeepFM算法原理&实现

text
DeepFM算法的Python代码实现
Tags
机器学习
深度学习
推荐系统
Created
Aug 25, 2022 10:09 AM
正如名称,DeepFM是由Deep与FM结合的产物,其兼具浅层和深层网络特征组合的能力。又因为其简单结构、低复杂度、训练效果良好,使得其在业界被广泛使用。
在2017年由哈尔滨工业大学和华为公司联合提出的DeepFM,将FM的模型结构和Wide&Deep模型进行整合;改进之处在于它用FM替代了原来的Wide部分,加强了浅层网络部分特征组合的能力。

算法原理

notion image

Sparse Features

表示数值特征和经过Onehot编码后的类别特征两者的拼接结果;

Dense Embeddings

嵌入层,将高维稀疏的01向量嵌入得到低维稠密的emb向量,然后将各个稠密向量进行横向拼接;

FM Layer

💡
分为线性部分和交叉部分,上图中黑线为线性部分,分配给每个特征一个权重;红色部分为交叉部分,对特征进行两两相乘后赋予权重加权求和;
具体FM算法:
⛸️
FM算法原理&实现

Hidden Layer

Deep部分就是将输入经过多层线性+非线性转换得到输出即可;

优缺点

优点

  • 两部分联合训练,无需加入人工特征,更易部署;
  • 结构简单,复杂度低,两部分共享输入,共享信息,可更精确的训练学习;

缺点

  • 将类别特征对应的稠密向量拼接作为输入,然后对元素进行两两交叉。这样将导致模型无法意识到域的概念;

代码实现

class DeepFM(Model): def __init__(self, feature_columns, k, w_reg, v_reg, hidden_units, output_dim, activation): super(DeepFM, self).__init__() self.dense_feature_columns, self.sparse_feature_columns = feature_columns self.embed_layer = EmbedLayer(self.sparse_feature_columns) self.fm = FMLayer(k, w_reg, v_reg) self.dnn = DNNLayer(hidden_units, output_dim, activation) def call(self, inputs, training=None, mask=None): dense_inputs, sparse_inputs = inputs[:, :13], inputs[:, 13:] sparse_embed = self.embed_layer(sparse_inputs) x = tf.concat([dense_inputs, sparse_embed], axis=-1) fm_output = self.fm(x) dnn_output = self.dnn(x) output = tf.nn.sigmoid(0.5 * (fm_output + dnn_output)) return output class FMLayer(Layer): def __init__(self, k, reg_w=1e-4, reg_b=1e-4): super(FMLayer, self).__init__() self.k = k self.reg_w = reg_w self.reg_b = reg_b def build(self, input_shape): self.w0 = self.add_weight(name='w0', shape=(1,), initializer=tf.zeros_initializer(), trainable=True) self.w1 = self.add_weight(name='w1', shape=(input_shape[-1], 1), initializer=tf.random_normal_initializer(), trainable=True, regularizer=l2(self.reg_w)) self.v = self.add_weight(name='v', shape=(input_shape[-1], self.k), initializer=tf.random_normal_initializer(), trainable=True, regularizer=l2(self.reg_b)) def call(self, inputs, *args, **kwargs): linear_part = tf.matmul(inputs, self.w1) + self.w0 inter_part1 = tf.pow(tf.matmul(inputs, self.v), 2) inter_part2 = tf.matmul(tf.pow(inputs, 2), tf.pow(self.v, 2)) inter_part = 0.5 * tf.reduce_sum(inter_part1 - inter_part2, axis=-1, keepdims=True) output = linear_part + inter_part return output

参考