FM一次项部分计算:
# step1: FM 一阶部分 none * f * 1 first_weights = self.first_weights(feature_index) # Wi*Xi, tf.math.multiply 是对应元素相乘, none * f * 1 first_weight_value =tf.math.multiply(first_weights, feature_value) # first_weight_value维度从none * f * 1降维为 none * f #只是降维,可以理解为concat(w1*x1, ..., wn*xn), 并不是sum(w1*x1, ..., wn*xn) fm_first_output = tf.math.reduce_sum(first_weight_value, axis=2) # none * f
FM二次项部分计算:
前面文章DeepFM模型理论与其运算过程,介绍过二阶部分运算的推导过程,不清楚的可以看前面文章,二次项的计算如下: # step2: FM 二阶部分 none * f * k feature_emb = self.feature_embeddings(feature_index) # none * f * k # Vi*Xi。tf.math.multiply广播(none * f * k) * (none * f * 1) = (none * f * k) feature_emb_value = tf.math.multiply(feature_emb, feature_value) # none * f * k # sum(Vi*Xi)**2, none * k sumed_feature_emb = tf.math.reduce_sum(feature_emb_value, axis=1) # none * k interaction_part1 = tf.math.pow(sumed_feature_emb, 2) # none * k # sum((Vi*Xi)**2), none * k squared_feature_emb = tf.math.pow(feature_emb_value, 2) # none * f * k interaction_part2 = tf.math.reduce_sum(squared_feature_emb, axis=1) # none * k # sum(Vi*Vj*Xi*Xj) none * k fm_second_output = 0.5 * tf.math.subtract(interaction_part1, interaction_part2) # none * k
2、Deep部分与结果输出
Deep部分很简单,与FM共享二次项部分的embedding层,再加几层全连接:
# step3: deep部分 # 输入形状变换为 none * (f * k) deep_feature = tf.reshape(feature_emb_value, (-1, self.num_field * self.embedding_size)) deep_feature = tf.keras.layers.Dropout(self.dropout_deep)(deep_feature) # 最终输出:none * layer_sizes[-1] for i in range(len(self.layer_sizes)): deep_feature = getattr(self, 'dense_' + str(i))(deep_feature) deep_feature = getattr(self, 'bn_' + str(i))(deep_feature) deep_feature = getattr(self, 'activation_' + str(i))(deep_feature) deep_feature = getattr(self, 'dropout_' + str(i))(deep_feature) # 所有中间特征合并:none * (f + k + layer_sizes[-1]) concat_input = tf.concat((fm_first_output, fm_second_output, deep_feature), axis=1) # 最终输出 output = self.output_layer(concat_input) # at_bias']))
3、遇到的一些问题
3.1、模型输入的数值类型 模型的输入数值类型,需要进行tf.cast转换,不然会报错:
# 训练的train data & train label, 并统一数据格式,不然tf.math.multiply会报错 index = tf.cast(data_index[cols].values, tf.float32) value = tf.cast(data_value[cols].values, tf.float32)
3.2、模型输入的数据形状
模型的输入需要feature_index、feature_value,刚开始在自定义model的前向传播时,是直接定义2个输入,训练没问题,但模型save时会报错:
# 前向传播 @tf.function def call(self, feature_index, feature_value): # 为了矩阵运算,需要对feature_value进行从内升维,从none * f 到 none * f * 1 # 之所以是f不是one-hot后的n,是因为这里进行了压缩,离散的值都是1,主要是通过feature_index索引决定的
把模型的输入格式改为list格式[feature_index, feature_value]作为输入后,模型可以训练、预测和保存后重新load进行预测,但是在进行tf serving部署进行预测时,遇到问题预测不成功:
# 前向传播 @tf.function def call(self, inputs): feature_index, feature_value = inputs # 为了矩阵运算,需要对feature_value进行从内升维,从none * f 到 none * f * 1 # 之所以是f不是one-hot后的n,是因为这里进行了压缩,离散的值都是1,主要是通过feature_index索引决定的
为了能进行tf serving部署预测,又尝试了把模型输入feature_index, feature_value拼接为一个整体作为输入,从而模型可以保存并可以通过tf serving部署预测:
index_value = tf.concat([index, value], axis=-1)
# 前向传播 @tf.function def call(self, inputs): feature_index = inputs[:, :self.num_field] feature_value = inputs[:, self.num_field:]
3.3、其他
在自定复杂模型时,如果自己没有自定义predict方法时,model.predict(x)会报错,预测要用model(x),或者model.call(x)进行预测:
# model_deepfm.call(feature_index_value) model_deepfm(feature_index_value)
自定义类模型时,起码要有两部分初始化部分__init__和前向运算部分call。@tf.function是把函数转换为计算图,以图执行模式运行可以提高运算速度:
class DeepFM(tf.keras.Model): def __init__(self, num_field, num_feature): super().__init__() # xxx # 前向传播 @tf.function def call(self, inputs): # xxx
4、总结
本文主要分享了在学习TF2.0过程中,参考其他一些资料,实现自定义deepfm,并通过tf serving进行部署中遇到的一些问题。代码中的方法可能不是最优方法或存在一些问题,需要详细代码和交流的朋友可以私信。
本次实现的deepfm,是通过自定义model类,即class DeepFM(tf.keras.Model)实现的,好处是对于初学者来说,前向运算过程比较清晰,但需要同时自定义模型的训练方法。
其实也可以通过自定义层:class FMLayer(tf.keras.layers.Layer)来实现,这样就不需要再自定义model类,从而可以用原始model类的一些方法,如 model.fit。git上的DeepCTR项目就是用的这种方法,有兴趣的朋友可以试试。
参考资料:《简明的TensorFlow2》
https://arxiv.org/pdf/1703.04247.pdf
https://zhuanlan.zhihu.com/p/32563337http://www.manongjc.com/article/33337.html
https://www.cnblogs.com/wkang/p/9881921.html
https://blog.csdn.net/maqunfi/article/details/99635620
https://mp.weixin.qq.com/s/QrO48ZdP483TY_EnnWFhsQ
https://mp.weixin.qq.com/s/4bw9GxQ10iyC08H0zYbSmw
https://github.com/yongqyu/DeepFM-tf2
https://github.com/shenweichen/DeepCTR
https://github.com/JianzhouZhan/Awesome-RecSystem-Models
https://github.com/princewen/tensorflow_practice/tree/master/recommendation