数学基础
- 线性代数
- 概率论与随机过程
- 数值计算
- 蒙特卡洛方法与 MCMC 采样
- 机器学习方法概论
统计学习
深度学习
- 深度学习简介
- 深度前馈网络
- 反向传播算法
- 正则化
- 深度学习中的最优化问题
- 卷积神经网络
- CNN:图像分类
- 循环神经网络 RNN
- Transformer
- 一、Transformer [2017]
- 二、Universal Transformer [2018]
- 三、Transformer-XL [2019]
- 四、GPT1 [2018]
- 五、GPT2 [2019]
- 六、GPT3 [2020]
- 七、OPT [2022]
- 八、BERT [2018]
- 九、XLNet [2019]
- 十、RoBERTa [2019]
- 十一、ERNIE 1.0 [2019]
- 十二、ERNIE 2.0 [2019]
- 十三、ERNIE 3.0 [2021]
- 十四、ERNIE-Huawei [2019]
- 十五、MT-DNN [2019]
- 十六、BART [2019]
- 十七、mBART [2020]
- 十八、SpanBERT [2019]
- 十九、ALBERT [2019]
- 二十、UniLM [2019]
- 二十一、MASS [2019]
- 二十二、MacBERT [2019]
- 二十三、Fine-Tuning Language Models from Human Preferences [2019]
- 二十四 Learning to summarize from human feedback [2020]
- 二十五、InstructGPT [2022]
- 二十六、T5 [2020]
- 二十七、mT5 [2020]
- 二十八、ExT5 [2021]
- 二十九、Muppet [2021]
- 三十、Self-Attention with Relative Position Representations [2018]
- 三十一、USE [2018]
- 三十二、Sentence-BERT [2019]
- 三十三、SimCSE [2021]
- 三十四、BERT-Flow [2020]
- 三十五、BERT-Whitening [2021]
- 三十六、Comparing the Geometry of BERT, ELMo, and GPT-2 Embeddings [2019]
- 三十七、CERT [2020]
- 三十八、DeCLUTR [2020]
- 三十九、CLEAR [2020]
- 四十、ConSERT [2021]
- 四十一、Sentence-T5 [2021]
- 四十二、ULMFiT [2018]
- 四十三、Scaling Laws for Neural Language Models [2020]
- 四十四、Chinchilla [2022]
- 四十七、GLM-130B [2022]
- 四十八、GPT-NeoX-20B [2022]
- 四十九、Bloom [2022]
- 五十、PaLM [2022] (粗读)
- 五十一、PaLM2 [2023](粗读)
- 五十二、Self-Instruct [2022]
- 句子向量
- 词向量
- 传统CTR 预估模型
- CTR 预估模型
- 一、DSSM [2013]
- 二、FNN [2016]
- 三、PNN [2016]
- 四、DeepCrossing [2016]
- 五、Wide 和 Deep [2016]
- 六、DCN [2017]
- 七、DeepFM [2017]
- 八、NFM [2017]
- 九、AFM [2017]
- 十、xDeepFM [2018]
- 十一、ESMM [2018]
- 十二、DIN [2017]
- 十三、DIEN [2019]
- 十四、DSIN [2019]
- 十五、DICM [2017]
- 十六、DeepMCP [2019]
- 十七、MIMN [2019]
- 十八、DMR [2020]
- 十九、MiNet [2020]
- 二十、DSTN [2019]
- 二十一、BST [2019]
- 二十二、SIM [2020]
- 二十三、ESM2 [2019]
- 二十四、MV-DNN [2015]
- 二十五、CAN [2020]
- 二十六、AutoInt [2018]
- 二十七、Fi-GNN [2019]
- 二十八、FwFM [2018]
- 二十九、FM2 [2021]
- 三十、FiBiNET [2019]
- 三十一、AutoFIS [2020]
- 三十三、AFN [2020]
- 三十四、FGCNN [2019]
- 三十五、AutoCross [2019]
- 三十六、InterHAt [2020]
- 三十七、xDeepInt [2023]
- 三十九、AutoDis [2021]
- 四十、MDE [2020]
- 四十一、NIS [2020]
- 四十二、AutoEmb [2020]
- 四十三、AutoDim [2021]
- 四十四、PEP [2021]
- 四十五、DeepLight [2021]
- 图的表达
- 一、DeepWalk [2014]
- 二、LINE [2015]
- 三、GraRep [2015]
- 四、TADW [2015]
- 五、DNGR [2016]
- 六、Node2Vec [2016]
- 七、WALKLETS [2016]
- 八、SDNE [2016]
- 九、CANE [2017]
- 十、EOE [2017]
- 十一、metapath2vec [2017]
- 十二、GraphGAN [2018]
- 十三、struc2vec [2017]
- 十四、GraphWave [2018]
- 十五、NetMF [2017]
- 十六、NetSMF [2019]
- 十七、PTE [2015]
- 十八、HNE [2015]
- 十九、AANE [2017]
- 二十、LANE [2017]
- 二十一、MVE [2017]
- 二十二、PMNE [2017]
- 二十三、ANRL [2018]
- 二十四、DANE [2018]
- 二十五、HERec [2018]
- 二十六、GATNE [2019]
- 二十七、MNE [2018]
- 二十八、MVN2VEC [2018]
- 二十九、SNE [2018]
- 三十、ProNE [2019]
- Graph Embedding 综述
- 图神经网络
- 一、GNN [2009]
- 二、Spectral Networks 和 Deep Locally Connected Networks [2013]
- 三、Fast Localized Spectral Filtering On Graph [2016]
- 四、GCN [2016]
- 五、神经图指纹 [2015]
- 六、GGS-NN [2016]
- 七、PATCHY-SAN [2016]
- 八、GraphSAGE [2017]
- 九、GAT [2017]
- 十、R-GCN [2017]
- 十一、 AGCN [2018]
- 十二、FastGCN [2018]
- 十三、PinSage [2018]
- 十四、GCMC [2017]
- 十五、JK-Net [2018]
- 十六、PPNP [2018]
- 十七、VRGCN [2017]
- 十八、ClusterGCN [2019]
- 十九、LDS-GNN [2019]
- 二十、DIAL-GNN [2019]
- 二十一、HAN [2019]
- 二十二、HetGNN [2019]
- 二十三、HGT [2020]
- 二十四、GPT-GNN [2020]
- 二十五、Geom-GCN [2020]
- 二十六、Graph Network [2018]
- 二十七、GIN [2019]
- 二十八、MPNN [2017]
- 二十九、UniMP [2020]
- 三十、Correct and Smooth [2020]
- 三十一、LGCN [2018]
- 三十二、DGCNN [2018]
- 三十三、AS-GCN
- 三十四、DGI [2018]
- 三十五、DIFFPOLL [2018]
- 三十六、DCNN [2016]
- 三十七、IN [2016]
- 图神经网络 2
- 图神经网络 3
- 推荐算法(传统方法)
- 一、Tapestry [1992]
- 二、GroupLens [1994]
- 三、ItemBased CF [2001]
- 四、Amazon I-2-I CF [2003]
- 五、Slope One Rating-Based CF [2005]
- 六、Bipartite Network Projection [2007]
- 七、Implicit Feedback CF [2008]
- 八、PMF [2008]
- 九、SVD++ [2008]
- 十、MMMF 扩展 [2008]
- 十一、OCCF [2008]
- 十二、BPR [2009]
- 十三、MF for RS [2009]
- 十四、 Netflix BellKor Solution [2009]
- 推荐算法(神经网络方法 1)
- 一、MIND [2019](用于召回)
- 二、DNN For YouTube [2016]
- 三、Recommending What Video to Watch Next [2019]
- 四、ESAM [2020]
- 五、Facebook Embedding Based Retrieval [2020](用于检索)
- 六、Airbnb Search Ranking [2018]
- 七、MOBIUS [2019](用于召回)
- 八、TDM [2018](用于检索)
- 九、DR [2020](用于检索)
- 十、JTM [2019](用于检索)
- 十一、Pinterest Recommender System [2017]
- 十二、DLRM [2019]
- 十三、Applying Deep Learning To Airbnb Search [2018]
- 十四、Improving Deep Learning For Airbnb Search [2020]
- 十五、HOP-Rec [2018]
- 十六、NCF [2017]
- 十七、NGCF [2019]
- 十八、LightGCN [2020]
- 十九、Sampling-Bias-Corrected Neural Modeling [2019](检索)
- 二十、EGES [2018](Matching 阶段)
- 二十一、SDM [2019](Matching 阶段)
- 二十二、COLD [2020 ] (Pre-Ranking 模型)
- 二十三、ComiRec [2020](https://www.wenjiangs.com/doc/0b4e1736-ac78)
- 二十四、EdgeRec [2020]
- 二十五、DPSR [2020](检索)
- 二十六、PDN [2021](mathcing)
- 二十七、时空周期兴趣学习网络ST-PIL [2021]
- 推荐算法之序列推荐
- 一、FPMC [2010]
- 二、GRU4Rec [2015]
- 三、HRM [2015]
- 四、DREAM [2016]
- 五、Improved GRU4Rec [2016]
- 六、NARM [2017]
- 七、HRNN [2017]
- 八、RRN [2017]
- 九、Caser [2018]
- 十、p-RNN [2016]
- 十一、GRU4Rec Top-k Gains [2018]
- 十二、SASRec [2018]
- 十三、RUM [2018]
- 十四、SHAN [2018]
- 十五、Phased LSTM [2016]
- 十六、Time-LSTM [2017]
- 十七、STAMP [2018]
- 十八、Latent Cross [2018]
- 十九、CSRM [2019]
- 二十、SR-GNN [2019]
- 二十一、GC-SAN [2019]
- 二十二、BERT4Rec [2019]
- 二十三、MCPRN [2019]
- 二十四、RepeatNet [2019]
- 二十五、LINet(2019)
- 二十六、NextItNet [2019]
- 二十七、GCE-GNN [2020]
- 二十八、LESSR [2020]
- 二十九、HyperRec [2020]
- 三十、DHCN [2021]
- 三十一、TiSASRec [2020]
- 推荐算法(综述)
- 多任务学习
- 系统架构
- 实践方法论
- 深度强化学习 1
- 自动代码生成
工具
- CRF
- lightgbm
- xgboost
- scikit-learn
- spark
- numpy
- matplotlib
- pandas
- huggingface_transformer
- 一、Tokenizer
- 二、Datasets
- 三、Model
- 四、Trainer
- 五、Evaluator
- 六、Pipeline
- 七、Accelerate
- 八、Autoclass
- 九、应用
- 十、Gradio
Scala
- 环境搭建
- 基础知识
- 函数
- 类
- 样例类和模式匹配
- 测试和注解
- 集合 collection(一)
- 集合collection(二)
- 集成 Java
- 并发
十三、Applying Deep Learning To Airbnb Search [2018]
Airbnb
的home sharing platform
是一个双边市场,其中房东host
可以出租他们的空间(称作listings
),以供来自世界各地的潜在租客guest
预订。典型的预订开始于租客在airbnb.com
上搜索特定地理位置的房屋。search ranking
任务是从库存中的成千上万个listing
中挑选一个有序的listing
列表来响应租客。search ranking
的第一个实现是手动制作的评分函数scoring function
。用梯度提升决策树gradient boosted decision tree: GBDT
模型代替手动评分函数是Airbnb
历史上房屋预订量方面最大的改进之一,随后还有多次成功的迭代。在线预订量的收益最终饱和,其中很长一段时间的实验都是中性的(即没有提升)。这为尝试对系统进行全面改造提供了时机。从这一背景出发,论文
《Applying Deep Learning To Airbnb Search》
讨论了作者将互联网上的一个大规模搜索引擎之一切换为深度学习的经验。本文针对是拥有机器学习系统、并开始考虑神经网络的团队。论文的目的并不是推进前沿的、新的建模技术,而是讲述了如何将神经网络应用于现实产品。- 首先,论文对模型体系结构随着时间的演变进行了总结。
- 然后,论文给出了特征工程
feature engineering
和系统工程system engineering
的注意事项。 - 最后,论文描述了一些工具和超参数探索。
Airbnb
的search ranking
模型是模型生态系统的一部分,所有这些模型都有助于决定向租客展示哪些listing
。这些模型包括:预测房东接受租客预订请求可能性的模型、预测租客将旅行体验评为五星好评5-star
的概率的模型等等。论文目前的讨论集中在这个生态系统中的一个特定模型上,并且被认为是排序难题ranking puzzle
中最复杂的一块。这个模型负责根据租客预订的可能性来对可用的listing
进行排序。典型的租客搜索会话
search session
如下图所示。- 租客通常会进行多次搜索,点击一些
listing
从而查看它们的详情页。 - 成功的
session
以租客预订一个listing
而结束。
租客的搜索以及他们和产品的交互被作为日志而记录下来。在训练期间,新模型可以访问交互日志,也可以访问产品中之前使用的模型。新模型被训练从而学习一个评分函数,该函数将曝光日志中预订
listing
分配到尽可能高的排名。然后,新模型在
A/B test
框架中进行在线测试,从而查看新模型和当前模型的对比,看看新模型是否可以实现统计意义上显著的预订量提升。- 租客通常会进行多次搜索,点击一些
13.1 模型演变
我们向深度学习的转变不是原子
atomic
操作的结果,而是一系列迭代改进的最终结果。- 下图
(a)
显示了我们的主要离线指标normalized discounted cumulative gain: NDCG
的相对提升,其中预订listing
的曝光impression
被分配为相关性1.0
、其它listing
的曝光被分配为相关性0.0
。X
轴描述了模型及其投入生产的时间。 - 下图
(b)
显示了模型在线预订量的相对增长。
总体而言,这代表了
Airbnb
上最有影响力的机器学习应用之一。以下各节简要描述了每个模型。- 下图
Simple NN
:Andrej Karpathy
对模型架构有一些建议:不要成为英雄don’t be a hero
。在 “我们为什么不能成为英雄?” 的驱动下,我们从一些复杂的自定义架构开始,结果却被它们的复杂性淹没,最终浪费了很多时间。我们最终想方设法上线的第一个体系架构是具有
ReLU
激活的、简单的单隐层(32
个神经元)神经网络NN
。事实证明该神经网络和GBDT
相比,预订量指标是中性neutral
的(即效果既不正向、也不负向)。NN
和GBDT
模型具有相同的特征,其训练目标也和GBDT
保持不变:最小化L2
回归损失regression loss
,其中预订listing
的效用utility
分配为1.0
、未预订listing
的效用分配为0.0
。整个练习
exercise
的价值在于,它验证了整个NN pipeline
已经准备就绪,并且能够为实时流量提供服务。稍后在特征工程和系统工程部分讨论该pipeline
的具体细节。Lambdarank NN
:不是英雄not being a hero
让我们有了一个开始,但没有走很远。最终我们及时的将Karpathy
的建议调整为:在开始的时候不要成为英雄don’t be a hero, in the beginning
。我们的第一个突破是将
Simple NN
和Lambdarank
思想相结合。在离线时,我们使用NDCG
作为主要指标。Lambdarank
为我们提供了一种直接针对NDCG
优化NN
的方法。这涉及为Simple NN
的regression based
公式的两个关键改进:转向
pairwise
偏好公式,其中预订者看到的listing
被用于构建pairwise
的{booked listing, not-booked listing}
,从而作为训练样本。在训练期间,我们将预订listing
和未预订listing
之间得分差异的交叉熵损失最小化。即:预订
listing
和未预订listing
之间差异尽可能大。通过交换组成该
pair
对的两个listing
的位置position
而导致的NDCG
差异,从而加权每个pairwise
损失。这使得预订listing
的排名优化rank optimization
朝向搜索结果列表的头部,而不是底部。例如,把预订listing
的排名从位置2
提升到1
,将优于把预订listing
的排名从位置10
提升到9
。即:预订
listing
位置尽可能靠前。
下面给出了
TensorFlow
中的部分实现,尤其是如何对paiwise loss
进行加权:x1 def apply_discount(x):2 '''3 计算位置折扣曲线 positional discount curve4 '''5 return np.log(2.0)/np.log(2.0 + x)6 def compute_weights(logit_op, session):7 '''8 根据 ndcg 的差异来计算损失的加权系数.9 logit_op 是一个形状为 [BATCH_SIZE, NUM_SAMPLES] 的张量,对应于网络的输出层。每一行代表一个搜索,每一列代表搜索结果中的一个 listing。列 0 表示预订的 listing,剩余的 NUM_SAMPLES-1 列表示未预订的 listing。10 '''11 logit_vals = session.run(logit_op)12 ranks = NUM_SAMPLES - 1 - logit_vals.argsort(axis=1).argsort(axis=1)13 discounted_non_booking = apply_discount(ranks[:, 1:])14 discounted_booking = apply_discount(np.expand_dims(ranks[:, 0], axis=1))15 discounted_weights = np.abs(discounted_booking - discounted_non_booking)16 return discounted_weight17 18 # 计算 pairwise loss19 pairwise_loss = tf.nn.sigmoid_cross_entropy_with_logits(20 targets=tf.ones_like(logit_op[:, 0]),21 logits=logit_op[:, 0] - logit_op[:, i:] )22 # 计算基于 ndcg 加权的 lambdarank 权重23 weights = compute_weights(logit_op, session)24 # 计算 lambdarank 权重加权的 pairwise loss25 loss = tf.reduce_mean(tf.multiply(pairwise_loss, weights))
Decision Tree/Factorization Machine NN
:虽然目前服务于生产流量的主力排序模型是神经网络,但是我们仍然在研究其它模型。值得一提的模型有:GBDT
模型,其中使用使用替代方法对搜索进行采样从而来构建训练数据。- 因子分解机
factorization machine:FM
模型,它通过将listing
和query
都映射到一个32
维的空间,从而预测一个listing
在给定query
的情况下被预订的概率。
这些研究
search ranking
问题的新方法揭露了一些有趣的东西:尽管这些模型在测试数据上的性能和神经网络相当,但是它们排名靠前upranked
的listing
却大不相同。受到
《Deep & Cross Network for Ad Click Predictions》
这样的神经网络体系架构的启发,新模型试图结合所有三种模型(GBDT
模型、FM
模型、NN
模型)的优势:- 对于
FM
模型,我们将最终预测作为特征纳入NN
模型。 - 对于
GBDT
模型,我们将每棵树激活的叶节点的索引作为离散特征纳入NN
模型。
下图给出了一个概览。
Deep NN
:Deep NN
模型的复杂性是惊人的,而且《Hidden Technical Debt in Machine Learning Systems》
中提到的一些问题开始出现。在我们的最后一次飞跃中,我们能够通过简单地将训练数据扩展10
倍,并切换到具有两层隐层的DNN
来消除所有这些复杂性。Deep NN
网络的典型配置:- 一个输入层
input layer
。其中,在将离散特征扩展到embedding
之后,输入一共有195
个特征。 - 第一个隐层
hidden layer
。其中,该层具有127
个全连接的ReLU
激活的神经元。 - 第二个隐层
hidden layer
。其中,该层具有83
个全连接的ReLU
激活的神经元。
馈入
DNN
的特征大部分是简单的listing
属性,诸如价格、设施amenities
、历史预订量等等。这些特征通过最少的特征工程来提供。除此之外,还包括从其它模型输出的特征:- 启用了智能定价
Smart Pricing
功能的listing
价格,该特征由专门的模型提供。 - 候选
listing
和用户历史查看listing
的相似度similarity
,这是基于co-view embedding
来计算得到。
这些模型利用了不直接隶属于
search ranking
训练样本的数据,为DNN
提供了额外的信息。为了更深入地了解
DNN
,我们在下图中绘制了它的学习曲线learning curve
。我们在训练集和测试集上对比了NDCG
,其中训练集有17
亿的pair
对。可以看到:我们能够弥合
close
训练集和测试集之间的泛化距离generalization gap
。- 一个输入层
我们能否跳过演变
evolution
的所有阶段直接启用DNN
?我们试图在追溯部分中回答这一问题。顺便说一句,虽然
DNN
在某些图像应用上取得了人类水平的性能,但我们很难判断我们在类似的比较中处于什么位置。问题的部分原因是,目前尚不清楚在search ranking
问题中如何定义人类水平的性能。通过浏览日志信息,我们很难准确地判断哪些listing
将会被预订。我们在日志中找不到客观的事实,只能根据租客的预算budget
和口味tastes
进行tradeoff
,而租客的口味大多数情况下还是看不到的。一些学者指出,即使是对于熟悉的shopping items
,也很难进行人工评估。对于我们的application
,由于库存的新颖性novelty
,这些困难将进一步加剧。说到困难,接下来我们讨论一些鲜为人知的事情:失败的尝试。
13.2 失败的模型
上一节中介绍的一个成功的
launch
后又接着另一个成功的launch
的叙述并没有讲出完整的故事。现实中失败的尝试比成功的尝试更多。复述每一次失败的尝试比较耗时,所以我们选择了两个特别有趣的失败来讲述。这些模型很有趣,因为它们说明了一些外部非常有效和受欢迎的技术,但是内部使用时可能会失效。Listing ID
:Airbnb
上的每个listing
都有相应的唯一ID
。NN
提供的一个令人兴奋的新能力是使用这些listing id
作为特征。想法是使用listing id
作为embedding
的索引index
,这使得我们能够学习每个listing
的向量representation
,从而编码listing
独有的属性property
。我们之所以兴奋,是因为其它
application
已成功地将如此高基数cardinality
的离散特征映射到embedding
,例如在NLP application
中学习word embedding
、在推荐系统中学习video id embedding
和user id embedding
。但是,在我们尝试的不同变体中,
listing id
大多数会导致过拟合。下图绘制了一次这类尝试的学习曲线,我们看到NDCG
在训练集上有显著提升,但是在测试集上却没有任何改善。这种成熟的技术在
Airbnb
上失败的原因是由于底层市场underlying marketplace
的某些独特属性property
。embedding
需要每个item
有大量数据才能收敛到合理的值。- 当
item
可以无限地重复时,例如在线视频或语言中的单词,那么item
拥有的用户交互数量也没有限制。为item
兴趣获取大量的数据相对容易。 - 另一方面,
listing
受到物理世界的限制。即使是最受欢迎的listing
,一年最多也就可以预订365
次。平均每个listing
的预订量要少得多。这一基础限制fundamental limitation
生成的数据在listing-level
非常稀疏。过拟合就是这种限制的直接后果。
如果
item id
频次太少,则很难学到有意义的embedding
。- 当
多任务学习
Multi-task Learning
:虽然预订有物理限制,但是用户对listing
详情页的查看并没有物理限制。下图显示了listing
的详情页查看量和预订量的比例的分布,预订量通常比查看量稀疏了几个数量级(横轴为查看量和预订量之比,纵轴为listing
数量)。更进一步,我们发现,不出所料,对listing
详情页的长时间观看long view
和预订相关。为了解决
listing id
过拟合的问题,我们建立了一个多任务学习模型。该模型使用两个独立的输出层同时预测预订概率和long view
的概率:- 一个以预订
listing
作为正样本来优化损失,从而预测预订概率。 - 另一个以
long view listing
作为正样本来优化损失,从而预测long view
概率。
两个输出层共享一个公共的隐层,如下图所示。更重要的是,
listing id embedding
是共享的。背后的想法是,模型能够将long view
中学到的知识迁移到预订任务中,从而避免过拟合。由于
long view
标签的数量比预订标签的数量多几个数量级,因此对预订损失施加了较高的补偿权重,从而保持对预订目标的关注。如
《Beyond Clicks: Dwell Time for Personalization》
所建议的,每个long view
标签的损失进一步由log(view_duration)
进行缩放。最终在线
listing
评分时,我们仅使用预订预测booking prediction
。但是当在线测试时,该模型大幅增加了
long view
,而预订量保持不变。人工检查了具有较高long view
的listing
,我们发现了可能导致这种gap
的几种原因:- 这种
long view
可能是由于高端的、但价格昂贵的listing
所驱动(所以用户会停留一段时间来慎重考虑)。 listing
的描述太长,且难以阅读。- 极其独特、且有时很幽默的
listing
。 - 还有一些其它原因。
同样,正是
Airbnb
市场的独特性,使得long view
和预订相关,但是也有很大的正交部分(即不相关的部分),这使得基于long view
来预测预订具有挑战性。更好地理解listing view
仍然是我们研究的主题。注:笔者在
ctr
和cvr
多任务建模过程中也发现类似的规律。即希望丰富的点击样本能够有助于迁移学习到转化预估任务。但是结果发现,ctr
预估任务效果很好,但是cvr
预估任务效果持平或略有下降。- 一个以预订
13.3 特征工程
我们开始的
baseline GBDT pipeline
具有广泛的特征工程。典型的变换包括计算比率ratio
、窗口平均等等。这些特征工程技巧是经过多年实验积累的。然而,目前还不清楚这些特征是否是最好的,或者是否随着市场动态变化而更新。NN
的一大吸引力在于引入了特征自动化feature automation
:馈入原始数据并让特征工程在以数据驱动的NN
的隐单元中自动进行。然而,本节内容是专门针对特征工程的,因为我们发现让
NN
有效工作不仅仅是提供原始数据,也需要特征工程。这种特征工程不同于传统的特征工程:在将特征输入到模型之前,无需人工对特征执行数学计算,而是将重点转移到确保特征符合某些属性properties
,以便神经网络可以自己有效地进行数学计算。特征归一化
Feature Normalization
:在我们第一次训练NN
的尝试中,我们简单地将所有用于训练GBDT
模型的特征输入到神经网络中。这种情况非常糟糕,损失函数在训练过程中达到饱和,后续的step
没有任何效果。我们将问题追溯到以下事实:特征未能正确地归一化。- 对于决策树,只要特征的相对顺序有意义,那么特征的确切数值几乎无关紧要。
- 神经网络对于特征的数值非常敏感。超出正常特征范围的馈入值可能会导致较大梯度的反向传播。由于梯度消失,这可以使得
ReLU
这类激活函数永久死亡。
为了避免这种情况,我们确保将所有特征限制在较小的取值范围内,并且大部分分布在
[-1,1]
区间、均值映射到0
。总的来说,这涉及检查特征,并应用以下两种转换中的任何一种:如果特征分布类似于正态分布,我们将其变换为:
$ \frac{\text{feature_value} - \mu}{\sigma} $其中 $ \mu $ 为特征均值, $ \sigma $ 为特征标准差。
如果特征分布类似于幂律分布
$ \log \left(\frac{1+ \text{feature_value}}{1+ \text{median}}\right) $power law distribution
,我们将其变换为:其中
median
为特征的中位数。
另一种简单的选择是采用
BN Layer
。特征分布
Feature Distribution
:除了将特征映射到有限的数值范围,我们还确保大多数特征都具有平滑的分布。为什么要纠结于分布的平滑性smoothness
?以下是我们的一些理由。发现错误
spotting bugs
:在处理上亿个特征样本时,如何验证其中一小部分没有bug
?范围检查很有用,但是很有限。我们发现分布的平滑性是发现错误的宝贵工具,因为错误的分布通常和典型的分布形成鲜明对比。举个例子,我们在某些地区记录的价格中发现了
bug
。对于超过28
天的区间,记录的价格是每月价格、而不是每日价格。这些错误在原始分布图上显示为尖峰。促进泛化
facilitating generalization
:确切回答为什么DNN
善于泛化是研究前沿的一个复杂课题。同时,我们的工作知识working knowledge
是基于以下观察:在为我们的application
构建的DNN
中,各层的输出在其分布方面变得越来越平滑。下图显示了来自一些样本的最终输出层分布、以及隐层分布。为了绘制隐层的分布,零值被省略,并且应用了log(1 + relu_output)
转换。这些图激发了我们的直觉:为什么
DNN
可以很好地泛化到我们的application
中。当建立一个基于数百个特征的模型时,所有特征取值的组合空间非常庞大,并且在训练过程中常常会覆盖一定比例特征组合。来自较低层的平滑分布确保了较高层可以正确地对未看过unseen
的值进行插值。将这种直觉一直扩展到输入层,我们尽力确保输入特征具有平滑的分布。这里有个平滑性假设:假设相似的特征带来相似的
label
。我们如何测试模型是否在样本上良好地泛化?真正的测试当然是模型的在线性能,但是我们发现以下技术可以作为完整性检查
sanity check
:将测试集中给定特征上所有的值都缩放(例如将price
特征缩放为2
倍或者3
倍或者4
倍),然后观察NDCG
的变化。我们发现,在这些从未见过的price
取值上,该模型的性能是非常稳定的。对特征的取值缩放可能会破坏样本的完整性。例如:对于郊区的、单个房间的
listing
,如果price
缩放4
倍会导致一个奇怪的listing
,看起来应该很便宜的listing
但是标价很高。在调试
debugged
并应用适当的归一化之后,大多数特征都获得了平滑分布。但是,有少数几个特征,我们不得不进行专门的特征工程。一个例子是listing
的地理位置geo-location
,以经度和纬度来表示。下图(a)
和(b)
显示了原始经纬度的分布。为了使得分布更加平滑,我们计算的是距展示给用户的地图的中心点的偏移量。如下图(c)
所示,质量似乎集中在中心,因为地图的尾部被zoomed out
了很多。因此,我们使用经度/纬度偏移量的log()
,从而得到了下图(d)
的分布。这使得我们能够构造两个平滑分布的特征,如下图(e)
和(f)
所示。需要明确的是,原始经度/纬度到地图中心的距离变换是有损的多对一函数
many-to-one function
。因为它可以将多个经度/纬度转换为相同的偏移量。这使得模型可以基于距离属性而不是特定的地理位置属性来学习全局属性。要学习特定于局部地理位置的属性,我们使用了稍后描述的高基数high cardinali
离散特征。检查特征完整性
checking feature completeness
:在某些情况下,调查某些特征缺乏平滑性会导致发现模型缺失missing
的特征。例如,我们有一个
listing
未来已预订天数占available days
的比例作为一个特征(即占用率occupancy
),这个特征是listing
质量的信号。背后的直觉是:高质量的listing
会提前售罄。但是,由于缺乏平滑性,占用率的分布却令人困惑,如下图(a)
所示。经过调查,我们发现了另一个影响占用率的因素:
listing
有不同的最低住宿时间minimum required stay
要求,有的会要求最低住宿几个月。因此这些listing
得到了不同的占用率。但是,我们没有在模型中添加最低住宿时间作为特征,因为它取决于日历并且被认为过于复杂。但是在查看了占用率分布之后,我们增加了listing
的平均住宿时间作为一个特征。在占用率通过平均住宿时间归一化之后,我们可以看到下图
(b)
中的分布。在一个维度中缺乏平滑性的特征可能在较高维度上变得平滑。这有助于我们思考这些维度是否可以应用在我们的模型中。
高基数离散特征
High Cardinality Categorical Features
:过拟合的listing id
并不是我们尝试的唯一高基数离散特征。还有其它尝试,如NN
的承诺所言,我们用很少的特征工程就取得了很高的回报。一个具体的例子最能说明这一点。租客对于城市各个街区
neighborhoods
的偏好是一个重要的位置信号location signal
。对于GBDT
模型,该信息是由一个精心设计的pipeline
提供的,该pipeline
跟踪了各个街区和城市的层级分布hierarchical distribution
。建立和维护该pipeline
的工作量很大,而且它也没有考虑诸如预订listing
价格之类的关键因素。在
NN
的世界中,处理这类信息本身就是简单的。我们基于query
中指定的城市、以及对应于listing
的level 12 S2 cell
创建的一个新的离散特征,然后使用哈希函数将这二者整体映射到一个整数。例如,给定query
“旧金山” 以及位于Embarcadero
附近的listing
,我们选择listing
所在的S2 cell
(539058204
),然后将将{"San Francisco", 539058204}
哈希映射到71829521
从而建立我们的离散特征。然后该离散特征被映射到一个embedding
,接着馈入NN
。在训练期间,该模型通过反向传播来学习embedding
,该embedding
编码了在给定城市query
的情况下由S2 cell
代表的街区的位置偏好location preference
。即将地域划分为一个个的网格,然后学习每个网格的
grid id embedding
。下图可视化了为
query
“旧金山” 学到的各街区的embedding
(通过t-SNE
)。这符合我们对该地区的直觉理解:embedding
值不仅突出了该城市的主要points of interest: poi
,它还表明了人们更喜欢位于西湾west bay
以南一点的位置,而不是靠近主要交通拥堵桥梁的位置。
13.4 系统工程
这部分是关于加速训练
training
和加速打分scoring
。我们pipeline
的一个quick summary
:- 来自租客的搜索
query
命中了一个进行检索retrieval
和评分scoring
的Java server
。 - 这个
server
还生成日志,这些日志存储为序列化的Thrift
实例。 - 日志使用
Spark pipeline
来处理从而创建训练数据。 - 使用
TensorFlow
来训练模型。 - 使用
Scala
和Java
编写的各种工具用于评估模型和计算离线指标。 - 模型上传到执行检索和评分的
Java server
。
所有这些组件都在
AWS
实例上运行。- 来自租客的搜索
Protobufs and Datasets
:GBDT
模型是以CSV
格式来提供训练数据的,并且我们重复使用这个pipeline
的大部分,从而使用feed dict
馈入TensorFlow
模型。乍一看,这似乎不是一个机器学习的问题,并且在我们的优先级清单中是相当低的。但是当我们发现
GPU
利用率接近25%
时,我们马上警醒了。大部分训练时间都花在解析CSV
和通过feed dict
拷贝数据上。我们实际上是在用骡子拖着一辆法拉利。重构
pipeline
以产生Protobufs
训练数据,并使用Dataset
可以将训练速度提高17
倍,并将GPU
利用率提高到大约90%
。这最终允许我们将训练数据从几周扩展到几个月。重构静态特征
refactoring static features
:我们的很多特征都是很少变化的listing
属性。例如,地理位置location
、卧室数量、便利设施amenities
、租客规则guest fules
等等。将所有这些特征作为训练样本的一部分将产生输入瓶颈input bottleneck
。为了消除这种磁盘流量,我们仅使用
listing id
作为离散特征。所有静态特征都被打包为由listing id
索引的、不可训练non-trainable
的embedding
。对于在训练期间发生突变的特征,这需要在少量噪声和训练速度之间进行trade-off
。注意:这个
embedding
就是这些静态特征拼接而成的,因此是不可训练的。是否对这些属性进行embedding
训练会更好?论文并未讨论这一点。这个
embedding
常驻在GPU
内存,消除了每个训练样本数千KB
的数据,这些数据通常是通过CPU
从磁盘加载的。这种效率使得探索全新类型的模型成为可能,该模型考虑了用户历史交互的数十个listing
的详细信息。Java NN library
:在2017
年初,当我们开始将Tensorflow
模型投入生产时,我们发现没有有效的解决方案可以在Java stack
中对模型进行评分scoring
。 通常需要在Java
和另一种语言之间来回转换数据,这个过程中引入的延迟latency
对我们而言是一个障碍。为了满足严格的搜索延迟要求,我们在
Java
中创建了一个自定义的神经网络评分库。虽然到目前为止这对我们很有帮助,但是我们希望重新讨论这个问题,看看有没有最新的替代方案。
13.5 超参数
尽管在
GBDT
世界中有一些超参数,如树的数量、正则化等,但是NN
却将超参数的规模提升到一个新的高度。在最初的迭代中,我们花了大量时间探索超参数世界。调研所有选项和试验组合上的努力并没有给我们带来任何有意义的改进。但是,这个练习exercise
确实让我们对我们的选择有了一些信息,我们将在下面描述。dropout
:我们最初的印象是,dropout
和神经网络的正则化相对应,因此必不可少。然而对于我们的application
,我们尝试了不同的dropout
形式,所有这些都会导致离线指标略有下降。为了理解
dropout
和我们的失败,我们目前对dropout
的解释更接近于一种数据增强技术。当随机性的引入模拟了有效的场景时,这种技术是有效的。对于我们的情况,随机性只能产生无效的场景。作为替代方案,我们在考虑特定特征的分布的情况下,添加了人工制作的噪声,从而使得离线
NDCG
降低了大约1%
。但是我们在在线性能方面没有取得任何统计意思上的显著提升。初始化
initialization
:出于纯粹的习惯,我们通过将所有权重和embedding
初始化为零来开始我们的第一个模型,结果发现这是开始训练神经网络的最差的方法。在研究了不同的技术之后,我们目前的选择是对网络权重使用Xavier
初始化,对embedding
使用{-1 ~ +1}
范围内的均匀随机初始化。学习率
learning rate
:这里面临着各种各样的策略,但是对于我们的application
,我们发现很难使用默认的设置来改善Adam
的性能。当前,我们使用了LazyAdamOptimizer
变体,我们发现使用large embedding
训练时该变体会更快。batch size
:batch size
的变化对于训练速度有着显著影响,但是对于模型本身的确切影响却难以把握。我们发现最有用的指南是《Don’t Decay the Learning Rate, Increase the Batch Size》
。但是我们并没有完全遵守该论文的建议。在LazyAdamOptimizer
解决了学习率问题之后,我们选择了200
的固定batch size
,这似乎对当前模型有效。
13.6 特征重要性
一般来说,特征重要性的估计和模型的可解释性
interpretability
是神经网络不擅长的一个领域。评估特征的重要性对于确定工程工作的优先级和指导模型迭代是至关重要的。NN
的优势在于找到特征之间的非线性相互作用。当理解特定特征扮演了什么角色时,这也是一个弱点,因为非线性相互作用使得很难孤立地研究任何特征。接下来,我们讲述解释神经网络的一些尝试。分数分解
Score Decomposition
:在NN
的世界中,试图了解单个特征的重要性只会导致混乱。我们第一个朴素的尝试是获取网络产生的最终得分,然后尝试将其分解为来自每个输入节点input node
的贡献。在查看了结果之后,我们意识到这个想法存在概念上的错误:没有一种干净
clean
的方法来区分一个特定的输入节点对像ReLU
这样的非线性激活的影响。消融测试
Ablation Test
:这是对这个问题的又一次简单的尝试。这里的想法是一次移除一个特征,重新训练模型并观察性能的差异。然后,我们可以将这些特征的重要性与移除它们所导致的性能下降成正比。然而这里的困难在于,通过移除一个特征获得的任何性能差异都类似于在重新训练模型时观察到的离线指标中的典型噪声。这可能是因为我们的特征集合中存在大量的冗余,模型似乎能够从剩余的特征中弥补一个缺失的特征。
这导致了忒休斯之船悖论
Ship-of-Theseus paradox
:你能一次从模型中删除一个特征,声称该模型没有显著的性能下降吗?忒修斯悖论:如果忒修斯的船上的木头被逐渐替换,直到所有的木头都不是原来的木头,那这艘船还是原来的那艘船吗?
即:假定某物体的构成要素被置换后,但它依旧是原来的物体吗?
排列测试
Permutation Test
:在接下来的尝试中,我们从针对随机森林提出的排列特征重要性permutation feature importance
中得到启发。我们在测试中随机排列了特征在各个样本中的取值之后,在测试集上观察了模型的性能。我们的期望是,特征越重要,扰动它导致的模型退化degradation
就越大。但是,该操作会导致有些荒谬的结果。原因是在一次排列
permuting
一个特征时,我们假设不同特征之间彼此独立,这是错误的。例如,预测预订概率的最重要特征之一就是listing
中的房间数。而房间数量和价格、住宿人数、便利设施等特征息息相关。对特征进行独立排列会创建在现实生活中从未发生过的样本,并且特征在无效空间invalid space
中的重要性使我们误入歧途。但是,该测试在确定没有发挥作用的特征方面有些用处。如果随机排列特征完全不影响模型性能,则可以很好地表明模型可能不依赖于该特征。
TopBot Analysis
:有一个自主开发的工具旨在解释这些特征,并且不会以任何方式干扰它们。这个工具叫做TopBot
,它提供了一些有趣的洞察insight
。TopBot
是自上而下分析器top-bottom analyzer
的缩写,它将一个测试集作为输入,并使用模型对每个测试query
的listing
进行排序。然后它为每个query
从排名在top
的listing
生成特征取值的分布图,并将该分布图和排名在bottom
的listing
生成特征取值的分布图进行比较。这个比较comparison
表明了模型是如何利用不同取值范围内的特征。下图显示了一个例子。排名最高的
listing
的价格分布偏向于较低的值,这表明模型对于价格的敏感性sensitivity
。但是,当比较排名top
和排名bottom
的listing
的评论数量的分布时,这两个分布看起来非常相似,表明这个版本的模型未按预期使用评论,从而为下一步研究提供了方向。还可以细化下:针对不同的细分市场(或者不同类型的
listing
)来可视化。
13.7 回顾
下图总结了目前为止的深度学习之旅。
- 根据无处不在的深度学习成功案例,我们从乐观主义的顶峰开始,认为深度学习将取代
GBDT
模型,并为我们带来惊人的收益。 - 许多最初的讨论集中在保持其他一切不变,用神经网络替代当前的模型,看看我们能够得到什么收益。当最初没有实现这些收益时,这让我们陷入了绝望的深渊。
- 随着时间的推移,我们意识到转向深度学习根本不是一个简单的模型替代,更确切的说这是关于系统扩展
sytem scaling
。因此,它需要重新思考围绕模型的整个系统。
如果仅局限于较小的规模,像
GBDT
这样的模型在性能上可以说是同等水平并且更易于处理,我们继续使用GBDT
来解决中等规模的问题。那么,我们会向其他人推荐深度学习吗?答案是Yes
。这不仅是因为深度学习模型的在线性能大幅提升。还有部分原因是与深度学习如何改变了我们未来的roadmap
有关。早期机器学习的重点主要放在特征工程上,但是在转向深度学习之后,试图手动特征工程已经失去了前景。这让我们可以在更高的层次上研究问题。比如,如何改进我们的优化目标?我们是否准确地代表了所有的用户?在迈出将神经网络应用于search ranking
第一步的两年之后,我们觉得我们才刚刚开始。- 根据无处不在的深度学习成功案例,我们从乐观主义的顶峰开始,认为深度学习将取代
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论