当前位置: 首页 > 科技观察

推荐系统的经典模型Wide&Deep

时间:2023-03-20 19:59:53 科技观察

今天我们来分析推荐领域的一篇经典论文,叫做Wide&DeepLearningforRecommenderSystems。2016年出版,作者为谷歌应用商店推荐团队。今年恰好是深度学习兴起的时候。本文讨论了如何使用深度学习模型来预测推荐系统的CTR,可以说是深度学习在推荐系统领域的一次成功尝试。著名的推荐模型Wide&deep就出自这篇论文。该模型由于实现简单,效果好,在各大公司得到广泛应用。因此也算是推荐领域的必读文章之一。长文预警,建议先阅读。摘要在大规模特征的场景中,我们通常(2016年之前)采用将非线性特征应用于线性模型的做法。这样,我们的输入将是一个非常稀疏的向量。虽然我们想要实现这样的非线性特征,可以通过一些特征转换和特征交叉的方法来实现,但这会消耗大量的人力物力。其实我们之前在介绍FM模型的时候就提到过这个问题。对于FM模型,其实也解决了同样的问题。只是解决方法不同而已。FM模型的方法是引入一个n×k的参数矩阵V来计算所有特征成对交叉的权重,从而减少参数数量,提高预测和训练效率。在本文中,讨论的是使用神经网络来解决这个问题。解决问题的核心在于embedding。Embedding直译为嵌入,但并不好理解。一般来说,我们可以将其理解为某种特征的向量表示。例如,在Word2Vec中,我们所做的是用一个向量来表示一个词。这些向量称为词嵌入。embedding的一个特点是长度是固定的,但是值一般是通过神经网络学习的。我们可以使用相同的训练嵌入方法来训练神经网络中的一些特征嵌入,这样我们需要的特征工程的工作量就大大减少了。但是仅仅使用嵌入是不够的。在某些场景下,可能会造成过拟合,所以我们需要将线性特征和稀疏特征结合起来,让模型既不会陷入过拟合,又不会有足够的能力。可以学习到更好的结果。简介正如我们在之前的文章中分享的那样,推荐系统也可以看作是搜索的排名系统。它的输入是一个用户信息和用户浏览的上下文信息,返回的结果是一个排序好的序列。正因如此,对于推荐系统来说,也会面临与搜索排名系统类似的挑战——记忆与泛化的权衡。可记忆性可以简单理解为成对出现的产品或特征的一种学习。由于用户的历史行为特征是很强的特征,记忆可以带来较好的效果。但与此同时,也会出现问题。最典型的问题是模型的泛化能力不够。对于泛化能力,其主要来源是特征之间的相关性和传递性。有可能特征A和B与标签直接相关,或者特征A与特征B相关,特征B与标签相关。这称为传递性。利用特征之间的传递性,我们可以探索一些历史数据中很少出现的特征组合,从而获得很强的泛化能力。在大规模在线推荐和排名系统中,LR等线性模型被广泛使用,因为这些模型非常简单、可扩展、高性能和可解释。这些模型通常使用二进制数据进行训练,例如one-hot。比如用户安装过netflix,特征user_installed_app=netflix为1,否则为0。因此,一些二阶特征的可解释性很强。比如用户也浏览过Pandora,那么联合特征user_installed_app=netflix,impression_app=pandora为1,联合特征的权重其实就是两者的相关性。然而,此类特征需要大量的人工操作,并且由于样本的稀疏性,模型无法学习到一些未出现在训练数据中的组合的权重。但是这个问题可以通过embedding-based的模型来解决,比如之前介绍的FM模型,或者深度神经网络。它可以使用嵌入向量通过在低维中训练嵌入来计算交叉特征的权重。但是,如果特征非常稀疏,我们就很难保证生成嵌入的效果。比如用户的喜好比较明显,或者产品比较小众。在这种情况下,大多数查询项对将没有任何行为。但是embedding计算出的权重可能会大于0,从而导致过拟合,导致推荐结果不准确。对于这种特殊情况,线性模型的拟合和泛化能力更好。在本文中,我们将介绍Wide&Deep模型,它将记忆和泛化结合在一个模型中。它可以同时训练线性模型和神经网络,从而取得更好的效果。论文主要内容如下:Wide&Deep模型,包括前馈神经网络embedding部分和线性模型特征转换,在广义推荐系统中的应用,Wide&Deep模型在GooglePlay场景中的实现与评估,GooglePlay是一个10亿以上DAU和100万个App的移动应用商店推荐系统概述这是一个典型的推荐系统架构图:当用户访问应用商店时,会产生一个请求,请求中会包含用户和上下文特征.推荐系统会返回一系列被模型筛选出来的用户可能会点击或购买的应用。当用户看到这些信息时,会产生一些行为,比如浏览(无行为)、点击、购买等。产生行为后,这些数据会记录在Logs中,成为训练数据。我们看上半部分,也就是从DataBase到Retrieval的部分。由于数据库中的数据量很大,有数百万条。因此,我们想对所有在指定时间内(10毫秒)调用该模型的应用程序进行打分,然后无法对它们进行排序。所以我们需要Retrieval请求,也就是召回。检索系统将召回用户的请求。召回的方式有很多种,可以使用机器学习模型,也可以使用规则。一般来说,先进行基于规则的快速过滤,再进行机器学习模型过滤。经过筛选检索,最终调用Wide&Deep模型进行CTR预估,根据预估的CTR对这些APP进行排序。在本文中,我们也忽略了其他技术细节,只关注Wide&Deep模型的实现。Wide&Deep原理首先我们来看一下业界常用模型的结构图:这张图来源于论文,从左到右分别是Wide模型、Wide&Deep模型、Deep模型。从图中我们也可以看出,所谓的Wide模型其实就是一个线性模型,而Deep模型就是一个深度神经网络模型。下图将对这两部分进行详细介绍。Wide部分Wide部分实际上是一个广义线性模型,如上图左边部分所示。y是我们要预测的结果,x是特征,是一个d维的向量。这里d是特征的数量。同样,w也是一个d维的权重向量,b是偏移量。这些我们在之前的线性回归模型中都有介绍过,大家应该都不陌生。特征由两部分组成,一部分是直接从原始数据中取出的数据,另一部分是我们经过特征变换后得到的特征。最重要的特征变换方法是交叉组合,可以定义如下:这里是一个bool变量,代表第i个特征的第k个变换函数的结果。由于使用了乘积的形式,所以只有所有项都为真,最后的结果才为1,否则为0。例如,“AND(gender=female,language=en)”是一个交叉特征。只有当用户的性别是女性,使用的语言是英语时,这个特征的结果才会是1。这样我们就可以捕捉到特征之间的相互作用,在线性模型中加入非线性特征。Deep部分Deep部分是一个前馈神经网络,也就是上图右边的部分。我们观察这张图,就会发现很多细节。比如它的输入是一个稀疏特征,可以简单理解为一个multihot数组。这个输入会在神经网络的第一层转化为一个低维的embedding,然后神经网络在这个embedding上进行训练。该模块主要是为了处理一些类别特征,比如物品类别、用户性别等。与传统的one-hot方法相比,embedding方法用一个向量来表示一个离散变量,表达能力更强,而且这个向量的值是模型自己学习到的,因此泛化能力也有所提高。巨大的改进。这也是深度神经网络中的常见做法。Wide&DeepMergerWide和Deep部分可用后,进行加权合并。这是上图的中间部分。之前顶层的输出其实是一个sigmoid层或者线性层,就是一个简单的线性累加。英文叫做joint。该论文还列出了joint和ensemble之间的区别。对于集成模型,它的每个部分都是独立训练的。联合模型的不同部分是联合训练的。集成模型中各部分的参数是相互独立的,而对于联合模型,其中的参数是同时训练的。这样做的结果是,由于每个部分都是分开训练的,所以每个子模型的参数空间都非常大,这样才能得到更好的结果。联合训练方法不存在这个问题。我们把线性部分和深度学习部分分开,可以弥补它们之间的缺陷,从而达到更好的效果,而且不需要人为地扩大训练参数的数量。系统实现应用推荐的数据流包括三个部分:数据生产、模型训练和模型服务。用一张图来表示大概是这样的:在数据生产阶段,我们用app暴露给用户一段时间作为样本。如果应用被用户点击安装,则样本标记为1,否则标记为0。这也是大多数推荐场景的做法。这个阶段系统会查表,将一些string类型的特征转换成int类型的id。比如娱乐对应1,摄影对应2,比如收费对应0,免费对应1,等等。同时将数字类型的特征标准化,缩放到[0,1]范围内。模型训练论文提供了模型的结构图:从上图我们可以看到,左边是一些连续的特征,比如年龄,安装的app数量等,右边是一些离散的特征,比如设备Information,安装的apps等。这些离散的特征会转化为embedding,然后和右边的连续特征一起进入神经网络进行学习。论文使用了32维的embedding。该模型每次将使用超过5000亿个样本进行训练,每次收集新的训练数据时都会对模型进行训练。但是如果我们每次训练都从头开始,显然会很慢,会浪费很多计算资源。因此论文中选择了一种增量更新的方式,即在更新模型时,会加载旧模型的参数,然后使用最新的数据进行更新训练。新模型更新上线前,会先验证模型的效果,确认效果没有问题后进行更新。模型服务模型训练加载完成后,对于每一次请求,服务端都会从召回系统中获取一系列候选应用和用户特征。然后调用模型对每个应用进行评分。得到分数后,服务器会根据分数从高到低对候选应用进行排序。为了保证服务器的响应性,在10ms以内返回结果,论文采用了多线程并发执行的方式。说实话,我觉得这个数据有点假。因为现在的模型没有使用并发执行,但是即使是并发执行,也很难保证使用深度学习来预测效率能达到这个水平。也许已经采用了一些其他的优化,但它们并没有完全写在论文中。模型结果为了验证Wide&Deep模型的效果,论文在真实场景中从两个角度进行了大量测试。包括应用获取和服务性能。在线上环境对app的获取量进行了为期3周的A/B测试,以1桶作为控制桶,使用上一版的线性模型。一个桶使用Wide&Deep模型,另一个桶只使用Deep模型,去除了线性部分。这三个桶各占流量的1%,最终结果如下:Wide&Deep模型不仅AUC更高,APP在线获取量也提升了3.9%。服务性能对于推荐系统来说,服务器的性能一直是个大问题,因为它需要承载大量的流量,同时还需要保证延迟很短。使用机器学习或深度学习模型来预测点击率的复杂度非常高。论文称,在高峰期,他们的服务器会承载1000万的qps。如果用单线程处理一批数据,需要31毫秒。为了提高速度,他们开发了多线程评分机制,将一个batch拆分成若干部分进行并发计算。通过这种方式,客户端的延迟减少到14毫秒。代码实现全是空谈,不做假动作。Wide&Deep曾在推荐领域表现出色,模型实现并不复杂。曾经用Pytorch实现过一个简单的版本,贴出来供大家参考。importtorchfromtorchimportnnclassWideAndDeep(nn.Module):def__init__(self,dense_dim=13,site_category_dim=24,app_category_dim=32):super(WideAndDeep,self).__init__()#线性部分self.logistic=nn.Linear(19,1,bias)=True)#embedding部分self.site_emb=nn.Embedding(site_category_dim,6)self.app_emb=nn.Embedding(app_category_dim,6)#fusion部分self.fusion_layer=nn.Linear(12,6)defforward(self,x):site=self.site_emb(x[:,-2].long())app=self.app_emb(x[:,-1].long())emb=self.fusion_layer(torch.cat((站点,app),dim=1))returntorch.sigmoid(self.logistic(torch.cat((emb,x[:,:-2]),dim=1)))由于我当时的应用场景比较简单,所以网络结构只有三层,但是原理是一样的。如果要应用于复杂场景,只需要增加特征和网络层即可。本文转载自微信公众号「TechFlow」,可通过以下二维码关注。转载请联系TechFlow公众号。