在大多数情况下,稀疏输入的大规模回归和分类问题都是通过线性模型和非线性特征来解决。 通过特征交叉带来的Memorization(记忆能力) 非常有效和可解释,然后generalization(泛化能力) 需要更多的特征工程的成本。但是,如果用DNN的话,不需要那么多特征工程,就有足够的泛化能力,对稀疏特征进行embedding后得到的低维稠密特征隐含了一些特征组合。不过,DNN容易导致over-generalize(过度泛化),当user-item交互行为矩阵较为稀疏并且是高秩的时候模型容易推荐出少部分一些不相关的item。 在这篇论文中,作者提出wide&deep的模型,对线性模型和DNN进行jointly trained(共同训练),取长补短获得较好的记忆能力和泛化能力,对推荐系统带来收益。该方法已在google play应用和验证过,Google play可是一款超过十亿活跃用户和超过百万app的商业化的手机应用市场。通过在线实验的结果发现,相对于wide-only和deep-only的模型,wide&deep模型能够显著地提升app的转化。另外,该模型的实现已经通过tensorflow进行了开源。
- memorization(记忆性): 即从历史数据中发现item或者特征之间的相关性。
- generalization(泛化性): 即相关性的传递,发现在历史数据中很少或者没有出现的新的特征组合。
- 模型的优点: Wide部分有利于增强模型的“记忆能力”,Deep部分有利于增强模型的“泛化能力”。
推荐系统可以认为是一个搜索排序系统,输入query是用户和上下文信息,输出是排好序的物品列表。推荐任务即找到数据库中最相关的物品,并给予一个目标(点击或者购买)对物品进行排序。
现在推荐系统的一个难点就是同时实现Memorization以及Generalization,这个难点与搜索排名问题相似。 Memorization可以认为是学习频繁共同出现的item或特征,挖掘历史数据中的相关性。 Generalization基于传递性的相关性,挖掘过去很少或者几乎没有出现的新的特征组合。 Memorization的推荐比较topical(局部),一般和用户之前有过交互的item直接相关。基于Generalization的推荐倾向于提高推荐item的多样性。 在本文中,我们专注于 Google Play 商店的应用推荐问题,但该方法应适用于通用推荐系统。
在工业界中大规模推荐系统的排序模块,广义线性模型比如逻辑回归被广泛应用,因为简单、可扩展、可解释。 型通常是通过one-hot编码的二值化特征输入进行训练(如果用户安装了 Netflix,则二进制特征“user_installed_app=netflix”的值为 1)。这种线性模型的记忆能力通常是通过特征交叉来表达, 比如AND(user_installed_app=netflix, impression_app=pandora")表示的是用户安装过netflix这个app并且当前即将展示的app是pandora。 (解释: 这种特征设计的方式,其实是想通过模型学习到user特征和item特征的关联性,就用这例子来说,假如在实际的数据上,很多安装过netflix的用户喜欢点击pandora这个内推荐的app,那么模型就可以根据这个交叉特征AND(user_installed_app=netflix, impression_app=pandora")学习到内在的关联性,如果模型的输入没有这个交叉特征那么模型就没法学习到)。这解释了特征对的共现如何与目标标签相关联。 在线性模型的这个前提下,模型的泛化能力需要更细粒度更为宽泛的特征作为输入,比如上面的交叉特征可以往上泛化衍生出一个新的交叉特征AND(user_installed_category=video,impression_category=music),显然,这需要大量的特征工程,(解释就这个例子来说,需要对netflix和pandora等等app进行分类或者打标签。特征交叉的方式能够使得线性模型具备捕获关联性的能力,但是泛化能力还需要输入的数据有具体的特征),假如query-item的feature-pair在训练数据中没有,模型就没法学习到,(解释: 比如上面的例子,假如模型的特征设计中没有AND(user_installed_category=video,impression_category=music)这种更为高阶的泛化交叉特征,模型就没法学习到“安装过视频app的用户更喜欢点击推荐的音乐app”这么一个关联性的规律。)
理解:Memorization通过一系列人工的特征叉乘(cross-product) 来构造这些非线性特征,捕捉sparse特征之间的高阶相关性,即“记忆” 历史数据中曾共同出现过的特征对。
例如,特征1——专业: {计算机、人文、其他},特征2——下载过音乐《消愁》:{是、否},这两个特征one-hot后的特征维度分别为3维与2维,对应的叉乘结果是特征3——专业☓下载过音乐《消愁》: {计算机∧是,计算机∧否,人文∧是,人文∧否,其他∧是,其他∧否}。
Memorization的缺点是:
- 更多的人工设计;
- 可能出现过拟合。
- 无法捕捉训练数据中未曾出现过的特征对。
对于FM或者DNN这种embedded的模型,一般会对输入的query-item feature pair进行embedding,每个query和每个item都得到一个低维稠密的向量,这种情况下,不需要更多的特征工程就使得模型具备泛化能力。 但是,如果输入的query-item的矩阵是稀疏和高秩的话,比如一些user有一些特殊罕见的特征和一些不热门的item,很难学习出有效的低维稠密向量表达。在这种情况下,大部分的query-item pair应该是不会有交互行为出现的,但是基于dense embedding的向量预测,会对所有的query-item产生很多非0的预测,从而导致过度泛化而推荐出一些不相关的item。另一方面,带交叉特征表达的线性模型可以通过少部分的参数记忆住这种特殊的规则,比如某些query-item pair并没有那么相关。
基于以上考虑,论文提出了一种wide&deep的学习框架,共同训练一个线性模型组件(wide组件)和一个神经网络模型组件(deep组件),在一个模型中学习到memorization(记忆能力)和generalization(泛化能力)。
本文的主要贡献:
Wide & Deep 学习框架,用于联合训练具有嵌入和具有特征转换的线性模型的前馈神经网络,用
于具有稀疏输入的通用推荐系统。
Wide and Deep 推荐系统的实践和评估在 Google Play 上实现,这是一个拥有超过 10 亿活跃用
户和超过 100 万个应用程序的移动应用商店。
我们开源了我们的实现以及 TensorFlow 中的高级 API
虽然这个想法很简单,但我们展示了 Wide & Deep 框架显着提高了移动应用商店的应用获取率,同时满足了训练和服务速度的要求。
当用户访问应用商店时,会生成一个查询,该查询可以包括各种用户和上下文特征。推荐系统返回一个应用程序列表,用户可以在这些应用程序上执行某些操作,例如点击或购买。这些用户操作连同查询和印象一起记录在日志中,作为学习者的训练数据。
由于数据库中有超过一百万个应用程序,因此很难在服务延迟要求(通常为 O(10) 毫秒)内对每个查询的每个应用程序进行详尽的评分。因此,收到查询的第一步是检索。 检索系统使用各种信号返回与查询最匹配的项目的简短列表,通常是机器学习模型和人工定义规则的组合。减少候选池后,排名系统按其分数对所有项目进行排名。 分数通常是 P(y|x),给定特征 x 的用户行为标签 y 的概率,包括用户特征(例如,国家、语言、人口统计)、上下文特征(例如,设备、一天中的小时、一天 周)和印象特征(例如,应用年龄、应用的历史统计数据)。 在本文中,我们专注于使用 Wide & Deep 学习框架的排序模型。
整个过程分为以下几步:
Recommender system = Retrieval system + Ranking system
- Retrieval system:对当前Query构造候选item集。
- Ranking system:对候选item集中的item进行打分,减小候选item集数量。得分score表示成P(y|x), 表示的是一个条件概率。y是label,表示user可以采取的action,比如点击或者购买。x表示输入,特征包括:
- User features(eg.country, language, demographics)
- Contextual features(eg.device, hour of the day, day of the week)
- Impression features(eg.app age, historical statistics of an app)
图1左边Wide部分是一个线性模型, y = w x T + b y=\bold w \bold x^T+b y=wxT+b, 如图所示:
y是预测, x = [ x 1 , x 2 , . . . , x d ] \bold x = [x_1, x_2,...,x_d] x=[x1,x2,...,xd]为d个特征向量, w = [ w 1 , w 2 , . . . , w d ] \bold w = [w_1, w_2,...,w_d] w=[w1,w2,...,wd]是参数, b b b是偏置。特征集包括: raw input 原始特征 + cross-product transformation 组合特征。 组合特征公式:
ϕ k ( x ) = ∏ i = 1 d x i c k i c k i ∈ 0 , 1 ( 1 ) \phi_k(\bold x) = \prod^d_{i=1}x^{c_{ki}}_i c_{ki} \in {0,1} \qquad\qquad (1) ϕk(x)=i=1∏dxickicki∈0,1(1)
其中 ϕ c k i \phi c_{ki} ϕcki是一个布尔变量, 如果第i个特征第k个转换 ϕ k \phi k ϕk 的一部分, 则为 1,否则为 0。( 示这个第i维度特征是否要参与第k个组合特征的构造); category特征进行one-hot编码后进行交叉组合,例如,AND(gender=female, language=en)。 当且仅当组成特征(“gender=female”和“language=en”)都为 1 时为 1,否则为 0。 交叉特征在wide部分很重要,可以捕捉到特征间的交互,起到添加非线性的作用。
Wide部分是一个线性模型:
- raw input 原始特征
- cross-product transformation 组合特征
图1右边部分,一个Feed-forward NN前馈神经网络。如图所示:
对于分类特征,原始输入是特征字符串(例如,“language=en”)。 首先将这些稀疏高维分类特征中的每一个转换成低维且密集的实值向量,通常称为embedding vector。 embedding 的维度通常在 O(10) 到 O(100) 的数量级上。embedding vector 随机初始化,然后作为隐层输入,再通过一个Relu激活层,通过最小化损失函数利用反向传播更新参数。具体来说,每个隐藏层执行以下计算:
a ( l + 1 ) = f ( W ( l ) a ( l ) + b ( l ) ) ( 3 ) a^{(l+1)} = f(W^{(l)}a^{(l)}+b^{(l)}) \qquad\qquad\qquad (3) a(l+1)=f(W(l)a(l)+b(l))(3)
其中l是层数,f是激活函数,通常为Relu, a ( l ) 、 b ( l ) 和 w ( l ) a^{(l)}、b^{(l)}和w^{(l)} a(l)、b(l)和w(l)为第l层的激活、偏置和权重。
Deep部分是一个前馈神经网络:
- 类别型特征(稀疏高纬)->embedding vector(10-100)
- embedding vector 随机初始化,输入隐层
需要注意的是,两部分的输入不同:
- Wide 部分:Dense Features + Sparse Features(onehot 处理)+ 特征组合
- Deep 部分:Dense Embeddings (Sparse Features 进行 onehot + embedding 处理)
wide组件和deep组件的输出的对数几率加权求和后再输入到共同的一个logistic loss function进行训练。 联合训练和模型集成要进行区分,他们有着以下两点区别:
Jointly training一个wide&deep模型是可以通过从模型输出到wide组件和deep组件反向传播梯度利用mini-batch的随机梯度的方法优化完成。在Google的实验中,对于wide组件是通过带L1正则项的ftrl优化,对于deep组件通过AdaGrad优化完成。模型的预测输出如下,由wide组件和deep组件加起来套进一个sigmoid函数。
P ( Y = 1 ∣ x ) = σ ( w w i d e T [ x , ϕ ( x ) ] + w d e e p T a ( l f ) + b ) ( 3 ) P(Y=1|\bold x) = \sigma(\bold w^T_{wide}[\bold x, \phi(\bold x)]+\bold w^T_{deep}a^{(l_f)}+b) \qquad\qquad\qquad (3) P(Y=1∣x)=σ(wwideT[x,ϕ(x)]+wdeepTa(lf)+b)(3)
其中 Y Y Y是label, σ ( ⋅ ) \sigma(·) σ(⋅)是sigmoid函数, ϕ ( x ) \phi(\bold x) ϕ(x)是原始特征 x \bold x x的交叉特征转换, b为权重。 w w i d e \bold w_{wide} wwide和 w d e e p \bold w_{deep} wdeep分别为应用于最终激活函数( a l f a^{l_f} alf)wide部分和deep部分的权重。
Wide&Deep联合训练:
- 训练方式:同时训练同时产出
- 模型规模:Wide与Deep部分取长补短
- wide部分和deep部分的输出的对数几率加权求和后再输入到共同的一个logistic loss function进行训练
- 公式(3)中 括号内第一项为线性模型的输出,第二项为深度模型的输出,将两部分输出相加,再加上一个偏置 b 之后输入 sigmoid 进行激活得到预测的概率值。
APP应用推荐系统的数据流实现包括三个阶段:数据生成、模型训练和模型服务,如图 3 所示。
数据生成的要点:
每一条曝光日志就生成一条样本,标签就是 1/0,安装了 App 就是 1,否则就是 0。
将字符串形式的特征映射为 ID,需要用一个阈值过滤掉那些出现样本较少的特征。 即至少在训练集中出现m次才会被加入。 (Categorical 特征sparse)
对连续值做归一化,归一化的方法是:对累积分布函数 $P(X<=x)4 划分 n q nq nq 个分位,落入第 i i i 个分位的特征都归一化为下式: (Continuous 特征dense)
i − 1 n q − 1 \frac{i-1}{n_q-1} nq−1i−1
主要说下数据 预处理
- 针对离散特征,构造Embedding 词典,然后对原始数据做str–>index的转换。
- 针对连续特征,使用cdf归一化方法归一化到[0, 1]区间内。
从上图当中我们可以看到,左边是一些连续性的特征,比如年龄,安装的app数量等等,右边是一些离散型的特征,比如设备信息,安装过的app等等。这些离散型的特征都会被转化成embedding, 离散型特征的embedding维度为32,连续型特征和离散型特征concat后是1200维,经过(1024,512,256)三层MLP后输出。为了减小训练压力( 模型在超过5千亿样本上训练。 ),论文采用了warm-starting系统,即更新模型时采用上次模型的embedding权重和线性模型权重。为了防止模型上线出故障,模型上线前会做 dry run 和 sanity check。
- 每个类别特征 embedding 成一个 32 维向量;
- 将所有类别特征的 embedding 变量连成一个 1200 维度左右的大向量;
- 1200 维度向量就送进三层以 ReLU 作为激活函数的隐藏层;
- 最终从 Logistic Regreesion 输出。
- 宽模型侧就是传统的做法:特征交叉组合。
模型训练结束且验证完毕后,会将模型load到model servers,当一个用户请求过来时,利用wide&deep的前向inference预估每个app的点击概率,并从高到低排序展示给用户。
为了提高线上响应时间,线上系统采用小batch和多线性的执行方式
为了验证Wide & Deep模型的效果,paper在真实的场景当中从两个角度进行了大量的测试。包括app的获取量以及服务的表现。
在线上环境进行了为期3周的A/B测试,1个桶作为对照桶,使用之前版本的线性模型。1个桶使用Wide & Deep模型,另外一个桶只使用Deep模型,去除了linear的部分。这三个桶各自占据了1%的流量,最后得到的结果如下:
Wide & Deep模型不仅AUC更高,并且线上APP的获取量也提升了3.9%。
另外,从上表可看出,Wide & Deep的线上AUC相对deep和wide的提升分别只有0.83%和0.28%,即使线下AUC只有微小的提升,但线上的提升却较大,可能是因为线下的曝光和标签都是静态的,而线上系统通过将deep和wide相结合来生成新的探索性推荐,可以从新的用户响应中学习到更多信息。
推荐服务器每秒可以获得超过1000万个应用。 使用单个线程,在一次批处理中为所有候选人打分需要31毫秒。 论文实现了多线程,将响应时间缩短到了14ms,详情如下表:
结合带叉积转换的广义线性模型与深层神经网络嵌入的灵感来自以前的工作,比如FM,通过在两个低维嵌入向量之间使用点积分解两个变量间的相互作用,将线性模型了进行推广。在本文中,通过神经网络代替点积来学习嵌入之间高度非线性的相互作用,从而扩展了模型容量。
在语言模型中,通过学习输入和输出之间的直接权值,提出了使用n元特征的递归神经网络(RNNs)和最大熵模型联合训练,以显著降低RNN的复杂性(例如,隐藏层大小)。在计算机视觉中,深度残差学习已被用于降低训练更深层次模型的难度,并通过跳过一个或多个层次的捷径连接提高准确性。
神经网络与图形模型的联合训练还被应用于基于图像的人体姿态估计。在这项工作中,探讨了前馈神经网络和线性模型的联合训练,在稀疏特征和输出单元之间直接连接,用于输入数据稀疏的通用推荐和排序问题。
在推荐系统文献中,将内容信息的深度学习与评分矩阵的协同过滤(CF)相结合来探索协同深度学习。以前的工作也曾致力于手机应用推荐系统,如AppJoy在用户的应用使用记录上使用CF。不同于之前工作中基于cf或基于内容的方法,我们在app推荐系统中,基于用户和印象数据使用Wide & Deep模型联合训练。
- Memorization(记忆能力) 和 generalization(泛化能力) 对推荐系统都很重要。
- wide网络负责学习对历史记忆能力: Wide linear models can effectively memorize sparse feature interactions using cross-product feature transformations(人工特征交叉).
- deep网络负责学习推理泛化能力: deep neural networks can generalize to previously unseen feature interactionsthrough low dimensional embeddings.
- 提出 Wide & Deep 学习框架,联合了deep和wide双方的优势。将Wide & Deep应用于Google Play(大规模商业化的app store),线上实验表明,跟单独用wide网络或deep网络相比,Wide & Deep有显著提升。
Q1 在应用场景中,哪些特征适合放在Wide侧,哪些特征适合放在Deep侧,为什么?
显然的,直接的,有规律可循的特征适合放在Wide侧,对于一些受上下文影响较大的,简单的规律或许能够反映更大的上下文原因的特征适合放在Deep层。
Q2: 为什么Wide部分要用L1 FTRL训练?
- FTRL with L1非常注重模型的稀疏性,同时FTRL是一个精度又不错的随机梯度下降方法,W&D采用L1 FTRL是想让Wide部分变得更加稀疏
- L1 FTRL会让Wide部分的大部分权重都为0,我们准备特征的时候就不用准备那么多0权重的特征了,这大大压缩了模型权重,也压缩了特征向量的维度。
Q3:Wide部分的稀疏性为什么这么关键?
- 稀疏性不见得一直是一个好东西,它不管怎样都会让模型的精度有一定的损伤。肯定是特征向量维度过高导致“稀疏性”成为了关键的考量。就涉及到Google Wide部分的特征选取
- Wide部分采用的是User Installed App 和 Impression App 的叉积
- 不难猜测Google的工程师使用这个组合特征的意图,他们是想发现当前曝光app和用户安装app的关联关系,以此来直接影响最终的得分。但是两个id类特征向量进行组合,在维度爆炸的同时,会让原本已经非常稀疏的multihot特征向量,变得更加稀疏。正因如此,wide部分的权重数量其实是海量的。为了不把数量如此之巨的权重都搬到线上进行model serving,采用FTRL过滤掉哪些稀疏特征无疑是非常好的工程经验。
Q4: 为什么Deep部分不特别考虑稀疏性的问题?
- Deep部分的输入,要么是Age,#App Installs这些数值类特征,要么是已经降维并稠密化的Embedding向量,工程师们不会也不敢把过度稀疏的特征向量直接输入到Deep网络中。
- Deep部分不存在严重的特征稀疏问题,自然可以使用精度更好,更适用于深度学习训练的AdaGrad去训练。