NMF
1.动机
NMF是2017 提出的一个模型,传统的FM模型仅仅局限于线性表达和二阶交互,无法胜任生活中的复杂数据。
作者提出了一种将FM融合进入DNN的策略,通过使用一个特征交叉池化层的结构,使得FM和DNN 进行了完美的衔接。
组合了FM的建模低阶特征的交互能力和DNN的学习高阶特征交互和非线性的能力。
那么这个是模型是如何做的呢?
对比FM 发现变化的只有第三项
这里改进的思路就是用一个表达能力更强的函数来替代原来的FM中的二阶隐向量的部分
而这个表达能力更强的函数我们
使用神经网络来进行替换,可以考虑底层的交叉,然后高层使用DNN网络,这就组成了我们最终的NFM网络。
2 模型的结构 原理
总结
输入: 稀疏离散特征居多,因此是 转化为One-hot
之后进行 Embedding
双向交互的池化层:核心结构 实现了FM和DNN的有效连接 组成了一个更大的网络,并且可以有效的反向传播。该层不需要额外的模型学习参数。
隐藏层: 全联接层 不是sigmoid 函数
预测层:回归问题,不用使用sigmoid激活
代码实现:
运行逻辑:
数据集的特征分为连续特征和离散特征。
输入也就分成liner input dnn input 。
1.linear part
这部分是有关线性计算
2.DNN : 这部分是计算交叉特征的部分计算
也就是fx
def NFM(linear_feature_columns, dnn_feature_columns):
"""
搭建NFM模型,上面已经把所有组块都写好了,这里拼起来就好
:param linear_feature_columns: A list. 里面的每个元素是namedtuple(元组的一种扩展类型,同时支持序号和属性名访问组件)类型,表示的是linear数据的特征封装版
:param dnn_feature_columns: A list. 里面的每个元素是namedtuple(元组的一种扩展类型,同时支持序号和属性名访问组件)类型,表示的是DNN数据的特征封装版
"""
# 构建输入层,即所有特征对应的Input()层, 这里使用字典的形式返回, 方便后续构建模型
# 构建模型的输入层,模型的输入层不能是字典的形式,应该将字典的形式转换成列表的形式
# 注意:这里实际的输入与Input()层的对应,是通过模型输入时候的字典数据的key与对应name的Input层
dense_input_dict, sparse_input_dict = build_input_layers(linear_feature_columns+dnn_feature_columns)
input_layers = list(dense_input_dict.values()) + list(sparse_input_dict.values())
# 线性部分的计算 w1x1 + w2x2 + ..wnxn + b部分,dense特征和sparse两部分的计算结果组成,具体看上面细节
linear_logits = get_linear_logits(dense_input_dict, sparse_input_dict, linear_feature_columns)
# DNN部分的计算
# 首先,在这里构建DNN部分的embedding层,之所以写在这里,是为了灵活的迁移到其他网络上,这里用字典的形式返回
# embedding层用于构建FM交叉部分以及DNN的输入部分
embedding_layers = build_embedding_layers(dnn_feature_columns, sparse_input_dict, is_linear=False)
# 过特征交叉池化层
pooling_output = get_bi_interaction_pooling_output(sparse_input_dict, dnn_feature_columns, embedding_layers)
# 加个BatchNormalization
pooling_output = BatchNormalization()(pooling_output)
# dnn部分的计算
dnn_logits = get_dnn_logits(pooling_output)
# 线性部分和dnn部分的结果相加,最后再过个sigmoid
output_logits = Add()([linear_logits, dnn_logits])
output_layers = Activation("sigmoid")(output_logits)
model = Model(inputs=input_layers, outputs=output_layers)
return model