NFM

背景

FNN模型是2016年提出的一个FM和DNN的一个组合, 这个模型的底层是FM,上层是DNN,该模型提出的目的依然是特征之间的交叉和表达能力的增强, 作者在论文中说FM虽然考虑了二阶交叉,但是无法延伸到高阶交叉信息的学习,于是乎提出了底层FM二阶交叉学习之后,再接一个DNN的组合,当然,还提出了一些有效的预训练方式。 但是该模型会存在一些问题,于是在2017年DeepFM出现了,该模型依然是FM和DNN的组合,但不是串行,而是基于W&D的架构,换成了并行的方式,让FM充当于W部分(当然不只是单纯的替换),这样既考虑了低阶交叉,也考虑高阶交叉,且实现了端到端,避免了W&D中W的特征工程。但是该模型的FM依然是二阶交叉,无可避免的限制了表达能力。于是乎,2017年,NFM也被提出,它改进了FM的二阶隐向量内积部分,换成了一个表达能力更强的函数,且Deep部分也加入了特征交叉池化层。这就是这三个模型的一个发展逻辑。
FM和DNN在稀疏数据的优势非常明显且正好又互补, 且W&D开辟了组合模型的先河,关键是如何组合的问题? FNN给出了一种思路, DeepFM给出了一种思路, NFM这里同样是有着组合的味道,但是不是那么简单的拼接式组合了,而是设计了一种结构,把FM和DNN拼接了起来

NFM模型结构

公式

y ^ N F M ( x ) = w 0 + ∑ i = 1 n w i x i + 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=1nwixi+f(x)

FM的一个问题,就是只能到二阶交叉, 且是线性模型, 这是他本身的一个局限性, 而如果想突破这个局限性, 就需要从他的公式本身下点功夫, 于是乎,作者在这里改进的思路就是用一个表达能力更强的函数来替代原FM中二阶隐向量内积的部分。
在这里插入图片描述
Bi-Interaction Pooling layer
f B I ( V x ) = ∑ i = 1 n ∑ j = i + 1 n x i v i ⊙ x j v j 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=1nj=i+1nxivixjvj
⊙表示两个向量的元素积操作,即两个向量对应维度相乘得到的元素积向量。这一个交叉完了之后k个维度不求和,最后会得到一个向量,而FM那里内积的话最后得到一个数, 在进行两两Embedding元素积之后,对交叉特征向量取和, 得到该层的输出向量, 很显然, 输出是一个k维的向量。这里很大的一点改进就是加入特征池化层之后, 把二阶交互的信息合并, 且上面接了一个DNN网络, 这样就能够增强FM的表达能力了, 因为FM只能到二阶, 而这里的DNN可以进行多阶且非线性,只要FM把二阶的学习好了, DNN这块学习来会更加容易

结构

底层考虑了交叉,然后高层使用的DNN网络
在这里插入图片描述
nfm

思考题

NFM中的特征交叉与FM中的特征交叉有何异同,分别从原理和代码实现上进行对比分析

FM公式计算的为内积,且最终需要对K个维度进行求和

concated_embeds_value = inputs # B x n x k
square_of_sum = tf.square(tf.reduce_sum(concated_embeds_value, axis=1, keepdims=True)) # B x 1 x k
sum_of_square = tf.reduce_sum(concated_embeds_value * concated_embeds_value, axis=1, keepdims=True) # B x1 xk
cross_term = square_of_sum - sum_of_square # B x 1 x k
cross_term = 0.5 * tf.reduce_sum(cross_term, axis=2, keepdims=False) # B x 1

在这里插入图片描述

NFM计算的是元素积,不需要对K个维度进行求和

concated_embeds_value = inputs # B x n x k
square_of_sum = tf.square(tf.reduce_sum(concated_embeds_value, axis=1, keepdims=False)) # B x k
sum_of_square = tf.reduce_sum(concated_embeds_value * concated_embeds_value, axis=1, keepdims=False) # B x k
cross_term = 0.5 * (square_of_sum - sum_of_square) # B x k

在这里插入图片描述

以下是基于PyTorch实现的NFM推荐算法代码,供参考: ``` import torch import torch.nn as nn import torch.nn.functional as F class NFM(nn.Module): def __init__(self, feature_dim, embedding_dim, hidden_dim, output_dim, dropout_prob): super().__init__() self.feature_dim = feature_dim self.embedding_dim = embedding_dim self.hidden_dim = hidden_dim self.output_dim = output_dim self.dropout_prob = dropout_prob self.embedding = nn.Embedding(feature_dim, embedding_dim) self.linear1 = nn.Linear(embedding_dim, hidden_dim) self.linear2 = nn.Linear(hidden_dim, output_dim) self.linear3 = nn.Linear(embedding_dim, output_dim) self.dropout = nn.Dropout(dropout_prob) def forward(self, x): # Embedding layer x_emb = self.embedding(x) # Bi-Interaction layer sum_square = torch.sum(x_emb, dim=1) ** 2 square_sum = torch.sum(x_emb ** 2, dim=1) bi_interaction = 0.5 * (sum_square - square_sum) # MLP layer mlp_output = F.relu(self.linear1(self.dropout(bi_interaction))) mlp_output = self.linear2(self.dropout(mlp_output)) # Output layer output = self.linear3(x_emb.mean(dim=1)) + mlp_output return output ``` 其中,`feature_dim`为特征维度,`embedding_dim`为嵌入维度,`hidden_dim`为隐层维度,`output_dim`为输出维度,`dropout_prob`为dropout概率。 在模型的前向传播过程中,首先通过`nn.Embedding`层将输入的离散特征转化为嵌入向量,然后通过Bi-Interaction Layer计算二阶交叉特征,再通过MLP Layer进行非线性变换,最后将MLP输出和原始嵌入向量的平均相加得到最终输出。 使用时,可以像以下代码一样初始化并训练模型: ``` # 初始化模型 model = NFM(feature_dim, embedding_dim, hidden_dim, output_dim, dropout_prob) # 定义损失函数和优化器 criterion = nn.BCEWithLogitsLoss() optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate) # 训练模型 for epoch in range(num_epochs): for inputs, targets in dataloader: optimizer.zero_grad() outputs = model(inputs) loss = criterion(outputs, targets) loss.backward() optimizer.step() ``` 其中,`feature_dim`、`embedding_dim`、`hidden_dim`、`output_dim`、`dropout_prob`、`learning_rate`、`num_epochs`等参数需要根据具体情况进行设置,`dataloader`是一个PyTorch的`DataLoader`对象,用于加载训练数据。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值