推荐系统遇上深度学习(十一)--神经协同过滤NCF原理及实战

2023-10-31

原创: 文文 小小挖掘机 2018-06-02

笔者是一个痴迷于挖掘数据中的价值的学习人,希望在平日的工作学习中,挖掘数据的价值,找寻数据的秘密,笔者认为,数据的价值不仅仅只体现在企业中,个人也可以体会到数据的魅力,用技术力量探索行为密码,让大数据助跑每一个人,欢迎直筒们关注我的公众号,大家一起讨论数据中的那些有趣的事情。

我的公众号为:livandata

论文地址:https://www.comp.nus.edu.sg/~xiangnan/papers/ncf.pdf

论文的翻译地址为:https://www.cnblogs.com/HolyShine/p/6728999.html

通过分析论文,写出一些简单的心得,如果不正确,请各位指正:

1)一般的协同过滤是指构建用户-项目矩阵,然后使用MF模型,进行模型的分解,将两者交互的信息作为用户或者项目的向量,然后来计算用户或者项目的相似度,相似的用户相互进行推荐;

但是这种方法存在一些问题:

即1.2中的缺陷,单纯的相似度运算,会引发相似度的可信度出问题,因此引入了隐含变量的说法,即将每个用户和项目分设出k维的隐含向量,然后通过隐含向量的内积运算得到用户对某个项目的评论值;

隐含向量的参数是通过神经网络的形式进行确定,由此产生了NCF模型,即为MF模型的扩展(MF模型是NCF模型的特例)。

1、Neural Collaborative Filtering

1.1 背景

本文讨论的主要是隐性反馈协同过滤解决方案,先来明确两个概念:显性反馈和隐性反馈:

显性反馈行为包括用户明确表示对物品喜好的行为
隐性反馈行为指的是那些不能明确反应用户喜好

举例来说:

很多应用场景,并没有显性反馈的存在。因为大部分用户是沉默的用户,并不会明确给系统反馈“我对这个物品的偏好值是多少”。因此,推荐系统可以根据大量的隐性反馈来推断用户的偏好值。

根据已得到的隐性反馈数据,我们将用户-条目交互矩阵Y定义为:

但是,Yui为1仅代表二者有交互记录,并不代表用户u真的喜欢项目i,同理,u和i没有交互记录也不能代表u不喜欢i。这对隐性反馈的学习提出了挑战,因为它提供了关于用户偏好的噪声信号。虽然观察到的条目至少反映了用户对项目的兴趣,但是未查看的条目可能只是丢失数据,并且这其中存在自然稀疏的负反馈。

在隐性反馈上的推荐问题可以表达为估算矩阵 Y中未观察到的条目的分数问题(这个分数被用来评估项目的排名)。形式上它可以被抽象为学习函数:

为了处理缺失数据,有两种常见的做法:要么将所有未观察到的条目视作负反馈,要么从没有观察到条目中抽样作为负反馈实例。

1.2 矩阵分解及其缺陷

传统的求解方法是矩阵分解(MF,Matrix Factorization),为每个user和item找到一个隐向量,问题变为:

这里的 K表示隐式空间(latent space)的维度。正如我们所看到的,MF模型是用户和项目的潜在因素的双向互动,它假设潜在空间的每一维都是相互独立的并且用相同的权重将它们线性结合。因此,MF可视为隐向量(latent factor)的线性模型。

论文中给出了一个例子来说明这种算法的局限性:

1(a)是user-item交互矩阵,1(b)是用户的隐式空间,论文中强调了两点来理解这张图片:
1)MF将user和item分布到同样的隐式空间中,那么两个用户之间的相似性也可以用二者在隐式空间中的向量夹角来确定。
2)使用Jaccard系数来作为真实的用户相似性。
通过MF计算的相似性与Jaccard系数计算的相似性也可以用来评判MF的性能。我们先来看看Jaccard系数

上面的示例显示了MF因为使用一个简单的和固定的内积,来估计在低维潜在空间中用户-项目的复杂交互,从而所可能造成的限制。解决该问题的方法之一是使用大量的潜在因子 K (就是隐式空间向量的维度)。然而这可能对模型的泛化能力产生不利的影响(e.g. 数据的过拟合问题),特别是在稀疏的集合上。论文通过使用DNNs从数据中学习交互函数,突破了这个限制。

1.3 NCF

本文先提出了一种通用框架:

针对这个通用框架,论文提出了三种不同的实现,三种实现可以用一张图来说明:

GMF
上图中仅使用GMF layer,就得到了第一种实现方式GMF,GMF被称为广义矩阵分解,输出层的计算公式为:

MLP
上图中仅使用右侧的MLP Layers,就得到了第二种学习方式,通过多层神经网络来学习user和item的隐向量。这样,输出层的计算公式为:

NeuMF
结合GMF和MLP,得到的就是第三种实现方式,上图是该方式的完整实现,输出层的计算公式为:

1.4 模型实验

论文通过三个角度进行了试验:

RQ1 我们提出的NCF方法是否胜过 state-of-the-art 的隐性协同过滤方法?
RQ2 我们提出的优化框架(消极样本抽样的logloss)怎样为推荐任务服务?
RQ3 更深的隐藏单元是不是有助于对用户项目交互数据的学习?

使用的数据集:MovieLens 和 Pinterest 两个数据集

评估方案:为了评价项目推荐的性能,论文采用了leave-one-out方法评估,即:对于每个用户,我们将其最近的一次交互作为测试集(数据集一般都有时间戳),并利用余下的培训作为训练集。由于在评估过程中为每个用户排列所有项目花费的时间太多,所以遵循一般的策略,随机抽取100个不与用户进行交互的项目,将测试项目排列在这100个项目中。排名列表的性能由命中率(HR)归一化折扣累积增益(NDCG)来衡量。同时,论文将这两个指标的排名列表截断为10。如此一来,HR直观地衡量测试项目是否存在于前10名列表中,而NDCG通过将较高分数指定为顶级排名来计算命中的位置。本文计算每个测试用户的这两个指标,并求取了平均分。

Baselines,论文将NCF方法与下列方法进行了比较:ItemPop,ItemKNN,BPR,eALS。

以下是三个结果的贴图,关于试验结果的解读,由于篇幅的原因,大家可以查看原论文。

RQ1试验结果

简单的结论,即NCF效果好于BaseLine模型,如果不好的话论文也不用写了,哈哈。

RQ2试验结果

Figure 6 表示将模型看作一个二分类任务并使用logloss作为损失函数时的训练效果。
Figure7 表示采样率对模型性能的影响(横轴是采样率,即负样本与正样本的比例)。

RQ3试验结果

上面的表格设置了两个变量,分别是Embedding的长度K和神经网络的层数,使用类似网格搜索的方式展示了在两个数据集上的结果。增加Embedding的长度和神经网络的层数是可以提升训练效果的。

2、NCF实战

本文的github地址为:https://github.com/princewen/tensorflow_practice/tree/master/recommendation/Basic-NCF-Demo

本文仅介绍模型相关细节,数据处理部分就不介绍啦。

项目结构如下:

数据输入
本文使用了一种新的数据处理方式,不过我们的输入就是三个:userid,itemid以及label,对训练集来说,label是0-1值,对测试集来说,是具体的itemid

def get_data(self):
    sample = self.iterator.get_next()
    self.user = sample['user']
    self.item = sample['item']
    self.label = tf.cast(sample['label'],tf.float32)

定义初始化方式、损失函数、优化器

def inference(self):
    """ Initialize important settings """
    self.regularizer = tf.contrib.layers.l2_regularizer(self.regularizer_rate)
 
    if self.initializer == 'Normal':
        self.initializer = tf.truncated_normal_initializer(stddev=0.01)
    elif self.initializer == 'Xavier_Normal':
        self.initializer = tf.contrib.layers.xavier_initializer()
    else:
        self.initializer = tf.glorot_uniform_initializer()
 
    if self.activation_func == 'ReLU':
        self.activation_func = tf.nn.relu
    elif self.activation_func == 'Leaky_ReLU':
        self.activation_func = tf.nn.leaky_relu
    elif self.activation_func == 'ELU':
        self.activation_func = tf.nn.elu
 
    if self.loss_func == 'cross_entropy':
        # self.loss_func = lambda labels, logits: -tf.reduce_sum(
        #       (labels * tf.log(logits) + (
        #       tf.ones_like(labels, dtype=tf.float32) - labels) *
        #       tf.log(tf.ones_like(logits, dtype=tf.float32) - logits)), 1)
        self.loss_func = tf.nn.sigmoid_cross_entropy_with_logits
 
    if self.optim == 'SGD':
        self.optim = tf.train.GradientDescentOptimizer(self.lr,
                                                       name='SGD')
    elif self.optim == 'RMSProp':
        self.optim = tf.train.RMSPropOptimizer(self.lr, decay=0.9,
                                               momentum=0.0, name='RMSProp')
    elif self.optim == 'Adam':
        self.optim = tf.train.AdamOptimizer(self.lr, name='Adam')

得到embedding值
分别得到GMF和MLP的embedding向量,当然也可以使用embedding_lookup方法:

with tf.name_scope('input'):
    self.user_onehot = tf.one_hot(self.user,self.user_size,name='user_onehot')
    self.item_onehot = tf.one_hot(self.item,self.item_size,name='item_onehot')
 
with tf.name_scope('embed'):
    self.user_embed_GMF = tf.layers.dense(inputs = self.user_onehot,
                                          units = self.embed_size,
                                          activation = self.activation_func,
                                          kernel_initializer=self.initializer,
                                          kernel_regularizer=self.regularizer,
                                          name='user_embed_GMF')
 
    self.item_embed_GMF = tf.layers.dense(inputs=self.item_onehot,
                                          units=self.embed_size,
                                          activation=self.activation_func,
                                          kernel_initializer=self.initializer,
                                          kernel_regularizer=self.regularizer,
                                          name='item_embed_GMF')
 
    self.user_embed_MLP = tf.layers.dense(inputs=self.user_onehot,
                                          units=self.embed_size,
                                          activation=self.activation_func,
                                          kernel_initializer=self.initializer,
                                          kernel_regularizer=self.regularizer,
                                          name='user_embed_MLP')
    self.item_embed_MLP = tf.layers.dense(inputs=self.item_onehot,
                                          units=self.embed_size,
                                          activation=self.activation_func,
                                          kernel_initializer=self.initializer,
                                          kernel_regularizer=self.regularizer,
                                          name='item_embed_MLP')

GMF
GMF部分就是求两个embedding的内积:

with tf.name_scope("GMF"):
    self.GMF = tf.multiply(self.user_embed_GMF,self.item_embed_GMF,name='GMF')

MLP

with tf.name_scope("MLP"):
    self.interaction = tf.concat([self.user_embed_MLP, self.item_embed_MLP],
                                 axis=-1, name='interaction')
 
    self.layer1_MLP = tf.layers.dense(inputs=self.interaction,
                                      units=self.embed_size * 2,
                                      activation=self.activation_func,
                                      kernel_initializer=self.initializer,
                                      kernel_regularizer=self.regularizer,
                                      name='layer1_MLP')
    self.layer1_MLP = tf.layers.dropout(self.layer1_MLP, rate=self.dropout)
 
    self.layer2_MLP = tf.layers.dense(inputs=self.layer1_MLP,
                                      units=self.embed_size,
                                      activation=self.activation_func,
                                      kernel_initializer=self.initializer,
                                      kernel_regularizer=self.regularizer,
                                      name='layer2_MLP')
    self.layer2_MLP = tf.layers.dropout(self.layer2_MLP, rate=self.dropout)
 
    self.layer3_MLP = tf.layers.dense(inputs=self.layer2_MLP,
                                      units=self.embed_size // 2,
                                      activation=self.activation_func,
                                      kernel_initializer=self.initializer,
                                      kernel_regularizer=self.regularizer,
                                      name='layer3_MLP')
    self.layer3_MLP = tf.layers.dropout(self.layer3_MLP, rate=self.dropout)

得到预测值

with tf.name_scope('concatenation'):
    self.concatenation = tf.concat([self.GMF,self.layer3_MLP],axis=-1,name='concatenation')
 
 
    self.logits = tf.layers.dense(inputs= self.concatenation,
                                  units = 1,
                                  activation=None,
                                  kernel_initializer=self.initializer,
                                  kernel_regularizer=self.regularizer,
                                  name='predict')
 
    self.logits_dense = tf.reshape(self.logits,[-1])

测试集构建
这里只介绍几行关键的测试集构建代码,整个流程希望大家可以看一下完整的代码。
需要明确的一点是,对于测试集,我们的评价不只是对错,还要关注排名,所以测试集的label不是0-1,而是具体的itemid
首先,对每个user取最后一行作为测试集的正样本:

split_train_test = []
 
for i in range(len(user_set)):
    for _ in range(user_length[i] - 1):
        split_train_test.append('train')
    split_train_test.append('test')
 
full_data['split'] = split_train_test
 
train_data = full_data[full_data['split'] == 'train'].reset_index(drop=True)
test_data = full_data[full_data['split'] == 'test'].reset_index(drop=True)

添加一些负采样的样本, 这里顺序是,1正样本-n负样本-1正样本-n负样本....,每个用户有n+1条数据,便于计算HR和NDCG:

feature_user.append(user)
feature_item.append(item)
labels_add.append(label)
 
for k in neg_samples:
    feature_user.append(user)
    feature_item.append(k)
    labels_add.append(k)

不打乱测试集的顺序,设置batch的大小为1+n:

dataset = tf.data.Dataset.from_tensor_slices(data)
dataset = dataset.batch(test_neg + 1)

计算HR和NDCG

def hr(gt_item, pred_items):
    if gt_item in pred_items:
        return 1
    return 0
 
 
def ndcg(gt_item, pred_items):
    if gt_item in pred_items:
        index = np.where(pred_items == gt_item)[0][0]
        return np.reciprocal(np.log2(index + 2))
    return 0

更详细的代码可以参考github,最好能够手敲一遍来理解其原理哟!

参考文章

https://www.comp.nus.edu.sg/~xiangnan/papers/ncf.pdf
https://www.cnblogs.com/HolyShine/p/6728999.html

MF:https://blog.csdn.net/shulixu/article/details/75349138

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

推荐系统遇上深度学习(十一)--神经协同过滤NCF原理及实战 的相关文章

  • 搜狐新闻算法原理

    转载 搜狐新闻推荐算法原理 导读 在当前这个移动互联网时代 各种信息内容爆炸 面对海量数据 用户希望在有限的时间和空间内 找到自己感兴趣的内容 这就是推荐需要解决的问题 接下来主要讲解新闻推荐的算法原理 01 新闻推荐算法架构 新闻算法的核
  • [推荐系统] 1. 深度学习与推荐系统

    文章目录 1 推荐系统 1 1 推荐系统的作用和意义 1 2 推荐系统架构 1 2 1 推荐系统的逻辑架构 1 2 2 推荐系统的技术架构 2 前置知识 2 1 传统推荐模型的演化 2 2 协同过滤 2 2 1 概述 2 2 2 用户相似度
  • Twitter开源时间线推荐架构整理(Twitter‘s Recommendation Algorithm)

    马斯克最近开源了部分 Twitter的代码 主要有两个仓库 main repo https github com twitter the algorithm ml repo https github com twitter the algo
  • 一文看懂推荐系统:概要01:推荐系统的基本概念

    一文看懂推荐系统 概要01 推荐系统的基本概念 提示 最近系统性地学习推荐系统的课程 我们以小红书的场景为例 讲工业界的推荐系统 我只讲工业界实际有用的技术 说实话 工业界的技术远远领先学术界 在公开渠道看到的书 论文跟工业界的实践有很大的
  • 推荐系统系列——推荐算法评价指标

    文章目录 同步读书之 菜根谭 9 静坐观心 真妄毕现 10 得意早回头 拂心莫停手 推荐算法评价指标 1 评分预测指标 1 1 符号定义 1 2 平均绝对误差 1 3 均方根误差 1 4 覆盖率 2 集合推荐指标 2 1 混淆矩阵 2 2
  • 推荐-社交推荐相关

    总结 近时间矩阵分解 社交信息的融合模型 2018 模型性能 不同社交推荐方法在不同数据集中不同用户社交强度下的性能对比 研究难点与热点 数据稀疏性 社交关系的有效挖掘 社交噪声 可解释性社交推荐 可扩展型社交推荐模型与多源信息的融合 社交
  • 【推荐算法】MMoE模型:Modeling Task Relationships in Multi-task Learning with Multi-gate Mixture-of-Experts

    1 MMoE背景 MMoE是谷歌在2018年发表在KDD上的一篇基于多任务学习的经典论文 其使用场景是对不相关任务的多任务学习 在推荐系统中 这些不相关的任务可以示例为 视频流推荐中的CTR 时长 点赞 分享 收藏 评论等相关性不强的多个任
  • 推荐系统的挑战

    推荐系统的挑战 推荐系统简介 随着互联网2 0的发展 用户不再是数据的消费者 满足于关键词的搜索和在线浏览 而成为了数据的生产者 数据逐渐由专业机构的生产转向由用户的生产 数据量也日益剧增 信息过载油然而生 具体的表现是一是信息过滤即如何从
  • 因果推断(四)——后门调整、前门调整、逆概率加权

    在因果推断 三 中 我们介绍了干预的相关概念 在本文中 我们对一些方法进行介绍 这些方法可用于利用干预分析变量之间的因果关系 在因果推断 三 中 我们得出了调整公式 如上式 假设PA为A节点的所有父节点的集合 则上 式可以修改为 其中b为P
  • 推荐系统学习总结

    前段时间参加了泰迪杯数据挖掘挑战赛 选的是B题电视产品营销推荐 由于涉及到推荐系统这一块比较大的知识领域 之前没有学过 于是在比赛之初找了一些网上的资料自学了几天 有了一些初步的了解与认识 因实训的项目中推荐系统仍是很重要的一部分 故重新再
  • mac改成类似微软键盘偏好设置

    以前我做过笔记 但是好像印象还不是很深刻 因为我自己还是忘记了 我又写了一篇 首先是蛋疼的切换输入法问题 中文输入法和英文输入法的问题真不习惯 切换输入法改正方法 进入系统偏好设置 键盘 快捷键 输入法 选择上一个输入法 勾选 发现右边 空
  • 推荐系统实践(一)----基于用户的协同过滤算法(UserCF)

    随着信息技术和互联网的发展 人们逐渐从信息匮乏的时代走入了信息过载的时代 在这个时代 无论是信息消费者还是信息生产者都遇到了很大的挑战 如何从大量信息中找到自己感兴趣的信息是一件非常困难的事情 这个时候就需要推荐系统 推荐系统不需要用户提供
  • 推荐系统 用户画像 标签聚类 个性化搜索

    最近在做短视频推荐 和别的部门配合着做 我们部门做用户画像这一部分 回头看看 我们部门以前做的用户画像只能称之为 所谓的用户画像 如果一个人不懂用户画像还好指挥来指挥去真的让人无言 不知道其他公司的有没有这样的人儿那 哈哈 扯远了 言归正传
  • ICML 2012 推荐系统部分文章小结及下载

    ICML2012 paper下载地址 感谢丹柯提供 http icml cc 2012 papers 个人比较感兴趣的 跟推荐系统相关的几篇文章 1 在有query的场景下 向用户推荐item Latent Collaborative Re
  • “基于机器学习算法的推荐系统” 在软件静态分析领域的应用方法

    一 软件静态分析背景 软件静态分析的相当部分的内容就是发现代码中的缺陷 缺陷的形式往往五花八门 各式各样 每当发现一个缺陷 测试人员首先会感到高兴 终于抓到了一条 虫 可继而很可能会感到心虚 因为 在现有技术条件下 一条软件行业的规律是仍然
  • 学习PGL课程:图卷积网络GCN、图注意力网络GAT

    一 GCN 什么是图卷积 不同的地方在于 图像像素点周围的像素个数通常是固定的 而图结构上某个节点周围的节点数是不固定的 图卷积网络计算公式 1 邻接矩阵解释 2 度矩阵 表示节点与之相连节点的个数 包括自环 3 H l 表示第l次迭代的节
  • 推荐系统实战2——EasyRec 推荐框架环境配置

    推荐系统实战2 EasyRec 推荐框架环境配置 学习前言 先验条件 EasyRec仓库地址 EasyRec环境配置 一 EasyRec的下载 二 EasyRec的初始化 三 EasyRec的安装 四 一些额外的情况 学习前言 EasyRe
  • 【技术经验分享】计算机毕业设计hadoop+spark知识图谱医生推荐系统 门诊人数预测 医疗数据可视化 医疗大数据 医疗数据分析 医生爬虫 大数据毕业设计 大数据毕设

    开发技术 springboot vue js element ui spark hadoop lstm情感分析模型 KNN CNN卷积神经 线性回归 协同过滤算法 用户 物品 MLP神经网络 SVD深度学习模型 echarts python
  • Sequential Recommendation with Graph Neural Networks

    Sequential Recommendation with Graph Neural Networks 文章目录 1 背景 2 模型 2 1 Interest Graph Construction 2 1 1 Raw graph cons
  • 直播预告

    点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入 6月9日晚7 30 9 00 AI TIME特别邀请了三位优秀的讲者跟大家共同开启ICLR专场六 哔哩哔哩直播通道 扫码关注AITIME哔哩哔哩官方账号 观看直播 链接 http

随机推荐