DeepFM、DIN-推荐系统小结

2023-10-18 20:20
文章标签 系统 推荐 小结 din deepfm

本文主要是介绍DeepFM、DIN-推荐系统小结,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

【DeepFM、DIN-推荐系统小结】

一.DeepFM

在这里插入图片描述

​ 对于CTR问题,被证明的最有效的提升任务表现的策略是特征组合(Feature Interaction), 在CTR问题的探究历史上来看就是如何更好地学习特征组合,进而更加精确地描述数据的特点。可以说这是基础推荐模型到深度学习推荐模型遵循的一个主要的思想。而组合特征大牛们研究过组合二阶特征,三阶甚至更高阶,但是面临一个问题就是随着阶数的提升,复杂度就成几何倍的升高。这样即使模型的表现更好了,但是推荐系统在实时性的要求也不能满足了。所以很多模型的出现都是为了解决另外一个更加深入的问题:如何更高效的学习特征组合?

  • 简单的线性模型虽然简单,同样这样是它的不足,就是限制了模型的表达能力,随着数据的大且复杂,这种模型并不能充分挖掘数据中的隐含信息,且忽略了特征间的交互,如果想交互,需要复杂的特征工程。
  • FM模型考虑了特征的二阶交叉,但是这种交叉仅停留在了二阶层次,虽然说能够进行高阶,但是计算量和复杂性一下子随着阶数的增加一下子就上来了。所以二阶是最常见的情况,会忽略高阶特征交叉的信息
  • DNN,适合天然的高阶交叉信息的学习,但是低阶的交叉会忽略掉
  • 那么如果把上面这几种结构组合一下子,是不是效果会强大一些呢? 所以W&D模型在这个思路上进行了一个伟大的尝试,把简单的LR模型和DNN模型进行了组合, 使得模型既能够学习高阶组合特征,又能够学习低阶的特征模式,但是W&D的wide部分是用了LR模型, 这一块依然是需要一些经验性的特征工程的,且Wide部分和Deep部分需要两种不同的输入模式, 这个在具体实际应用中需要很强的业务经验。总体:1.wide&deep需要较为精巧的特征工程2.在output Units阶段直接将低阶和高阶特征进行组合,很容易让模型最终偏向学习到低阶或者高阶的特征

在这里插入图片描述

DeepFM是2017年哈工大和华为公司联合提出的一个模型,改动地方已经框出,论文作者提出:通过高阶和低阶交互特征一块来进行反向传播更新参数反而会使得模型表现更佳,当然,这个也依赖于共享Embedding输入的策略

所以与Wide&Deep不同的是,DeepFM中的Wide部分与Deep部分共享了输入特征,即Embedding向量

在这里插入图片描述

一些细节梳理

(1).特征工程改进

​ 一些特征工程比较容易理解,就比如上面提到的那两个, 这时候往往我们都能很容易的设计或者组合那样的特征。 然而,其他大部分特征交互都隐藏在数据中,难以先验识别(比如经典的关联规则 "尿布和啤酒 "就是从数据中挖掘出来的,而不是由专家发现的),只能由机器学习自动捕捉,即使是对于容易理解的交互,专家们似乎也不可能详尽地对它们进行建模,特别是当特征的数量很大的时候.

(2).与’‘前辈们’'的对比

在这里插入图片描述

(3).工业经验

  1. MLP这端神经网络的层数, 工业上的经验值不超过3层,一般用两层即可。

  2. MLP这端隐藏神经元的个数,工业上的经验值,一般128就差不多,最多不超过500

  3. embedding的维度一般不要超过50维, 经验值10-50

    模型复现

    使用Torch-RecHub实现DeepFm

    Torch-RecHub中不仅给出了现成的DeepFm,而且还可以分模块地自己组装DeepFM

    from torch_rechub.basic.layers import FM, MLP, LR, EmbeddingLayerclass MyDeepFM(torch.nn.Module):# Deep和FM为两部分,分别处理不同的特征,因此传入的参数要有两种特征,由此我们得到参数deep_features,fm_features# 此外神经网络类的模型中,基本组成原件为MLP多层感知机,多层感知机的参数也需要传进来,即为mlp_paramsdef __init__(self, deep_features, fm_features, mlp_params):super().__init__()self.deep_features = deep_featuresself.fm_features = fm_featuresself.deep_dims = sum([fea.embed_dim for fea in deep_features])self.fm_dims = sum([fea.embed_dim for fea in fm_features])# LR建模一阶特征交互self.linear = LR(self.fm_dims)# FM建模二阶特征交互self.fm = FM(reduce_sum=True)# 对特征做嵌入表征self.embedding = EmbeddingLayer(deep_features + fm_features)self.mlp = MLP(self.deep_dims, **mlp_params)def forward(self, x):input_deep = self.embedding(x, self.deep_features, squeeze_dim=True)  #[batch_size, deep_dims]input_fm = self.embedding(x, self.fm_features, squeeze_dim=False)  #[batch_size, num_fields, embed_dim]y_linear = self.linear(input_fm.flatten(start_dim=1))y_fm = self.fm(input_fm)y_deep = self.mlp(input_deep)  #[batch_size, 1]# 最终的预测值为一阶特征交互,二阶特征交互,以及深层模型的组合y = y_linear + y_fm + y_deep# 利用sigmoid来将预测得分规整到0,1区间内return torch.sigmoid(y.squeeze(1))
    

    二、DIN-Deep Interest Network

    ​ DIN是2018年阿里巴巴提出来的模型, 该模型基于业务的观察,从实际应用的角度进行改进,相比于之前很多“学术风”的深度模型, 该模型更加具有业务气息。之前的那些深度学习模型,是没法很好的去表达出用户这广泛多样的兴趣的,如果想表达的准确些, 那么就得加大隐向量的维度,让每个特征的信息更加丰富, 那这样带来的问题就是计算量上去了,毕竟真实情景尤其是电商广告推荐的场景,特征维度的规模是非常大的。 并且根据上面的例子, 也并不是用户所有的历史行为特征都会对某个商品广告点击预测起到作用。所以对于当前某个商品广告的点击预测任务,没必要考虑之前所有的用户历史行为。

    ​ DIN的动机就是在业务的角度,我们应该自适应的去捕捉用户的兴趣变化,这样才能较为准确的实施广告推荐;而放到模型的角度, 我们应该考虑到用户的历史行为商品与当前商品广告的一个关联性

    在这里插入图片描述

    ​ 上面的图表示basemodel, 用户的历史行为特征和当前的候选广告特征在全都拼起来给神经网络之前,是一点交互的过程都没有, 而拼起来之后给神经网络,虽然是有了交互了,但是原来的一些信息,比如,每个历史商品的信息会丢失了一部分,因为这个与当前候选广告商品交互的是池化后的历史特征embedding, 这个embedding是综合了所有的历史商品信息, 这个通过我们前面的分析,对于预测当前广告点击率,并不是所有历史商品都有用,综合所有的商品信息反而会增加一些噪声性的信息,可以联想上面举得那个键盘鼠标的例子,如果加上了各种洗面奶,衣服啥的反而会起到反作用。其次就是这样综合起来,已经没法再看出到底用户历史行为中的哪个商品与当前商品比较相关,也就是丢失了历史行为中各个商品对当前预测的重要性程度。最后一点就是如果所有用户浏览过的历史行为商品,最后都通过embedding和pooling转换成了固定长度的embedding,这样会限制模型学习用户的多样化兴趣。

    ​ 那么改进这个问题的思路有哪些呢?

    ​ 第一个就是加大embedding的维度,增加之前各个商品的表达能力,这样即使综合起来,embedding的表达能力也会加强, 能够蕴涵用户的兴趣信息,但是这个在大规模的真实推荐场景计算量超级大,不可取。 另外一个思路就是在当前候选广告和用户的历史行为之间引入注意力的机制,这样在预测当前广告是否点击的时候,让模型更关注于与当前广告相关的那些用户历史产品,也就是说与当前商品更加相关的历史行为更能促进用户的点击行为

    ​ 第二点是DIN通过给定一个候选广告,然后去注意与该广告相关的局部兴趣的表示来模拟此过程。 DIN不会通过使用同一向量来表达所有用户的不同兴趣,而是通过考虑历史行为的相关性来自适应地计算用户兴趣的表示向量(对于给的的广告)。 该表示向量随不同广告而变化。

    在这里插入图片描述

    ​ 对比basemodel,DIN只不过是在这个的基础上加了一个注意力机制来学习用户兴趣与当前候选广告间的关联程度, 用论文里面的话是,引入了一个新的local activation unit, 这个东西用在了用户历史行为特征上面, 能够根据用户历史行为特征和当前广告的相关性给用户历史行为特征embedding进行加权。这个相关性相当于每个历史商品的权重,把这个权重与原来的历史行为embedding相乘求和就得到了用户的兴趣表示 v U ( A )
    这个东西的计算公式如下:
    在这里插入图片描述

    这里的*{ v A , e 1 , e 2 , … , e H }* 是用户U的历史行为特征embedding, vA表示的是候选广告A的embedding向量, a ( e j , v A ) = w j 表示的权重或者历史行为商品与当前广告A 的相关性程度。a ( ⋅ ) 表示的上面那个前馈神经网络,也就是那个所谓的注意力机制, 当然,看图里的话,输入除了历史行为向量和候选广告向量外,还加了一个它俩的积操作(对应位置元素乘),作者说这里是有利于模型相关性建模的显性知识,有的还加上差的,就类似于PNN里面的(concat(A, B, A-B, A*B)。

    这里有一点需要特别注意,就是这里的权重加和不是1, 准确的说这里不是权重, 而是直接算的相关性的那种分数作为了权重,也就是平时的那种scores(softmax之前的那个值),这个是为了保留用户的兴趣强度。

    一些问题:

    • 为什么增加叉乘作为输入呢?因为两个embedding的叉乘是显示地反映了两者之间的相关性,加入后有助于更好学习weight。
    • 为什么选叉乘而非其他形式呢?其实论文的初版使用的是两个embedding的差,发表的最新版才转为使用叉乘,相信也都是经过了一系列的尝试和实验对比。
    • 为什么使用简单的MLP实现AU呢?同样是尝试出来的,作者也尝试过 LSTM 结构实现AU,效果并不理想。文中给出的一个possible解释是,文本是在语法严格约束下的有序序列,而用户历史行为序列可能包含了多个同时存在的用户兴趣点,用户会在这些兴趣点之间“随意切换”,这使得这个序列并不是那么严格的“有序”,产生了一些噪声。

    两个训练技术(之后再补充)

    1. Mini-batch Aware Regularization
    2.Data Adaptive Activation Function

    DIN的数据处理(待办)

    Torch-RecHub实现(待复习)

    # DIN网络搭建
    def DIN(feature_columns, behavior_feature_list, behavior_seq_feature_list):"""这里搭建DIN网络,有了上面的各个模块,这里直接拼起来:param feature_columns: A list. 里面的每个元素是namedtuple(元组的一种扩展类型,同时支持序号和属性名访问组件)类型,表示的是数据的特征封装版:param behavior_feature_list: A list. 用户的候选行为列表:param behavior_seq_feature_list: A list. 用户的历史行为列表"""# 构建Input层并将Input层转成列表作为模型的输入input_layer_dict = build_input_layers(feature_columns)input_layers = list(input_layer_dict.values())# 筛选出特征中的sparse和Dense特征, 后面要单独处理sparse_feature_columns = list(filter(lambda x: isinstance(x, SparseFeat), feature_columns))dense_feature_columns = list(filter(lambda x: isinstance(x, DenseFeat), feature_columns))# 获取Dense Inputdnn_dense_input = []for fc in dense_feature_columns:dnn_dense_input.append(input_layer_dict[fc.name])# 将所有的dense特征拼接dnn_dense_input = concat_input_list(dnn_dense_input)   # (None, dense_fea_nums)# 构建embedding字典embedding_layer_dict = build_embedding_layers(feature_columns, input_layer_dict)# 离散的这些特特征embedding之后,然后拼接,然后直接作为全连接层Dense的输入,所以需要进行Flattendnn_sparse_embed_input = concat_embedding_list(sparse_feature_columns, input_layer_dict, embedding_layer_dict, flatten=True)# 将所有的sparse特征embedding特征拼接dnn_sparse_input = concat_input_list(dnn_sparse_embed_input)   # (None, sparse_fea_nums*embed_dim)# 获取当前行为特征的embedding, 这里有可能有多个行为产生了行为列表,所以需要列表将其放在一起query_embed_list = embedding_lookup(behavior_feature_list, input_layer_dict, embedding_layer_dict)# 获取历史行为的embedding, 这里有可能有多个行为产生了行为列表,所以需要列表将其放在一起keys_embed_list = embedding_lookup(behavior_seq_feature_list, input_layer_dict, embedding_layer_dict)# 使用注意力机制将历史行为的序列池化,得到用户的兴趣dnn_seq_input_list = []for i in range(len(keys_embed_list)):seq_embed = AttentionPoolingLayer()([query_embed_list[i], keys_embed_list[i]])  # (None, embed_dim)dnn_seq_input_list.append(seq_embed)# 将多个行为序列的embedding进行拼接dnn_seq_input = concat_input_list(dnn_seq_input_list)  # (None, hist_len*embed_dim)# 将dense特征,sparse特征, 即通过注意力机制加权的序列特征拼接起来dnn_input = Concatenate(axis=1)([dnn_dense_input, dnn_sparse_input, dnn_seq_input]) # (None, dense_fea_num+sparse_fea_nums*embed_dim+hist_len*embed_dim)# 获取最终的DNN的预测值dnn_logits = get_dnn_logits(dnn_input, activation='prelu')model = Model(inputs=input_layers, outputs=dnn_logits)return model
    
    参考资料[ღ( ´・ᴗ・` )比心]:

    AI上推荐 之 FNN、DeepFM、NFM
    推荐系统精排模型:DIN与DeepFM
    FunRec-datawhale

这篇关于DeepFM、DIN-推荐系统小结的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

Nginx配置系统服务&设置环境变量方式

《Nginx配置系统服务&设置环境变量方式》本文介绍了如何将Nginx配置为系统服务并设置环境变量,以便更方便地对Nginx进行操作,通过配置系统服务,可以使用系统命令来启动、停止或重新加载Nginx... 目录1.Nginx操作问题2.配置系统服android务3.设置环境变量总结1.Nginx操作问题

Spring Cloud Hystrix原理与注意事项小结

《SpringCloudHystrix原理与注意事项小结》本文介绍了Hystrix的基本概念、工作原理以及其在实际开发中的应用方式,通过对Hystrix的深入学习,开发者可以在分布式系统中实现精细... 目录一、Spring Cloud Hystrix概述和设计目标(一)Spring Cloud Hystr

Keepalived+Nginx双机配置小结

《Keepalived+Nginx双机配置小结》本文主要介绍了Keepalived+Nginx双机配置小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录1.1 软硬件要求1.2 部署前服务器配置调优1.3 Nginx+Keepalived部署1.3

nginx upstream六种方式分配小结

《nginxupstream六种方式分配小结》本文主要介绍了nginxupstream六种方式分配小结,包括轮询、加权轮询、IP哈希、公平轮询、URL哈希和备份服务器,具有一定的参考价格,感兴趣的可... 目录1 轮询(默认)2 weight3 ip_hash4 fair(第三方)5 url_hash(第三

Python中conda虚拟环境创建及使用小结

《Python中conda虚拟环境创建及使用小结》本文主要介绍了Python中conda虚拟环境创建及使用小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们... 目录0.前言1.Miniconda安装2.conda本地基本操作3.创建conda虚拟环境4.激活c

Vue项目的甘特图组件之dhtmlx-gantt使用教程和实现效果展示(推荐)

《Vue项目的甘特图组件之dhtmlx-gantt使用教程和实现效果展示(推荐)》文章介绍了如何使用dhtmlx-gantt组件来实现公司的甘特图需求,并提供了一个简单的Vue组件示例,文章还分享了一... 目录一、首先 npm 安装插件二、创建一个vue组件三、业务页面内 引用自定义组件:四、dhtmlx

CSS3 最强二维布局系统之Grid 网格布局

《CSS3最强二维布局系统之Grid网格布局》CS3的Grid网格布局是目前最强的二维布局系统,可以同时对列和行进行处理,将网页划分成一个个网格,可以任意组合不同的网格,做出各种各样的布局,本文介... 深入学习 css3 目前最强大的布局系统 Grid 网格布局Grid 网格布局的基本认识Grid 网

前端 CSS 动态设置样式::class、:style 等技巧(推荐)

《前端CSS动态设置样式::class、:style等技巧(推荐)》:本文主要介绍了Vue.js中动态绑定类名和内联样式的两种方法:对象语法和数组语法,通过对象语法,可以根据条件动态切换类名或样式;通过数组语法,可以同时绑定多个类名或样式,此外,还可以结合计算属性来生成复杂的类名或样式对象,详细内容请阅读本文,希望能对你有所帮助...

MobaXterm远程登录工具功能与应用小结

《MobaXterm远程登录工具功能与应用小结》MobaXterm是一款功能强大的远程终端软件,主要支持SSH登录,拥有多种远程协议,实现跨平台访问,它包括多会话管理、本地命令行执行、图形化界面集成和... 目录1. 远程终端软件概述1.1 远程终端软件的定义与用途1.2 远程终端软件的关键特性2. 支持的

Python爬虫selenium验证之中文识别点选+图片验证码案例(最新推荐)

《Python爬虫selenium验证之中文识别点选+图片验证码案例(最新推荐)》本文介绍了如何使用Python和Selenium结合ddddocr库实现图片验证码的识别和点击功能,感兴趣的朋友一起看... 目录1.获取图片2.目标识别3.背景坐标识别3.1 ddddocr3.2 打码平台4.坐标点击5.图