NeuralCF 模型:神经网络协同过滤模型

实验和完整代码

完整代码实现和jupyter运行:https://github.com/Myolive-Lin/RecSys--deep-learning-recommendation-system/tree/main

引言

NeuralCF 模型由新加坡国立大学研究人员于 2017 年提出,其核心思想在于将传统协同过滤方法与深度学习技术相结合,从而更为有效地捕捉用户与物品之间的复杂交互关系。该模型利用神经网络自动学习用户和物品的低维表示,并通过这些表示实现对用户评分的精准预测。

1. NeuralCF模型简介

NeuralCF 模型融合了矩阵分解与深度学习两种方法的优势,采用基于神经网络的结构来建模用户与物品间的非线性交互。传统矩阵分解方法通过计算用户与物品隐向量的内积来进行评分预测,而 NeuralCF 则利用多层感知机(MLP)对用户与物品隐向量进行联合建模。具体而言,模型首先为每个用户和物品分配低维嵌入向量,然后将这些向量进行拼接(concatenate),再输入到深层神经网络中以提取潜在交互特征,最后通过输出层得到预测评分。

2. NeuralCF的模型架构

NeuralCF 模型的架构主要包括以下关键组件:

  1. 用户与物品嵌入(Embedding)
    与传统矩阵分解方法类似,NeuralCF 为每个用户与物品分配低维嵌入向量,分别表征用户兴趣和物品特征。
  2. 嵌入向量拼接(Concatenation)
    在模型中,用户与物品的嵌入向量被拼接为一个更高维度的向量,作为神经网络的输入。这种拼接不仅保留了各自的特征信息,同时为网络提供了学习复杂交互模式的可能性。
  3. 多层感知机(MLP)
    拼接后的向量经过多个全连接层(MLP)的处理,每一层均采用激活函数(通常为 ReLU)引入非线性变换,以便捕捉用户与物品之间更高阶的特征交互。
  4. 输出层
    多层感知机的输出经过一个线性层转换后,最终得到评分预测。在实际应用中,该预测值可以代表二分类问题(例如点击与否)或回归问题(例如具体评分)

在这里插入图片描述

2.1 数学模型

1. 用户和物品嵌入(Embedding)

NeuralCF模型首先为每个用户和每个物品分配一个低维度的隐向量。假设有 M M M 个用户和 N N N 个物品,用户 u u u 的隐向量为 p u ∈ R d \mathbf{p_u} \in \mathbb{R}^d puRd,物品 i i i 的隐向量为 q i ∈ R d \mathbf{q_i} \in \mathbb{R}^d qiRd,其中 d d d 是隐向量的维度。

2. 嵌入向量的拼接

传统的矩阵分解方法直接计算用户和物品隐向量的内积来预测评分,而NeuralCF通过将用户和物品的隐向量拼接(concatenate)在一起,构成一个新的向量:

z = concat ( p u , q i ) ∈ R 2 d \mathbf{z} = \text{concat}(\mathbf{p_u}, \mathbf{q_i}) \in \mathbb{R}^{2d} z=concat(pu,qi)R2d

3. 多层感知机(MLP)

将拼接后的向量z输入到包含L层的多层感知机中,每一层的变换公式为:

h l = ReLU ( W l h l − 1 + b l ) , l = 1 , 2 , … , L \mathbf{h_l} = \text{ReLU}(\mathbf{W_l} \mathbf{h_{l-1}} + \mathbf{b_l}), \quad l = 1, 2, \dots, L hl=ReLU(Wlhl1+bl),l=1,2,,L

其中,初始输入为 h 0 = z \mathbf{h_0} = \mathbf{z} h0=z W l \mathbf{W_l} Wl 和偏置 b l \mathbf{b_l} bl分别为第 l层的权重和偏置参数

4. 输出层

经过多层感知机后,最终输出层采用线性变换:

r u i ^ = σ ( W L h L + b L ) \hat{r_{ui}} = \sigma(\mathbf{W_L} \mathbf{h_L} + \mathbf{b_L}) rui^=σ(WLhL+bL)

其中, σ \sigma σ​ 表示sigmoid激活函数,输出值位于 0 与 1 之间,适用于二分类任务;对于回归任务,则可去除 Sigmoid 激活。

5. 损失函数

针对不同任务,NeuralCF 可采用不同的损失函数:

  • 回归问题:通常使用均方误差(MSE):

L = 1 N ∑ ( u , i ) ( r u i − r u i ^ ) 2 \mathcal{L} = \frac{1}{N} \sum_{(u,i)} \left( r_{ui} - \hat{r_{ui}} \right)^2 L=N1(u,i)(ruirui^)2

  • 二分类问题, 损失函数为交叉熵:

L = − 1 N ∑ ( u , i ) ( r u i log ⁡ ( r u i ^ ) + ( 1 − r u i ) log ⁡ ( 1 − r u i ^ ) ) \mathcal{L} = -\frac{1}{N} \sum_{(u,i)} \left( r_{ui} \log(\hat{r_{ui}}) + (1 - r_{ui}) \log(1 - \hat{r_{ui}}) \right) L=N1(u,i)(ruilog(rui^)+(1rui)log(1rui^))

3 NeuralCF混合模型

为进一步提升特征组合能力和非线性表达能力,NeuralCF 在原有架构基础上引入了广义矩阵分解(Generalized Matrix Factorization, GMF)模块。需要指出的是,GMF 与 MLP 部分分别采用独立的嵌入层,这一设计有效提升了模型的灵活性和表现力。

在这里插入图片描述

3.2 GMF广义矩阵分解

广义矩阵分解模型扩展了传统矩阵分解方法,通过引入不同的用户与物品交互方式来建模。与经典矩阵分解方法通过内积计算用户与物品之间的相似性不同,GMF 采用元素积(Hadamard 乘积)来刻画二者间的交互关系:

ϕ 1 ( p u , q i ) = p u ⊙ q i \phi_1(p_u, q_i) = p_u \odot q_i ϕ1(pu,qi)=puqi

其中, p u p_u pu q i q_i qi 是用户和物品的嵌入向量, ⊙ \odot 是元素积操作。

3.4 GMF和MLP的融合

为了解决共享嵌入层的限制,本方法提出了让GMF和MLP分别学习独立的嵌入层,并通过连接它们的最后一层隐藏层进行融合。具体而言,GMF和MLP的输出通过以下公式进行联合建模:

  1. GMF 部分

ϕ G M F = p u G ⊙ q i G , \phi_{GMF} = p_u^G \odot q_i^G, ϕGMF=puGqiG,

其中, p u G p_u^G puG q i G q_i^G qiG 分别表示GMF部分的用户和物品嵌入向量。

  1. MLP 部分

通过多层非线性变换,MLP 部分的用户与物品嵌入向量先进行拼接,再逐层传递,形式上可描述为:

ϕ M L P = a L ( W L T ( a L − 1 ( . . . a 2 ( W 2 T [ p u M q i M ] + b 2 ) . . . ) ) + b L ) , \phi_{MLP} = a_L(W_L^T (a_{L-1}(...a_2(W_2^T [p_u^M \quad q_i^M] + b_2)...)) + b_L), ϕMLP=aL(WLT(aL1(...a2(W2T[puMqiM]+b2)...))+bL),

其中, p u M p_u^M puM q i M q_i^M qiM 分别表示MLP部分的用户和物品嵌入向量; a L ( ⋅ ) a_L(\cdot) aL() 是激活函数, W L W_L WL b L b_L bL 是MLP的权重和偏置参数。

  1. 融合与预测

最后,GMF和MLP的输出通过全连接层进行融合并计算最终预测:

y ^ u i = σ ( h T [ ϕ G M F ϕ M L P ] ) \hat{y}_{ui} = \sigma(h^T [\phi_{GMF} \quad \phi_{MLP}]) y^ui=σ(hT[ϕGMFϕMLP])

其中, σ ( ⋅ ) \sigma(\cdot) σ() 是Sigmoid激活函数, h T h^T hT 是融合层的权重。

该融合策略使得模型可以分别从不同角度捕捉用户与物品的特征,并通过联合表示进一步提升预测准确性与模型灵活性。

4.代码实现

以下代码段展示了基于 PyTorch 的 NeuralCF 模型实现,包括模型配置、数据集构建与模型定义。

模型配置与数据集构建

class Config:num_users = 1000num_items = 2000embed_dim = 16hidden_dims = [64, 32, 16]batch_size = 32lr = 0.001num_epochs = 30# 自定义数据集类
class CFDataset(Dataset):def __init__(self, num_samples=10000):# 生成示例数据(实际使用时替换为真实数据)self.user_ids = np.random.randint(0, Config.num_users, size=num_samples)self.item_ids = np.random.randint(0, Config.num_items, size=num_samples)self.labels = np.random.randint(0, 2, size=num_samples).astype(np.float32)def __len__(self):return len(self.user_ids)def __getitem__(self, idx):return (torch.tensor(self.user_ids[idx], dtype=torch.long),torch.tensor(self.item_ids[idx], dtype=torch.long),torch.tensor(self.labels[idx], dtype=torch.float))

NeuralCF 模型实现

class NeuralCF(nn.Module):def __init__(self, Config):super().__init__()# 定义用户和物品的隐向量self.user_embed_gmf = nn.Embedding(Config.num_users, Config.embed_dim)  # GMF用户隐向量self.item_embed_gmf = nn.Embedding(Config.num_items, Config.embed_dim)  # GMF物品隐向量self.user_embed_mlp = nn.Embedding(Config.num_users, Config.embed_dim)  # MLP用户隐向量self.item_embed_mlp = nn.Embedding(Config.num_items, Config.embed_dim)  # MLP物品隐向量# MLP层input_dim = 2 * Config.embed_dimmlp_layers = []for output_dim in Config.hidden_dims:mlp_layers.append(nn.Linear(input_dim, output_dim))mlp_layers.append(nn.ReLU())input_dim = output_dimself.mlp = nn.Sequential(*mlp_layers)# 输出层total_dim = Config.embed_dim + Config.hidden_dims[-1]  # GMF + MLP层维度self.fc = nn.Sequential(nn.Linear(total_dim, 1),nn.Sigmoid())def forward(self, user_ids, item_ids):# 获取用户和物品的隐向量user_emb_gmf = self.user_embed_gmf(user_ids)item_emb_gmf = self.item_embed_gmf(item_ids)user_emb_mlp = self.user_embed_mlp(user_ids)item_emb_mlp = self.item_embed_mlp(item_ids)# GMF: 逐元素乘积gmf = user_emb_gmf * item_emb_gmf# MLP: 拼接并通过多层感知机concat_emb = torch.cat([user_emb_mlp, item_emb_mlp], dim=1)mlp = self.mlp(concat_emb)# 拼接GMF和MLP的结果neuralcf_emb = torch.cat([mlp, gmf], dim=1)# 输出层output = self.fc(neuralcf_emb).squeeze()return output

5. NeuralCF的优势

NeuralCF 模型通过引入深度神经网络,有效突破了传统矩阵分解方法的线性限制,能够捕捉用户与物品之间的复杂非线性交互。其主要优势包括:

  • 非线性建模能力:利用多层神经网络对用户与物品的隐向量进行非线性组合,充分发掘潜在高阶交互信息。
  • 架构灵活性:模型结构可以根据实际问题需求灵活调整隐藏层层数和神经元数量,适应不同数据规模与复杂度。
  • 优异的泛化性能:深度学习框架使得 NeuralCF 在处理稀疏数据时能够更好地防止过拟合,提升了模型的泛化能力。

Reference

[1]. He, X., Liao, L., Zhang, H., Nie, L., Hu, X., & Chua, T.-S. (2017). Neural Collaborative Filtering. In Proceedings of the 26th International Conference on World Wide Web (WWW ’17), 173–182. ACM.

[2]. 王喆 《深度学习推荐系统》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/69182.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【自动化办公】批量图片PDF自定义指定多个区域识别重命名,批量识别铁路货物运单区域内容改名,基于WPF和飞桨ocr深度学习模型的解决方案

项目背景介绍 铁路货运企业需要对物流单进行长期存档,以便后续查询和审计。不同的物流单可能包含不同的关键信息,通过自定义指定多个区域进行识别重命名,可以使存档的图片文件名具有统一的规范和明确的含义。比如,将包含货物运单…

Qt跨屏窗口的一个Bug及解决方案

如果我们希望一个窗口覆盖用户的整个桌面,此时就要考虑用户有多个屏幕的场景(此窗口要横跨多个屏幕),由于每个屏幕的分辨率和缩放比例可能是不同的,Qt底层在为此窗口设置缩放比例(DevicePixelRatio&#xf…

LeetCode:63. 不同路径 II

跟着carl学算法,本系列博客仅做个人记录,建议大家都去看carl本人的博客,写的真的很好的! 代码随想录 LeetCode:63. 不同路径 II 给定一个 m x n 的整数数组 grid。一个机器人初始位于 左上角(即 grid[0][0]…

自定义数据集 使用paddlepaddle框架实现逻辑回归

导入必要的库 import numpy as np import paddle import paddle.nn as nn 数据准备: seed1 paddle.seed(seed)# 1.散点输入 定义输入数据 data [[-0.5, 7.7], [1.8, 98.5], [0.9, 57.8], [0.4, 39.2], [-1.4, -15.7], [-1.4, -37.3], [-1.8, -49.1], [1.5, 75.6…

如何利用maven更优雅的打包

最近在客户现场部署项目,有两套环境,无法连接互联网,两套环境之间也是完全隔离,于是问题就来了,每次都要远程到公司电脑改完代码,打包,通过网盘(如果没有会员,上传下载慢…

Elasticsearch 指南 [8.17] | Search APIs

Search API 返回与请求中定义的查询匹配的搜索结果。 http GET /my-index-000001/_search Request GET /<target>/_search GET /_search POST /<target>/_search POST /_search Prerequisites 如果启用了 Elasticsearch 安全功能&#xff0c;针对目标数据流…

string类OJ练习题

目录 文章目录 前言 一、反转字符串 二、反转字符串 II 三、反转字符串中的单词 III 四、验证一个字符串是否是回文 五、字符串相加&#xff08;大数加法&#xff09; 六、字符串相乘&#xff08;大数乘法&#xff09; 七、把字符串转化为整数&#xff08;atoi&#xff09; 总结…

(一)DeepSeek大模型安装部署-Ollama安装

大模型deepseek安装部署 (一)、安装ollama curl -fsSL https://ollama.com/install.sh | sh sudo systemctl start ollama sudo systemctl enable ollama sudo systemctl status ollama(二)、安装ollama遇到网络问题&#xff0c;请手动下载 ollama-linux-amd64.tgz curl -L …

[CMake]报错: Qt requires a C++17 compiler

1.报错&#xff1a; #error 指令: "Qt requires a C17 compiler, and a suitable value for __cplusplus. On MSVC, you must pass the /Zc:__cplusplus option to the compiler." 2.解决 Qt5项目升级到Qt6项目&#xff0c;cmake需要做兼并配置&#xff1b; # 设置…

面对全球化的泼天流量,出海企业如何观测多地域网络质量?

作者&#xff1a;俞嵩、白玙 泼天富贵背后&#xff0c;技术挑战接踵而至 随着全球化进程&#xff0c;出海、全球化成为很多 Toc 产品的必经之路&#xff0c;保障不同地域、不同网络环境的一致的用户体验成为全球化应用的不得不面对的问题。在跨运营商、跨地域的网络环境中&am…

Django框架的全面指南:从入门到高级

Django框架的全面指南&#xff1a;从入门到高级 目录 引言Django简介安装与配置创建第一个Django项目Django的MVT架构模型&#xff08;Model&#xff09;视图&#xff08;View&#xff09;模板&#xff08;Template&#xff09;URL路由表单处理用户认证与权限Django Admin高级…

VMware下Linux和macOS遇到的一些问题总结

1.解决.NET程序通过网盘传到Linux和macOS不能运行的问题 这是文件权限的问题。当你通过U盘将文件传输到虚拟机的macOS和Linux系统时&#xff0c;文件的权限和所有权可能得到了保留或正确设置。但如果你通过网盘上传&#xff0c;文件的权限或所有权可能没有正确设置&#xff0c…

Java程序员 面试如何介绍项目经验?

项目经历是面试过程中重点问的&#xff0c;但是很多人在回答的时候往往会有问题&#xff1a; 重点是介绍项目&#xff0c;而忽略了个人的经历。 经历是你做了什么、你怎么做的、做完后的结果。例如&#xff1a;项目中的哪些部分是你做的&#xff1f;你是不是核心人员&#xf…

浏览器是否能自动将过多并发请求分段处理?

看了管理浏览器是否能自动处理过多并发请求的文章&#xff0c;看到大家争论不休我在这里想发表一下自己的看法 首先我们应该明确我们为什么要去处理并发请求&#xff0c;怕服务器崩溃&#xff1f;在实际使用场景下如果用户通过不停的点击发送请求就能让服务器崩溃&#xff0c;…

【springboot】拦截器和过滤器的区别

【springboot】拦截器和过滤器的区别 【一】区别【二】适用场景【1】过滤器【2】拦截器 【三】使用案例【1】过滤器使用案例【2】拦截器使用案例 在 Spring Boot 中&#xff0c;拦截器&#xff08;Interceptor&#xff09;和过滤器&#xff08;Filter&#xff09;都是用于对请求…

蓝桥杯备考:模拟算法之字符串展开

P1098 [NOIP 2007 提高组] 字符串的展开 - 洛谷 | 计算机科学教育新生态 #include <iostream> #include <cctype> #include <algorithm> using namespace std; int p1,p2,p3; string s,ret; void add(char left,char right) {string tmp;for(char ch left1;…

FPGA学习篇——Verilog学习1

1 数电基础知识&#xff08;后续可能还会继续补充&#xff09; 1.1 逻辑电平 这张图比较重要以及陌生的应该是高阻态Z&#xff0c;他是一个未知值&#xff0c;不一定为高也不一定为低电平&#xff0c;X是只能高电平和低电平中二选一。 1.2 进制 进制有常见的二进制&#xff0…

虚幻基础17:动画蓝图

能帮到你的话&#xff0c;就给个赞吧 &#x1f618; 文章目录 animation blueprint图表&#xff08;Graph&#xff09;&#xff1a; 编辑动画逻辑。变量&#xff08;Variables&#xff09;&#xff1a; 管理动画参数。函数&#xff08;Functions&#xff09;&#xff1a; 自定义…

java中的锁面试题

1、多线程中 synchronized 锁升级的原理是什么&#xff1f; synchronized 是JVM层面的锁&#xff0c;是 Java 关键字&#xff0c;通过 monitor 对象来完成&#xff0c;synchronized 的实现涉及到锁的升级&#xff0c;具体为无锁、偏向锁、自旋锁、重量级锁 synchronized 锁升级…

C++的 I/O 流

本文把复杂的基类和派生类的作用和关系捋出来&#xff0c;具体的接口请参考相关文档 C的 I/O 流相关的类&#xff0c;继承关系如下图所示 https://zh.cppreference.com/w/cpp/io I / O 的概念&#xff1a;内存和外设进行数据交互称为 I / O &#xff0c;例如&#xff1a;把数…