推荐系统论文回顾:神经协同过滤理解与实现

2024-06-21 09:08

本文主要是介绍推荐系统论文回顾:神经协同过滤理解与实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

点击上方“AI公园”,关注公众号,选择加“星标“或“置顶”


作者:Kung-Hsiang, Huang (Steeve)

编译:ronghuaiyang

导读

今天给大家回顾一篇论文,神经协同过滤,看名字就知道,神经网络版本的协同过滤,推荐算法的经典的方法之一。

神经协同过滤(NCF)是新加坡国立大学、哥伦比亚大学、山东大学、德州农工大学于 2017 年共同发表的一篇论文。利用神经网络的灵活性、复杂性和非线性,建立了一个推荐系统。证明了传统的推荐系统矩阵分解是神经协同过滤的一个特例。此外,它还表明 NCF 在两个公共数据集中的表现优于最先进的模型。本文将解释 NCF 的概念,并演示如何在 Pytorch 中实现它。

必备知识点

在深入研究论文之前,你应该知道什么是推荐系统,以及一些基本的推荐系统。

矩阵分解

我们从矩阵分解开始。它将效用矩阵分解为两个子矩阵。在预测过程中,我们将两个子矩阵相乘来重建预测的效用矩阵。对效用矩阵进行因式分解,使两者相乘的损失与真实效用矩阵的损失最小化。一个常用的损失函数是均方误差。

本质上,每个用户和物品都被投射到潜空间中,由潜向量表示。两个潜向量越相似,对应的用户偏好越相关。由于我们将效用矩阵分解成相同的潜在空间,所以我们可以用余弦相似度或点积来度量任意两个潜向量的相似度。实际上,每个用户/物品的预测是通过对应的潜向量的点积计算出来的。

预测等于潜向量的内积

然而,本文认为点积限制了用户和物品潜向量的表达。让我们考虑下面的情况。我们首先关注效用矩阵的前三行。

设 S{x,y}表示用户 x 与用户 y 之间的相似度,通过计算用户 1、2、3 之间的余弦相似度,可知 S{2, 3} > S{1, 2} > S{1, 3}。在不失一般性的情况下,我们将用户映射到一个二维的潜空间,如下所示。

现在,我们考虑用户 4。通过与其他算法的相似性比较,我们得到了 S{1,4} > S{3,4} > S{2,4}。但是,无论我们把潜向量 P4 放在 P1 的左右,它都必然会比 P3 更接近 P2。

因此,这个例子显示了内积在充分模拟用户和项目在潜在空间中的交互方面的局限性。

神经协同过滤

本文提出了如下图所示的神经协同滤波方法。在输入层,用户和物品是独热编码的。然后,通过相应的嵌入层映射到隐藏空间。神经网络 FC 层可以是任何类型的神经元连接。例如,多层感知器可以放在这里。该模型具有神经 CF 层的复杂连接和非线性,能够较好地估计潜空间中用户与物品之间的复杂交互作用。

NCF结构

那么,NCF 是如何成为泛化版本的矩阵分解的呢?让我在下图中给你展示。我们首先用乘法层替换神经 CF 层,乘法层对两个输入执行元素级的乘法。然后利用线性激活函数,将乘法层到输出层的权值设为 K×1 维的固定单位矩阵(全一矩阵)。

然后,我们有以下方程。

未被发现的交互 ŷ_ui 表示预测值(u, i)进入了重建的效用矩阵。L 为线性激活函数,⊙ 为元素乘操作。p_u 和 q_i 分别是用户和项目的潜在向量,J 是维数(K,1)的单位矩阵。因为 J 是一个单位矩阵,所以在这个线性函数里面变成了潜向量 p_u 和 q_i 的内积。此外,由于线性函数的输入和输出是相同的,所以可以归结为最后一行。预测标签是对应用户和物品的潜向量的内积。这个方程与矩阵分解部分所示的方程相同。从而证明了矩阵分解是 NCF 的一个特例。

NeuMF

为了引入额外的非线性能力,提出的最终模型 NeuMF 除了广义矩阵分解(GMP)层外,还包括一个多层感知器(MLP)模块。

GMF 和 MLP 模块的输出连接到 sigmoid 激活输出层。

性能

本文对 NCF 模型和其他模型进行了评价。也就是说,每个用户的最后一次交互被保留下来进行评估。考虑两个评估指标,命中率@10 和 NDCG@10。命中率@K 表示每个用户获得 10 个推荐的预测命中率。假设我们为每个用户推荐 10 个项目,10 个用户中的 4 个与我们推荐的项目进行交互,然后点击 Ratio@10=0.4。另一方面,NDCG 可以被看作是命中率的扩展,它还考虑了命中的顺序。这意味着如果你的命中发生在较高的推荐上,NDCG 将更高。

性能比较如下图所示。在所有情况下,NeuMF 的表现都优于其他模型。

此外,本文还证明了对 NeuMF 各个模块进行预训练的有效性。分别训练 GMF 和 MLP 后,将训练后的 GMF 和 MLP 的权重设置为 NeuMF 的初始化。

实现

在本节中,我将向你展示如何在 Pytorch 中轻松实现 NeuMF。你只需为每个模型实现两个函数,__init__函数指定模型结构,而forward()函数定义如何将输入张量进行前向传播。

def __init__(self, config):super(NeuMF, self).__init__()#mf partself.embedding_user_mf = torch.nn.Embedding(num_embeddings=self.num_users, embedding_dim=self.latent_dim_mf)self.embedding_item_mf = torch.nn.Embedding(num_embeddings=self.num_items, embedding_dim=self.latent_dim_mf)#mlp partself.embedding_user_mlp = torch.nn.Embedding(num_embeddings=self.num_users, embedding_dim=self.latent_dim_mlp)self.embedding_item_mlp = torch.nn.Embedding(num_embeddings=self.num_items, embedding_dim=self.latent_dim_mlp)self.fc_layers = torch.nn.ModuleList()for idx, (in_size, out_size) in enumerate(zip(config['layers'][:-1], config['layers'][1:])):self.fc_layers.append(torch.nn.Linear(in_size, out_size))self.logits = torch.nn.Linear(in_features=config['layers'][-1] + config['latent_dim_mf']  , out_features=1)self.sigmoid = torch.nn.Sigmoid()

研究结果表明,采用单独的嵌入层,MLP 和 GMF 的嵌入效果更好。因此,我们为这两个模块定义了指定的嵌入层。此外,ModuleList 还用于构建多层感知器。

def forward(self, user_indices, item_indices, titles):user_embedding_mlp = self.embedding_user_mlp(user_indices)item_embedding_mlp = self.embedding_item_mlp(item_indices)user_embedding_mf = self.embedding_user_mf(user_indices)item_embedding_mf = self.embedding_item_mf(item_indices)#### mf partmf_vector =torch.mul(user_embedding_mf, item_embedding_mf)mf_vector = torch.nn.Dropout(self.config.dropout_rate_mf)(mf_vector)#### mlp partmlp_vector = torch.cat([user_embedding_mlp, item_embedding_mlp], dim=-1)  # the concat latent vectorfor idx, _ in enumerate(range(len(self.fc_layers))):mlp_vector = self.fc_layers[idx](mlp_vector "idx")mlp_vector = torch.nn.ReLU()(mlp_vector)mlp_vector = torch.nn.Dropout(self.config.dropout_rate_mlp)(mlp_vector)vector = torch.cat([mlp_vector, mf_vector], dim=-1)logits = self.logits(vector)output = self.sigmoid(logits)return output

forward()函数相当简单。我们只是让用户和物品索引在定义的网络中流动。特别要注意的是,我在 GMP 和 MLP 模块的末尾添加了 Dropout 层,因为我发现这有助于网络的正则化和性能的提高。

—END—

英文原文:https://towardsdatascience.com/paper-review-neural-collaborative-filtering-explanation-implementation-ea3e031b7f96

请长按或扫描二维码关注本公众号

喜欢的话,请给我个好看吧

这篇关于推荐系统论文回顾:神经协同过滤理解与实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1080799

相关文章

python设置环境变量路径实现过程

《python设置环境变量路径实现过程》本文介绍设置Python路径的多种方法:临时设置(Windows用`set`,Linux/macOS用`export`)、永久设置(系统属性或shell配置文件... 目录设置python路径的方法临时设置环境变量(适用于当前会话)永久设置环境变量(Windows系统

Python对接支付宝支付之使用AliPay实现的详细操作指南

《Python对接支付宝支付之使用AliPay实现的详细操作指南》支付宝没有提供PythonSDK,但是强大的github就有提供python-alipay-sdk,封装里很多复杂操作,使用这个我们就... 目录一、引言二、准备工作2.1 支付宝开放平台入驻与应用创建2.2 密钥生成与配置2.3 安装ali

Spring Security 单点登录与自动登录机制的实现原理

《SpringSecurity单点登录与自动登录机制的实现原理》本文探讨SpringSecurity实现单点登录(SSO)与自动登录机制,涵盖JWT跨系统认证、RememberMe持久化Token... 目录一、核心概念解析1.1 单点登录(SSO)1.2 自动登录(Remember Me)二、代码分析三、

PyCharm中配置PyQt的实现步骤

《PyCharm中配置PyQt的实现步骤》PyCharm是JetBrains推出的一款强大的PythonIDE,结合PyQt可以进行pythion高效开发桌面GUI应用程序,本文就来介绍一下PyCha... 目录1. 安装China编程PyQt1.PyQt 核心组件2. 基础 PyQt 应用程序结构3. 使用 Q

Linux系统中查询JDK安装目录的几种常用方法

《Linux系统中查询JDK安装目录的几种常用方法》:本文主要介绍Linux系统中查询JDK安装目录的几种常用方法,方法分别是通过update-alternatives、Java命令、环境变量及目... 目录方法 1:通过update-alternatives查询(推荐)方法 2:检查所有已安装的 JDK方

Linux系统之lvcreate命令使用解读

《Linux系统之lvcreate命令使用解读》lvcreate是LVM中创建逻辑卷的核心命令,支持线性、条带化、RAID、镜像、快照、瘦池和缓存池等多种类型,实现灵活存储资源管理,需注意空间分配、R... 目录lvcreate命令详解一、命令概述二、语法格式三、核心功能四、选项详解五、使用示例1. 创建逻

Python实现批量提取BLF文件时间戳

《Python实现批量提取BLF文件时间戳》BLF(BinaryLoggingFormat)作为Vector公司推出的CAN总线数据记录格式,被广泛用于存储车辆通信数据,本文将使用Python轻松提取... 目录一、为什么需要批量处理 BLF 文件二、核心代码解析:从文件遍历到数据导出1. 环境准备与依赖库

linux下shell脚本启动jar包实现过程

《linux下shell脚本启动jar包实现过程》确保APP_NAME和LOG_FILE位于目录内,首次启动前需手动创建log文件夹,否则报错,此为个人经验,供参考,欢迎支持脚本之家... 目录linux下shell脚本启动jar包样例1样例2总结linux下shell脚本启动jar包样例1#!/bin

go动态限制并发数量的实现示例

《go动态限制并发数量的实现示例》本文主要介绍了Go并发控制方法,通过带缓冲通道和第三方库实现并发数量限制,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录带有缓冲大小的通道使用第三方库其他控制并发的方法因为go从语言层面支持并发,所以面试百分百会问到

Go语言并发之通知退出机制的实现

《Go语言并发之通知退出机制的实现》本文主要介绍了Go语言并发之通知退出机制的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1、通知退出机制1.1 进程/main函数退出1.2 通过channel退出1.3 通过cont