当前位置: 代码迷 >> 综合 >> 推荐系统——Neural Collaborative Filtering(NMF)
  详细解决方案

推荐系统——Neural Collaborative Filtering(NMF)

热度:17   发布时间:2023-11-21 13:10:00.0

前言

论文地址:https://arxiv.org/pdf/1708.05031.pdf?ref=https://codemonkey.link
代码地址:https://github.com/hexiangnan/neural_collaborative_filtering

系列文章

推荐系统——Neural Collaborative Filtering(NMF)
推荐系统——Deep Interest Network for Click-Through Rate Prediction(DIN)
推荐系统——Deep Interest Evolution Network for Click-Through Rate Prediction(DIEN)
推荐系统——Deep Session Interest Network for Click-Through Rate Prediction(DSIN)
推荐系统——Multi-Interest Network with Dynamic Routing for Recommendation at Tmall(MIND)
推荐系统——Behavior Sequence Transformer for E-commerce Recommendation in Alibaba(BST)
持续更新中…

动机

这是比较早的文章了,推荐系统经常用向量的点积来学习向量间的交互信息,

向量点积的目的:这样的好处是计算速度快所以粗排的时候经常采用这种策略。向量点积如果两个向量都已经L2 norm的话表征的意义就是两个向量的余弦距离。但是我看很多推荐系统的代码实现上并不会事先对两个向量进行L2 norm,目前感觉合理的解释是一般点积完后面还会接FC层去做分类或者降维之类的,FC是不是一定程度可以实现L2 norm的功能呢所以事先L2 norm是不必要的。

本文的作者提出使用多层线性层来学习user和item的交互信息,作者认为更深的神经网络能比简单的点积更好的表征推荐系统的特征。

结构

在这里插入图片描述
推荐系统的结构真的看的比较简单明了,整个结构分为左右两个分支,两个分支可以是独立的,首先输入的user特征和item是one hot的格式,通过torch.nn.Embedding就可以把onehot的特征编码成维度相同的特征并且与onehot直接相关。

接下来MF User Vector和MLP User Vector是将user的特征经过两个不同的FC层得到的两个两个特征,右侧的MF item vector和MLP item Vector同理。用不同的FC是为了左右两个分支可以完全独立,目的在后面会说。

左侧分支:MF的user和item特征在GMF layer里面进行点乘。
右侧分支:MLP的user和item特征送入MLP层。

最后将MLP和GMF输出的特征在维度上concat起来,经过FC层后进行分类等任务。

下面是user侧有10个长度的序列进行nmf的demo:

import torch
import torch.nn as nnclass RecoClsNMF(nn.Module):def __init__(self,input_dim,output_dim):super().__init__()self.input_dim = input_dimself.output_dim = output_dimself.mf_user = torch.nn.Linear(self.input_dim, self.input_dim)self.mf_item = torch.nn.Linear(self.input_dim, self.input_dim)self.mlp_user = torch.nn.Linear(self.input_dim, self.input_dim)self.mlp_item = torch.nn.Linear(self.input_dim, self.input_dim)self.fc_layers = torch.nn.ModuleList()layers = [2, 8, 4, 2, 1]for idx, (in_size, out_size) in enumerate(zip(layers[:-1], layers[1:])):self.fc_layers.append(torch.nn.Linear(in_size * self.output_dim, out_size * self.output_dim))def forward(self, user, item):# user:[bs,lebgth,dim] item:[bs,dim]user = torch.sum(user,dim=1) # [bs,dim]# user vectormf_user = self.mf_user(user)mlp_user = self.mlp_user(user)# item vectormf_item = self.mf_item(item)mlp_item = self.mlp_item(item)# GMFGMF_out = torch.mul(mf_user, mf_item)  # batch,dim# MLPvector = torch.cat([mlp_user, mlp_item], dim=-1)  # batch,dim*2for idx, _ in enumerate(range(len(self.fc_layers))):vector = self.fc_layers[idx](vector)vector = torch.nn.ReLU()(vector)MLP_out = vector  # vector->batch,dim# NeuMFx = torch.cat([MLP_out, GMF_out], dim=-1)  # batch,dim*2return xif __name__ == '__main__':model = RecoClsNMF(128,128)user = torch.randn((16,10,128))item = torch.randn((16,128))print("user shape",user.shape)print("item shape", item.shape)out = model(user, item)print("out shape",out.shape)

输出结果:

user shape torch.Size([16, 10, 128])
item shape torch.Size([16, 128])
out shape torch.Size([16, 256])

代码很简单,效果还可以。

  相关解决方案