由于之前没有看过NFM,这里先把.md文件进行了阅读、理解并将其复制到了笔记里,然后就是整体的tf的实现及结果的展示
WideNDeep、DeepFm、NFM代码演示中的区别
- 线性部分
- 一阶线性部分相同
- DeepFm多了个二阶特征交叉,内积得到了一个数
- nfm元素积操作,得到的是向量,在进行两两Embedding元素积之后,对交叉特征向量取和, 得到该层的输出向量, 很显然, 输出是一个 𝑘 维的向量。
- deep部分
- widendeep在演示的代码中是对数值型特征和类别型特征都进行了deep
- DeepFm和nfm都是对类别型特征进行了deep
1. 动机
NFM(Neural Factorization Machines)是2017年由新加坡国立大学的何向南教授等人在SIGIR会议上提出的一个模型,传统的FM模型仅局限于线性表达和二阶交互, 无法胜任生活中各种具有复杂结构和规律性的真实数据, 针对FM的这点不足, 作者提出了一种将FM融合进DNN的策略,通过引进了一个特征交叉池化层的结构,使得FM与DNN进行了完美衔接,这样就组合了FM的建模低阶特征交互能力和DNN学习高阶特征交互和非线性的能力,形成了深度学习时代的神经FM模型(NFM)。
那么NFM具体是怎么做的呢? 首先看一下NFM的公式:
y^NFM(x)=w0+∑i=1nwixi+f(x) \hat{y}_{N F M}(\mathbf{x})=w_{0}+\sum_{i=1}^{n} w_{i} x_{i}+f(\mathbf{x}) y^NFM(x)=w0+i=1∑nwixi+f(x)
我们对比FM, 就会发现变化的是第三项,前两项还是原来的, 因为我们说FM的一个问题,就是只能到二阶交叉, 且是线性模型, 这是他本身的一个局限性, 而如果想突破这个局限性, 就需要从他的公式本身下点功夫, 于是乎,作者在这里改进的思路就是用一个表达能力更强的函数来替代原FM中二阶隐向量内积的部分。

而这个表达能力更强的函数呢, 我们很容易就可以想到神经网络来充当,因为神经网络理论上可以拟合任何复杂能力的函数, 所以作者真的就把这个f(x)f(x)f(x)换成了一个神经网络,当然不是一个简单的DNN, 而是依然底层考虑了交叉,然后高层使用的DNN网络, 这个也就是我们最终的NFM网络了:

这个结构,如果前面看过了PNN的伙伴会发现,这个结构和PNN非常像,只不过那里是一个product_layer, 而这里换成了Bi-Interaction Pooling了, 这个也是NFM的核心结构了。这里注意, 这个结构中,忽略了一阶部分,只可视化出来了f(x)f(x)f(x), 我们还是下面从底层一点点的对这个网络进行剖析。
2. 模型结构与原理
2.1 Input 和Embedding层
输入层的特征, 文章指定了稀疏离散特征居多, 这种特征我们也知道一般是先one-hot, 然后会通过embedding,处理成稠密低维的。 所以这两层还是和之前一样,假设vi∈Rk\mathbf{v}_{\mathbf{i}} \in \mathbb{R}^{k}vi∈Rk为第iii个特征的embedding向量, 那么Vx={ x1v1,…,xnvn}\mathcal{V}_{x}=\left\{x_{1} \mathbf{v}_{1}, \ldots, x_{n} \mathbf{v}_{n}\right\}Vx={ x1v1,…,xnvn}表示的下一层的输入特征。这里带上了xix_ixi是因为很多xix_ixi转成了One-hot之后,出现很多为0的, 这里的{ xivi}\{x_iv_i\}{ xivi}是xix_ixi不等于0的那些特征向量。
2.2 Bi-Interaction Pooling layer
在Embedding层和神经网络之间加入了特征交叉池化层是本网络的核心创新了,正是因为这个结构,实现了FM与DNN的无缝连接, 组成了一个大的网络,且能够正常的反向传播。假设Vx\mathcal{V}_{x}Vx是所有特征embedding的集合, 那么在特征交叉池化层的操作:
fBI(Vx)=∑i=1n∑j=i+1nxivi⊙xjvj f_{B I}\left(\mathcal{V}_{x}\right)=\sum_{i=1}^{n} \sum_{j=i+1}^{n} x_{i} \mathbf{v}_{i} \odot x_{j} \mathbf{v}_{j} fBI(Vx)=i=1∑nj=i+1∑nxivi⊙xjvj
⊙\odot⊙表示两个向量的元素积操作,即两个向量对应维度相乘得到的元素积向量(可不是点乘呀),其中第kkk维的操作:
(vi⊙vj)k=vikvjk \left(v_{i} \odot v_{j}\right)_{k}=\boldsymbol{v}_{i k} \boldsymbol{v}_{j k} (vi⊙vj)k=