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 = 1000
    num_items = 2000
    embed_dim = 16
    hidden_dims = [64, 32, 16]
    batch_size = 32
    lr = 0.001
    num_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_dim
        mlp_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_dim

        self.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]. 王喆 《深度学习推荐系统》

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【ChatGPT:开启人工智能新纪元】

一、ChatGPT 是什么 最近,ChatGPT 可是火得一塌糊涂,不管是在科技圈、媒体界,还是咱们普通人的日常聊天里,都能听到它的大名。好多人都在讨论,这 ChatGPT 到底是个啥 “神器”,能让大家这么着迷?今天咱就好好唠唠。 ChatGPT,全称是 Chat Generative Pre-trained Trans…

c++ 定点 new 及其汇编解释

&#xff08;1&#xff09; 代码距离&#xff1a; #include <new> // 需要包含这个头文件 #include <iostream>int main() {char buffer[sizeof(int)]; // 分配一个足够大的字符数组作为内存池int* p new(&buffer) int(42); // 使用 placement new…

Linux系统之whereis命令的基本使用

Linux系统之whereis命令的基本使用 一、whereis命令介绍二、whereis命令的使用帮助2.1 whereis命令的帮助信息2.2 whereis命令帮助解释 三、whereis命令的基本使用3.1 查找命令的位置3.2 仅查找二进制文件3.3 仅查找手册页3.4 输出实际使用的查找路径3.5 指定自定义搜索路径 四…

CH340G上传程序到ESP8266-01(S)模块

文章目录 概要ESP8266模块外形尺寸模块原理图模块引脚功能 CH340G模块外形及其引脚模块引脚功能USB TO TTL引脚 程序上传接线Arduino IDE 安装ESP8266开发板Arduino IDE 开发板上传失败上传成功 正常工作 概要 使用USB TO TTL&#xff08;CH340G&#xff09;将Arduino将程序上传…

整形的存储形式和浮点型在计算机中的存储形式

在计算机科学的底层世界里&#xff0c;数据存储是基石般的存在。不同数据类型&#xff0c;如整形与浮点型&#xff0c;其存储方式犹如独特的密码&#xff0c;隐藏着计算机高效运行的秘密。理解它们&#xff0c;是深入掌握编程与计算机原理的关键。 一、整形的存储形式 原码、反…

无人机PX4飞控 | PX4源码添加自定义uORB消息并保存到日志

PX4源码添加自定义uORB消息并保存到日志 0 前言 PX4的内部通信机制主要依赖于uORB&#xff08;Micro Object Request Broker&#xff09;&#xff0c;这是一种跨进程的通信机制&#xff0c;一种轻量级的中间件&#xff0c;用于在PX4飞控系统的各个模块之间进行高效的数据交换…

QMK启用摇杆和鼠标按键功能

虽然选择了触摸屏&#xff0c;我仍选择为机械键盘嵌入摇杆模块&#xff0c;这本质上是对"操作连续性"的执着。   值得深思的是&#xff0c;本次开发过程中借助DeepSeek的代码生成与逻辑推理&#xff0c;其展现的能力已然颠覆传统编程范式&#xff0c;需求描述可自动…

Rust 所有权特性详解

Rust 所有权特性详解 Rust 的所有权系统是其内存安全的核心机制之一。通过所有权规则&#xff0c;Rust 在编译时避免了常见的内存错误&#xff08;如空指针、数据竞争等&#xff09;。本文将从堆内存与栈内存、所有权规则、变量作用域、String 类型、内存分配、所有权移动、Cl…

基于深度学习的视觉检测小项目(十七) 用户管理后台的编程

完成了用户管理功能的阶段。下一阶段进入AI功能相关。所有的资源见文章链接。 补充完后台代码的用户管理界面代码&#xff1a; import sqlite3from PySide6.QtCore import Slot from PySide6.QtWidgets import QDialog, QMessageBoxfrom . import user_manage # 导入使用ui…

ubuntuCUDA安装

系列文章目录 移动硬盘制作Ubuntu系统盘 前言 根据前篇“移动硬盘制作Ubuntu系统盘”安装系统后&#xff0c;还不能够使用显卡。 如果需要使用显卡&#xff0c;还需要进行相关驱动的安装&#xff08;如使用的为Nvidia显卡&#xff0c;就需要安装相关的Nvidia显卡驱动&#xff…

Docker Compose的使用

文章首发于我的博客&#xff1a;https://blog.liuzijian.com/post/docker-compose.html 目录 Docker Compose是什么Docker Compose安装Docker Compose文件Docker Compose常用命令案例&#xff1a;部署WordPress博客系统 Docker Compose是什么 Docker Compose是Docker官方的开源…

【深度分析】DeepSeek 遭暴力破解,攻击 IP 均来自美国,造成影响有多大?有哪些好的防御措施?

技术铁幕下的暗战&#xff1a;当算力博弈演变为代码战争 一场针对中国AI独角兽的全球首例国家级密码爆破&#xff0c;揭开了数字时代技术博弈的残酷真相。DeepSeek服务器日志中持续跳动的美国IP地址&#xff0c;不仅是网络攻击的地理坐标&#xff0c;更是技术霸权对新兴挑战者的…

使用python实现与本地ollama部署的deepseek对话

专栏总目录 按照ollama官方doc的example操作&#xff0c;没有成功与本地ollama上的deepseek-r1:1.5b通讯后&#xff0c;发现vscode可以调用本地ollama上的deepseek模型。 为了实现与ollama上的deepseek模型通讯&#xff0c;我使用wireshark对本地回环地址进行侦听后&#xff0c…

基于STM32的智能健康监测手环

1. 引言 随着可穿戴设备的普及&#xff0c;健康监测技术正逐步融入日常生活。本文设计了一款基于STM32的智能健康监测手环&#xff0c;能够实时采集用户心率、血氧饱和度、体温及运动数据&#xff0c;并通过低功耗蓝牙&#xff08;BLE&#xff09;与手机APP交互。该系统结合了…

OpenGL学习笔记(六):Transformations 变换(变换矩阵、坐标系统、GLM库应用)

文章目录 向量变换使用GLM变换&#xff08;缩放、旋转、位移&#xff09;将变换矩阵传递给着色器坐标系统与MVP矩阵三维变换绘制3D立方体 & 深度测试&#xff08;Z-buffer&#xff09;练习1——更多立方体 现在我们已经知道了如何创建一个物体、着色、加入纹理。但它们都还…

麦芯(MachCore)应用开发教程5 --- 工位和晶圆传输

麦芯是构建在windows系统上的设备应用操作系统&#xff0c;利用该系统可以快速高效的开发一款设备专用软件。希望进一步了解请email: acloud163.com 黄国强 2025/02/03 一、工位与子设备的关系 想象工厂中的流水线工作站&#xff0c;每个工位&#xff08;Station&#xff09…

冰蝎v3.0 beta7来啦

我用了一台kali&#xff0c;一台centos&#xff0c;一台windows&#xff0c;做了一个文件上传和一个反弹shell实验&#xff0c;载荷是AES加密的&#xff0c;终于感受到了对加密流量的无可奈何~ kali&#xff08;php8.1&#xff09;centos&#xff08;php7.1&#xff09;window…

Golang 并发机制-5:详解syn包同步原语

并发性是现代软件开发的一个基本方面&#xff0c;Go&#xff08;也称为Golang&#xff09;为并发编程提供了一组健壮的工具。Go语言中用于管理并发性的重要包之一是“sync”包。在本文中&#xff0c;我们将概述“sync”包&#xff0c;并深入研究其最重要的同步原语之一&#xf…

【PyQt】超级超级笨的pyqt计算器案例

计算器 1.QT Designer设计外观 1.pushButton2.textEdit3.groupBox4.布局设计 2.加载ui文件 导入模块&#xff1a; sys&#xff1a;用于处理命令行参数。 QApplication&#xff1a;PyQt5 应用程序类。 QWidget&#xff1a;窗口基类。 uic&#xff1a;用于加载 .ui 文件。…

Flutter Scaffold 页面结构

Material是一套设计风格&#xff0c;提供了大量的小部件&#xff0c;这里用Material风格搭建一个常见的应用页面结构。 创建Material应用 import package:flutter/material.dart;class App extends StatelessWidget {overrideWidget build(BuildContext context) {return Mat…