主要挑选了一些笔者比较感兴趣的方向,并整理了对应的文章名称。读者可以大致读一下文章名,判断是否和自己的研究方向或工作方向一致,从中选择感兴趣的文章进行精读。
涉及到采样、负样本等。
Google: Bootstrapping for Batch Active Sampling
Google: Bootstrapping Recommendations at Chrome Web Store
Alibaba:Real Negatives Matter: Continuous Training with Real Negatives for Delayed Feedback Modeling
Google: Learning to Embed Categorical Features without Embedding Tables for Recommendation
华为:An Embedding Learning Framework for Numerical Features in CTR Prediction
腾讯:Learning Reliable User Representations from Volatile and Sparse Data to Accurately Predict Customer Lifetime Value
阿里:Representation Learning for Predicting Customer Orders
阿里:Debiasing Learning based Cross-domain Recommendation
腾讯:Adversarial Feature Translation for Multi-domain Recommendation
阿里:Contrastive Learning for Debiased Candidate Generation in Large-Scale Recommender Systems
阿里:Debiasing Learning based Cross-domain Recommendation
华为:Dual Graph enhanced Embedding Neural Network for CTR Prediction
美团:Signed Graph Neural Network with Latent Groups
阿里:DMBGN: Deep Multi-Behavior Graph Networks for Voucher Redemption Rate Prediction
百度:MugRep: A Multi-Task Hierarchical Graph Representation Learning Framework for Real Estate Appraisal
Google:Understanding and Improving Fairness-Accuracy Trade-offs in Multi-Task Learning
美团:Modeling the Sequential Dependence among Audience Multi-step Conversions with Multi-task Learning for Customer Acquisition
百度:MugRep: A Multi-Task Hierarchical Graph Representation Learning Framework for Real Estate Appraisal
Facebook:Training Recommender Systems at Scale: Communication-Efficient Model and Data Parallelism
Facebook:Hierarchical Training: Scaling Deep Recommendation Models on Large CPU Clusters
阿里,FleetRec: Large-Scale Recommendation Inference on Hybrid GPU-FPGA Clusters
腾讯,Large-Scale Network Embedding in Apache Spark
Microsoft,On Post-Selection Inference in A/B Testing
阿里巴巴:AliCG: Fine-grained and Evolvable Conceptual Graph Construction for Semantic Search at Alibaba
阿里巴巴:AliCoCo2: Commonsense Knowledge Extraction, Representation and Application in E-commerce
百度:Pretrained Language Models for Web-scale Retrieval in Baidu Search
微软:Domain-Specific Pretraining for Vertical Search: Case Study on Biomedical Literature
微软:Diversity driven Query Rewriting in Search Advertising
百度:Meta-Learned Spatial-Temporal POI Auto-Completion for the Search Engine at Baidu Maps
Google: Mondegreen: A Post-Processing Solution to Speech Recognition Error Correction for Voice Search Queries
Facebook:VisRel: Media Search at Scale
百度:Norm Adjusted Proximity Graph for Fast Inner Product Retrieval
百度:JIZHI: A Fast and Cost-Effective Model-As-A-Service System for Web-Scale Online Inference at Baidu
这一块文章不是很多,就不细分了。
Google: Clustering for Private Interest-based Advertising
阿里:A Unified Solution to Constrained Bidding in Online Display Advertising
阿里:Exploration in Online Advertising Systems with Deep Uncertainty-Aware Learning
微软:NAS-BERT: Task-Agnostic and Adaptive-Size BERT Compression with Neural Architecture Search
阿里:M6: Multi-Modality-to-Multi-Modality Multitask Mega-transformer for Unified Pretraining
微软:TUTA: Tree-based Transformers for Generally Structured Table Pre-training
微软:Generalized Zero-Shot Extreme Multi-label Learning
微软:Zero-shot Multi-lingual Interrogative Question Generation for “People Also Ask” at Bing
NewsEmbed: Modeling News through Pre-trained Document Representations
Understanding and Improving Fairness-Accuracy Trade-offs in Multi-Task Learning
Bootstrapping for Batch Active Sampling
Table2Charts: Recommending Charts by Learning Shared Table Representations
TabularNet: A Neural Network Architecture for Understanding Semantic Structures of Tabular Data
TUTA: Tree-based Transformers for Generally Structured Table Pre-training
Contextual Bandit Applications in a Customer Support Bot
Diversity driven Query Rewriting in Search Advertising
Domain-Specific Pretraining for Vertical Search: Case Study on Biomedical Literature
On Post-Selection Inference in A/B Testing
Reinforced Iterative Knowledge Distillation for Cross-Lingual Named Entity Recognition
Reinforcing Pretrained Models for Generating Attractive Text Advertisements
Zero-shot Multi-lingual Interrogative Question Generation for “People Also Ask” at Bing
后续笔者会针对感兴趣的文章进行解读。如果大家有感兴趣的文章,也欢迎在公众号后台跟我留言,我会优先挑选大家感兴趣的文章进行解读。当然,如果你有解读好的笔记,也欢迎投稿或交流~~
[1] KDD2021 Accepted Papers: https://kdd.org/kdd2021/accepted-papers/index
也欢迎关注我的公众号”蘑菇先生学习记“,更快更及时地获取推荐系统前沿进展!
]]>下面按照Motivation,Solution,Evaluation和Summarization来介绍。
研究对象:电商平台的商品搜索引擎(product search engines)。
整体淘宝搜索系统包括四阶段:match-prerank-rank-rerank,召回,粗排,精排,重排。本文重点在于召回。
挑战:电商平台的文本通常较短,没有语法结构,因此要考虑海量的用户历史行为。基于词匹配(lexical matching)的搜索引擎(倒排索引),性能好、可控性强,尽管存在一些语义鸿沟问题,但仍被广泛的应用在现有的搜索引擎架构中。但是,这种搜索引擎无法有效区分相同query下, 不同用户的兴趣差异,无法捕捉用户个性化的特征。因此,如何高效地检索出【最相关】、【最能够满足用户需求】的产品,发现【query语义】和【用户个性化历史行为】之间的关系,是电商平台主要的挑战。
工业界经典的EBR系统文章有,
电商平台:
其它:
作者指出上述大多数文章避重就轻,只强调在指标上提升很多,却没有说明向量召回会降低相关性,引入很多相关性的CASE。
作者也部署了向量检索系统在淘宝搜索中,观察了很长一段时间,有几个发现:
随机负采样在召回阶段被广泛使用,用于训练大规模的深度语义检索模型,来保证训练阶段的样本空间和推理阶段是一致的[2,3]。然而,仍然存在一些离线训练和线上推理不一致的情况[1,2]。例如,推理阶段,模型需要从所有的候选集中,选择和目标Query最相关的top-K个商品,需要一个全局的比较能力。而大部分工作如京东和亚马逊[1,2]都是采用hinge pairwise loss作为训练目标,而hinge pairwise loss本身只具备局部的比较能力。
这篇文章的核心贡献总结如下:
问题形式化:$\mathcal{U}={u_1,…,u_u,…,u_n}$表示$N$个用户集合;$\mathcal{Q}={q_1,…,q_u,…,q_N}$表示相应的queries,$\mathcal{I}={i_1,…,i_i,…,i_M}$表示$M$个物品的集合。同时,作者将用户$u$的历史行为根据离当前的时间间隔划分为3个子集合,
任务:给定用户$u$的历史行为序列$(\mathcal{R}^u, \mathcal{S}^u, \mathcal{L}^u)$,在时间$t$发起了一次搜索请求$q_u$,我们期望返回物品的集合$i \in \mathcal{I}$来满足该用户的搜索需求。具体而言,目标是基于用户$(\text{query}, \text{behaviors})$和物品items之间的得分$z$,从$\mathcal{I}$中预测出Top-$K$候选物品。即:
$$
z = \mathcal{F}(\phi(q_u, \mathcal{R}^u, \mathcal{S}^u, \mathcal{L}^u), \psi(i))
$$
其中,$\mathcal{F}(\cdot)$是打分函数,$\phi(\cdot)$是query/behaviors的编码器,$\psi(i)$是item编码器。作者也是采用了双塔的召回模型,$\mathcal{F}$用内积函数来表示。下文主要介绍用户towers和物品towers。
先介绍下整体的网络框架结构:
典型的双塔结构,在user tower部分做的比较重,item tower部分做的比较轻量。user tower输出的用户表征向量和item tower输出的物品表征向量做点积得到预测值,再使用sampled softmax损失函数在全局item pool中进行优化。其中,
user tower包含三个重量的部分,
分别对应图中user tower的左侧、中间和上半部分。
item tower包含三个轻量的部分,
优化:
下面将分别围绕上述三个部分user tower, item tower和优化方法展开,最后介绍系统架构。
淘宝搜索的query通常是中文。经过query分词后,每个分词结果的长度通常小于3。因此,作者提出了一种【多粒度语义单元】来多粒度地挖掘query语义。具体而言,输入:
其中,词:$w_n \in \mathbb{R}^{1\times d}$,字:$c_m \in \mathbb{R}^{1 \times d}$,$q_k \in \mathbb{R}^{1 \times d}$,即:每个词、字、query整体的embedding维度数都设置为$d$。可以获得如下6种粒度的表征,$Q_{mgs} \in \mathbb{R}^{6 \times d}$,
最终,$Q_{mgs} \in \mathbb{R}^{6 \times d}$由上述6种拼接而成。具体计算公式如下:
其中,$Trm$即为Transformer,$q_{his}$的计算同$q_{seg}$。
可以看到,作者从两个方面来充分地对query进行语义表征,由此可以回答开篇的第一个问题,query如何充分地进行语义表征?
当然,只讲结果,没有讲为什么这么做。有点过于经验性/实验性驱动,而不是问题/动机驱动。
用户行为包括:用户的实时、短期或长期的点击或者购买行为。用户$u$在$t$时刻点击item $i$,用$i_t^u$来表示。对于物品$i_t^u$的表征向量,首先使用ID和side information(叶子类目、一级类目、品牌和所属店铺)做嵌入,然后对得到的嵌入向量做pooling或者拼接在一起。
不同于广告和推荐场景中常用的target-item注意力机制(如DIN,DIEN等),此处使用query注意力机制来捕捉用户历史行为和当前query的语义相关性。目的是发现哪些历史行为和本次query相关,来丰富用户在当前query下的语义/意图表征。比如:历史购买行为,篮球鞋、裙子,此次搜索query是红裙,显然篮球鞋历史行为(可能送人的)对此次query毫无帮助,直接引入还会带来噪声,而裙子历史行为对此次query是有帮助的。
具体而言,在搜索场景中,用户的历史行为和当前query可能都无关,参考[6]的做法,作者加了一个全零的向量到用户的行为数据中,来消除潜在噪声和解决用户历史行为和当前query可能完全无关的情况。
这个优化点非常巧妙,如果不加全零向量,模型无论如何都会强制关注到至少一个行为,这在历史行为和当前query都无关的时候,显然是噪声。加了零向量后,在完全无关的时候,模型attend到这个零向量即可,不会引入额外的噪声。个人认为这个优化点在搜索场景中至关重要,也是和推荐场景差别较大的地方,鲜有论文会提到这点。
接下来介绍如何融合用户的实时行为、短期行为和长期行为。
实时点击行为序列:$\mathcal{R}^u={i_1^u, …, i_t^u, …, i_T^u}$,其中,$i_t^u$是ID和辅助特征嵌入拼接在一起实现。
短期点击行为序列:$\mathcal{S}^u={i_1^u, …, i_t^u, …, i_T^u}$,其中,$i_t^u$是ID和辅助特征嵌入拼接在一起实现。
和实时行为序列表征相比,少了第一步LSTM,其它都一样。
长期点击/购买/收藏行为序列:$\mathcal{L}^u={i_1^u, …, i_t^u, …, i_T^u}$,考虑到线上用户行为变化很快,$i_t^u$是ID和辅助特征嵌入做mean pooling得到,和实时行为、短期行为中用的”拼接“方式不同。
除此之外,使用4种属性序列来描述1个月内用户的长期行为序列,包括:
每种属性行为使用用户的点击、购买、收藏行为来表示。例如:物品序列$\mathcal{L}_{item}^u$包含了用户的物品点击序列$\mathcal{L}_{\text{click_item}}^u$,购买序列$\mathcal{L}_{\text{buy_item}}^u$和收藏序列$\mathcal{L}_{\text{collect_item}}^u$,全部拼接在一起,形成长期行为序列,$L_{item}^u={0, h_{click}, h_{buy}, h_{collect}}$,可以看到同样添加了零向量。则,使用query对长期行为应用注意力机制捕捉这种长期行为表征。
$$
H_{\text{a_item}}=softmax(Q_{mgs} \cdot L_{\text{item}}^T) \cdot L_{\text{item}}^T \in \mathbb{R}^{6 \times d}
$$
则:长期行为表征向量为:$H_{long}=H_{\text{a_item}} + H_{\text{a_shop}} + H_{\text{a_leaf}} + H_{\text{a_brand}} \in \mathbb{R}^{6 \times d}$。
由此可以回答开篇的第二个问题,query注意力机制而非target-item注意力机制以及引入零向量,能够保证捕捉和query相关的历史行为信息。
输入:
使用自注意力机制来捕捉二者的关系。特别的,作者添加了$[CLS]$ token在首位,形成输入:$I={[CLS], Q_{mgs}, H_{real}, H_{short}, H_{long}}$。
输出:
然后将self自注意力机制的输出作为user tower的表征,$H_{qu} \in \mathbb{R}^{1 \times d}$
$$
H_{qu} = \text{Self_Att}^{first}([[CLS], Q_{mgs}, H_{real}, H_{short}, H_{long})
$$
$first$我理解是指用单头自注意力机制即可。$[CLS]$模仿BERT中的结构,可学习的向量,浓缩信息。
根据作者的实验经验,使用Item ID和Item的Title来获得Item的表征$H_{item}$。具体而言,给定item $i$的ID,其嵌入为:$e_i \in \mathbb{R}^{1 \times d}$。给定title的分词结果$T_i={w_1^i, w_2^i, …, w_N^i}$,得到物品的表征,$H_{item} \in \mathbb{R}^{1 \times d }$,即:
$$
H_{item} = e + tanh(W_t \cdot \frac{\sum_{i=1}^N w_i}{N})
$$
其中,$W_t$是可学习的变换矩阵。作者表示,通过实验发现,使用LSTM、Transformer等来捕捉title上下文感知的表征,其效果还不如上述简单的mean-pooling。给出的理由是:大部分的title由关键词堆叠而成,且缺乏语法结构。个人理解,可能想说字面上的语义信息足够凸显,上下文信号较弱,不需要复杂的模型来捕捉语义。
为了保证训练时的样本空间和在线推理时的样本空间一致,大部分工作会使用随机负采样的方法。但是这些工作都采用了pairwise hinge loss作为损失函数,只能进行局部的比较,和在线推理时需要的全局比较不一致。为此,作者使用了softmax交叉熵损失函数,具体而言,给定正样本$i^{+}$,
$$
\hat{y}(i^{+}|q_u) = \frac{\exp(\mathcal{F}(q_u, i^{+}))}{\sum_{i^{\prime} \in I}\exp(\mathcal{F}(q_u, i^{\prime}))}
$$
$$
L = -\sum_{i \in I} y_i \log(\hat{y}_i)
$$
$I$是全部的item集合。实际上就是softmax交叉熵损失,然后因为$I$的数量很大,使用sampled softmax来优化即可。此处没有太大的创新点。在sampled softmax中,仍然需要负样本,参考[2]京东的做法,作者使用同一个batch内的其它样本作为当前正样本$i^{+}$的负样本对,这个效果和使用随机任意的样本作为负样本差不多,而前者还能省不少计算资源。
接着,为了提高EBR系统的相关性,增加更多相关性的样本进入后续的排序阶段。作者提出了两种优化策略,
对训练集中的样本进行噪声平滑:作者引入了温度参数$\tau$。此处也没有什么太大的创新点。$\tau$无穷小时,相当于拟合one-hot分布,无限拉大正样本和负样本之间的差距;$\tau$无穷大时,相当于拟合均匀分布,无视正样本还是负样本。作者认为,训练集中用户的点击和购买行为包含有不少噪声数据,不仅受到query-product相关性的影响,也受到图片、价格、用户偏好等诸多因素的影响,即用户点击/购买的item不一定和query相关,如果一味地拟合点击/购买行为,可能会带来很多相关性问题,因此引入温度参数来平滑,温度参数参数越大,则平滑的作用越明显,让模型不去过分关注点击样本,也花点”心思”去关注没有点击但是可能是相关的样本。形如:
$$
\hat{y}(i^{+}|q_u) = \frac{\exp(\mathcal{F}(q_u, i^{+})/\tau)}{\sum_{i^{\prime} \in I}\exp(\mathcal{F}(q_u, i^{\prime})/\tau)}
$$
生成相关性增强的困难负样本:先前有些工作[8]会引入额外的人工标注数据来提升EBR模型的相关性。和这些工作不同,作者提出了一种在embedding空间自动生成困难负样本的方法。特别的,给定一个训练样本$(q_u, i^{+}, i^{-})$,其中$i^{-}$是随机负采样的item表征,$q_u$是用户表征,$i^+$是正样本item的表征,为了得到困难负样本:
使用$q_u$去Item Pool中找到和其点积最大的top-N个负样本集合:$I_{hard}$,然后通过插值的方式,来混合正样本$i^{+} \in \mathbb{R}^{1 \times d}$和困难负样本$I_{hard} \in \mathbb{R}^{N \times d}$,即:
$$
I_{mix} = \alpha i^{+} + (1-\alpha)I_{hard}
$$
$I_{mix} \in \mathbb{R}^{N \times d}$,形成N个困难负样本。其中,$\alpha \in \mathbb{R}^{N \times 1}$是从均匀分布$U(a,b)$中采样到的,$0 \leq a < b \leq 1$,显然,$\alpha$越接近1,生成的样本越接近正样本,即:生成的样本越困难。把生成的样本也纳入损失函数的计算:
$$
\hat{y}(i^{+}|q_u) = \frac{\exp(\mathcal{F}(q_u, i^{+})/\tau)}{\sum_{i^{\prime} \in I \cup I_{mix}}\exp(\mathcal{F}(q_u, i^{\prime})/\tau)}
$$
可以通过调参$a$和$b$来控制负样本的”困难程度”。
好奇的是,实现上如何高效地对$q_u$和Item Pool中所有负样本计算top-N点积?难道也是拿当前batch中的样本来计算的?另外,万一top-N里头存在相关的会有影响吗?
由此可以回答开篇的第三个问题,如何保证EBR系统的相关性。
最后,我们来欣赏下淘宝搜索引擎的系统架构。
搜索的整个过程如下:
本文重点在基于向量的检索:
还有个很重要的相关性模块还没有介绍。开篇提到过,EBR检索系统在个性化和模糊匹配方面做的很好,但是相关性上缺点也很大。归根结底在于,EBR不是完全匹配的方式,在搜索里,其实就是指不是Term Query。也即,结构化检索,比如品牌,颜色,类型等结构化字段,这些结构化字段能够很大程度上保证相关性。但是EBR却做不到这点。比如:用户检索阿迪达斯运动鞋,那么完全匹配查询能够去检索品牌:阿迪达斯,类目:运动鞋;但是EBR可能在embedding空间检索到耐克运动鞋,这显然是不相关的,会影响用户的体验。因此,作者在ANN结果的后面,又加了层相关性控制模块,对query进行了查询理解,识别出品牌、类目等意图,然后对item的title中也挖掘出品牌、类目等结构化字段,然后用这些查询理解的意图对item做term query,过滤掉未命中这些结构化字段取值的item。
作者还提到,Facebook[3]的文章是通过EBR系统来弥补基于完全匹配的检索系统在个性化、模糊匹配上的不足;而淘宝搜索出发点相反,是通过基于完全匹配的检索系统来提升EBR系统的相关性。总之,二者相辅相成。
离线实验以及实现细节也是工业界文章的核心亮点,值得大家好好品。
离线指标:
在线指标:
实现细节:
数据集,
淘宝真实的搜索行为数据集,2020年12月连续8天的点击和购买日志,过滤掉了作弊用户行为。
全量的候选item的数量级是1亿,和线上真实推断时的候选集保持一致。
Baseline:$\alpha$-DNN,MLP结构,很强的baseline。静态特征,统计特征,序列特征做pooling作为输入。怎么训练的没说清楚,难道是二分类任务?
MGDSPR:本文的方法,如上文所述。作者提到一点,加入统计特征到MGDSPR中,recall指标并没有提升。挺神奇的。
提升还是挺大的,尤其是相关性样本的占比,以及进入粗排的相关性item的数量。
几大组件,唯一没说清楚的是,不使用mgs, trm等时,用的什么做baseline?拼接?
看了消融实验,对召回指标帮助大的是mgs和trm;对相关性指标帮助大的是温度参数和困难负样本。
有挺大的线上指标提升。
其它的分析实验比较常规,总结下来就是:
总体而言,这篇文章干货很多,细读会发现很多细节。有几大亮点,
个人认为还有几个疑问没解释清楚:
困难负样本生成的时候,如何高效地对所有Item求点积最大的top-N?这里头Top-N是否有可能存在和当前query相关的item,是否会产生负面影响?
相关性模块:EBR和完全匹配的Term Query结果取交集保证相关性,那和直接用完全匹配做召回相比,增益在哪里?我理解这种只可能在召回候选集合item数量远大于排序候选集合item数量的时候才有效,EBR提前考虑了个性化因素,能够防止满足个性化需求的item无法进入排序阶段。
总之,同以往的EBR文章一样,值得细品和实践!
这是KDD 21工业界文章的第一篇分享,更多KDD 21 工业界文章参见:https://zhuanlan.zhihu.com/p/388115800
[1] Priyanka Nigam, Yiwei Song, Vijai Mohan, Vihan Lakshman, Weitian Ding, Ankit Shingavi, Choon Hui Teo, Hao Gu, and Bing Yin. 2019. Semantic product search. In Proceedings of the 25th ACM SIGKDD International Conference on Knowledge Discovery & Data Mining. 2876–2885.
[2] Han Zhang, Songlin Wang, Kang Zhang, Zhiling Tang, Yunjiang Jiang, Yun Xiao, Weipeng Yan, and Wen-Yun Yang. 2020. Towards Personalized and Semantic Retrieval: An End-to-End Solution for E-commerce Search via Embedding Learning. arXiv preprint arXiv:2006.02282 (2020).
[3] Jui-Ting Huang, Ashish Sharma, Shuying Sun, Li Xia, David Zhang, Philip Pronin, Janani Padmanabhan, Giuseppe Ottaviano, and Linjun Yang. 2020. Embedding-based retrieval in facebook search. In Proceedings of the 26th ACM SIGKDD International Conference on Knowledge Discovery & Data Mining. 2553–2561.
[4] Miao Fan, Jiacheng Guo, Shuai Zhu, Shuo Miao, Mingming Sun, and Ping Li. 2019. MOBIUS: towards the next generation of query-ad matching in baidu’s sponsored search. In Proceedings of the 25th ACM SIGKDD International Conference on Knowledge Discovery & Data Mining. 2509–2517.
[5] Tao Wu, Ellie Ka-In Chio, Heng-Tze Cheng, Yu Du, Steffen Rendle, Dima Kuzmin, Ritesh Agarwal, Li Zhang, John Anderson, Sarvjeet Singh, et al. 2020. Zero-Shot Heterogeneous Transfer Learning from Recommender Systems to Cold-Start Search Retrieval. In Proceedings of the 29th ACM International Conference on Information & Knowledge Management. 2821–2828.
[6] Qingyao Ai, Daniel N Hill, SVN Vishwanathan, and W Bruce Croft. 2019. A zero attention model for personalized product search. In Proceedings of the 28th ACM International Conference on Information & Knowledge Management. 379–388.
[7] Fuyu Lv, Taiwei Jin, Changlong Yu, Fei Sun, Quan Lin, Keping Yang, and Wilfred Ng. 2019. SDM: Sequential deep matching model for online large-scale recommender system. In Proceedings of the 28th ACM International Conference on Information & Knowledge Management. 2635–2643.
[8] Thanh V Nguyen, Nikhil Rao, and Karthik Subbian. 2020. Learning Robust Models for e-Commerce Product Search. arXiv preprint arXiv:2005.03624 (2020).
[9] Embedding-based Product Retrieval in Taobao Search: https://arxiv.org/abs/2106.09297
也欢迎关注我的公众号”蘑菇先生学习记“,更快更及时地获取推荐系统前沿进展!
]]>还有些研究点也是值得一读的,比如推荐系统中的冷启动,偏差与纠偏,序列推荐,可解释性,隐私保护等,这些研究很有意思和启发性,有助于开拓大家的研究思路**。
下面主要根据自己读题目或者摘要时的一些判断做的归类,按照推荐系统研究方向分类、推荐技术分类以及专门实验性质的可复现型文章分类,可能存在漏归和错归的情况,请大家多多指正。
信息茧房/回音室(echo chamber)/过滤气泡(filter bubble),这3个概念类似,在国内外有不同的说法。大致是指使用社交媒体以及带有算法推荐功能的资讯类APP,可能会导致我们只看得到自己感兴趣的、认同的内容,进而让大家都活在自己的小世界里,彼此之间难以认同和沟通。关于这部分的概念可参见知乎文章:https://zhuanlan.zhihu.com/p/71844281。有四篇文章探讨了这样的问题。
The Dual Echo Chamber: Modeling Social Media Polarization for Interventional Recommending
Tim Donkers and Jürgen Ziegler
I want to break free! Recommending friends from outside the echo chamber
Antonela Tommasel, Juan Manuel Rodriguez, and Daniela Godoy
Follow the guides: disentangling human and algorithmic curation in online music consumption
Quentin Villermet, Jérémie Poiroux, Manuel Moussallam, Thomas Louail, and Camille Roth
An Audit of Misinformation Filter Bubbles on YouTube: Bubble Bursting and Recent Behavior Changes
Matus Tomlein, Branislav Pecher, Jakub Simko, Ivan Srba, Robert Moro, Elena Stefancova, Michal Kompan, Andrea Hrckova, Juraj Podrouzek, and Maria Bielikova
此次大会在探索与利用上也有很多探讨,例如多臂老虎机、谷歌的新工作,即:用户侧的探索等。
Burst-induced Multi-Armed Bandit for Learning Recommendation
Rodrigo Alves, Antoine Ledent, and Marius Kloft
Values of User Exploration in Recommender Systems
Google, Minmin Chen, Yuyan Wang, Can Xu, Ya Le, mohit sharma, Lee Richardson, and Ed Chi
Designing Online Advertisements via Bandit and Reinforcement Learning
Yusuke Narita, Shota Yasui, and Kohei Yata
The role of preference consistency, defaults and musical expertise in users’ exploration behavior in a genre exploration recommender
Yu Liang and Martijn C. Willemsen
Top-K Contextual Bandits with Equity of Exposure
Olivier Jeunen and Bart Goethals
涉及排序学习的纠偏、用户的偏差探索等。
Debiased Explainable Pairwise Ranking from Implicit Feedback
Khalil Damak, Sami Khenissi, and Olfa Nasraoui
Mitigating Confounding Bias in Recommendation via Information Bottleneck
Dugang Liu, Pengxiang Cheng, Hong Zhu, Zhenhua Dong, Xiuqiang He, Weike Pan, and Zhong Ming
User Bias in Beyond-Accuracy Measurement of Recommendation Algorithms
Ningxia Wang, and Li Chen
利用图学习、表征学习等做冷启动。
Cold Start Similar Artists Ranking with Gravity-Inspired Graph Autoencoders
Guillaume Salha-Galvan, Romain Hennequin, Benjamin Chapus, Viet-Anh Tran, and Michalis Vazirgiannis
Shared Neural Item Representations for Completely Cold Start Problem
Ramin Raziperchikolaei, Guannan Liang, and Young-joo Chung
涉及离线或在线评估方法,准确性和多样性等统一指标的设计等。
Evaluating Off-Policy Evaluation: Sensitivity and Robustness
Yuta Saito, Takuma Udagawa, Haruka Kiyohara, Kazuki Mogi, Yusuke Narita, and Kei Tateno
Fast Multi-Step Critiquing for VAE-based Recommender Systems
Diego Antognini and Boi Faltings
Online Evaluation Methods for the Causal Effect of Recommendations
Masahiro Sato
Towards Unified Metrics for Accuracy and Diversity for Recommender Systems
Javier Parapar and Filip Radlinski
涉及session维度的短序列推荐;使用NLP中常用的Transformers做序列推荐的鸿沟探讨和解决,这个工作本人还挺感兴趣的,后续会精读下!
Next-item Recommendations in Short Sessions
Wenzhuo Song, Shoujin Wang, Yan Wang, and SHENGSHENG WANG
Transformers4Rec: Bridging the Gap between NLP and Sequential / Session-Based Recommendation
Gabriel de Souza Pereira Moreira, Sara Rabhi, Jeong Min Lee, Ronay Ak, and Even Oldridge
Denoising User-aware Memory Network for Recommendation
Zhi Bian, Shaojun Zhou, Hao Fu, Qihong Yang, Zhenqi Sun, Junjie Tang, Guiquan Liu, kaikui liu, and Xiaolong Li
Large-Scale Modeling of Mobile User Click Behaviors Using Deep Learning
Xin Zhou and Yang Li
结合联邦学习做隐私保护等。
Privacy Preserving Collaborative Filtering by Distributed Mediation
Alon Ben Horin, and Tamir Tassa
Stronger Privacy for Federated Collaborative Filtering With Implicit Feedback
Lorenzo Minto, Moritz Haller, Ben Livshits, and Hamed Haddadi
Black-Box Attacks on Sequential Recommenders via Data-Free Model Extraction
Zhenrui Yue, Zhankui He, Huimin Zeng, and Julian McAuley
Large-scale Interactive Conversational Recommendation System
Ali Montazeralghaem, James Allan, and Philip S. Thomas
EX3: Explainable Attribute-aware Item-set Recommendations
Yikun Xian, Tong Zhao, Jin Li, Jim Chan, Andrey Kan, Jun Ma, Xin Luna Dong, Christos Faloutsos, George Karypis, S. Muthukrishnan, and Yongfeng Zhang
Towards Source-Aligned Variational Models for Cross-Domain Recommendation
Aghiles Salah, Thanh Binh Tran, and Hady Lauw
利用视觉信息做推荐。
Ambareesh Revanur, Vijay Kumar, and Deepthi Sharma
Huiyuan Chen, Yusan Lin, Fei Wang, and Hao Yang
Local Factor Models for Large-Scale Inductive Recommendation
Longqi Yang, Tobias Schnabel, Paul N. Bennett, and Susan Dumais
Learning to Represent Human Motives for Goal-directed Web Browsing
Jyun-Yu Jiang, Chia-Jung Lee, Longqi Yang, Bahareh Sarrafzadeh, Brent Hecht, Jaime Teevan
探讨了美食场景下,多用户意图的推荐系统的交互设计。
“Serving Each User”: Supporting Different Eating Goals Through a Multi-List Recommender Interface
Alain Starke, Edis Asotic, and Christoph Trattner
涉及传统协同过滤、度量学习的迭代;新兴的图学习技术、联邦学习技术、强化学习技术等的探索。
Matrix Factorization for Collaborative Filtering Is Just Solving an Adjoint Latent Dirichlet Allocation Model After All
Florian Wilhelm
Negative Interactions for Improved Collaborative-Filtering: Don’t go Deeper, go Higher
Harald Steck and Dawen Liang
ProtoCF: Prototypical Collaborative Filtering for Few-shot Item Recommendation
Aravind Sankar, Junting Wang, Adit Krishnan, and Hari Sundaram
知识图谱的应用以及图嵌入技术和上下文感知的表征技术的融合,这两个工作个人都挺感兴趣。
Antonio Ferrara, Vito Walter Anelli, Tommaso Di Noia, and Alberto Carlo Maria Mancino
Marco Polignano, Cataldo Musto, Marco de Gemmis, Pasquale Lops, and Giovanni Semeraro
Partially Observable Reinforcement Learning for Dialog-based Interactive Recommendation
Yaxiong Wu, Craig Macdonald, and Iadh Ounis,
Pessimistic Reward Models for Off-Policy Learning in Recommendation
Olivier Jeunen and Bart Goethals
Hierarchical Latent Relation Modeling for Collaborative Metric Learning
Viet-Anh Tran, Guillaume Salha-Galvan, Romain Hennequin, and Manuel Moussallam
A Payload Optimization Method for Federated Recommender Systems
Farwa K. Khan, Adrian Flanagan, Kuan Eeik Tan, Zareen Alamgir, and Muhammad Ammad-ud-din
Stronger Privacy for Federated Collaborative Filtering With Implicit Feedback
Lorenzo Minto, Moritz Haller, Ben Livshits, and Hamed Haddadi
涉及训练、优化、检索、实时流等。
cDLRM: Look Ahead Caching for Scalable Training of Recommendation Models
Keshav Balasubramanian, Abdulla Alshabanah, Joshua D Choe, and Murali Annavaram
Reverse Maximum Inner Product Search: How to efficiently find users who would like to buy my item?
Daichi Amagata and Takahiro Hara
Page-level Optimization of e-Commerce Item Recommendations
Chieh Lo, Hongliang Yu, Xin Yin, Krutika Shetty, Changchen He, Kathy Hu, Justin M Platz, Adam Ilardi, and Sriganesh Madhvanath
Accordion: A Trainable Simulator for Long-Term Interactive Systems
James McInerney, Ehtsham Elahi, Justin Basilico, Yves Raimond, and Tony Jebara
Information Interactions in Outcome Prediction: Quantification and Interpretation using Stochastic Block Models
Gaël Poux-Médard, Julien Velcin, and Sabine Loudcher
Learning An Adaptive Meta Model-Generator for Incrementally Updating Recommender Systems
Danni Peng, Sinno Jialin Pan, Jie Zhang, and Anxiang Zeng
Recommendation on Live-Streaming Platforms: Dynamic Availability and Repeat Consumption
Jeremie Rappaz, Julian McAuley, and Karl Aberer
Reproducibility papers可复现实验性质的文章,共3篇。分别探索了:序列推荐中的采样评估策略;对话推荐系统中生成式和检索式的方法对比;神经网络推荐系统和矩阵分解推荐系统的对比。
A Case Study on Sampling Strategies for Evaluating Neural Sequential Item Recommendation Models
by Alexander Dallmann, Daniel Zoller, Andreas Hotho (Data Science Chair, University of Würzburg, Würzburg, Germany)
Generation-based vs. Retrieval-based Conversational Recommendation: A User-Centric Comparison
by Ahtsham Manzoor and Dietmar Jannach (University of Klagenfurt, Klagenfurt, Austria)
Reenvisioning the comparison between Neural Collaborative Filtering and Matrix Factorization
*by Vito Walter Anelli (Polytechnic University of Bari, Bari, Italy), Alejandro Bellogin (Information Retrieval Group, Universidad Autonoma de Madrid, Madrid, Spain), Tommaso Di Noia Polytechnic (University of Bari, Bari, Italy), and Claudio Pomo (Polytechnic University of Bari, Bari, Italy)
通过论文的整理和分类,笔者也发现了一些自己感兴趣的研究点,比如:推荐系统的回音室效应探讨文章;Transformers在序列推荐和NLP序列表征中的鸿沟和解决文章:Transformers4Rec;图嵌入表征和上下文感知表征的融合文章;NCF和MF的实验对比文章;谷歌的用户探索文章等。希望读者也能够发现自己感兴趣的文章。下期分享见!
也欢迎关注我的公众号”蘑菇先生学习记“,更快更及时地获取推荐系统前沿进展!
]]>文章的方法很简洁,这种思想和陈丹琦的工作,基于对比学习的句子表征SimCSE[4]有异曲同工之处,值得借鉴到实际的图表征学习中。相应的代码也开源在:https://github.com/wujcan/SGL[3]。感兴趣的同学可以去阅读一下。
欢迎关注我的公众号”蘑菇先生学习记”,更快更及时地获取关于推荐系统的前沿进展!
解决目前基于user-item二分图表征学习的推荐系统面临的两大核心问题:
因此,作者提出了图自监督学习的方法SGL(Self-supervised Graph Learning),来提高基于二分图推荐的准确性和鲁棒性。
核心的思想是,在传统监督任务的基础上,增加辅助的自监督学习任务,变成多任务学习的方式。具体而言,同一个结点先通过数据增强 (data augmentation)的方式产生多种视图(multiple views),然后借鉴对比学习(contrastive learning)的思路,最大化同一个结点不同视图表征之间的相似性,最小化不同结点表征之间的相似性,实际上是一个self-discrimination的任务。对于数据增强,对同一个结点,为了产生不同的视图,使用了3种方式,从不同维度来改变图的结构。包括,结点维度的node dropout;边维度的edge dropout(能够降低高度结点的影响力);图维度的random walk。这种图结构的扰动和数据增强操作,能够提高模型对于噪声交互的鲁棒性。
SGL方法和具体使用的图模型无关,可以和任意的图模型搭配使用。作者在LightGCN[2]的基础上,来引入SGL图自监督学习方法。通过对比学习范式的理论分析,阐明了SGL能够有助于挖掘困难负样本(hard negatives),不仅提高了准确性,也能够提高训练过程收敛速度。通过在三个数据集上的经验性分析,也能够阐明这个SGL的有效性,尤其是在长尾items的推荐准确性以及对于噪声交互数据的鲁棒性。
开篇已经对文章的方法做了总结,即:先做数据增强操作,来产生多种视图;然后通过图编码的方式形成不同视图下的结点表征,并在这些视图表征上做对比学习。最后将对比学习辅助目标和传统的监督目标融合在一起,形成多目标学习的范式。
先看一下GNN进行结点编码的范式:
$$
\boldsymbol{Z}_1^{(l)}=H(\boldsymbol{Z}_1^{(l-1)}, \mathcal{G}),
$$
输入:上一层的结点表征向量和原始图,输出:该层的结点表征向量。具体的卷积步骤,可以参考LightGCN[2]的做法,这里不做过多赘述。
在本文中,要做个小变化,即:原始图$\mathcal{G}$要进行dropout操作$s(\mathcal{G})$,要做两次,形成两个子视图。形式化地,
$$
\boldsymbol{Z}_1^{(l)}=H(\boldsymbol{Z}_1^{(l-1)}, s_1(\mathcal{G})), \boldsymbol{Z}_2^{(l)}=H(\boldsymbol{Z}_2^{(l-1)}, s_2(\mathcal{G})),
$$
下标1和2代表两次完全独立的dropout操作,形成2个视图$s_1(\mathcal{G})$和$s_2(\mathcal{G})$,再各自进行卷积操作得到结点的表征$\boldsymbol{Z}_1^{(l)},\boldsymbol{Z}_2^{(l)}$。具体的dropout操作包括如下三种:
Node Dropout:以一定的概率丢掉结点以及和该结点相连的边。
$$
s_1(\mathcal{G}) = (\boldsymbol{M}^{\prime} \odot \mathcal{V}, \mathcal{E}), s_2(\mathcal{G}) = (\boldsymbol{M}^{\prime\prime} \odot \mathcal{V}, \mathcal{E})
$$
其中,$\boldsymbol{M}^{\prime}, \boldsymbol{M}^{\prime\prime} \in {0,1}^{|\mathcal{V}|}$是掩码向量,通过伯努利分布$m \sim \text{Bernoulli}(\rho)$来随机生成,其中$\rho$是dropout概率。$\boldsymbol{M}^{\prime}, \boldsymbol{M}^{\prime\prime}$完全独立。
Edge Dropout:以一定的概率丢掉部分边。
$$
s_1(\mathcal{G}) = (\mathcal{V}, \boldsymbol{M}_{1} \odot \mathcal{E}), s_2(\mathcal{G}) = (\mathcal{V}, \boldsymbol{M}_{2} \odot \mathcal{E})
$$
类似Node Dropout,只不过对边做的。
Random Walk:前两种方法,产出的子视图在不同的卷积层之间是共享的,即:不同卷积层面对的子视图是一样的。random walk想要产生layer-aware的子视图,即:不同卷积层输入的图是不一样的,这个实现方式就是针对不同卷积层,都随机生成不同的掩码向量,实现方式也是通过dropout实现的,不同层子图不一样,达到类似随机游走的效果。
$$
s_1(\mathcal{G}) = (\mathcal{V}, \boldsymbol{M}_{1}^{(l)} \odot \mathcal{E}), \ \ s_2(\mathcal{G}) = (\mathcal{V}, \boldsymbol{M}_{2}^{(l)} \odot \mathcal{E})
$$
和edge dropout的差异体现在掩码向量是layer-aware的,多了个上标$(l)$。
举例如下图,
同一个结点在不同视图下,可以产生不同的表征向量。作者将同一结点不同视图下的表示看成一对正样本,即:${(\boldsymbol{z}_u^{\prime}, \boldsymbol{z}_u^{\prime\prime})|u \in \mathcal{U}}$,而不同结点的表征看成一对负样本,即:${(\boldsymbol{z}_u^{\prime}, \boldsymbol{z}_v^{\prime\prime})|u,v \in \mathcal{U}, u \neq v}$。对比学习的目标期望最大化同一结点不同视图表征向量之间的相似性,最小化不同结点表征之间的相似性。采用了类似SimCLR[5]中的InfoNCE[6]的目标,即:
$$
\mathcal{L}_{ssl}^{user}=\sum_{u \in \mathcal{U}} - \log \frac{\exp(s(\boldsymbol{z}_u^{\prime},\boldsymbol{z}_u^{\prime\prime})/\tau)}{\sum_{v \in \mathcal{U}} \exp(s(\boldsymbol{z}_u^{\prime},\boldsymbol{z}_v^{\prime\prime})/\tau)}
$$
$s$是相似性函数,作者采用的是cosine相似性,$\tau$是温度参数。item侧和user侧是对称的,同理可以得到。则最终的自监督学习损失函数为:
$$
\mathcal{L}_{ssl} = \mathcal{L}_{ssl}^{user} + \mathcal{L}_{ssl}^{item}
$$
和推荐系统常用的BPR-pairwise损失函数$\mathcal{L}_{main}$结合起来做联合训练,即:
$$
\mathcal{L} = \mathcal{L}_{main} + \lambda_1 \mathcal{L}_{ssl} + \lambda_2 ||\Theta||_2^2
$$
值得注意的是,$\mathcal{L}_{ssl}$没有引入任何学习参数,因此最后一项正则化项都是图卷积神经网络的参数。
这个部分是全文最精彩的地方,作者从梯度贡献角度来理论地分析了SGL方法为何会有效。作者分析了其中重要的一个原因,SGL有助于挖掘困难负样本,这部分样本能够贡献取值大且有意义的梯度,来引导结点的表征学习。
首先,对某个结点$u$,求$\mathcal{L}_{ssl}^{user}(u)$关于$\boldsymbol{z}_u^{\prime}$的导数。
$$
\frac{\partial \mathcal{L}_{ssl}^{user}(u)}{\partial \boldsymbol{z}_u^{\prime}} = \frac{1}{\tau || \boldsymbol{z}_u^{\prime}||} \{c(u) + \sum_{v \in \mathcal{U} \text{/} {u}} c(v) \}
$$
$c(u)$衡量了正样本$u$对于$\boldsymbol{z}_u^{\prime}$梯度的贡献度,${v}$衡量了负样本$v$对于$\boldsymbol{z}_u^{\prime}$梯度的贡献度。其中,
$$
c(u)=\left(s_u^{\prime \prime} - ({s_u^{\prime}}^T s_u^{\prime \prime})s_u^{\prime}\right)(P_{uu}-1)
$$
$$
c(v)=\left(s_v^{\prime \prime} - ({s_u^{\prime}}^T s_v^{\prime \prime})s_u^{\prime}\right)P_{uv}
$$
$P(uv)=\frac{\exp({\boldsymbol{s}_u^{\prime}}^T \boldsymbol{s}_v^{\prime\prime})/\tau)}{\sum_{v \in \mathcal{U}} \exp({\boldsymbol{s}_u^{\prime}}^T \boldsymbol{s}_v^{\prime\prime})/\tau))}$即为softmax概率值,其中$s_u^{\prime}=\frac{z_u^{\prime}}{||z_u^{\prime}||}$是$u$结点在对应视图下表征的归一化值,$s_u^{\prime \prime}$同理。我们重点关注下负样本$v$对于梯度的贡献度,即$c(v)$,用L2范数来衡量梯度贡献度,即:
$$
||c(v)||_2 \propto \sqrt{ 1-({\boldsymbol{s}_u^{\prime}}^T \boldsymbol{s}_v^{\prime\prime})^2} \exp{({\boldsymbol{s}_u^{\prime}}^T \boldsymbol{s}_v^{\prime\prime}/\tau)}
$$
又因为$s_u^{\prime}, s_v^{\prime \prime}$都是单位向量,引入$x={\boldsymbol{s}_u^{\prime}}^T \boldsymbol{s}_v^{\prime\prime} \in [-1,1]$来简化式子,即:
$$
g(x) = \sqrt{1-x^2} \exp(\frac{x}{\tau})
$$
其中,$x$也直接反映了正样本$u$和负样本$v$之间的相似性。根据$x$的取值,可以把$v$分为两类:
简单负样本,$-1 \leq x < 0$,即:$v$和$u$不相似,很容易区分开。
为了观察困难负样本和简单负样本对于梯度的贡献情况,作者画出了$g(x)$随着$x$取值变化的变化情况:
(a)是$\tau=1$时的情况,可以看出$g(x)$位于$(0,1.5)$之间,随着$x$的变化,$g(x)$的变化幅度很小,也即:不管是困难负样本还是简单负样本,对于梯度的贡献差距不是很大。
除此之外,作者还做了一些复杂度的分析,相比于LightGCN,主要多的复杂度就是数据增强操作,即对邻接矩阵来做;以及自监督学习任务,这个的复杂度主要在于负样本选取,优化思路是拿同一个batch内其他的结点作为负样本,而不是整个图上所有其他结点都作为负样本。总体上,复杂度略涨,是在可以接受的范围内。
可以看出,SGL-ED使用edge dropout的SGL效果比LightGCN好不少。
长尾物品的推荐有效性的经验性分析,即:为何能够对长尾物品的推荐有帮助。
作者按照结点度的大小来对结点分组,度数越小则越长尾,然后看看SGL和LightGCN在不同组上的推荐性能差异。
如上图所示,SGL在低度的组别上(分组ID越小,度数越小),指标比LightGCN高不少;在高度的组别上,不相上下,LightGCN有的略好一些。这从经验上说明了SGL对于长尾物品推荐的有效性。
更深入的原因作者没有分析。不过,从这种实验结果可以看出,SGL自监督学习的范式对于长尾、稀疏交互的场景是很有效果的。
验证SGL的鲁棒性。方法也很简单粗暴,在训练集中加入对抗样本,即一定比例的user-item未交互的样本,然后看SGL和LightGCN在测试集上的表现。
可以看出,SGL依然完虐LightGCN。作者给出的原因是,通过对比学习同一结点的不同视图表征,模型能够有效地发现最有意义的模式,尤其是结点的图结构,使得模型不会过于依赖某些边。总而言之,SGL提供了一种能够去掉噪声交互信息的方法。
温度参数$\tau$的选择,不宜过大,也不宜过小。
可以看出,$\tau=0.2$的时候最佳。
预训练的有效性,自监督的另一种方法是先自监督地预训练结点向量,然后用于初始化结点向量,再通过推荐监督任务来finetune。最终的效果是,SGL-ED>SGL-pre >LightGCN。说明预训练方式也是有效的。
负采样方法,
SGL-ED > SGL-ED-batch > SGL-ED-merge。SGL-ED-batch和SGL-ED差距不是非常大,说明batch内采样是个很好地优化方法。
SGL的收敛速度快,这主要得益于困难负样本。值得一提的是,作者提到了一个很有意思的店,SGL的BPR损失下降和Recall指标的上升存在时间上的小gap,说明了BPR损失在排序任务中不一定是最优的。
1 | Another observation is that the origin of the rapid-decline period of BPR loss is slightly later than the rapid-rising period of Recall. This indicates the existence of a gap between the BPR loss and ranking task。 |
SGL方法很简洁,可以快速结合各种图模型,在各种各样的推荐任务上尝试。实验论证也做的非常充分,是个很有借鉴意义的工作。整篇文章看下来,最大的收获是,对比学习的理论分析以及为何能够解决长尾推荐和对噪声交互有鲁棒性的实验论证。作者给出了一些经验的分析,可能缺一些更细致深入的剖析,但是从直觉上给到了很重要的原因。按照我的理解,总结两点,
通过数据增强来改变图结构,使得图模型于不会过于依赖某些边或者某些高度结点。
通过对比学习同一结点的不同视图表征,模型能够有效地发现最有意义的模式,尤其是结点的图结构信息,同时还能挖掘困难负样本,提高模型的区分能力。
更多基于二分图的推荐系统文章请参见:
基于二分图表征学习的推荐系统调研:https://zhuanlan.zhihu.com/p/110682271
MM’19 | MMGCN 面向短视频推荐的多模态图神经网络
[1] SIGIR21,Self-supervised Graph Learning for Recommendation
[2] SIGIR20,LightGCN:Simplifying and powering graph convolution network for recommendation
[3] SGL源代码:https://github.com/wujcan/SGL
[4] SimCSE: Simple Contrastive Learning of Sentence Embeddings:https://arxiv.org/abs/2104.08821
[5] SimCLR: A Simple Framework for Contrastive Learning of Visual Representations. CoRR 2020
[6] InfoNCE:Michael Gutmann and Aapo Hyvärinen. 2010. Noise-contrastive estimation: A new estimation principle for unnormalized statistical models. In AISTATS, Vol. 9. 297–304.
[7] CoRR20,Self-supervised Learning for Deep Models in Recommendations.
[8] WWW18,Variational Autoencoders for Collaborative Filtering
[9] SIGIR19, NGCF,Neural Graph Collaborative Filtering
也欢迎关注我的公众号”蘑菇先生学习记“,更快更及时地获取推荐系统前沿进展!
]]>欢迎关注我的公众号”蘑菇先生学习记”,更快更及时地获取关于推荐系统的前沿进展!
概念(Concept)蕴含着世界知识,指导着人类认知的发展。从海量的web文档中挖掘概念并构建相应的标签体系在文本理解领域是非常重要的研究问题。但是目前为止,大部分工作都是从百科或者网页文章中提取通用、浅层、粗粒度的概念,和用户认知视角以及用户兴趣并不一致。举个例子:”丰田4Runner”是一款”丰田SUV”(浅层概念),但用户可能更感兴趣的点在于:”底盘高的汽车”或者”越野型汽车”。为此,这篇文章提出了ConcepT概念挖掘系统,通过海量的用户查询和搜索点击日志,能够挖掘以用户为中心、符合用户兴趣的概念。进一步,作者提出了一种文档概念标签打标的方法并构建了topic-concept-instance的三级标签体系,应用于腾讯QQ浏览器的搜索引擎和新闻feeds推荐系统中,能够有效提高feeds的分发效率和搜索引擎的用户体验。
核心的工作包括如下几个部分:
候选概念挖掘。从海量的query日志中挖掘候选的概念。包括了两种无监督策略和一种监督策略。
无监督策略,(1) 基于模式匹配的自助法。通过预定义的pattern来找到新的概念;同样,通过新的概念来反向补充和丰富pattern池;进一步,通过新发现的pattern,继续去找新的概念。周而复始,可以发现很多概念。(2) 查询词-标题对齐法。核心假设在于是query中重要的概念一定会在用户点击的文档标题中反复出现。这样可以从标题中挖掘出用户意图导向的概念。
监督策略,基于无监督方法挖掘出来的种子概念集构造监督训练集,训练一个CRF序列标注模型和质量判别模型。质量判别模型用于控制CRF抽取的concept的质量。
文档概念打标。包括了两种方法。 (1) 基于匹配的方法。挖掘文档的关键实例(key instances),然后基于key instances和concept之间的匹配,前提是key instances和concept之间是isA关系,且出现在已经构建好的标签体系中。(2) 基于概率推断的方法。基于key instances的上下文词相关的concept,来给文档打标,主要解决concept未出现在文档中的情况。比如:一篇文档中的关键词包括:芹菜,全麦面包,番茄,那么可能可以推断出”减肥饮食”的概念标签。
标签体系构建。 三层标签体系。topic-concept-instance,主题-概念-实例。三者之间的关系是isA。
在QQ浏览器的搜索推荐场景上都取得了好的离线和线上效果。
总体上对方法做个梳理。
先直观感受下从query中挖掘出来的概念。
再总体一览下三种挖掘概念的方法:从query以及title中挖掘概念。根据右侧图例来对照看。
英文是:Bootstrapping by Pattern-Concept Duality。目标是从query中抽取出符合模式的概念。如图1所示,最上面的一行。包括如下步骤:
附录中还提到了,作者随机从1个月的搜索日志中抽取了15000条query,然后用模式匹配自助法抽取了一批concept,再经过腾讯的产品经理人工校验了一下。最终形成了一批种子concept集合,每个concept也记录了其来源的query,因此实际上也隐含着有一批种子query集合。
英文名是:Concept mining by query-title alignment。上述Boostraping法抽取能力太有限,精度很高,但召回率很低。查询-标题对齐法的目标是从query和top点击的titles中抽取出概念,即:利用了query和用户的点击行为中蕴含的doc标题信息。直觉来源在于,用户搜索的query中的concept通常是和用户点击的doc的title强相关。比如:用户的query是”好看的香港僵尸电影”,出来的doc的标题可能是”香港最后一部僵尸电影”或者”香港搞笑僵尸电影”。即:title能够更好地传达出query本身的语义信息和用户感兴趣的点。这个例子中,抽取到的concept为”香港僵尸电影”。那怎么抽取出这样的concept呢?
对每个query $q$,通过统计所有用户点击数据,获取top个点击的doc的title集合$T^q$。具体而言,作者统计了1个月内点击次数超过5次的title加入top title集合。
对每个query $q$和title $t \in T^q$,遍历序列获取所有的N-grams(存疑,字粒度还是词语粒度?推测是词语粒度)。
遍历query和title的所有子串,比较query的n-gram子串和title的m-gram子串,将title的子串选作候选的concept当且仅当 (1)title子串包含所有query子串中的词,且词之间相对的序都相同;(2) query子串和title子串各自的头部词相同,尾部词也相同。 比如:
query:”好看的香港僵尸电影”的子串”香港僵尸电影”;
title:”香港最后一部僵尸电影”的子串”香港最后一部僵尸电影”。
条件(1)满足,title子串包含了query子串所有词”香港僵尸电影”;条件(2)满足头部词”香港”相同,尾部词”电影”相同。因此,”香港最后一部僵尸电影“可以选作候选概念。当然这个候选概念粒度太细,后续质量控制会被过滤掉。
可以推测,上述query也是有一定的选取规则来把控质量的。比如从1.1中选出来的种子query集合对应的top titles中抽取。
英文名是:Supervised Sequence Labeling。训练一个CRF模型来标注带概念词的序列,包括query和title。监督标注数据的来源是前面两种方法,即boostrapping和query-title对齐法中挖掘到的概念。按照我的理解,序列标注监督数据是这么构造的:
boostraping方法的query序列:根据挖掘到的concept,就可以给原始query打上标注,concept词序列的起始词用B,中间词用I,其它词用O。比如:”十大游戏手机”中挖掘到concept为:”游戏手机”。那么”十大游戏手机”的标注为:
1 | 十 大 游 戏 手 机 |
query-title对齐方法的title序列。比如,query:”好看的香港僵尸电影”,title:”十大香港僵尸电影”,抽取到的concept为:香港僵尸电影。显然用上述方法,可以对query和title都打上标注。
有了序列标注数据,那么就可以训练CRF模型了。训练的时候,会提取序列中每个token的特征,比如词性、实体标签、上下文特征(e.g., 前后序词的词性pair)等。如下:
作者用CRF++ v0.58来训练,80%训练集,10%验证集,10%测试集。CRF对于那些有明显非概念词作为边界的短文本挖掘很有效,比如”省油的汽车有哪些?”中的概念”省油的汽车”。对于那些概念分散在多处的效果则一般,比如:”父母过生日准备什么礼物?” 的概念”父母生日礼物“。后者使用query-title对齐方法更好。(btw, 个人不认为这个例子query-title对齐方法能抽取出来父母生日礼物,query-title是基于n-gram匹配的,这个例子中”父母生日礼物”这个n-gram不符合3.1.2中的条件,即:title子串包含所有query子串中的词)。
英文名是:A Discriminator for quality control。上述方法挖掘出来的concept并不都是高质量的,有的粒度太粗,有的太细。比如:香港最后一部僵尸电影,粒度过细,很少有用户这么搜。因此,本部分主要为了训练一个质量判别分类器,用于判断抽取出来的候选概念短文本是否是合适且恰当的concept。
作者做了一个简单的分类器GBDT/LR,统计了每个候选concept的一些特征,比如:是否出现在某个query中,被搜索多少次,文本词袋向量,query对应的用户点击文档的主题分布等。具体的特征如下表所示:
上述数据的标签是人工标注的。作者说只需要300个样本就能够训练一个好的分类器。这有点不可思议。说明存在超强特征,比如被搜索的次数等。但个人仍然存疑。
先直观感受下打标的例子。如下图所示,第二条新闻打上了油耗低的车这以concept。
下图是整个文档打标的流程图。包括了keyword instances抽取,再基于key intances和concept二者之间的关联来打标,打标的方法包括:基于匹配的打标和基于概率推断的打标。
上图3左下角部分对应key instance的抽取过程。
先基于监督方法GBRank[4]对文档的words进行排序,GBRank是一种pair-wise的排序学习方法,主要是基于doc - key instance pairs数据来训练,输入的特征包括词频、词性、实体等信息。这部分重点是doc-key instance pairs怎么来?文中没仔细说明。下表是输入特征。
对TopK(原文取10)排序好的词进行词向量表征,用到方法[5]。这部分用word2vec,GloVe,BERT等词向量个人认为也是可行的。
对TopK的词,基于词向量之间的cosine相似性构造带权无向图。
使用TextRank[6]无监督方法来做重排序并打分。
保留分数大于$\delta_{w}$(原文取0.5)的关键词,作为抽取到的doc的key intances。
作者的经验是,采用GBrank和基于词向量的TextRank能够很好地抽取出和doc主题一致的关键词。
基于概率推断的打标法,核心问题在于估计$p(c|d)$,其中$c$是待打的concept,$d$是待打的doc。作者做了两步的链式法则拆解:
第一步:用key intances来表示$d$;第二步,用key instances的上下文词来代表key instances。
首先是第一步,用key intances来表示$d$,则可以根据链式法则拆解$p(c|d)$为:
$$
p(c|d)=\sum_{i=1}^{|E^d|} p(c|e_i^d) p(e_i^d|d)
$$
其中,$E^d$是doc $d$的所有key instance集合。$p(c|e_i^d)$衡量了key instance $e_i^d$和concept $c$之间的关联性;$p(e_i^d|d)$则衡量了doc $d$和key instance $e_i^d$之间的关联性,可以用$e_i^d \in E^d$在$d$中词频分布来表示。因此核心问题转成了:如何表示 $p(c|e_i^d)$。
第二步,作者进一步用链式法则,用key instance $e_i^d$的上下文词和$c$的关联性来表示,
$$
p(c|e_i^d) = \sum_{j=1}^{|X_{E_d}|} p(c|x_j) p(x_j | e_i^d)
$$
$X_{E_d}$是key instance $e_{i}^d$的上下文词的集合,$p(x_j|e_i^d)$正比于上下文词$x_j$和$e_i^d$之间的共现概率。如果两个词出现在1个句子中,则共现。因此,可以求$x_j$和$e_i^d$同时出现在一句话中的次数,除以$e_i^d$出现总次数,来求$p(x_j|e_i^d)$。
因此,问题转成了求 $p(c|x_j)$,即:concept $c$和上下文词$x_j$的关联性。这个关联性作者用字符串的匹配程度来表示,即:如果上下文词$x_j$包含在$c$的某个子串中,则存在关联。比如concept为”省油的汽车”,上下文词为”省油”,则”省油的汽车”包含”省油”。为了估计$p(c|x_j)$,就去看包含$x_j$子串的concept集合$C^{x_j}$大小,这个集合中的concept平分这个概率,不包含$x_j$的concept则概率为0。
$$
p(c|x_j) = \frac{1}{|C^{x_j}|}, x_j为c的子串
$$
这种方式在key instances和concept存在isA关系时使用。首先定义isA的关系。concept和instance之间的isA关系。根据concept的修饰词和query(或title)中的修饰词的对齐来抽取。比如:某个concept是”省油的汽车”,抽取包含”省油的”修饰词的query(或者title),比如”省油的丰田RAV4”,从中抽取到instance “丰田RAV4”,这样instance”丰田RAV4”和concept”省油的汽车”之间就是isA关系。concept和instance的isA关系可以提前算好。当然,通过这种规则后,可能还需要人工检查或者进一步做语义匹配建模。
有了isA关系后,接着介绍基于匹配打标法。给定:doc文档title,doc文档的候选key instance集合,以及每个key instance对应的isA的concept集合,目标是去给doc打上某个concept标签。
根据key instance获取isA对应的concept:比如:某个doc的key instance为”白雪公主”,对应的isA的concept为”睡前故事”,”童话故事”。
丰富concept的表示:对每个候选的concept,作者用top 5用户点击的链接的title(应该是concept的来源title)来丰富其表示,即:concept和top5 title拼接在一起,比如: concept:”睡前故事”;top的title:”儿童睡前故事”,”白雪公主和七个小矮人”。二者拼接在一起,睡前故事, 儿童睡前故事, 白雪公主和七个小矮人,…。并用TF-IDF向量来表示,即:所有词典上每个词的tf-idf值构成的向量,维度为词典大小。”童话故事”也同理。可以获得每个concept的tf-idf向量。
这种方法和3.2的区别在于,3.2中找不到key instance和concept之间的isA强关联关系,退而求其次,用key instance的上下文词和concept之间关联关系来间接表示。3.3中,因为key instance和concept之间存在isA强关联关系,因此要合理利用。即:先找到key instance的isA关系的concepts,如果key instance抽取得更好,理论上可以直接打上该concept标签。但是作者做了进一步的校验,用title-enriched的concept的tf-idf向量和doc的title的tf-idf向量相似性来做限定,核心假设在于key instance如果够好,应该传达的主题和title是近似的,因此用instance的isA关系的concept和title做了相似性校验。
作者构造了3级标签体系,即:主题-概念-实例,topic-concept-instance。其中,
进一步细看图4中的三级分类体系,是一个有向无环图,有向边意味着isA关系。concept和instance之间的isA关系前文已经提到。剩下就是topic和concept之间的关系。作者采用的方法如图6所示,先用词向量+max pooling的方式表征doc(标题,作者,doc内容),再通过DNN模型来做主题的多分类任务,输出doc的分类。作者提到在一个35,000个新闻文章标注数据上可以达到95%的准确率。
但现在的目标是求topic和concept的关系。怎么做呢?通过doc来做桥梁。
给定一个concept $c$和topic $p$,假设有$n_c$个doc包含了该concept标签,其中有$n_p^c$个文档属于主题$p$,那么可以估计$P(p|c)=n_{p}^c / n^c$,这个大于某个阈值$\delta_t$(作者取0.3)则认为该doc和该topic存在isA关系。
搞了一个开源的小数据集来做评估。User-Centered Concept Mining Dataset (UCCM),是从QQ浏览器的query日志中抽样的。数据开源在github [8],数据示意图如下:
针对concept的挖掘,对比了如下几种keyword抽取的方法,
对于TextRank,THUCKE,AutoPhrase,输入:用户query和点击的title的拼接,输出top 5关键词或短语,选出和query词重叠最多的关键词或短语作为最终结果。
指标:完全匹配Exact Match(EM)和F1。EM就是看挖掘出的词和人工打标的词的完全匹配占比;F1看挖掘的词和人工打标的词之间的重叠tokens的比例。
从表中结果可以看出差距很大。但是个人对对比方法的结果存在质疑。比如:AutoPhrase的结果这么差,是不是作者用的不恰当?作者解释是说这些方法适合从长文本中去提取,而本文的方法是适用于query/title的短文本中去提取。那么为什么不去对比适用于短文本抽取的方法呢?
作者人工标注了一份doc和concept的数据,参见github [8]中的concept_tagging_data.txt。打标的精确率可以达到96%。
对于类目体系的评估,作者从这个体系中随机抽取了1000个concepts。作者只针对concept和instance之间的isA关系做评估,因为这二者的关系对于查询理解非常重要。此处的评估主要靠人工判断,判断是否是isA关系。准确率为96.59%。
框架如下图所示,用户和文档都会打上topic,concepts和instances的画像信息。召回的时候,根据二者画像的匹配来做;然后用ctr模型来排序并推荐。
AB实验方法,将用户分桶,每个桶包括80W用户,观察每个桶的的多种指标:
从中选出两个上述指标最相近的桶,排除其他干扰因素,然后用这个两个桶做对比实验。1个桶用concept的文档标注做召回推荐,1个桶不用。跑了3天的线上实验,重点关注UD和IE。
可以看出每个指标都涨了,尤其是IE。
基于query改写来做离线的用户体验调研。挑了108个query,对每个query $q$,通过ConcepT系统分析出concept,然后取出该concept对应的isA关系的instances。对每个instance $e$,分别将原始query做改写,形如$q \ e$。然后用百度搜索来测试用户体验:
作者找了3个人来判断query和结果的相关性。结论是经过改写,相关性从73.1%提高到了85.1%。原因是,concept能够辅助理解用户意图。
这篇文章很偏工程化,比较适合落地实践。全文技术上的亮点很少,主要是成熟的技术、规则来结合具体的业务场景做定制和实践。但是,对于实践而言,这篇文章的信息量很丰富,很多行之有效的简单方法值得在内容理解,查询理解上应用。但是也不得不提,要想很好得借鉴和落地,需要非常强的领域知识,尤其是pattern的设计,因此仍然需要大量底层的工作,而无法直接借用文中开源的一些seed patterns。总而言之,是一篇真实应用落地的好文,但是离一把梭距离比较远,可以借鉴其中的一些思路做尝试。
[1] A User-Centered Concept Mining System for Query and Document Understanding at Tencent:https://arxiv.org/abs/1905.08487
[2] KDD | 用户视角看世界:腾讯提出ConcepT概念挖掘系统,助力推荐搜索,https://cloud.tencent.com/developer/article/1458043
[3] 腾讯提出概念挖掘系统ConcepT-学习笔记,https://zhuanlan.zhihu.com/p/85494010
也欢迎关注我的公众号”蘑菇先生学习记“,更快更及时地获取推荐系统前沿进展!
]]>欢迎关注我的公众号”蘑菇先生学习记”,更快更及时地获取关于推荐系统的前沿进展!
为了解释这两句话,我们不妨从一个简单的例子入手来理解。
假设我们的问题是预测用户是否会点击化妆品广告。显然,在这一场景下,根据我们的先验知识,年轻的女性更倾向于点击化妆品,因此:年龄和性别可以看做是一对Co-Action特征,对目标label的预测有显著的影响。
第一类迭代路线,很自然的想法,人工构造年龄和性别的交叉特征sex & age,比如:sex取值男性和女性,age分段。通过笛卡尔积,可以构造出很多组合交叉特征,如:”女性&18~25岁”,”男性&18~25岁”等。每个组合特征都单独进行嵌入表示,并独立地从数据中学习到这些嵌入。所谓的独立,可以从两个方面来理解。特征标识独立性上,”女性 &18~25岁”和”女性”以及”18~25岁”分别用三种不同的符号来唯一标识,在构造完特征后,三者之间是完全独立的;学习独立性上,只有同时满足”女性且18~25岁”的样本才能影响该交叉特征嵌入的学习,不会受到诸如”女性且30~40岁样本”或者”男性且18~25岁样本”的影响。
这种人工特征交叉拥有对数据的强记忆性优点。举个极端的例子,只要同时满足”女性”和”18~25岁”这两个条件的用户都会点击化妆品,不同时满足的用户都不会点击化妆品。那么就可以构造”女性&18~25岁”这个交叉特征,且只需要为该交叉特征设置1维的嵌入(等价于单变量线性模型$wx$中的$w$参数),取值为正无穷大,那么sigmoid激活后预测交互概率肯定接近1,相当于通过1维的嵌入就能够记住整个数据中蕴含的规律。但是问题是,实际情况没有这么简单,通过这种方式会产生大量稀疏的特征,复杂度高,学习困难,迭代负担重,有大量组合特征的缺乏充足的样本来学习,导致学习过程不置信和不稳定。这也是传统逻辑回归用于手工特征交叉建模的主要问题所在。
第二类迭代路线,为了解决这一问题,涌现了FM/DeepFM/PNN等大量工作,通过模型来实现特征的自动交叉。即:两两交叉特征通过单一特征的嵌入之间的点积或外积等方式来间接表达。例如:”女性&18~25岁”这个交叉特征通过”女性“的嵌入和”18~25岁”的嵌入之间的点积来间接表达,并且这个交叉特征嵌入并不是直接且独立地从数据中学习来的,而是通过”女性”这一嵌入和”18~25岁”这一嵌入来间接表达和学习的,显然会受到单一的女性样本或者单一的18~25岁样本的影响,即不是独立学习的。虽然解决了稀疏性问题,带来了一定的泛化性,但是在一些Co-Action非常强烈的场景中,这样的泛化可能是过度的。比如在上面这个例子中,假设样本中有大量的”18~25岁男性样本”,根本不想点化妆品,但是在第二类迭代路线中,这类样本会影响”18~25岁”这一特征嵌入的学习,导致可能带偏”女性&18~25岁”这一交叉特征的表达。相反,在第一类迭代路线中,就不存在这样的影响。因此,模型层面的交叉,如果不涉及到独立交叉特征嵌入的学习,本质上都是伪交叉[3],可能学不好高阶的交叉信息。
那么如何在上述两大类迭代路线之间做一个折衷,做到既有很强的记忆性,又不会过度泛化呢?CAN提供了一种新的思路和迭代路线。核心目的是让Co-Action的建模过程中有相对比较稳定和独立的参数来维持对建模信息的学习记录,同时又想让不同的Co-Action间有一定的信息共享[2]。个人认为,前者体现了记忆性,让交叉特征能够比较独立的学习,有效建模co-action特征;后者体现了泛化性,能够控制模型的参数复杂度,通过一定的信息共享来提高学习的泛化能力。
首先介绍下Co-action特征的概念。Co-action指的是特征之间的协同效应,对于目标的预测有显著的影响。比如:在电商场景下,用户最近一次历史点击item和目标item就是一对很强的Co-action特征,对于预测用户是否会点击目标item非常有帮助。也可以从图的视角来理解Co-action特征。
如上图右侧所示,假设只有2种特征A和B用于预测目标。那么特征A和B之间的co-action等价于建模A和B之间的连边,且该连边对于目标的预测也是有影响的,如图中右侧所示:A和B的连边也显式地与目标相连接,这种特征之间的协同效应能够显著影响目标的预测。而没有co-action的系统如图中左侧所示,不同特征之间是独立的,比如通过广义线性模型来预测点击率。
作者认为目前的CTR模型的工作并不能深入地探索到潜在的Co-action特征,并做了相应地实验论证了Co-action被很多模型忽视或低估了。为此,作者提出了一种建模Co-action特征建模网络CAN,即:Co-action Network来挖掘Co-action特征的潜力。CAN能够高效地捕获特征间的Co-action关系,提高模型的性能,并降低计算和存储消耗。实验表明了CAN能够大幅度超越现有的CTR模型。CAN模型已经被部署在阿里巴巴展示广告系统中,获得了12%的CTR提升和8%的RPM提升。
回顾整个研究历程,通过模型来建模co-action效应的方法可以大致分为三大类。
为了证明如上三种方法在建模co-action方面效果不好,作者和最直接的笛卡尔积方法做比较。所谓的笛卡尔积,即:当特征A和B取值出现共现时,就构造一个新的特征,即A&B,e.g, sex和age特征,某个新特征为:”女性&18岁”,且这个新特征是独立更新的,不会受到诸如”男性&18岁”、”女性&20岁”等特征学习过程的影响。这种方式实际上就是笛卡尔积,也是建模co-action最直接的方式。但是这种方式参数量过大,存在大量低频的稀疏特征。但是作者表明,即便是这样,在实验中,大部分基于组合嵌入的方法都无法打败笛卡尔积方法,可能是因为组合嵌入的方法要同时权衡好单一原始特征的表示学习和多个特征的co-action建模是很困难的。
为了解决这一问题,作者提出了Co-Action Network(CAN)。这个网络可以在输入阶段就能捕获原始特征的co-action效应,同时能够有效利用不同”co-action特征对”之间通用共享的信息。笛卡尔积的方式的参数量为$O(N^2 \times D)$,$N$为特征量,$D$为向量维度。CAN的参数量为$O(N \times T)$,其中 $T << N$,$D < T$。$CAN$能够将表征学习的嵌入空间和co-action建模的嵌入空间区分开,尽可能减少冲突。具体的,本文的主要贡献点。
总体上概括下方法。CAN网络和正常的深度CTR网络几乎一样,所不同的是多了个CAN Unit结构。CAN Unit本质上是一种特征提取器,输入是要建模的co-action特征对,输出是建模后的co-action向量。这样,常规的embedding向量和co-action向量拼接起来经过多层MLP,就能输出点击率预估值。CAN Unit的特点是能够将要建模的”特征对”分为weight side和input side。weight side可以reshape成MLP的参数,input side作为MLP的输入,通过多层MLP来建模co-action。
首先回顾下深度CTR预估方法。如果不考虑Co-Action,则预估的label可以表示为:
$$
\hat{y} = \text{DNN}(E(u_1), …, E(u_i), E(m_1), …, E(m_j))
$$
$u$表示user,$m$表示item。$E(\cdot) \in \mathbb{R}^d$表示将稀疏特征映射到嵌入。
如果考虑Co-Action,则预估的label可以表示为:
$$
\hat{y} = \text{DNN}(E(u_1), …, E(u_i), E(m_1), …, E(m_j), {F(u_i, m_j)}_{i,j})
$$
${F(u_i, m_j)}_{i,j} \in \mathbb{R}^d$代表用户特征$u_i$和物品特征$m_j$的交互嵌入表示。构造这种组合特征的直觉来源在于,相比于单一的特征,特征组合可能和label更相关。比如:用户历史点击item和目标预测的item之间的特征组合。
如果$F$是独立的嵌入映射函数,即:和$E$不相关,那么相当于新造了一个特征并独立地映射到某个嵌入表示上,此时这种组合特征是独立地学习的,记忆性最好,对co-action的建模很有效,实际上就是笛卡尔积方法。但是这样的话,组合特征量很大,且大多是低频的,学习过程不稳定。因此不是合理的方法。
如果$F$完全是用$E$来表示的,比如$F(u_i,m_j)=E(u_i) \odot E(m_j)$,$\odot$是element-wise乘积。此时co-action建模不是很有效,因为会受到$E(u_i)$和$E(m_j)$各自单独的学习过程的影响,会导致过度泛化问题。
上述两种方式是两种极端,前者是强记忆性,后者是强泛化性,各有优劣,作者提出的CAN网络希望在二者中做一个折衷,既有记忆性,又有泛化性。
先从总体上介绍下CAN的结构,如下图所示。
每种特征有两种方式作为CAN的输入。
则:CAN网络可以形式化为:
$$
\hat{y}=DNN(e_{item}, e_{user}, H(x_{user}, x_{item}, \boldsymbol{\Theta}_{CAN}), \boldsymbol{\Theta}_{DNN})
$$
即:DNN的输入包括了原始特征的嵌入$e_{user}, e_{item}$以及CAN网络输出的co-action嵌入$H$。$\boldsymbol{\Theta}_{CAN}$实际上就是图中Parameter Lookup中的参数。可以看出上述最重要的结构为:Co-action Unit:$H(x_{user}, x_{item}, \boldsymbol{\Theta}_{CAN})$。我们不妨先看下CAN Unit的结构图。
Co-action Unit本质上也是一种特征提取器。输入是要建模的co-action特征对,输出是建模后的co-action向量。
根据上文,想要做到既有记忆性又有泛化性。那么,相比于文章开头所述的第二条迭代路线,即:FM/DeepFM等通过原始单一特征来间接表达co-action的方法,肯定要在此基础上拓展参数空间的大小,并有效地使用这些参数来建模co-action,使得不同特征的学习相对独立,从而提高记忆性。而相比于文章开头所述的第一条迭代路线,即笛卡尔积手动构造组合特征的方法,肯定要在这个基础上一定程度上增加不同的co-action组合特征之间的信息共享,提高泛化性。
为了实现上述目的。作者将要建模co-action效应的两个特征分为了两端。一端拓展了特征的向量维度数,并切分成多个slot向量。不同slot向量可以通过reshape的方式来充当MLP网络不同层参数的角色,另一端则通过手动构造高阶的特征来作为MLP的输入。二者通过多层的MLP来实现co-action效应的建模。
为了符号的清晰,我会用加粗的符号表示矩阵,不加粗的表示向量或者常量。$\boldsymbol{P}_{item} \in \mathbb{R}^{M \times T}$作为MLP每层的权重和偏置参数;$\boldsymbol{P}_{user} \in \mathbb{R}^{N \times D}$作为MLP网络的输入,最终网络输出建模好的co-action向量$H$。
$M$表示item unique ID的数量,$N$是user unique ID的数量(个人认为应该用$N$表示,原文用$M$表示)。$T$是item端拓宽的向量维度数,$D$是user端的向量维度数,$D < T$。当然,user和item可以角色对调。之所以这么做,是因为广告系统中,候选的item数量很少,只占全部item的一小部分,比用户点击历史中的item少的多。(我推测,由于候选item被更多地共享了,所以要拓宽其参数空间,让其学习过程更独立)。
具体而言,MLP第1层每个神经元的连接数和某个user的向量$p_{user} \in \mathbb{R}^D$是一样的,都是$D$维;而$p_{item} \in \mathbb{R}^T$充当着多层MLP参数的容器,即:所有MLP层总共的维度为$T$。为了建模co-action,分为几个步骤:
$p_{item} \in \mathbb{R}^T$通过reshape的方式转成MLP层的权重矩阵和偏置向量参数。即:
$$
P_{item}=\text{concatenate}({\text{flatten}(\boldsymbol{w}^{(i)}), b^{(i)}}_{i=0,…,{K-1}})
$$
$\boldsymbol{w}^{(i)}$是MLP第$i$层的权重矩阵,而$b^{(i)}$是第$i$层的偏置向量。把$\boldsymbol{w}^{(i)}$矩阵拍扁成向量,并和$b^{(i)}$向量拼在一起,这样就形成了第$i$层网络的参数的向量化形式,所有$K$层网络的参数拼接在一起,则形成了所有$K$层网络参数的向量化形式,共T维度。这个过程反向执行,其实就是reshape操作,就能将$T$维向量转成MLP网络的各层参数。比如三层网络,每层参数量一样,即:三层网络的权重矩阵都为$D \times D$维,偏置都为$D$维,则$T=3 \times (D \times D+D)$。
$p_{user} \in \mathbb{R}^D$作为MLP的输入,进行多层MLP前向传播,不同层之间有激活函数。即:
$$
\begin{aligned}
&h^{(0)}=p_{user} \\
&h^{(i)}=\sigma(\boldsymbol{w}^{(i-1)} \otimes h^{(i-1)} + b^{(i-1)}), i=1,2,…,K-1 \\
&H(p_{user}, p_{item}) = h^{(K)}
\end{aligned}
$$
$\otimes$表示矩阵乘法。$H$代表最终输出的feature co-action向量。如果$p_{user}$是用户点击序列中的item,每个历史点击item都会和目标item建模co-action输出1个向量,那么最终的向量表示是这个序列所有item的co-action向量的sum-pooling结果。
那么为何通过这样的网络就能够实现记忆性和泛化性的折衷呢?如何保证Co-Action的建模过程中有相对比较稳定和独立的参数来维持对建模信息的学习记录,同时又想让不同的Co-Action间有一定的信息共享?作者在论文中没有做很直接的解释,下面是个人的一些理解,欢迎纠正。
参数空间的拓展。头部的item出现的次数多,因此通过拓宽其参数空间,并转成MLP的形式;而user作为MLP的输入,这样能够使得两侧特征的参数都能够得到比较好的学习和更新。而在传统的方式中,在提取高阶特征的时候,通常使用共享的MLP,这样不同特征最终的表征向量会受到共享MLP的影响,其梯度又会反向作用MLP的学习,进而又通过共享的MLP影响其他特征的表征向量的学习过程。不同特征之间的梯度信息是耦合在一起的,无法保证稳定且独立的学习。
DNN的计算能力。MLP的主要作用实际上是体现在不同层之间的激活函数,激活函数可以认为充当着门控的角色。reshape操作本质上相当于是对向量空间做了切分,划分为不同的slot,每个slot映射到某层MLP的参数上,且不同slot之间是有信息协同、过滤、递进的关系,通过MLP前向传播矩阵乘法和激活函数来实现的,保证不同slot各司其职,低层的slot负责低level的信息,通过激活函数过滤了噪声后,传到高层的slot来负责高level信息的提取。在梯度反传的时候,不同slot通过激活函数门控机制会接收到不同层次的信息,来保证各自的参数有相对比较独立的更新。进一步,由于激活函数的存在,item A和不同的user特征如B或C做co-action时,B提供给A的梯度信息和C提供给A的梯度信息都会不太一样,保证了参数更新的独立性。
如果不以MLP的视角来看,相当于第一个item slot和user特征做个交互,提取出低阶的信息,激活函数过滤掉无用信息后,再和第二个负责高阶信息提取的item slot做个交互,以此类推。
参数共享。笛卡尔积的话,要学习的co-action特征参数量为$O(N^2 \times D)$。用CAN网络参数量为$O(N \times T)$。而$T$远小于$N$。显然复杂度降低了不少。同时不同co-action之间是有参数共享的。比如,20~25岁 & 化妆品;40~50岁 & 化妆品。物品侧化妆品特征向量是会和多个用户侧年龄特征向量做co-action建模的,因此化妆品会被20~25岁和40~50岁的样本所共享。只不过通过拓宽参数向量为$T$,并通过MLP的门控机制,能够有效地保证这种共享不是过度泛化的,即:$T$维向量不同部分是相对比较独立的。当然,这种共享的程度是否是合适的,很大程度上是受到$T$的大小的影响,$T$太大就过度独立,$T$太小就过度共享。如果有一些参数独立性的措施来保证,可能更有效。后文会提到。
关于user端特征多阶提升的部分,我就不做解读,毕竟这不是文章的关键亮点所在。即:
$$
H(p_{user}, p_{item})=\sum_{c=1}^C MLP_{can}({(p_{user})}^c) \approx MLP_{can} (\sum_{c=1}^C((p_{user})^c)
$$
即:$C$是阶数。$MLP_{can}$是同一个。没有额外的参数量。只在user输入侧对特征做了个多项式变换和相加。
接下来我重点讲一下作者最后一部分提到的多层次独立性multi-level Independence。
Amazon和Taobao建模目标item和用户点击item序列之间的co-action;Avazu建模非序列、离散的特征的co-action。
对比模型,DIEN,笛卡尔积,PNN,NCF,DeepFM。
实现细节:$p_{item}$侧,即$MLP_{can}$的参数量:(4x4+4)x8=160维,即8层MLP,每层4个神经元。$p_{user}$的阶数设置为2;参数用零均值标准差为0.01的高斯分布初始化;Adam作为优化器;batchsize为128;学习率0.001;预测层用3层的MLP,尺寸为200x100x2。AUC指标来评估。
模型效果对比:
上述几种不同的方法是怎么实现的作者没有具体说明。DIEN,PNN,NCF,DeepFM和原始论文的工作应该是一样的。按照我的理解,这几种方法唯一不同就是co-action特征建模方式。比如对于目标item和点击item序列:DIEN中用attention的方式做加权汇聚;PNN中用内积+外积;NCF用concat+MLP;DeepFM用FM来做。DIEN+Cartesian我认为是先构造目标item和点击item序列的笛卡尔积序列,即:目标item&点击item1,item&点击item2,item&点击item3,..,得到新的序列后,新序列不同项都单独做嵌入,再用DIEN来建模。CAN用CAN-Unit来建模;CAN+Cartesian我个人的理解是multi-level Independence中第二种组合独立中提到的方法。否则,用笛卡尔积构造新序列后,就没必要用CAN来建模了吧。
对比了user侧的阶数,MLP的层数,激活函数不同的差异,看实验结果,这个差异都很小。
如上图,这种情况下,笛卡尔积还不如NCF,DeepFM等方法,因为笛卡尔积建模的记忆性发挥不了作用,测试集中有很多未看见的特征组合。只要$p_{item}, p_{user}$能够很好地训练,CAN就能表现得很好。我猜测这种情况下,CAN+Cartesian表现得也不好,但是作者没有提到。
最初使用笛卡尔积模型遇到了很多困难。即使做了频率过滤,仍然面临着$M \times N$量级的embedding查表操作。用CAN缓和了很多。CAN最终使用了21种特征来做特征组合,包括6种广告特征,15种用户特征。因此,根据参数独立性,有21种额外的参数空间被分配用于建模co-action。这种仍然无法忍受,因为用户特征很多是长序列特征,超过100,内容访问延迟增加了不少。解决思路:
最终,CAN的CTR预估的时间耗时是12ms,每块GPU可以处理1K的QPS。在两种场景下(没有说是什么场景)的提升如下表。
本文作者提出了一种特征交互的新思路,在记忆性和泛化性之间做了折中。CAN网络能够将表征学习和Co-action建模二者区分开,并通过多层次的独立性等技巧来提升模型的表达能力。
总之,不管是DIN/DIEN还是CAN,其目的都是为了增强co-action特征的表达能力。DIN这类方法比较soft,而笛卡尔积又过于hard。CAN在二者之间做了个折中,通过网络参数化的方式能够增强co-action特征的表达能力,同时由于拓宽了co-action的参数空间、co-action的参数空间和表征学习的嵌入空间之间的独立性、激活函数门控机制等,就能够保证co-action参数不同的部分有相对比较稳定和独立的参数来维持对建模信息的学习记录,同时又能让不同的co-action间有一定的信息共享。
现在的研究工作通常将特征工程的工作转移到模型层面来做,更fancy,更简便,通用性更强。但是也值得强调的是,模型层面的很多工作可以由特征工程替代,且在实际场景中可能更快拿到收益。比如将用户的行为按时间周期做划分并分别统计,可以刻画周期时间与用户兴趣的关系;比如将目标Item特征和用户历史行为Item特征做手动交叉,可以直接刻画用户行为与Item的联系,将DIN或者DIEN想要达成的目标转化为手工特征作为信息输入是可行的。CAN这个工作虽然也是模型层面建模特征的工作,但是其核心思想融入了很多手工特征的思路,个人认为是一个很有启发性的工作。
[1] CAN: Revisiting Feature Co-Action for Click-Through Rate Prediction:https://arxiv.org/abs/2011.05625
[2] 想为特征交互走一条新的路: https://zhuanlan.zhihu.com/p/287898562
[3] 推荐系统之Co-action Network理解与实践:https://mp.weixin.qq.com/s/45fYiM2FK3ZwigIUrmCnmg
[4] DIN,KDD2018,Deep Interest Network for Click-Through Rate Prediction:https://arxiv.org/abs/1706.06978
[5] DIEN,AAAI2019,Deep Interest Evolution Network for Click-Through Rate Prediction:https://arxiv.org/abs/1809.03672
[6] MIMN,KDD2019,Practice on Long Sequential User Behavior Modeling for Click-through Rate Prediction:https://arxiv.org/abs/1905.09248
[7] GCN,ICLR 2017,Semi-Supervised Classification with Graph Convolutional Networks:https://arxiv.org/abs/1609.02907
[8] HINE,TKDE 2019 Heterogeneous Information Network Embedding for Recommendation:https://arxiv.org/pdf/1711.10730.pdf
[9] FM,ICDM 2010,Factorization machines:https://ieeexplore.ieee.org/document/5694074
[10] DeepFM,IJCAI 2017,DeepFM: a Factorization-Machine based Neural Network for CTR prediction:http://www.ijcai.org/Proceedings/2017/0239.pdf
[11] PNN,ICDM 2016,Product-based neural networks for user response prediction:https://arxiv.org/abs/1611.00144
最后,欢迎大家关注我的微信公众号,蘑菇先生学习记。会定期推送关于算法的前沿进展和学习实践感悟。
]]>后续我会基于这样的范式,重新梳理图表示学习在推荐系统中常见的用户-物品交互数据上的建模方法。我们可以将用户-物品的交互数据看做是关于user-item的二分图(Bipartite Graph),这样可以基于GNN的方法进行user和item嵌入的学习。我将重点探讨如何基于信息传递框架来拆解目前主流的二分图表示学习方法,不同的方法是如何针对不同的组件做改进和迭代,我会对8篇顶会文章的改进脉络做一个系统性地梳理。
本篇文章将主要介绍基于信息传递框架的图自编码范式。
在之前的文章中图表示学习Encoder-Decoder框架中,我们介绍了一种应用于图表示学习的Encoder-Decoder框架。该框架是对所有图表示学习的方法的所有过程的抽象,即:编码,解码,相似性度量和损失函数。而其中最重要的步骤是Encoder,实际上,大部分方法主要的差异只体现在Encoder上,其它三种都大同小异,比如GraphSAGE和GATs。因此,如何对Encoder进一步做抽象就显得很重要了。
信息传递框架就是为Encoder的进一步抽象所服务的,也是近年来大部分GNN工作所采用的设计范式。信息传递框架最早是在ICML 2017,Neural Message Passing for Quantum Chemistry[8]中被提出来,作者在这篇论文将现有神经网络模型抽象出其共性并提出一种信息传递神经网络框架(Message Passing Neural Networks, MPNN),同时利用 MPNN 框架在分子分类预测中取得了一个不错的成绩。MPNN包括了两个阶段:信息传递阶段(Message Passing) 和 读出阶段(Readout)。其中,信息传递阶段可以细分为信息构建、信息汇聚和信息更新,得到每个结点的表征。读出阶段是指系统更新多次达到某个状态后,从图中的所有结点状态映射得到Graph-Level的表征(原文是做分子分类预测,因此需要得到Graph表征)。
我们这里讨论的是Node-Level的表征,因此可以借鉴信息传递阶段。图神经网络GNN在设计Encoder的时候,会做基于邻域汇聚的卷积操作,涉及到的卷积操作会有很多步骤,可以采用Message-Passing信息传递框架来组织和提炼其中的核心步骤,并封装成各个组件,每个组件都能够单独进行设计和改进。这些组件包括:信息构建组件,邻域汇聚组件和表征更新组件。
信息构建组件:负责构建从邻域结点到目标结点要传递的信息;
邻域汇聚组件:负责汇聚从邻域结点集合传递到目标结点的信息;
上述3个步骤构成了一个完整的迭代步。第一步迭代结束后,每个结点都融合了一阶的邻域结点的信息;依次类推,多次迭代,就能够融合多阶的邻域结点信息。值得一提的是,著名的图学习框架DGL[7]就是基于消息传递框架来组织和设计代码,下面依次介绍各个组件。
Information Construction 信息构建组件:构建从1个邻域结点到目标结点要传递的信息。
如下图所示,信息构建组件使用信息构建网络,输入数据是前一层的目标结点和邻域结点的表征,还有个decay系数/正则化项,表示信息传递过程中的衰减系数,输出数据是从邻域结点$v$到目标结点$u$要传递的信息。总结起来,这里头核心的组成元素包括:
Neighborhood Aggregation 邻域汇聚组件:基于上述构建好的每个邻域结点要传递的信息,来汇聚所有的邻域结点的信息。
如下图所示,邻域汇聚使用汇聚函数,其输入是上述构建好的信息;输出是汇聚好的所有邻域的信息。总结下核心的组成元素:
Representation Update:表征更新组件:融合从邻域集合汇聚到的信息和自己本身的信息,来做自我表征的更新。
如下图所示,表征更新使用融合函数,输入是步骤1.2中汇聚到的邻域信息以及结点$u$本身的信息,输出是结点新的表征。比如:融合函数可以使用sum操作或者concat+非线性变换操作。总结下核心组成元素:
下面以GraphSAGE[4]和GATs[5]为例,来介绍这两个主流的GNN模型中Encoder结构拆解示例。
$$
\boldsymbol{m}_{v \rightarrow u}^{(k-1)}=f_1^{(k-1)}=h_v^{(k-1)}
$$
即:传递的信息为邻域结点表征。
$$
\boldsymbol{h}_{\mathcal{N}_u}^{(k-1)}=\text{Agg}({\boldsymbol{h}_v^{k-1} , \forall v \in \mathcal{N}_u })
$$
其中Agg汇聚函数在GraphSAGE中有多种形式。
GCN Aggregator: 这个是GCN中矩阵形式乘法的等价形式。细节推导可参见:图表示学习Encoder-Decoder框架中的GraphSAGE一节。
LSTM aggregator: 直接对邻域节点随机扰动permutation,然后将扰动后的序列使用LSTM来聚合。感觉有点简单粗暴了。
Pooling aggregator:
$$
\boldsymbol{h}_{\mathcal{N}_u}^{(k-1)}=\max({\sigma(\boldsymbol{W}_{pool}\boldsymbol{h}_{v}^{(k-1)} + \boldsymbol{b}), \forall v \in \mathcal{N}(u)})
$$
即:每个邻居节点的表示先经过一个MLP,然后进行sigmoid激活;最后应用element-wise max pooling策略,此处的max pooling,作者提到用mean pooling也是可以的。内部的MLP也可以改成多层的MLP。
$$
\boldsymbol{h}_u^{(k)}=\sigma(\boldsymbol{W}_1^{(k)} \cdot \boldsymbol{h}_{\mathcal{N}_u}^{(k-1)} || \boldsymbol{W}_2^{(k)} \boldsymbol{h}_u^{(k-1)})
$$
即:2.1.2邻域汇聚得到的信息做一个线性变换;目标结点$u$在前一层的表征$\boldsymbol{h}_u^{(k-1)}$做一个线性变换;二者拼接起来,过一个激活函数,得到更新后的第$k$阶表征。
上述核心的邻域汇聚组件和表征更新组件总结下来如下图所示:
$$
\boldsymbol{m}_{v \rightarrow u}^{(k-1)}=f_1^{(k-1)}=h_v^{(k-1)}
$$
同GraphSAGE。即:传递的信息为邻域结点表征。
$$
\boldsymbol{h}_{\mathcal{N}_u}^{(k-1)}=\text{Agg}({\boldsymbol{h}_v^{k-1} , \forall v \in \mathcal{N}_u })
$$
基于注意力框架的邻域汇聚组件。引入了self-attention机制,每个节点attend到自身的邻域节点上。不同于GraphSAGE采用Mean/Pooling Aggregator,GATs采用了基于self-attention机制的Aggregator。也就是说,把目标节点的表示和邻域节点的表示通过一个注意力网络,计算注意力值,再依据该注意力值来汇聚邻域节点。对于节点$u$及其邻域节点$v$。我们要计算$u$节点attend到$v$的注意力值,attention score计算如下:
先对$u$和$v$的前一层的表征$\boldsymbol{h}_u^{(k-1)}, \boldsymbol{h}_v^{(k-1)}$做一个线性变换 (即multi-head attention的特例,1-head attention),$\boldsymbol{W} \boldsymbol{h}_u^{(k-1)}, \boldsymbol{W} \boldsymbol{h}_v^{(k-1)}$。
再把变换后的表示送到attention网络并进行softmax得到注意力值,
$$
\alpha_{uv} = \text{softmax}(\text{attention}(\boldsymbol{W} \boldsymbol{h}_u^{(k-1)} , \boldsymbol{W} \boldsymbol{h}_v^{(k-1)}))
$$
这个attention网络结构如下:
$$
\text{attention}(\boldsymbol{W} \boldsymbol{h}_u^{(k-1)} , \boldsymbol{W} \boldsymbol{h}_v^{(k-1)})=\text{LeakyReLU}(\boldsymbol{a}[\boldsymbol{W} \boldsymbol{h}_u^{(k-1)} || \boldsymbol{W} \boldsymbol{h}_v^{(k-1)}])
$$
即:二者拼接到一起后,经过一个线性变换$\boldsymbol{a}$ (attention网络的参数),再LeakyReLU激活。
则Aggregator直接依注意力值对线性变换后的向量加权并激活即可:
$$
\boldsymbol{h}^{(k-1)}_{\mathcal{N}_u} = \sum_{v \in \mathcal{N}_u}\alpha_{uv} \boldsymbol{W} \boldsymbol{h}_v^{(k-1)}
$$
实际上,GATs中的邻域汇聚组件和表征更新组件是可以合在一起实现的。即:对于节点$u$和自身的attention score,作者提到直接代入$v=u$即可。这样,统一公式:
$$
\boldsymbol{h}^{(k)}_{u} = \sigma(\sum_{v \in \mathcal{N}_u \cup {u}}\alpha_{uv} \boldsymbol{W} \boldsymbol{h}_v^{(k-1)})
$$
另外,作者提到,可以采用multi-head attention来拓展,即:2.2.2中attention score计算的第一步中,将node feature变换到不同的语义子空间,再进行attention score计算并汇聚。每个head输出一个$\boldsymbol{h}^{(k)}_{u}$,将所有的输出拼接到一起;或者做mean pooling,作为节点更新后的表征。
上述核心的邻域汇聚组件和表征更新组件总结下来如下图所示:
本文讨论了WSDM 2020/CIKM 2019上王翔老师分享的关于信息传递框架的图自编码器范式,并介绍了如何基于这种范式,对GraphSAGE和GATs中的Encoder进行重新提炼和组织。
后续我会基于这样的范式,重新梳理图表示学习在推荐系统中常见的用户-物品交互数据上的建模。我将重点探讨如何基于信息传递框架来拆解目前主流的二分图表示学习方法,即:不同的方法是如何针对不同的组件做改进和迭代以及不同的方法间有什么区别和联系,我将在以后的文章中分享的8篇顶会工作如下,敬请期待。
[1] 王翔老师个人主页:https://xiangwang1223.github.io/
[2] 何向南老师个人主页:http://staff.ustc.edu.cn/~hexn/
[3] WSDM 2020/CIKM2019 Tutorial: Learning and Reasoning on Graph for Recommendation, https://dl.acm.org/doi/abs/10.1145/3336191.3371873
[4] NeurIPS 2017,Hamilton et al., GraphSAGE: Inductive Representation Learning on Large Graphs.
[5] ICLR 2018,Velickovic et al. Graph Attention Networks.
[6] WWW2018, Tutorial Jure Leskovec et al. Representation Learning on Networks
[7] Python package built to ease deep learning on graph, on top of existing DL frameworks: https://github.com/dmlc/dgl
[8] ICML 2017,Neural Message Passing for Quantum Chemistry: https://arxiv.org/pdf/1704.01212.pdf
最后,欢迎大家关注我的微信公众号,蘑菇先生学习记。会定期推送关于算法的前沿进展和学习实践感悟。
]]>该综述系统地介绍了nlp中的预训练模型。主要的贡献包括:
由于篇幅原因,本文主要针对前面两点进行梳理,即目前主流的预训练模型和预训练模型的分类体系。
nlp、cv领域的传统方法极度依赖于手动特征工程。例如nlp中的log-linear、CRF模型等,cv中各种抽取特征的模型,如sift特征等。深度学习中本质上是一种表示学习,能够一定程度上避免手动的特征工程。究其原因,主要得益于深度学习中一系列很强大的特征提取器,如CNN、RNN、Transformer等,这些特征提取器能够有效地捕获原始输入数据中所蕴含的特点和规律。
nlp领域的发展比cv领域相对缓慢的原因是什么呢?相比于cv领域,nlp领域的劣势在于有监督数据集大小非常小(除了机器翻译),导致深度学习模型容易过拟合,不能很好地泛化。但是相反,nlp领域的优势在于,存在大量的无监督数据集,如果能够充分利用这类数据进行训练,那么势必能够提升模型的能力以及在下游任务中的表现。nlp中的预训练模型就是这样一类能够在大规模语料上进行无监督训练,学习得到通用的语言表征,有助于解决下游任务的nlp模型。
那么什么是好的语言表征呢?作者引用了Bengio的话,好的表征能够表达非特定任务的通用先验知识,能够有助于学习器来解决AI任务。
1 | "a good representation should express general-purpose priors that are not task-specific but would be likely to be useful for a learning machine to solve AI-tasks." |
nlp领域好的文本表征则意味着能够捕捉蕴含在文本中的隐性的语言学规则和常识性知识 。
1 | "capture the implicit linguistic rules and common sense knowledge hiding in text data, such as lexical meanings, syntactic structures, semantic roles, and even pragmatics." |
目前主流的语言表征方式采用的是分布式表征(distributed representation),即低维实值稠密向量,每个维度没有特定的含义,但是整个向量表达了一种具体的概念。预训练模型是学习分布式表征的重要途径之一,它的好处主要包括:
下面将围绕四种分类方式来介绍目前主流的预训练模型,这些分类方式包括:
这些分类方式是交叉的,也就是说同一个模型可以划分到多个分类体系下。
先一睹为快,这幅图是该综述的精华之一。下面将围绕上述4种分类体系来介绍预训练任务的工作。
根据表征类型的不同可以分为:非上下文感知的表征 (Non-Contextual Representation)和上下文感知的表征(Contextual Representation)。上下文可以从字面上来理解,即:这个词所在的上下文,如句子,段落等。
如上图,将非上下文和上下文结合在一起。形成通用的NLP任务的架构。即:非上下文感知的词嵌入(如word2vec训练的embeddings),输入到上下文感知的Encoder(例如:Transformer,能够捕获句子中词之间的依赖关系),每个词的表示都会融入句子中其它上下文词的信息,得到上下文感知的词嵌入。同一个词在不同的语句中会得到不同的表示。
根据表征类型的不同,作者将预训练模型的发展主要划分为了两代:
第一代预训练模型由于不是致力于解决下游任务,主要致力于学习好word embeddings本身,即不考虑上下文信息(context-free),只关注词本身的语义(semantic meanings),,同时为了计算的考虑,这些模型通常非常浅。如Skip-Gram, GloVe等。由于是上下文无关的,这些方法通常无法捕获高阶的概念(high-level concepts),如一词多义,句法结构,语义角色,指代消解。代表性工作包括:NNLM[2],word2vec[3],GloVe[4]。
第二代预训练模型致力于学习contextual word embeddings。第一代预训练模型主要是word-level的。很自然的想法是将预训练模型拓展到sentence-level或者更高层次,这种方式输出的向量称为contextual word embeddings,即:依赖于上下文来表示词。此时,预训练好的Encoder需要在下游任务特定的上下文中提取词的表征向量。代表性工作包括两方面,
1. 仅作为特征提取器(feature extractor),
特征提取器产生的上下文词嵌入表示,在下游任务训练过程中是固定不变的。相当于只是把得到的上下文词嵌入表示喂给下游任务的模型,作为补充的特征,只学习下游任务特定的模型参数。
代表性工作包括:
(1) CoVe[5]. 用带注意力机制的seq2seq从机器翻译任务中预训练一个LSTM encoder。输出的上下文向量(CoVe)有助于提升一系列NLP下游任务的性能。
(2) ELMo[6]. 用两层的Bi-LSTM从双向语言模型任务BiLM(包括1个前向的语言模型以及1个后向的语言模型)中预训练一个Bi-LSTM Encoder。能够显著提升一系列NLP下游任务的性能。
2.微调 (fine-tune),
在下游任务中,上下文编码器的参数也会进行微调。即:把预训练模型中的encoder模型结构都提供给下游任务,这样下游任务可以对Encoder的参数进行fine-tune。
代表性工作包括:
(1) ULMFiT[7] (Universal Language Model Fine-tuning): 通过在文本分类任务上微调预训练好的语言模型达到了state-of-the-art结果。这篇也被认为是预训练模型微调模式的开创性工作。提出了3个阶段的微调:在通用数据上进行语言模型的预训练来学习通用语言特征;在目标任务所处的领域特定的数据上进行语言模型的微调来学习领域特征;在目标任务上进行微调。文中还介绍了一些微调的技巧,如区分性学习率、斜三角学习率、逐步unfreezing等。
1 | 微调技巧拓展: |
(2) GPT[8](Generative Pre-training) :使用单向的Transformer预训练单向语言模型。单向的Transformer里头用到了masked self-attention的技巧(相当于是Transformer原始论文里头的Decoder结构),即当前词只能attend到前面出现的词上面。之所以只能用单向transformer,主要受制于单向的预训练语言模型任务,否则会造成信息leak。
(3) BERT [9](Bidirectional Encoder Representation from Transformer):使用双向Transformer作为Encoder(即Transformer中的Encoder结构),引入了新的预训练任务,带mask的语言模型任务MLM和下一个句子预测任务NSP。由于MLM预训练任务的存在,使得Transformer能够进行双向self-attention。
除此之外,还有些挺有意思的工作研究上下文嵌入中所融入的知识,如语言知识、世界知识等[10][11][12]。
对于上下文感知的Encoder,根据架构的不同,可以进一步分为3种,
卷积模型 (convolutional models):通过卷积操作来汇聚目标词的邻居的局部信息,从而捕获目标词的语义。优点在于容易训练,且能够很捕获局部上下文信息。典型工作是EMNLP 2014的文章TextCNN[13],卷积网络应用于nlp中特征提取的开创性工作。还比如Facebook在ICML2017的工作[14]。
序列模型 (Sequential models):以序列的方式来捕获词的上下文信息。如LSTMs、GRUs。实践中,通常采取bi-directional LSTMs或bi-directional GRUs来同时捕获目标词双向的信息。优点在于能够捕获整个语句序列上的依赖关系,缺点是捕获的长距离依赖较弱。典型工作是NAACL 2018的文章:ELMo[6]。
图模型 (Graph-based models):将词作为图中的结点,通过预定义的词语之间的语言学结构(e.g., 句法结构、语义关系等)来学习词语的上下文表示。缺点是,构造好的图结构很困难,且非常依赖于专家知识或外部的nlp工具,如依存关系分析工具。典型的工作如:NAACL 2018上的工作[15]。
作者还提到,Transformer实际上是图模型的一种特例。这个观点醍醐灌顶,也解释了Transformer应用于图神经网络中的可行性。即:句子中的词构成一张全连接图,图中任意两个词之间都有连边,连边的权重衡量了词之间的关联,通过self-attention来动态计算,目标是让模型自动学习到图的结构(实际上,图上的结点还带了词本身的属性信息,如位置信息等)。值得注意的是,Transformer在预训练中的应用一般会拆解为3种方式,单向的 (即:Transformer Decoder,使用了masked self-attention防止attend到future信息),如GPT, GPT-2;双向的 (即:Transformer Encoder,两侧都能attend),如Bert,XLBert等;或者单双向都使用(即:Transformer)。这些编码器的示意图如下:
卷积编码器只能编码局部的信息到目标词上;序列模型能够捕获整个语句上的依赖关系,但长距离依赖较弱;图编码器任意两个词都有连接,能够捕获任意词之间的依赖关系,不受距离影响。
预训练任务对于学习通用的表征非常重要。甚至可以说是最重要的一环,引导着表征学习的整个过程。作者将预训练任务分为了3种,
在nlp领域,除了机器翻译存在大量的监督数据,能够采用监督学习的方式进行预训练以外(例如CoVe利用机器翻译预训练Encoder,并应用于下游任务),大部分预训练任务都是使用自监督学习的方式。下面围绕自监督学习,来介绍主流的预训练任务。
最著名的预训练任务是语言模型 (Language Modeling),语言模型是指一类能够求解句子概率的概率模型,通常通过概率论中的链式法则来表示整个句子各个单词间的联合概率。
形式化的,给定文本序列,$\boldsymbol{x}_{1:T}=[x_1, x_2, …,x_T]$,其联合概率$p(x_{1:T})$可以被分解为:
$$
p(\boldsymbol{x}_{1:T})= \prod_{t=1}^T p(x_t| \boldsymbol{x}_{0:t-1}), x_t \in \mathcal{V}
$$
其中,$x_0$是特殊的token,用于标识句子的开头 (此处应该也要有个标识句子结尾的特殊token)。$\mathcal{V}$是词典。
上述式子是典型的概率论中的链式法则。链式法则中的每个部分$p(x_t|\boldsymbol{x}_{0:t-1})$是给定上下文$\boldsymbol{x}_{0:t-1}$条件下,当前要预测的词$x_t$在整个词典上的条件概率分布。这意味着当前的单词只依赖于前面的单词,即单向的或者自回归的,这是LM的关键原理,也是这种预训练任务的特点。因此,LM也称为auto-regressive LM or unidirectional LM。
对于上下文$\boldsymbol{x}_{0:t-1}$,可以采用神经编码器$f_{enc}(\cdot)$来进行编码,然后通过一个预测层来预测单词$x_t$的条件概率分布,形式化的:
$$
p(x_t|\boldsymbol{x}_{0:t-1}) =g_{\text{LM}}(f_{enc}(\boldsymbol{x}_{0:t-1}))
$$
其中,$g_{\text{LM}}$是预测层 (比如softmax全连接层),用于输出当前单词$x_t$在整个词典上的条件概率分布。目标损失函数为:
$$
\mathcal{L}_{\text{LM}} = - \sum_{t=1}^T \log p(x_t | \boldsymbol{x}_{<t}), \boldsymbol{x}_{<t}=x_0,x_1,….,x_{t-1}
$$
LM的缺点在于,除了本身的信息之外,每个单词的编码只融入了其所在句子左侧的上下文单词的信息。而实际上,每个单词左右两侧上下文信息都是非常重要的。为什么不能同时融入左右两侧的单词信息呢?主要是因为我们的学习目标是预测下一个词,如果让当前词同时融入两侧的信息,会造成label的leak问题。解决这个问题的方法是采用bidirectional LM (Bi-LM)即:分别考虑从左到右的LM和从右到左的LM,这两个方向的LM是分开建模的。也就是说,训练过程中,不会在一个LM预测下一个词的时候,用到另一个LM的encode的信息。最后训练完成后,每个单词可以把两个$f_{\text{left-enc}}$和$f_{\text{right-enc}}$的输出拼接在一起来形成最终的表征。
MLM主要是从BERT开始流行起来的,能够解决单向的LM的问题,进行双向的信息编码。MLM就好比英文中的完形填空问题,需要借助语句/语篇所有的上下文信息才能预测目标单词。具体的做法就是随机mask掉一些token,使用特殊符号[MASK]来替换真实的token,这个操作相当于告知模型哪个位置被mask了,然后训练模型通过其它没有被mask的上下文单词的信息来预测这些mask掉的真实token。具体实现时,实际上是个多分类问题,将masked的句子送入上下文编码器Transformer中进行编码,[MASK]特殊token位置对应的最终隐向量输入到softmax分类器进行真实的masked token的预测。损失函数为:
$$
\mathcal{L}_{\text{MLM}} = - \sum_{\hat{x} \in m(\boldsymbol{x})} \log p(\hat{x}| \boldsymbol{x}_{\backslash m(\boldsymbol{x})})
$$
其中,$m(\boldsymbol{x})$表示句子$\boldsymbol{x}$中被mask掉的单词集合;$\boldsymbol{x}_{\backslash m(\boldsymbol{x})}$是除了masked单词之外的其它单词。
MLM的缺点有几大点:
MLM的变体有很多种。
Sequence-to-Sequence MLM (Seq2Seq MLM): 将MLM分类任务变成seq2seq序列自回归预测任务,采用encoder-decoder的方式。原始的语句中有一段连续出现的单词被mask掉了。encoder的输入是masked的句子,decoder以自回归的方式来依次地预测masked tokens。这种预训练任务很适合用于生成式任务。代表性工作有:微软的 MASS[16] 和 Google的T5[17] 。这种预训练认为能够有效提高seq2seq类型的下游任务的表现。其损失函数为:
$$
\mathcal{L}_{\text{S2SMLM}} = - \sum_{t=i}^j \log p(x_t|\boldsymbol{x}_{\backslash \boldsymbol{x_{i:j}}}, \boldsymbol{x}_{i:t-1})
$$
$\boldsymbol{x_{i:j}}$是句子$\boldsymbol{x}$被masked的n-gram span,是连续出现的单词。基于encoder端的输入序列$\boldsymbol{x}_{\backslash \boldsymbol{x_{i:j}}}$以及decoder已经解码的部分$\boldsymbol{x}_{i:t-1}$来自回归地预测下一个时间步$t$的单词。
Enhanced MLM (E-MLM):增强版MLM。
PLM在XLNet[23]中被提出。动机来源主要在于上文阐述的MLM的几大缺点,如预训练和微调阶段的gap,mask词之间的独立性假设等。在传统的单向自回归语言模型LM中,句子的联合概率因子分解是按照从左到右或者从右到左的方式分解成条件概率的链式乘积的,这可以看作是其中两种联合概率的因子分解序。实际上,句子的联合概率的因子分解序还可以有很多种,可以任意的排列组合进行因子分解。PLM就是对联合概率进行因子分解得到排列,分解得到的排列只决定了模型自回归时的预测顺序,不会改变原始文本序列的自然位置。即:PLM只是针对语言模型建模不同排列下的因子分解排列,并不是词的位置信息的重新排列。
那么为什么这种方式每个位置能够编码原始语句中双向的上下文信息呢? 首先,前提是,模型的参数在所有的分解序下是共享的。其次,在每种因子分解序对应的排列语句下,对某个位置,会编码排列句子中出现在该位置前面的其它词的信息;那么在所有的因子分解下,每个词都有机会出现在该位置的左侧,那么总体上该词就会编码所有词的信息。
理想优化的目标是所有因子分解序得到的排列上的期望对数似然。
$$
\max_{\theta} \mathcal{\mathbb{E}}_{\boldsymbol{z} \sim \mathcal{Z}_T} \left[\sum_{t=1}^T \log p_{\theta}(x_{z_t}| \boldsymbol{x}_{\boldsymbol{z}<t}) \right]
$$
其中,$\mathcal{Z}_T$是所有的因子分解序集合。$x_{z_t}$代表某种因子分解序$\boldsymbol{z}$中,第$t$个位置的序号对应的原序列中的词。比如,原始句子$\boldsymbol{x}=[a,b,c,d]$,某个因子分解序$\boldsymbol{z}=[3,2,1,4]$,即$z_1=3$,则$x_{z_1}=x_3=c$,因此,这个因子分解序对应的排列句子为$[c,b,a,d]$。实际实现的时候,作者没有预测所有的$T$个词,只把每个排列句的尾部的词进行预测来减少计算量。
进一步,强调下实现上的亮点。实际实现的过程中,仍然采用原始输入语句,即保持原始句子的自然序,而模型内部会自动进行排列操作,对transformer进行适当的attention mask操作就能达到在因子分解序上进行自回归预测的目的。然而,预测的时候如果没有考虑目标词在原始序列中的位置信息的话,会导致预测的目标词不管在排列句子中的哪个位置,其分布都是一样的(虽然输入语句自然序不变,但是建模的时候不进行考虑的话,相当于对随机扰动的序列进行建模预测,直观上感觉这样显然无效)。作者做了改进,在预测$x_{z_t}$词本身时,要利用到其在原始句子的位置编码信息,即:$p_{\theta}(x_{z_t}| \boldsymbol{x}_{\boldsymbol{z}<t}, z_t)$,即target-position-aware的next-token预测 (这样就能在排列句上预测过程中,时刻兼顾原始输入语句序)。但是为了实现自回归预测,transformer在编码的时候不能把目标预测词本身的内容编码进目标词对应位置的隐状态中,而只能使用目标预测词的位置信息;而目标预测词之前的其它词就要考虑其本身的内容信息。每个位置的词都有两种隐状态向量,因此需要做这两种区分,是使用$z_t$位置信息还是其对应的内容信息$x_{z_t}$。为了方便实现该操作,作者采用了two-stream self-attention。
DAE在原始文本上加了噪声,即corrupted input作为输入,目标是基于corrupted input来恢复原始的文本。MLM属于DAE的一种形式,除此之外DAE还有其它的形式。下面的这些细类别,综述参考的是Facebook2019的文章BART[24]。
前面介绍的方法主要是基于上下文的PTMs,即:基于数据本身的上下文信息构造辅助任务。这里作者介绍的另一大类的预训练方法是基于对比的方法,即:通过对比来进行学习。很像learning to rank中的pairwise方法。CTL全称:Contrastive Learning,假设了观测文本对之间的语义比随机采样的文本对之间的语义更近。因此优化的目标是:
$$
\mathcal{L}_{CTL} = \mathbb{E}_{x, y^{+}, y^{-}}[-\log \frac{\exp(s(x, y^{+}))}{\exp(s(x, y^{+}))+\exp(s(x, y^{-}))}]
$$
$(x,y^{+})$是观测的文本相似对,$(x,y^{-})$是负样本对。上述损失实际上是二路的softmax,实际上又等价于learning to rank中的BPR Loss,只需要把分子除到分母上,就可以整理成类似BPR的形式了,即:$\frac{1}{1+\exp(s(x, y^{-})-s(x, y^{+}))} \rightarrow \text{sigmoid}(s(x, y^{+})-s(x, y^{-})) $,
得分函数$s(x,y)$可以使用神经网络编码器来构造。通常有两种方式:各自编码后求点击相似性作为分数$s(x,y)=f_{enc}(x)^T f_{enc(y)}$,或者逐元素操作后送入到编码器进行打分,$s(x,y)=f_{enc}(x \oplus y)$
基于对比的方法主要包括如下一些具体的预训练任务类型,只不过下面这些对比的方法和上面的优化目标在形式上差异挺大的。
再总体看下不同模型在架构和预训练任务上的区别,本篇综述的精华总结之二:
还给了不同模型在GLUE上的综合表现,可以看到google出品的XLNet,T5,ELECTRA以及Facebook提出的RoBERTa综合实力上是最强的。不过除这些之外,截止至2020.11.27号,最新榜单[30] 里头,排名是这样的,可以看出技术迭代速度之惊人。
预训练模型延伸出了很多新的研究方向。包括了:
PTMs主要学习通用语言表征,但是缺乏领域特定的知识。因此可以考虑把外部的知识融入到预训练过程中,让模型同时捕获上下文信息和外部的知识。早期的工作主要是将知识图谱嵌入和词嵌入一起训练。从BERT开始,涌现了一些融入外部知识的预训练任务。代表性工作如:
SentiLR[31] : 引入word-level的语言学知识,包括word的词性标签(part-of-speech tag),以及借助于SentiWordNet获取到的word的情感极性(sentiment polarity),然后将MLM拓展为label-aware MLM进行预训练。包括:给定sentence-level的label,进行word-level的知识的预测 (包括词性和情感极性); 基于语言学增强的上下文进行sentence-level的情感倾向预测。作者的做法挺简单的,就是把sentence-level label或word-level label进行embedding然后加到token embedding/position embedding上,类似BERT的做法。然后,实验表明该方法在下游的情感分析任务中能够达到state-of-the-art水平。
ERNIE (THU)[32] : 将知识图谱上预训练得到的entity embedding融入到文本中相对应的entity mention上来提升文本的表达能力。具体而言,先利用TransE在KG上训练学习实体的嵌入,作为外部的知识。然后用Transformer在文本上提取文本的嵌入,将文本的嵌入以及文本上的实体对应的KG实体嵌入进行异构信息的融合。学习的目标包括MLM中mask掉的token的预测;以及mask文本中的实体,并预测KG上与之对齐的实体。
类似的工作还包括KnowBERT, KEPLER等,都是通过实体嵌入的方式将知识图谱上的结构化信息引入到预训练的过程中。
K-BERT[33] : 将知识图谱中与句子中的实体相关的三元组信息作为领域知识注入到句子中,形成树形拓展形式的句子。然后可以加载BERT的预训练参数,不需要重新进行预训练。也就是说,作者关注的不是预训练,而是直接将外部的知识图谱信息融入到句子中,并借助BERT已经预训练好的参数,进行下游任务的fine-tune。这里头的难点在于,异构信息的融合和知识的噪音处理,需要设计合适的网络结构融合不同向量空间下的embedding;以及充分利用融入的三元组信息(如作者提到的soft position和visible matrix)。
这个方向主要包括了跨语言理解和跨语言生成这两个方向。
对于跨语言理解,传统的方法主要是学习到多种语言通用的表征,使得同一个表征能够融入多种语言的相同语义,但是通常需要对齐的弱监督信息。但是目前很多跨语言的工作不需要对齐的监督信息,所有语言的语料可以一起训练,每条样本只对应一种语言。代表性工作包括:
对于跨语言生成,一种语言形式的句子做输入,输出另一种语言形式的句子。比如做机器翻译或者跨语言摘要。和PTM不太一样的是,PTM只需要关注encoder,最后也只需要拿encoder在下游任务中fine-tune,在跨语言生成中,encoder和decoder都需要关注,二者通常联合训练。代表性的工作包括:
多模态预训练模型,即:不仅仅使用文本模态,还可以使用视觉模态等一起预训练。目前主流的多模态预训练模型基本是都是文本+视觉模态。采用的预训练任务是visual-based MLM,包括masked visual-feature modeling and visual-linguistic matching两种方式,即:视觉特征掩码和视觉-语言语义对齐和匹配。这里头关注几个关于image-text的多模态预训练模型。这类预训练模型主要用于下游视觉问答VQA和视觉常识推理VCR等。
双流模型:在双流模型中文本信息和视觉信息一开始先经过两个独立的Encoder(Transformer)模块,然后再通过跨encoder来实现不同模态信息的融合,代表性工作如:NIPS 2019, ViLBERT[37]和EMNLP 2019, LXMERT[38]。
单流模型:在单流模型中,文本信息和视觉信息一开始便进行了融合,直接一起输入到Encoder(Transformer)中,代表性工作如:VisualBERT [39],ImageBERT[40]和VL-BERT [41]。
预训练模型的参数量过大,模型难以部署到线上服务。而模型压缩能够显著减少模型的参数量并提高计算效率。压缩的方法包括:
知识蒸馏(knowledge diistillation):用一些优化目标从原始的大型teacher模型中蒸馏出一个小的student模型。通常,teacher模型的输出概率称为soft label,大部分蒸馏模型让student去拟合teacher的soft label来达到蒸馏的目的。蒸馏之所以work,核心思想是因为好模型的目标不是拟合训练数据,而是学习如何泛化到新的数据。所以蒸馏的目标是让学生模型学习到教师模型的泛化能力,理论上得到的结果会比单纯拟合训练数据的学生模型要好。
当然,模型压缩通常还会结合上述多种方法,比如剪枝+蒸馏的融合方法。常见的知识蒸馏的 PTMs如下表所示。
想深入了解BERT蒸馏原理的话,推荐参考rumor大神的文章,BERT蒸馏完全指南|原理/技巧/代码,里面详细介绍了上表中涉及到的各种蒸馏方法,同时对蒸馏做了很多细致的总结。如:蒸馏的提升来源:一方面来源于从精调阶段蒸馏->预训练阶段蒸馏,另一方面则来源于蒸馏最后一层知识->蒸馏隐层知识->蒸馏注意力矩阵;温度参数$T$以及soft label和hard label的loss比例$\alpha$的设置;蒸馏的代码实战等。
本文是对邱锡鹏老师2020年的一篇预训练模型survey的简单梳理。主要针对survey中提到的四大类预训练模型的分类体系做了梳洗,这四大类预训练模型分类体系为:
这篇综述文章信息量非常足,关于其他部分,如下游任务中的应用,预训练的技巧,未来方向等将在以后的文章中进行分享。
最后,欢迎大家关注我的微信公众号,蘑菇先生学习记。会定期推送关于算法的前沿进展和学习实践感悟。
]]>首先解释下Disentangled的概念。这个概念最早可以追溯到Bengio et al., 2013的文章 Representation Learning: A Review and New Perspectives,Disentangled可以翻译为分离式、解耦式或者解离式。与之对应的是Entangled,即:耦合式。参考ICML 2019 best paper中的论述:challenging common assumptions in the unsupervised learning of disentangled representations,目前非正式的定义如下:
按照个人的理解来解读下上面三条非正式定义。第一条想表达的是变化的数据中总蕴含着一些不变的隐因子,是这些隐因子决定了真正的数据分布。即:真实数据实际上是由这些隐因子生成的,思想类似混合高斯分布,分离式表征目标是将这些隐因子解离出来。这一条实际上阐明了分离式表征的核心原理和假设,即:真实的观测数据是由两阶段的生成过程生成的。首先,会从一个分布$P(\boldsymbol{z})$随机抽取一个隐变量$\boldsymbol{z}$,该隐变量蕴含着原始数据中的某种语义;接着会基于该条件概率分布$P(\boldsymbol{x}|\boldsymbol{z})$采样生成真实的观测样本$\boldsymbol{x}$。这种生成模型的关键思想在于高维数据$\boldsymbol{x}$能够通过低维的隐语义因子$\boldsymbol{z}$来解释和映射生成。第二条想表达的是不同隐因子之间相互独立,表征向量中某些维度的取值只会受到对应的隐因子的变化的影响,对其它隐因子的变化鲁棒性高。第三条是对第二条的补充,分离式表征中的不同维度与不同隐因子之间有着映射关系,某个隐因子的变化会引起该分离式表征中对应的维度取值的变化。
总结一下,第一条指出了隐因子的重要性和分离式表征的核心原理和假设;第二条是隐因子的鲁棒性性质;第三条是隐因子和分离式表征之间的关系,隐因子应当能够各自独立地映射到分离式表征不同的维度上。
进一步阐述分离式表征的特点,仍然参考:ICML2019 Best Paper: Challenging Common Assumptions in the Unsupervised Learning of Disentangled Representations,
总结一下,Distentangled的目的就是希望从低阶的观测数据中分离抽象出潜在(latent, underlying)、高阶的解释性因子 (explanatory factors);而Disentangled Representation的目的是希望将分离出来的factors独立地映射到表征向量中不同维度的的latent units上。一方面,这样的表征能够融合多种的解释性因子,语义性和解释性更强;另一方面,不同因子之间独立性较强,某个因子的轻微扰动,不会对其它因子造成过多影响,鲁棒性较强;最后,如果某个task和某个factor高度相关,而与其它factor不相关时,分离式表征也能够更好地通过该相关的factor解决任务,适用性更强,有利于迁移学习和小样本学习。相反,Entangled Representation由于耦合了所有的factor,学习出来的Representation是高度依赖于特定任务的,且解释性不够强。
个人认为,目前主流的LDA,LSA,矩阵分解等方法,其实都是entangled representation,虽然不同隐维度能够表征一定的语义,但是不同维度之间实际上是耦合的,语义存在重叠,是目标任务导向的,在可解释性上比较牵强。Distentangled Representation希望能够将隐因子解耦开,学习到的表征中的不同部分能够反映不同隐因子,由于不同隐因子表达着不同的语义,因此学习到的表征的不同维度实际上蕴含着相互独立的语义,具备较强的可解释性,并且有利于迁移学习。
但是这里头值得强调的一点是,Disentangled Representation可以是任意形式的数据以及依赖于这个数据的问题抽象形式,它应该能够反映问题本身的一些内在结构。但是通常情况下,这样的抽象通常要建立在我们对数据的先验认知上,也即:具备归纳偏置(inductive bias)。比如graph图数据中,结点连边关系可能是受到某种潜在因子的约束,那么就可以用Distentangled Representation的方式来解离并表征这种潜在的因子。或者进一步通过监督信号来引导分离式表征的学习,此时才有可能学习到well-Disentangled的表征。这也是ICML2019 best paper的主要观点,数据或模型不具备归纳偏置时,无监督分离式表征是无法学习好的。下面要介绍的两篇文章都有引入监督信息,因此不在这个范畴里。
下面将展开介绍两篇在GNN领域应用分离式表征的文章。ICML 2019 DisenGCN 和 SIGIR 2020 DGCF。DisenGCN是基于分离式表征的图神经网络的奠基性工作;而DGCF借鉴了DisenGCN的思想,将分离式表征应用于图协同过滤中,也是分离式表征在推荐系统中的奠基性工作。
DisenGCN的动机主要是为了解决传统的GCN不能将潜在的因子解离开来进行节点表示学习的问题。也就是说传统的GCN方法都是Entangled,对邻居进行卷积形成耦合式表征,即:表征向量不同维度因子之间的语义是耦合的,忽略了不同维度对连边形成的影响程度可能是不同的,不仅容易模糊不同维度的语义边界,也很容易造成过平滑的表征。
为了将分离式表征用于图神经网络模型,作者认为图结构中的结点之间的连接方式是受到潜在的因子影响的,也就是说,不同的隐因子会造成不同的连边关系。在进行表征学习时,将造成节点连边的因子解离出来,并独立地映射到相对应的表征向量不同维度上,可以让模型更具有可解释性,学习到的表征对变化的适应性也更强,鲁棒性更强,泛化能力更好。
为了解决这样的问题,作者提出了一种创新的邻域路由机制 (neighborhood routing mechanism),对某个结点,能够动态地识别出造成该结点与某邻域结点间连边关系的隐因子,并相应地将该邻居结点分配到该隐因子所属channel,通过该channel上的结点的卷积操作来形成与该隐因子相关的Distangled Representation。
从总体上先梳理下整个方法。作者对于图数据的抽象和假设的点体现在,结点之间连边的形成可能受到多种潜在因子的影响。这个假设是符合我们对于图数据的先验认知的。现实世界中,各种各样的图,其连边拓扑结构是受到不同因素的影响而形成的。这种因素通常不容易显式地在数据中记录和表达出来,我们的目标是解离出这种潜在因子,并将这些潜在因子独立地映射到结点表征向量不同维度上,从而形成分离式表征,即表征的不同部分都对应着某种语义。
DisenGCN的输入是Graph $G=(V,E)$,每个结点$u \in V$有对应的特征向量$\boldsymbol{x}_u \in \mathbb{R}^{d_{in}}$。DisenGCN的目标是学习结点的分离式表征,即:
$$
\boldsymbol{y}_u=f(\boldsymbol{x}_u, {\boldsymbol{x}_v:(u,v) \in G })
$$
$f$看做是DisenGCN,输入是目标结点$u$的特征向量以及其邻域结点的特征向量,输出是$u$结点的分离式表征$\boldsymbol{y}_u \in \mathbb{R}^{d_{out}}$。其中,$\boldsymbol{y}_u$由$K$个独立的组件构成,即:$\boldsymbol{y}_u=[\boldsymbol{c}_1, \boldsymbol{c}_2,…,\boldsymbol{c}_K]$,$K$是要分离出来的隐因子数量,是超参数。$\boldsymbol{c}_k \in \mathbb{R}^{d_{out}/K}$是分离出来的第$k$个隐因子对应的表征组件,各组件的维度数假设相同。即:不同隐因子会各自独立地映射到表征向量的部分维度上,极端情况下,当$K=d_{out}$时,此时每个隐因子都映射到向量的一个维度上。可以看出,DisenGCN的核心目标就是学习出各个隐因子对应的表征,然后拼接在一起形成最终的分离式表征。
DisenGCN的核心组成:DisenConv layer的结构如下,DisenConv layer的输入为目标结点特征向量$\boldsymbol{x}_u$以及其邻域结点特征向量集合${\boldsymbol{x}_{v}}$,输出是该目标结点$u$的分离式表征。
图中的隐因子数量超参数为3,即:3个通道。从隐因子的抽象语义来说,任意一个结点$u$可能是通过任意一种通道到达其邻居结点$v$的。因此,我们的目标是希望解离出形成每种连边关系的通道隐因子,将这种通道隐因子解离出来,并形成每个结点在每个通道下的分离式表征,最终的分离式表征是由这三种通道下的分离式表征拼接形成的,每段分离式表征衡量了结点在相应通道下的语义。
首先,每个邻居结点$v$对应的原始的特征向量会经过一个通道特定的参数映射矩阵$\boldsymbol{W}_k$映射到该通道$k$,并经过L2-norm,得到$v$结点该通道上的特征向量$\boldsymbol{z}_{v,k}$,称之为邻居结点$\boldsymbol{v}$在通道向量。
$$
\boldsymbol{z}_{v,k}= \text{norm}(\sigma(\boldsymbol{W}_k^T \boldsymbol{x}_v+ \boldsymbol{b}_k))
$$
每个结点都可以通过上述公式来得到初始的通道特定的向量。
接下来是卷积操作的迭代步骤,
$$
p_{v,k}^{(t-1)}=\text{softmax}(\boldsymbol{z}_{v,k}^T \boldsymbol{c}_k^{(t-1)}/\tau)= \frac{\exp(\boldsymbol{z}_{v,k}^T\boldsymbol{c}_k^{(t-1)}/\tau)}{\sum_{k^{\prime}=1}^K \exp(\boldsymbol{z}_{v,k^{\prime}}^T{\boldsymbol{c}_{k^{\prime}}}^{(t-1)}/\tau)}
$$
$\boldsymbol{c}_k^0$使用上述公式,即$\boldsymbol{z}_{u,k}$来初始化。
$$
\boldsymbol{c}_k^{(t)}=\text{norm}(\boldsymbol{z}_{u,k}+\sum_{v:(u,v) \in G} p_{v,k}^{(t-1)}\boldsymbol{z}_{v,k})
$$
$t$是迭代次数,上述两个步骤可以反复迭代多次。上述更新过程非常像EM算法。实际上,作者在证明上述路由机制的收敛性的时候就用到了EM算法来证明。做个类比,$\boldsymbol{c}_k^{(t)}$是$k$通道下的聚类中心$u$,与$u$结点相连的邻居结点是属于该聚类簇里的结点,需要根据这些结点来不断更新聚类中心向量,更新的方式是看这些邻居结点在$k$通道下与$u$结点的亲和度值,根据该亲和度值来加权更新。
另一方面,又很像GATs中的注意力机制,$p$就像是注意力分数的概率分布,只不过GATs中的注意力概率分布是定义在所有邻居结点上的;而此处的p是定义在所有通道上的概率分布。通过上述路由过程,能够把和连边相关的因子解离出来,并通过这种soft形式的亲和度来加权形成分离式表征。
对每个通道$k$,都执行上述过程,从而形成一阶的分离式表征,$\boldsymbol{y}^{(1)}_u=[\boldsymbol{c}_1^{(1)}, \boldsymbol{c}_2^{(1)},…,\boldsymbol{c}_K^{(1)}]$。这个过程是1层DisenConv layer输出的。
为了捕获多阶的结点关系,叠加多层DisenConv layer,从而形成多阶的分离式表征,递推公式即:
$$
\boldsymbol{y}_u^{(l)}= \text{dropout}(f^{(l)}(\boldsymbol{y}_u^{(l-1)}, {\boldsymbol{y}_v^{(l-1)}:(u,v) \in G }), 1 \leq l \leq L
$$
作者此处的下游任务是多分类,因此在$\boldsymbol{y}_{u}^{(L)}$后面接一层全连接层。即:$\boldsymbol{y}_{u}^{(L+1)}={\boldsymbol{W}^{(L+1)}}^T \boldsymbol{y}_u^{(L)}+\boldsymbol{b}^{(L+1)}$。
如果每个样本的分类标签只可能有1种,就使用多分类交叉熵损失来训练。即:
$$
-\frac{1}{C}\sum_{c=1}^C \boldsymbol{y}_u(c) \ln (\hat{\boldsymbol{y}}_u(c))
$$
其中,$\hat{\boldsymbol{y}}_u(c)=\text{softmax}(\boldsymbol{y}_{u}^{(L+1)})$。
如果每个样本的分类标签有可能多取值,就使用多个二分类损失来训练。即:
$$
-\frac{1}{C}\sum_{c=1}^C [\boldsymbol{y}_u(c) \text{sigmoid}(\boldsymbol{y}_{u}^{(L+1)}(c)) + (1-\boldsymbol{y}_u(c)) \text{sigmoid}(-\boldsymbol{y}_{u}^{(L+1)}(c))]
$$
注意,$\boldsymbol{y}_u(c)$和$\text{sigmoid}(\boldsymbol{y}_{u}^{(L+1)}(c)$都是向量。
作者把要解离的因子定义和抽象在结点与结点之间的连边关系上,认为不同的因子对连边形成的影响程度是不同的。因此可以将邻居卷积分通道来卷积,这样可以分离出和通道相关的该隐因子对应的表征。想法挺巧妙的,实践中是否真正有效,有待验证。另外,不同连边因子稀疏性可能不太一样,有的可能过分稀疏,强行给每种连边关系都提高影响力可能会造成有些因子并不能很好地学习到。而这种情况下,感觉耦合式表征能更好地学习,因为其它因子也可以一定程度上迁移到稀疏因子上,所有因子之间是互帮互助的。最后,作者开篇提到不同因子之间是独立的,但是实际上该方法理论上无法保证不同因子是独立的,文中也没有通过某些独立性约束来达到该目的。因此,可能学习到的表征并不是weill-disentangled,不同因子间可能仍然存在着较大的联系。最后,对于语义直觉上的刻画和实验比较欠缺,这些隐因子具体对应于观测数据中的哪些语义,是什么样的映射关系,是需要探究的。
这篇文章是何向南老师的团队发表在SIGIR2020上的一篇关于分离式图协同过滤的推荐方法,将分离式表征和GNN结合在一起,应用于二分图建模和推荐上。
用户对物品的交互意图是多种多样的,传统的图神经网络没有加以区分,假定了所有user和item之间的交互关系是无差别的。导致的问题是:学习到的嵌入表示是次优的,且无法建模多种多样的交互关系,发掘出细粒度的用户意图。disentangle纸面上含义是解开。也就是说,对于传统方法,学习到的表征只蕴含着粗粒度的user-item交互意图,也即意图是纠缠在一起,未解开的,因为模型并没有显式地去建模和挖掘这种细粒度的意图。disentangle的目的是希望去挖掘和解开用户的意图,使得学习到的表征能够表达出用户多种多样的意图,并且能够将该意图映射到用户的表征上。这样的表征称为:disentangled representations. 因此本文提出了DGCF (Disentangled Graph Collaborative Filtering) 方法,去建模每对user-item交互关系上用户的隐意图分布,并将该隐意图映射到表征上,从而形成分离式表征。可以看出,本文作者应用分离式表征在GNN上,其对图数据内在结构的抽象依然是建立在结点连边关系上,和DisenGCN类似,认为结点之间之所以能够形成连边,是受到一些潜在的因子影响的,具体的,在基于二分图的推荐系统上,这种因子从语义上反映了用户多种多样的交互意图。
先从整体上梳理DGCF。整个方法仍然遵循着基于消息传递机制的GNN那套框架,如NGCF。在NGCF中,任意user-item边的类型没有区分对待。而在DGCF中,我们的目标是从用户细粒度的意图角度来探索任意user-item连边关系形成的原因;并基于探索到的意图来生成分离式表征。从直觉上来举例,这种意图可能是用户为了消遣时间,才选择交互某个物品;也可能是为了给家人购物,才选择交互某个物品等等。不同的意图对用户交互行为产生的贡献度是不同的。挖掘出这种细粒度的意图,并独立地映射到最终的分离式表征向量上,使得表征向量的不同维度能够反映不同的用户意图,是本文的重点目标。当然,从本质上来说,本文所说的意图仍然是潜在、隐式的意图,刻画的真实语义需要通过实验来观察。
为了挖掘出细粒度的用户意图,作者首先将最终的表征向量划分成多个chunk,每个chunk独立地与某种待挖掘的意图关联起来,因此需要针对每种意图,来形成意图感知的chunk表征,最终的分离式表征则由所有的chunk表征拼接而成。那么问题的关键在于如何发掘潜在的意图以及如何基于挖掘的意图生成分离式表征。
1.首先,针对意图的挖掘,作者将意图隐因子抽象在图数据中的连边关系上,建模每条连边在所有$K$个意图上的概率分布:$\boldsymbol{A}(u,i)=(A_1(u,i), A_2(u,i), …, A_K(u,i))$。$A_k(u,i)$表示第$k$个意图促使用户$u$交互$i$的置信度,即连边$(u,i)$形成的置信度。$A$可以看作是邻接矩阵。邻接矩阵$A_k$的某个单元$(u,i)$取值非零,则代表用户$u$交互了物品$i$,其取值反映了意图$k$促成此次交互行为的置信度。因此,$K$个意图的话,就会有$K$个邻接矩阵,该邻接矩阵的取值会在训练的过程中不断调整,直至收敛,也即邻接矩阵是可变的。针对$K$个邻接矩阵的同一个单元$(u,i)$,最终的取值即为每种意图对该条连边形成的贡献度,通过横向比较所有邻接矩阵同一个单元取值大小就可以看出每种意图对同一个交互行为的影响力了。
2.其次,针对分离式表征的生成,每个邻接矩阵都对应着一个sub-graph,$A_k$则对应着意图$k$下的用户物品二分图,我们称之为意图感知的加权子图,即:intent-aware weighted sub-graph。所有$K$个sub-graph的结点以及连边拓扑结构完全一样,差异只在连边的权重不一样。因此,意图$k$对应的分离式表征可以通过在对应的intent-aware weighted sub-graph上,使用GNN来提取。由于所有意图子图的结点和连边关系都相同,为了体现差异性,关键点就在于连边权重如何纳入GNN卷积过程中 (下文会提到, 通过消息传递机制中的decay系数)。
上述两个步骤会纳入一个统一的迭代框架下,也是1层Graph Disentangling Layer的核心过程,
1.首先,通过$K$个邻接矩阵对应的意图sub-graph来提取$K$个意图下的chunk表征。
2.接着,每种意图sub-graph下,每条连边对应的两个结点使用步骤1提取到的chunk表征之间的亲和度来动态调整和提炼新的连边权重,即邻接矩阵的取值会发生变化。
上述两个步骤不断迭代 (类似EM算法),比如,接着步骤2,基于改变了权重后的意图sub-graph,进一步来进行GNN卷积生成新的意图chunk表征,然后继续基于新的chunk表征来调整连边权重。周而复始。
当然,在表征学习的过程中,作者还施加了一些chunk表征之间的独立性约束等条件,从而使得学习到的表征更well-disentangled。
总之,我们应当先明确DGCF的输入:user-item 交互二分图;输出:目标产物,即user和item的分离式表征;随机初始化的0阶表征是唯一可训练参数,除此之外,在训练的过程中,中间产物,即每个意图对应的邻接矩阵也是可变的 (通过表征向量之间的亲和度来表示,即:邻接矩阵的取值是关于表征向量的函数,因此邻接矩阵并不是训练参数)。
了解了整个方法的大体思路后,DGCF方法整体上还是比较简洁的,我们先来看DGCF的框架图:
最左侧是原始的user-item交互二分图以及用户的ID embedding;ID embedding($d$维)根据latent intent factor的数量(e.g., $K$个),平均切成$K$ chunk,每个chunk的embedding size为$d/K$,每个chunk embedding $\boldsymbol{e}_{ku} \in \mathbb{R}^{d/K}$对应一种意图$k$。所有的chunk embedding拼接形成最终的表征向量,即:$\boldsymbol{e}_u=(\boldsymbol{e}_{1u},\boldsymbol{e}_{2u},…,\boldsymbol{e}_{Ku})$。即:每个chunk embedding会各自独立地映射到最终的表征向量部分维度上。物品侧同理。
中间部分,每种意图$k$都对应一个intent-aware weighted sub-graph $\mathcal{G}_k$,也可用邻接矩阵$\boldsymbol{A}_k$来表示,该sub-graph用于提取用户和物品的chunk embedding,即 $\boldsymbol{e}_{ku}$和$\boldsymbol{e}_{ki}$。不同的sub-graph连边关系和原图一样,权重是可变的,在迭代中不断调整。在下文中的Graph Disentangling Module中会进一步介绍。
意图是隐因子latent factor,每个意图对应一个intent-aware的带权交互子图,边的权重是动态调整的,会随着迭代的进行,来不断提炼(refine)。针对每个意图子图,迭代的过程大致如下:意图子图→基于消息传递的GNN邻域汇聚→形成子图对应的chunk表征→基于表征间的亲和度调整该子图连边权重→对调整后的子图继续使用基于消息传递的GNN邻域汇聚→形成新的子图对应的chunk表征→基于新的表征间的亲和度继续调整子图连边权重→……;周而复始,不断迭代直到收敛。
前面Solution的开篇提到了,本文中唯一可训练对象是目标产物的分离式表征,但是中间产物意图邻接矩阵也是随着迭代的进行不断变化的。因此二者都要进行初始化。只不过意图邻接矩阵的初始化是用常数来初始化的,随着迭代的进行,其取值是关于表征向量的函数。
首先需要对用户的chunk embedding $\boldsymbol{e}_{ku}^{(0)}$进行初始化。记随机初始化的embedding向量为:$\boldsymbol{u}=(\boldsymbol{u}_1,…,\boldsymbol{u}_K)$。也即:$\boldsymbol{e}_{1u}^{(0)}=\boldsymbol{u_1},…,\boldsymbol{e}_{Ku}^{(0)}=\boldsymbol{u_K}$。$(0)$代表0阶。每个意图下的chunk embedding都是各自独立地进行随机初始化,这样能够保证不同的chunk embedding在开始训练的时候就存在比较大的差异。
同理,每个意图子图中的连边的权重或者说邻接矩阵的值,也要进行初始化。记连边$(u,i)$在所有$K$个意图子图下的权重构成的向量为:$\boldsymbol{S}(u,i)$,则初始时,默认所有子图下该连边的权重都为1,即:$\boldsymbol{S}{(u,i)=(S_1(u,i),…,S_K(u,i))=(1,…,1)}$,代表迭代开始的时候,所有的意图促成某个交互行为的贡献度是一样的,。
下面都以用户为例,来介绍用户分离式表征提取的整个过程。物品侧是对称的,同理可得。首先来看单独一层Graph Disentangling Layer的输入与输出,
$$
\boldsymbol{e}_{ku}^{(1)}=g(\boldsymbol{u}_k, {\boldsymbol{i}_k| i \in \mathcal{N}_u})
$$
输入为用户$u$在意图$k$下的初始化表征 $\boldsymbol{u}_k$以及用户的邻域结点集合$\mathcal{N}_u$中物品的初始化表征$\boldsymbol{i}_k$,输出是一阶的用户分离式表征。
接下来是本文的重点和亮点,即:分离式表征提取的过程,涉及开篇提到的迭代过程。记迭代的总步数为$T$。此处要强调下,这里头涉及两个迭代的步数符号,一个是Graph Disentangling Layer层数,也即我们所熟悉的GNN的阶数,用带括号的$(l)$符号表示第$(l)$阶,总共的层数用$L$表示;另一个是,某一个Graph Disentangling Layer的内部,我们有一个迭代步数$t$,总共的步数为$T$(不带括号),代表提取某个意图$k$的分离式表征时所需要的迭代步数。下面介绍某个意图$k$的分离式表征的迭代过程。初始迭代时,分离式表征为:$\boldsymbol{u}_k^0, \boldsymbol{i}_k^0$,对第$t$步,
针对每条连边$(u,i)$,根据$K$个意图子图下的权重构成的向量$\boldsymbol{S}(u,i)$,进行跨意图的归一化,转成概率分布,来衡量不同意图对于该连边形成的贡献度,即:
$$
\hat{S}_k^t(u,i)= \text{softmax}(S_{k}^t(u,i))=\frac{\exp(S_{k}^t(u,i))}{\sum_{k^{\prime}=1}^K \exp S_{k^{\prime}}^t(u,i)}
$$
接着根据$\hat{S}_k^t(u,i)$计算消息传递时的decay系数,用于衡量在意图子图$\mathcal{G}$中,从$i$结点传递信息到$u$结点时的信息折扣比例,
$$
\mathcal{L}_k^t(u,i)=\frac{\hat{S}_k^t(u,i)}{\sqrt{D_k^t(u) \cdot D_{k}^t(i)}}
$$
其中,$D_k^t(u)=\sum_{i^{\prime} \in \mathcal{N}_u} \hat{S}_k^t(u,i^{\prime})$,$D_{k}^t(i)=\sum_{u^{\prime} \in \mathcal{N}_i} \hat{S}_k^t(u^{\prime},i)$。第一次迭代的时候,$D_k^t(u),D_k^t(i)$即分别为结点$u$和$i$的度。这个和NGCF论文中的衰减系数是类似的。
结点信息汇聚和更新:基于该系数来进行消息传递。值得注意的是,作者在做目标结点信息更新的时候,没有使用目标结点本身的信息,而只用了邻域汇聚到的信息来更新目标结点(结点0阶的表征在最后做layer combination有用到)。
$$
\boldsymbol{u}_k^t=\sum_{i \in \mathcal{N}_u} \mathcal{L}_k^t(u,i) \cdot \boldsymbol{i}_k^0
$$
使用$t=0$时的初始表征$\boldsymbol{i}_k^0$来表示要传递的信息。随着迭代步$t$的增加,要传递的信息保持不变。
意图$k$对应的邻接矩阵权重值的更新:基于更新后的表征,重新计算在意图$k$下,每条连边$(u,i)$中$u$和$i$结点之间的亲和度值,即:更新意图$k$对于这条连边形成的贡献值,这就是所谓的refine sub-graph的过程。
$$
S_{k}^{t+1}(u,i)=S_k^t(u,i)+{\boldsymbol{u}_k^t}^{\text{T}} \text{tanh}(\boldsymbol{i}_k^0)
$$
紧接着,基于更新后的邻接矩阵,继续重新开始迭代$t+1$步。上述4个步骤构成1个完整的迭代步,重复迭代至T步,就能够得到单层Graph Disentangling Layer输出的该意图$k$的分离式表征,也即1阶的分离式表征,即:
$$
\boldsymbol{e}_{ku}^{(1)}=\boldsymbol{u}_k^T
$$
作为副产物,一阶的邻接矩阵为:$\boldsymbol{A}_k^{(1)}=\hat{S}_k^T$,这个邻接矩阵蕴含着很丰富意图语义信息,能够用来做可解释性,在实验案例分析一节会用到。所有的$K$个意图都经过上述步骤,就能够形成一阶的分离式表征:$\boldsymbol{e}_u^{(1)}=(\boldsymbol{e}_{1u}^{(1)},\boldsymbol{e}_{2u}^{(1)},…,\boldsymbol{e}_{Ku}^{(1)})$
上述Graph Disentangling Layer叠加$L$层,就能够输出$L$阶的分离式表征,$\boldsymbol{e}_u^{(L)}$。层之间的递推式为:
$$
\boldsymbol{e}_{ku}^{(l)}=g(\boldsymbol{e}_{ku}^{(l-1)}, {\boldsymbol{e}_{ki}^{(l-1)}| i \in \mathcal{N}_u})
$$
按照我的理解,副产物$A_{k}^{(l)}$也会作为第$(l+1)$个卷积层的初始邻接矩阵来迭代,而不是对邻接矩阵重新赋值为全1来初始化。这一步文中没有强调,需要通过代码来佐证。
最终用户和物品的表征,作者采用了sum pooling的方式来对所有层输出的分离式表征做一个sum pooling,即:
$$
\begin{aligned}
\boldsymbol{e}_{ku}=\boldsymbol{e}_{ku}^{(0)}+…+\boldsymbol{e}_{ku}^{(L)} \\
\boldsymbol{e}_{ki}=\boldsymbol{e}_{ki}^{(0)}+…+\boldsymbol{e}_{ki}^{(L)}
\end{aligned}
$$
每个子图都会各自独立地提取对应的intent-aware representation;所有子图对应的chunk representation拼接在一起形成最终的disentangled representations. 为了使得每种意图之间互相独立,高度浓缩和蒸馏出和该意图最相关的信息,作者还提出了一种独立性建模模块。目标是希望不同意图子图得到的chunk representation之间相互独立。为此,作者采用了协方差相关性损失函数,称为independence loss:
$$
loss_{ind}=\sum_{k=1}^K \sum_{k^{\prime}=k+1}^K \text{dCor}(\boldsymbol{E}_k, \boldsymbol{E}_{k^{\prime}})
$$
$\boldsymbol{E}_k \in \mathbb{R}^{(M+N) \times (d/K)}$由意图$k$下的用户和物品表征拼接而成的矩阵。$dCor$为协方差,即:$\text{dCor}(\boldsymbol{E}_k, \boldsymbol{E}_{k^{\prime}})=\frac{\text{dCov}(\boldsymbol{E}_k, \boldsymbol{E}_{k^{\prime}})}{\text{dVar}(\boldsymbol{E}_k)\text{dVar}(\boldsymbol{E}_{k^{\prime}})}$。
最终,模型使用BPR Loss和independence loss这两个损失。且优化的时候,这两个损失是交替优化的。而不是相加起来同时优化。
MF,GC-MC(KDD2019),NGCF (SIGIR2019),DisenGCN (ICML2019),MacridVAE (NIPS 2019)。MF矩阵分解是最基本的baseline;GC-MC和NGCF是最近两年来比较流行的二分图协同推荐模型;DisenGCN和MacridVAE是基于分离式表征的方法。
可以看出,在3个公开数据集上,模型简直完虐其它方法,还是很给力的。最大的亮点在于,DGCF相比于NGCF和LightGCN等,没有引入任何额外的参数(不同意图的chunk表征的维度是从完整表征维度中平均分配而来的),相当于在相同参数量的情况下,提升了模型的泛化能力。
对于阶数,可以看出,DGCF叠加多层时,效果变好,说明对过度平滑的问题有一定的应对能力。
对于意图个数,可以看出,总体上意图在4个的时候最好。
对于独立建模模块,可以看出,有一定的影响,但是影响的程度其实很小。关键的提升在于Graph Disentangling Layer。
案例分析主要的目的是希望观察学习到的分离式表征是否真正具备语义。采用了Yelp2018数据集,从其辅助信息review中来观察语义。
随机抽取了两个用户$u_{10362}$和$u_{10360}$,对最终学习到的意图邻接矩阵(对应意图子图),观察某个用户的所有物品交互历史中,哪个分数最高,就用这个交互行为来代表这个意图的语义。比如在意图$k_1$对应的邻接矩阵中,用户$u_{10362}$交互物品$i_{88}$的意向分数最大,即邻接矩阵第10362行中,第88列的取值最大,就用第88列对应的物品的review来刻画这个意图$k_1$的语义;同理,用户$u_{10360}$ 交互的物品$i_{11732}$的review也可以用来刻画这个意图$k_1$的语义,通过纵向对比这两个物品的辅助信息,来观察意图对应的实际语义。例如:从图中可以看出,第一个交互意图的语义是用户独特的兴趣,第二个交互意图的语义是服务,第三个交互意图的语义是价格,第四个交互意图的语义是消遣。
这个案例分析还是比较有意思的,直观上来感受分离式表征的语义。
这篇文章引入了分离式表征到GNN模型中,是对ICML 2019文章DisenGCN很好的拓展。在推荐任务中也表现的很好,是可解释性推荐系统重要工作之一。文章的code也相应地开源了,因此很值得借鉴和实践一下。不过也存在一些疑惑,比如:
论文阅读—Disentangled GCN:https://zhuanlan.zhihu.com/p/72505821
如何评价ICML2019上挑战Disentanglement的Best Paper: https://www.zhihu.com/question/329270182/answer/716460545
传统的序列推荐方法主要建模的是session-level的短期序列,仅能够捕获蕴含在用户近期交互物品中的短期偏好,缺乏对用户长期偏好的挖掘。因此,本文的主要动机就是考虑用户长期的交互序列,希望能够从中挖掘出用户长期稳定的偏好。除此之外,作者还希望能够显式地建模物品与物品之间的共现关系。为此,作者提出了几种方法来分别捕获用户的短期兴趣,长期兴趣以及物品之间的共现关系,并融合这些因素进行打分和推荐。
先从总体上介绍下整个方法。整个方法实际上很像矩阵分解那一套框架。只不过分解的时候考虑了短期兴趣和长期兴趣。这里头最重要的是理解输入序列数据怎么规整成矩阵分解的形式,即point-wise分解和打分 (比如:用户嵌入和物品嵌入点积)。
原始的输入数据是user-level的序列。$S^u=(I_1,I_2,…,I_{|S_u|})$,由于是user-level的序列,每条序列长度很长,如果直接建模的话,总的样本量正比于用户数,相对较少。因此需要对序列进行切割来做数据增强和长短期序列区分。可以通过在user-level的序列数据上做窗口滑动来增强,窗口内部的子序列构成了短期序列,从窗口左侧端点开始向左到起始点的子序列构成了长期序列,从窗口右侧端点开始向右的子序列构成了目标序列。这里头有好几个超参数。滑动窗口的大小$|L|$(即:决定了短期序列的长度),滑动窗口的左端点起始值 $l$(即:决定了长期序列长度的最小值),以及目标序列的长度 $|T|$。
形式化地,增强后的每个sample有3段子序列,即:$S_{u,l}=[H_{u,l} ; L_{u,l} ; T_{u,l}]$,$l$是滑动窗口的左侧端点,则:$H_{u,l}=(I_1, I_2,…,I_{l-1})$是长期交互序列,$L_{u,l}=(I_l,I_{l+1},…,I_{l+|L|-1})$是滑动窗口内部的长度为$|L|$短期交互序列,$T_{u,l}$是大小为$|T|$的目标序列。
则,本文的问题是输入长期序列$H_{u,l}$和短期序列$L_{u,l}$,来输出用户$u$接下来会感兴趣的$\text{Top-K}$个物品,并在目标序列$T_{u,l}$上进行评估。命中越多目标序列$T_{u,l}$中的物品,说明模型泛化性越好。所谓的长短期,实际上就是从物品交互时间的久远来衡量,最近交互的若干个物品构成了短期交互序列,再之前的交互构成了长期交互序列。
在解决序列推荐方法上,除了物品和序列表征的过程有所差异之外,目前主流的方法都是利用物品表征和用户表征,来预测next item,即:预测所有的$N$个物品上的概率分布,推荐$K$个概率最大的,实际上是个多分类问题。但是这篇文章将多分类转成了二分类问题,即:将目标序列$T_{u,l}$中的物品$i$和用户$u$作配对,转化成$(u,i)$ 正样本对,这样就可以使用矩阵分解的方式来拟合分数。此外,此处采样了负样本,即:$(u,i,j)$三元组,$j$是采样的负样本,最后用pair-wise的BPR损失来训练。总之,输入的用户短期序列和长期序列都只是为了获取某种刻画用户兴趣维度的表征,并基于多样化的用户兴趣表征来多维度地联合预测分数。
因此,问题的关键是如何捕获输入的短期和长期序列中蕴含的用户偏好。先总体看下该方法的架构示意图。
如上图所示,最左侧是初始的兴趣表征模块,包含了用户通用兴趣表征,短期序列中的物品表征和长期序列中的物品表征。中间是兴趣建模模块,即:如果对初始的表征进行处理和融合;右侧是基于建模得到的兴趣表征进行分数的预测,包括了3个分数来源,通用兴趣贡献分,长短期融合兴趣贡献分以及物品共现分。
$$
\hat{r}_{u,j}=\boldsymbol{p_u}^T \boldsymbol{q}_j + {\boldsymbol{p}_{u,l}^C}^T \boldsymbol{q}_j + \frac{1}{|L|} \sum_{i \in L_{u,l}}\boldsymbol{e}_i^T\boldsymbol{W}_r\boldsymbol{q}_j
$$
其中,$\boldsymbol{p}_u$是用户的通用兴趣表征,$\boldsymbol{q}_j$是目标物品的初始表征,$\boldsymbol{p}_{u,l}^C$是用户的长短期兴趣融合表征,最后一项是目标物品和用户短期交互序列中的物品的共现分数。这三项分别对应着通用兴趣建模、短期和长期兴趣建模以及物品共现建模。下面依次来介绍。
输入的短期序列$S_{u,l}$和长期序列$H_{u,l}$都记录着产生该行为序列的用户$u$,因此作者在做序列建模的时候,将该用户$u$也考虑进去了。作者采用随机初始化的$\boldsymbol{p}_u$来表征用户静态和通用的的兴趣。最后在预测层预测分数的时候,采用了简单矩阵分解策略,即:$\boldsymbol{p}_u^T \boldsymbol{q}_j$,$q_j$是目标预测物品$j$的embedding(实际上就是目标序列集合中的物品),该分数即:通用兴趣贡献分。
输入是短期序列$S_{u,l}$,输出是蕴含在短期序列中用户的兴趣表征$\boldsymbol{p}_{u,l}^S$,$S$是short-term的缩小。如图所示,左下角的部分。作者采用了两层的GNN网络来捕获蕴含在序列中的局部结构信息,并形成用户短期兴趣表征。为了能够用GNN来建模,需要将序列转成session graph。策略是,短期序列中的每个物品和其后面的3个物品做连接,并对形成的邻接矩阵按照行做归一化。如下图所示:
信息传播和聚合:接着,基于该邻接矩阵来进行邻域信息传播和汇聚。即:
$$
\boldsymbol{h}_i=\text{tanh}(\boldsymbol{W}^{(1)}\cdot [\sum_{k \in \mathcal{N}_i} \boldsymbol{e}_k \boldsymbol{A}_{i,k} || \boldsymbol{e}_i]), \forall i \in L_{u,l}
$$
$\sum_{k \in \mathcal{N}_i} \boldsymbol{e}_k \boldsymbol{A}_{i,k}$是从邻域传播的信息;和自身$\boldsymbol{e}_i$做一个拼接($||$),再过一个非线性变换。
上述得到了序列中每个物品的表征后,需要形成用户的短期兴趣表征。先mean pooling得到短期序列表征,再和用户的通用表征做一个拼接并过一层非线性变换融合。即:
$$
\boldsymbol{p}_{u,l}^S=\text{tanh}(\boldsymbol{W}^{(2)}[\frac{1}{|L|}\sum_{i \in L_{u,l}}\boldsymbol{h}_i || \boldsymbol{p}_u])
$$
这个是本文主要的亮点所在,如果对多维度注意力机制和带记忆网络的注意力机制不太熟悉的话,强烈建议先阅读我之前的一篇博客:深度学习中的注意力机制调研。这部分的输入是长期序列$H_{u,l}$,输出是用户的长期兴趣表征。为了能够捕获长期兴趣,通常可以采用外部记忆单元来存储用户随时间变化的动态偏好,但是如果为每个用户都存储这样的偏好,会耗费很大的存储空间,而且通过这种方式捕获到的兴趣可能和通用兴趣$p_u$相似。为了解决这些问题,作者采用了一个记忆网络来存储所有用户共享的隐兴趣表征,每种隐单元都代表着某种特定的用户隐兴趣,给定用户长期交互序列$H_{u,l}$,我们可以学习到多种不同兴趣融合的用户长期兴趣表征。记长期序列中每个物品的表征形成的表征矩阵为:$\boldsymbol{H}_{u,l}\in \mathbb{R}^{d \times |H_{u,l}|}$,即:第$j$列为长期序列中第$j$个物品的表征向量。记忆网络中存储着所有用户共享的隐兴趣表征,针对每一个用户以及其长期交互序列,我们需要为该用户生成与其兴趣匹配的query embedding $\boldsymbol{z}_{u,l}$,然后根据该query embedding去记忆网络中检索有用的隐兴趣表征,从而形成该用户特定的长期兴趣表征。这里面最重要的就是query embedding的产生,作者采用了多维度的注意力机制。具体而言,
$$
\boldsymbol{H}_{u,l}:=\boldsymbol{H}_{u,l}+PE(H_{u,l})
$$
$$
\boldsymbol{S}_{u,l} = \text{softmax}\Big(W_a^{(3)} \tanh\big(W_a^{(1)}\boldsymbol{H}_{u,l}+(W_a^{(2)} \boldsymbol{p}_u)\otimes \boldsymbol{1}_{|H_{u,l}|}\big)\Big)
$$
其中,$W_a^{(1)}, W_a^{(2)}\in\mathbb{R}^{d\times d}, W_a^{(3)}\in\mathbb{R}^{h\times d}$是可学习的注意力参数,$\otimes$是外积操作。上述注意力机制考虑了用户的通用兴趣表征和长期行为序列,因此该注意力是general-interest and long-term sequence aware的。多维度注意力机制和通常的注意力机制其实差不太多。从语义上而言,$\boldsymbol{S}_{u,l}$每一行向量从某个语义角度衡量了长期行为序列中每个物品在该语义上的权重值,softmax应该是按照每行来做的,即:求每个序列中每个物品在该语义下的概率分布;基于该行向量所代表的注意力概率分布对长期序列做加权汇聚,可以得到在该语义上的用户query表征;共$h$行,则会形成$h$个用户query表征向量,即形成表征矩阵$\boldsymbol{Z}_{u,l} \in \mathbb{R}^{h \times d}$。
$$
\boldsymbol{Z}_{u,l} = \tanh(\boldsymbol{S}_{u,l} \cdot \boldsymbol{H}_{u,l}^T)
$$
$$
\boldsymbol{z}_{u,l}=\text{avg}(\boldsymbol{Z}_{u,l})
$$
实际上从语义上来讲,相当于将不同语义汇聚到的query embedding通过mean pooling汇聚在一起形成最终的query embedding。
总之,通过上述步骤,就能够形成用户通用兴趣和长期行为序列感知的检索向量$\boldsymbol{z}_{u,l}$。接下来就是根据该检索向量去记忆网络中检索出和该用户兴趣就相关的记忆,从而形成用户的长期兴趣表征。
使用门控机制来融合短期兴趣和长期兴趣。这里头的做法借鉴了LSTM/GRU,实际上和SR-GNN做结点信息更新的时候的策略是类型的,不作赘述。唯一要提的点就是,这里头实际上可以直接融合长短期序列表征$\boldsymbol{p}_{u,l}^S$和$\boldsymbol{p}_{u,l}^H$,但是作者实际用的时候融合的是,用户长期交互序列表征$\boldsymbol{p}_{u,l}^H$以及$\sum_{i \in L_{u,l}}\boldsymbol{h}_i$。可能是因为$\boldsymbol{p}_{u,l}^S$中融入了通用兴趣表征,而最后预测分数的时候,通用兴趣表征是单独作为一项贡献分的,再融合进长短期兴趣表征显得冗余。
做法很简单,门控的输出值是近期交互行为、通用兴趣表征、长期兴趣表征感知的,
$$
\boldsymbol{g}_{u,l}=\sigma(\boldsymbol{W}_g^{(1)} \cdot \frac{1}{|L|} \sum_{i \in L_{u,l}}\boldsymbol{h}_i + \boldsymbol{W}_g^{(2)} \boldsymbol{p}_{u,l}^H + \boldsymbol{W}_g^{(3)} \boldsymbol{p}_u)
$$
基于该门控值进行融合,得到的融合后的兴趣表征为:
$$
\boldsymbol{p}_{u,l}^C=\boldsymbol{g}_{u,l} \odot \frac{1}{|L|} \sum_{i \in L_{u,l}}\boldsymbol{h}_i + (\boldsymbol{I}_d - \boldsymbol{g}_{u,l}) \odot \boldsymbol{p}_{u,l}^H
$$
显式地对用户短期交互过的物品和目标物品做共现建模,采用了双线性函数:
$$
\boldsymbol{e}_i^T\boldsymbol{W}_r\boldsymbol{q}_j
$$
$\boldsymbol{W}_r$是可学习的物品相关性矩阵。$\boldsymbol{e}_i$是短期交互序列中的物品$i$的初始表征,$\boldsymbol{q}_j$是目标物品。
最后用BPR Loss来学习。不做赘述。
实验主要包括几个部分,
对比实验(方法包括:BPRMF,GRU4Rec,GRU4Rec+,GC-SAN,Caser,SASRec,MARank),居然没有选SR-GNN(个人认为虽然GC-SAN论文中战胜了SR-GNN,但是本人在很多实践中发现SR-GNN比GC-SAN好)。
消融实验:主要考察了通用兴趣,通用兴趣+短期兴趣,通用兴趣+短期兴趣+长期兴趣+gating长短期融合,通用兴趣+短期兴趣+长期兴趣+concat长短期融合,通用兴趣+短期兴趣+长期兴趣+GRU长短期融合。
(3)和(6)对比可以看出共现建模的好处;(1)和(2)对比看出短期兴趣建模的好处;(3)和(4)和(5)的结果说明gating机制的有效性,但是这个结果太不可思议了,gating比concat以及GRU好这么多?gating和GRU的差异主要就是有没有用$\boldsymbol{p}_u$吧?为了公平性,$\boldsymbol{p}_u$可以直接用到GRU里面来对比的。对此表示疑惑。
记忆单元的可视化: 验证每个记忆单元是否可以表示某种特定的兴趣。作者在MovieLens上做了case study。作者随机选了某个用户以及他观看过的电影,用其观看的电影直接作为query embedding,去计算在memory network上的注意力分数,即$s_i $。期望观察到的效果是,给定不同的电影query embedding,注意力分数分布不一样,在类似的电影上,某些维度的注意力分数也应该类似。
可以看到有三部Three Colors的电影的注意力分数分布挺近似的。DIe Hard是惊悚片,和其他的分布不一样。
这种可视化应该是目前论文写作的标配。
这篇文章总体上有一些借鉴的地方。全文最大的亮点在于长期兴趣的建模。基于长期行为序列来构造query embedding,然后去memory network中检索有用的兴趣。这种长期兴趣的建模范式可以借鉴到日常工作优化中。但是缺点是长期序列长度可能比较长,多维度注意力机制可能复杂度相对高一些。但是,另一方面,这篇文章创新度一般,主要是一些已有的机制的叠加和尝试,是否真正有效还有待实践和验证。
AAAI 2020:Memory Augmented Graph Neural Networks for Sequential Recommendation
]]>先从整体上梳理下整个方法。
下面围绕着几个方面来介绍,首先看下整个框架结构。
session-graph: 有向图。包括了4种边关系,入度边,出度边,同时入度和出度边(两个结点互相指向),自连接边。
如图中左下角的部分,每条序列构造连边的时候,根据相邻物品结点构造转移边以及自连接边。其中,相邻结点的转移边又可以根据两个结点之间的关系区分为,仅入度边,仅出度边,同时入度和出度边(两个结点互相指向)。
global-graph: 定义一个$\epsilon-\text{Neighbor Set}$,实际上就是说同一个序列,任意两个结点想构造连边时,这两个结点之间的单位距离必须小于$\epsilon$。构造得到的图是带权无向图。连边权重使用共现的次数来表示。对每个结点,只保留Top-N权重的边。$\epsilon$和Top-N机制的目的都是为了减小复杂度,如果序列所有结点之间做全连接,那么构造得到的图的边规模会非常庞大。
针对目标序列$S$中的某个物品结点$v_i$,我们要首先对它进行表征。结点$v_i$既出现在由序列$s$构成的session-graph中,又出现在global-graph中,我们可以从这两个图中分别提取结点$v_i$的表征,然后融合起来形成单个物品的表征。
提取全局图上的物品表征的主要好处是能够借鉴其它session中和目标session相关的有用信息。因此,这里头的关键点是,如何衡量全局图上的信息是否和目标session序列$S$相关,是否对目标结点$v_i$的表征有作用。
信息传播:为了实现这一点,作者提出了一种session-aware的注意力机制,计算global-graph上和$v_i$相邻的结点$v_j$的贡献值$\pi(v_i, v_j)$
$$
\pi(v_i, v_j)=\text{softmax}(\boldsymbol{q}_1^T \text{LeakyRelu}(\boldsymbol{W}_1[\boldsymbol{s} \odot \boldsymbol{h}_{v_j} || w_{ij}]))
$$
其中,$\boldsymbol{s}$是目标序列的表征,是目标序列中所有结点的mean pooling结果,即$\boldsymbol{s}=\frac{1}{|S|}\sum_{v_i \in S}\boldsymbol{h}_{v_i}$。$\boldsymbol{h}_{v_j}$是结点$v_j$的表征;$w_{ij}$是结点$v_i$和$v_j$在global graph上的连边权重。这个公式的好处是把目标序列$S$和邻居结点$v_j$以及目标结点$v_i$和$v_j$的亲和度$w_{ij}$都考虑进去了,求出来的注意力值能够衡量global-graph上的邻居结点$v_j$和目标session序列是否相关,对目标结点的表征是否有用。softmax在$v_i$的所有邻居结点上求一个概率分布。这个注意力机制是此部分的主要亮点,intuition很符合我们的认知。剩余的步骤就是常规的加权邻域汇聚结点并叠加多层来提取global-graph上多阶的结点关系。
$$
\boldsymbol{h}_{\mathcal{N}_{v_i}^g}=\sum_{v_j \in \mathcal{N}_{v_i}^g} \pi(v_i,v_j)\boldsymbol{h}_{v_j}
$$
$\boldsymbol{h}_{\mathcal{N}_{v_i}^g}$是从邻域结点传播到目标结点的信息。
信息汇聚:和自身的信息融合起来。拼接在一起过一个非线性变换。
$$
\boldsymbol{h}_{v_i}^g=\text{Relu}(\boldsymbol{W}_2[\boldsymbol{h}_{v_i}||\boldsymbol{h}_{\mathcal{N}_{v_i}^g}])
$$
上述步骤可以抽象成一个agg函数,叠加多层网络提取多阶关系,递推式:$\boldsymbol{h}_{v_i}^{g,(k)}=\text{agg}(\boldsymbol{h}_{v_i}^{g,(k-1)}, \boldsymbol{h}_{\mathcal{N}_{v_i}^g}^{g,(k-1)})$。
session-level的物品表征就是从session-graph中和目标结点$v_i$相邻的邻域结点$v_j$中提出信息。这里头的主要亮点就是注意力机制的设计。在计算序列中结点之间的attention值时,attention的设计考虑了结点之间的4种连边类型(即:出度,入度,自连接,双向),即:edge-type specific attention机制。这个是和基于SR-GNN的工作的差异点之一。SR-GNN基于出度和入度邻接矩阵来算每个结点的贡献度,而不是根据attention机制。
$$
\boldsymbol{\alpha}_{ij}=\text{softmax}(\text{LeakyRelu}(\boldsymbol{a}_{r_{ij}}^T (\boldsymbol{h}_{v_i} \odot \boldsymbol{h}_{v_j})))
$$
$r_{ij}$是序列中的两个结点$v_i$和$v_j$连边类型,$\boldsymbol{a}_{r_{ij}}$是该连边类型特定的参数向量。根据该注意力值加权汇聚邻域结点。由于有自连接边,所以加权汇聚的过程中实际上相当于同时做了信息传播和信息汇聚。
$$
\boldsymbol{h}_{v_i}^s=\sum_{v_j \in \mathcal{N}_{v_i}^s} \alpha_{ij} \boldsymbol{h}_{v_j}
$$
作者在session-graph上只提取了一阶的结点关系,即:上述步骤只进行1次。
最终,每个结点的表征是global-level的表征和session-level的表征sum pooling的结果,即图中加号的部分。具体而言,作者对global-level的表征加了一层dropout来防止过拟合。即:
$$
\boldsymbol{h}_{v_i^s}^{\prime}=\text{dropout}(\boldsymbol{h}_{v_i}^{g,(k)}) + \boldsymbol{h}_{v_i}^s
$$
得到了序列中每个结点的表征后,需要对序列中的每个结点表征进行汇聚,从而形成序列表征。主要包括几个关键点:
结点的位置信息很重要,即位置ID的嵌入。故:首先在序列结点$v_i$的表征$\boldsymbol{h}_{v_i}^{\prime}$中融入了位置信息。位置编码包括顺序编码和逆序编码,二者存在差异的原因主要在于,不同序列的长度是不一样的。因此肯定会设置一个最大编码长度参数,大于这个最大编码长度的就是取默认编码值。此时,顺序编码会导致部分长序列末尾的位置编码都是默认值,逆序编码会导致部分长序列头部的位置编码都是默认的。作者特意强调了逆序编码更有用。符合认知。
$$
\boldsymbol{z}_i=\text{tanh}(\boldsymbol{W_3}[\boldsymbol{h}_{v_i^s}^{\prime} || \boldsymbol{p}_{l-i+1}]+\boldsymbol{b}_3)
$$
$\boldsymbol{p}_{l-i+1}$就是位置的嵌入,$l$是最大编码长度。
然后对序列中的结点表征作mean pooling得到session information,可以认为是这个session序列浓缩后的信息。
$$
\boldsymbol{s}^{\prime}=\frac{1}{l}\sum_{i=1}^l \boldsymbol{h}_{v_i^s}^{\prime}
$$
这个session information作为序列attention的trigger去和序列中的每个结点做soft attention,得到表示每个结点对序列表征的贡献度值。作者称这种注意力机制为position-aware attention($\boldsymbol{z}_i$中融入了位置信息)。这个和基于SR-GNN的工作是比较大的差异点,SR-GNN中用的last item作为trigger去做attention。
$$
\beta_i=\boldsymbol{q_2}^T\sigma(\boldsymbol{W}_4\boldsymbol{z_i} + \boldsymbol{W}_5 \boldsymbol{s}^{\prime}+\boldsymbol{b}_4)
$$
最后的预测层很简单,预测下一次交互,多分类问题。序列表征和物品初始表征做点击,再softmax,得到该物品是下一次交互的概率值。
$$
\hat{y}_i=\text{softmax}(\boldsymbol{S}^T \boldsymbol{h}_{v_i})
$$
最后训练的时候用交叉熵损失。上述公式写成矩阵形式就是$\boldsymbol{S}$和物品的初始嵌入矩阵$H$做点击,得到在所有物品上的概率分布。
这篇文章总体上还是有值得借鉴的地方。比如从所有的session序列中构造全局图,这样能够通过借助其它session的信息来辅助目标session的表征。为了能够从全局图中提取相关的信息,作者提出了session-aware注意力机制来自适应地选择相关的全局信息。另一方面,针对由目标session序列构造而来的局部图,文章的核心贡献包括序列中结点之间edge type specific的注意力机制来进行邻域信息汇聚;为了得到整个session序列的表征,需要计算每个结点对序列表征的贡献度,大部分工作会用最后一个item去和每个结点做attention,而这篇文章,作者用整个序列浓缩后的信息去和每个结点做attention,且该attention机制是position-aware的。这些亮点都能作为独立的组件去改进原来的基于GNN的序列推荐方法,都值得在实践中去尝试。
首先从总体上预览一下paper提出的EBR系统的架构 (Embedding-based Retrieval System):
paper中涉及工程实现细节的主要是索引构建模块和检索模块。下文我会先介绍索引构建模块,这里头涉及很多向量量化的概念,比如PQ量化、粗糙量化、残差量化等,我会先介绍一些量化的背景知识,核心的索引过程和搜索过程,然后介绍在线检索模块,认识基于构建好的向量索引,线上是如何运转和实现召回的;接着探讨paper中提到的工程优化点和调参经验。最后,做个总结。
基于Product Quantization的近似最近邻搜索,核心的一些问题预览一下:
给定D维向量$x$和集合$\Gamma ={ y_1,y_2 … y_N }$ ,需要找到与$x$距离最短的k个最近邻。距离的衡量可以是欧式距离、余弦距离等。
如果以最粗暴的方法进行穷举搜索,构造距离矩阵的复杂度为:$O(D N^2)$。从距离矩阵中查找到k个最近邻,最小堆,则复杂度为$O((N-k)\log k)$。
举个例子:假设$N=2000W, k=1000$,则构造的距离矩阵包含$400T$个元素,假设每个距离值32bit,至少占用1600TB空间,构建距离矩阵的时间是$10^{17}$量级,查找Top-K搜索时间是$10^9$量级。
所谓向量量化,就是将原来无限的空间$R^D$映射到一个有限的向量集合 $\mathcal{C} = {\boldsymbol{c}_i, i\in[1,l]}$ 中,其中$||\mathcal{C}||=l$是一个自然数。将这个从 $R^D$ 到集合$\mathcal{C}$的函数记为$q$,则$\forall q(y) \in \mathcal{C}$,在信息论中称$\mathcal{C}$ 为codebook。即:通过$q(y)$来近似代表$y$。
最常用的就是k-means聚类,通过聚类后的聚类中心向量来近似量化原始的向量。聚类中心的个数即为codebook大小。因为量化的存在,任意两个向量之间的距离可以通过对应的量化向量的距离进行近似,也就是聚类中心向量的距离。因为聚类中心的个数小了很多,故计算距离的复杂度也下降了很多。(显然,这种方式太粗糙了,误差很大。除非聚类数非常大,极端情况下,聚类数等于样本数时,每个样本一个聚类簇,此时无误差,但是没有起到减少计算复杂度的目的)
聚类量化的结果:产出聚类中心向量的过程对应train的过程的一部分。量化后,每个向量都可以用聚类簇中心下标ID来标识,根据ID可以获取聚类簇的中心向量。
如上图所示,N个向量,通过聚类量化产生多个聚类中心,每个向量属于某个聚类簇中,那么就用该聚类簇对应的中心向量来量化该向量,可以用聚类簇中心对应的下标ID来表示,比如:C1量化vec1。
Faiss中对应的实现是IndexIVFFlat。
动机:即:PQ量化,很多时候我们向量不同部分之间的分布不同的,比如下图(3段向量),因此可以考虑对向量分段,并分别进行分块量化。这个只是直觉原因,本质原因下文讲。
乘积量化定义:将向量分成$m$个不同的部分,对每个部分进行向量量化,假设平均划分,则每个部分的维度大小为$D^{\star}=D/m$
一个向量$[x_1,x_2,…,x_{D^{\star}},…,x_{D-D^{\star}+1},…,x_D]$,可以划分为m组向量,第$i$组向量形如:$[x_{i_1},x_{i_2},…,x_{i_D^{\star}}]$,每组的codebook为$\mathcal{C_i}$,对应的量化器记为$q_i$, ($\forall q_i(x_{i^{\star}}) \in \mathcal{C_i}$)。则最终的全局codebook就是 $\mathcal{C} = \mathcal{C_1} * \mathcal{C_2} … * \mathcal{C_m}$,乘积量化的名称也来源于此。
分块量化也可以采取聚类量化来实现,则分块聚类中心的个数即为分块codebook的大小。相当于在这个方法下,对每个向量,有【m个分块向量】来量化它,即:【m个分块聚类中心向量】。示意图如下:
如上图所示,将原始向量等分为m组分块向量,每组都进行聚类量化,那么每个向量就有m个分块聚类中心向量来表示,比如vec1用$C_{1-1}$, …, $C_{m-2}$共m个向量来量化。
乘积量化的好处:假设每个子codebook大小一样,记做$||\mathcal{C}_i||=k^{\star}$,排列组合一下,那么相当于能表达的向量空间容量是这么大,$||k^{\star}||^m$,但是只需要$m k^{\star}$的codebook空间,这也是乘积量化大幅度降低空间占用的本质原因。PQ量化原论文中给出的经验取值是$k^{\star}=256,m=8$,即:分成8块,每个分块的codebook大小为256,对应的向量空间大小为约$256^8=2^{64}≈1.8 \times 10^{19}$,能够表达的向量个数足够大了。
乘积量化结果:$m \times k^{\star}$个分块聚类中心向量。每个向量可以用m个分块聚类簇中心下标ID来标识,所有ID连起来称为code。假设每块的聚类中心个数为256,则需要8bits,即1byte标识某分块下哪个聚类中心,m块则需要m bytes,即code大小为m bytes。
核心思想:层次化量化,这个也是Faiss中PQ索引的实现方式。其中粗糙量化使用聚类量化,用划分到的粗糙聚类簇的中心向量来粗粒度量化该向量,该结果存在较大的误差;接着对残差结果进行细粒度乘积量化。这样的话,误差就小了。
1 | 1. 总体上,每个向量先进行粗糙量化划分到某个粗糙聚类簇里,1个向量对应1个粗糙聚类簇标识,通常称为粗糙量化ID; |
过程:具体而言,向量库先构造一个小规模codebook $\mathcal{C}_c$,量化器为$q_c$。这个就是所谓的粗糙量化,或者称为粗糙聚类。接着,每个向量y都会有一个残差$r(y)=y−q_c(y)$。具体而言:记残差量化步骤的量化器为$q_p$,则y可以通过$q_c(y)+q_p(y−q_c(y))$来表示。
$$
y = q_c(y) + q_p(y-q_c(y)) = y_C + y_R
$$
其中, $y_C$是粗糙量化结果,$y_R$是残差量化结果。
这样的话,【查询向量x】和y之间的距离:
$$
d(x,y) = ||x-y||^2=||x-y_C-y_R||^2=\underbrace{||x-y_C||^2}_{\text{term 1}} +
\underbrace{||y_R||^2 + 2 y_C y_R}_{\text{term 2}} - \underbrace{2 x y_R}_{\text{term 3}}
$$
对应Faiss中的实现是 IndexIVFPQ。
做个小结,量化的结果:
聚类量化 | 乘积量化 | 粗糙量化+残差量化 |
---|---|---|
k个聚类簇中心下标id | m x k*个分块聚类中心下标组成的code | k个聚类簇中心下标ID,m x k*个分块聚类中心下标组成的code |
也就是说,为了表示每个doc的量化结果,可以为doc可以添加两种结构化字段:粗糙量化id, 残差量化code,用于实时检索使用。
建立从粗粒度聚类中心id 到 doc的映射关系,其中doc的信息包括:向量id,向量的残差量化code。每个doc通过粗糙聚类中心id和残差量化code就能知道原始向量如何映射到量化向量。
整个倒排索引不需要存储原始向量本身,索引结构存储的内容:
存储标识:粗糙量化id,doc id和残差量化code。
空间占用很小。m bytes 残差量化code,即:code_size或者pq_bytes。这个数越大,那么细粒度聚类簇越大,则精度越高。
基于id,可以找到对应的粗粒度量化向量 (共k个) ;基于code可以找到对应细粒度残差量化向量(共 m x k* 个)。
搜索场景中,y可以理解为doc。
搜索场景中,x可以理解为查询向量。
通过粗糙量化器来量化查询向量x,即:找到离x最近的w个粗糙聚类簇。实际上是用于限定搜索的范围,只搜索w个粗糙聚类簇ID索引下的向量。w是个超参数,即nprobes,量化的结果对应term 1。
选定某个粗糙聚类簇,
计算x和该粗糙聚类簇下的k*(默认即256)个中心点向量的内积。对应term 3,计算时间复杂度O(m x D/m x k*) = O(Dk*),记录下来,下一步查表用。
遍历该聚类簇下的doc文档,计算距离时,实际上全是查表操作,term 2是提前算的,term 1粗糙量化时算的,term 3上一步算的。查表时间复杂度实际上是O(m)
w个粗糙聚类簇,搜索时间复杂度为O(w(Dk* + m)), 另外,返回top-k的话,要加上最小堆排序时间。
Facebook在自研的检索引擎Unicorn中支持了第一代的近邻搜索。
首先简单介绍下Unicorn。Unicorn原本的检索方式主要以Term布尔匹配为主。
doc侧:以Term词袋的方式来表示doc,会基于Term的语义来区分命名空间。Term上还可以添加一些term特定的payload信息。举例:John living in Seattle会表示成【text: john and location: seattle】。
query侧:定义 Term-level 的布尔表达式来表示query。举例:下述query主要返回doc的文本中有john和smithe字眼,并住在seattle和menlo_park的用户。
为了支持embedding,需要扩展doc和query的表示
索引和计算向量距离时,Facebook将向量索引和向量在线检索通过某种方式转化成上述已有的布尔检索语言,很巧妙,可以完美融入现有的布尔检索系统,而不需要重新写一套系统。
先做个对应关系。
布尔匹配检索 | 语义向量检索 |
---|---|
Term | 粗糙聚类中心ID 标识,Cluster-ID |
Payload | 细粒度聚类中心CODE 标识, Cluster-Code |
doc侧:每个doc embedding会被量化并转成一个term和一个payload,相当于是两个doc的结构化字段,完美兼容已有的检索系统Unicorn的设计。
query侧:
term: (nn) 重写成和粗糙聚类相关的 term。
重写规则:计算query embedding和所有粗糙聚类中心距离,选出nprobes个最近的,用粗糙聚类中心ID来标识 (和doc的结构化字段Cluster-ID进行比较),不同聚类中心对应的Term之间的关系就是or的关系。
payload: 对query进行残差量化,得到满足radius约束条件的细粒度聚类中心,用code标识。
重写规则:对每个粗糙聚类簇,计算query embedding和其细粒度聚类中心的距离,距离满足<radius约束的细粒度聚类中心对应的Code取值记录一下 (和doc的结构化字段Cluster-Code进行比较),Code之间是OR关系,但是Code和ID是AND关系。
举个query改写的例子:
1 | or ((and( (term(Cluster-ID, '粗糙聚类中心ID-a')), |
另外,作者强调了radius-mode和topk-mode的差异,radius方式的性能和质量更高。radius是一种受限制NN搜索。top-K需要扫描整个索引库来找Top-K结果。radius性能更好,但是需要确定radius值。
正是因为在已有的布尔查询语言上融入目前的EBR语义检索,使得混合检索的实现非常方便。特别是在模糊匹配场景、或者query存在错误的场景。举个例子:
上述查询,用户把smith->smithe了,这样基于term匹配的话,可能会没有结果。但是基于nn检索,只要满足query embedding和doc embedding的余弦相似性小于0.24的话,就会有结果。nprobe是超参数,扫描的粗糙聚类中心个数。
模型改进不大的时候,多调调参数,会有奇效。
此次分享主要介绍了Facebook在KDD 2020发表的文章中的工程实践经验。首先从全局总览其系统架构,然后针对索引构建模块和实时检索模块展开讨论。其中,索引构建模块主要介绍了ANN中向量量化方法的背景知识。实时检索模块主要介绍系统实现,如何将向量检索通过query改写规则等融入现有的布尔检索系统中。最后介绍了一些调参的经验。
做向量召回的初期可以先重点关注模型层面上的优化,索引上也可以先采用简单的聚类量化的索引构建方式。当向量召回优化到一定程度时,如果想进一步提升性能和召回率,可以考虑借鉴文中的一些经验,比如以PQ量化的方式来构建索引,调参等。
KDD 2020: Embedding-based Retrieval in Facebook Search
A library for efficient similarity search and clustering of dense vectors
]]>Transformers: State-of-the-art Natural Language Processing
参考上面的论文,transformers开源库的核心组件包括3个:
另外,针对上述三大类,transformer还额外封装了AutoConfig, AutoTokenizer,AutoModel,可通过模型的命名来定位其所属的具体类,比如’bert-base-cased’,就可以知道要加载BERT模型相关的配置、切词器和模型。非常方便。通常上手时,我们都会用Auto封装类来加载切词器和模型。
所有已实现的Transformer-based Pre-trained models:
1 | CONFIG_MAPPING = OrderedDict( |
上述是该开源库实现的模型,包括了BERT,GPT2,XLNet,RoBERTa,ALBERT,ELECTRA,T5等家喻户晓的预训练语言模型。
下面将以BERT为例,来介绍BERT相关的源码。建议仔细阅读源码中我做的一些注释,尤其是步骤的细分。同时,关注下目录的层次,即:不同类之间的关系。
BertModel, The bare Bert Model transformer outputting raw hidden-states without any specific head on top。这个类的目标主要就是利用Transformer获取序列的编码向量。抽象出来的目标是为了适配不同的预训练任务。例如:MLM预训练任务对应的类为BertForMaskedLM,其中有个成员实例为BertModel,就是为了编码序列,获取序列的hidden states后,再构建MaskedLM task进行训练或者预测。
核心构造函数和Forward流程代码如下:
1 | # BertModel的构造函数 |
参数如下:
tensor([[ 101, 1188, 1110, 1126, 7758, 1859, 102]])
, 其中101和102分别是[CLS],[SEP]对应的token id。 其shape: $B \times S$,B为batch size, S为序列的长度,此例即:1x7。其中,
第一步Step 1,获取序列的embeddings
token embedding + position embedding + segment embedding
1 | embedding_output = self.embeddings( |
1 | # BertEmbeddings core forward code: |
此处还做了layer_norm和dropout。输出的embedding的shape为,$B \times S \times D$。D默认为768。此处输出的embeddings标记为$X$。
第二步,step 2,利用Transformer对序列进行编码
1 | # encoder是BertEncoder类 |
1 | # BertEncoder由12层BertLayer构成 |
1 | # BertEncoder Forward核心代码 |
上述代码最重要的是循环内的BertLayer迭代过程,其核心代码:
1 | def forward(self, hidden_states, attention_mask=None, head_mask=None, |
其中,step 1分为了2个小步骤。如果是encoder (BERT只用了encoder),只有1.0起作用,即只对输入序列进行self-attention。如果是做seq2seq的模型,还会用到transformer的decoder,此时1.0就是对decoder的seq做self-attention,相应的attention_mask实际上是类下三角形式的矩阵;而1.1步骤此时就是基于1.0得到的self-attention序列的hidden states,对encoder_hidden_states进行cross-attention。这是本部分的重点。
BertAttention是上述代码中attention实例对应的类,也是transformer进行self-attention的核心类。包括了BertSelfAttention和BertSelfOutput成员。
1 | class BertAttention(nn.Module): |
BertSelfAttention: 是self-attention,BertSelfAttention可以被实例化为encoder侧的self-attention,也可以被实例化为decoder侧的self-attention,此时attention_mask是非空的 (类似下三角形式的mask矩阵)。同时,还可以实例化为decoder侧的cross-attention,此时,hidden_states即为decoder侧序列的self-attention结果,同时需要传入encoder侧的encoder_hidden_states和encoder_attention_mask来进行cross-attention。
1 | def forward(self, hidden_states, attention_mask=None, head_mask=None, |
不同head均分768维度,12个head则每个为64维度;具体计算的时候合在一起,即同时算multi-head。记本步骤的输出为:$\text{Multi-head}(X)$ ,输入$X$即为hidden_states参数。
BertSelfOutput
上述输出$O^{‘’}_1$作为下一个BertLayer的输入,输出$O^{‘’}_2$,依次类推,进行迭代,最终输出$O=O^{‘’}_{12}$,即共12层BertLayer。
第三步,step3, 获取sequence-level embedding。
拿到上述BertEncoder的输出$O$,shape为$B \times S \times D$,其中每个样本序列(S维度)的第一个token为[CLS]标识的hidden state,标识为$o$,即:$B \times D$。则得到序列级别的嵌入表征:$\text{pooled-sentence-enocding}=\text{tanh}(W \cdot o)$,shape为$B \times D$。这个主要用于下游任务的fine-tuning。
1 | def forward(self, hidden_states): |
上文介绍了BERT核心的Transformer编码器,下面将介绍Bert的预训练任务。
Bert Model with a language modeling head on top。上述介绍了BertModel的源码,BertModel主要用于获取序列的编码。本部分要介绍的BertForMaskedLM将基于BertModel得到的序列编码,利用MaskedLM预训练任务进行预训练。
Bert主要利用了Transformer的Encoder,基于encoder得到的序列编码进行预训练,而MLM使得encoder能够进行双向的self-attention。
BertForMaskedLM的构造函数:
1 | def __init__(self, config): |
核心Forward代码:
1 | def forward(self, input_ids=None, attention_mask=None, |
参数基本上和BertModel一模一样,多了一个labels参数,主要用于获取MLM loss。
其中,cls对应的BertOnlyMLMHead类 (其实就是类BertLMPredictionHead) 做的主要事情如下公式,即:MLM多分类预测任务,其中$E$为BertModel得到的sequence-token-level encoding,shape为$B \times S \times D$。
$$
\text{Score} = W_1 \cdot \text{LayerNorm}(\text{GELU}(W_0 \cdot E))
$$
其中,$W_0 \in \mathbb{R}^{D \times D}, W_1^{D \times V}$,$V$为vocab的大小。$\text{Score}$的shape为:$B \times S \times V$。
特别的,label的形式:
labels (torch.LongTensor
of shape (batch_size, sequence_length)
, optional, defaults to None
) – Labels for computing the masked language modeling loss. Indices should be in [-100, 0, ..., config.vocab_size]
(see input_ids
docstring) Tokens with indices set to -100
are ignored (masked), the loss is only computed for the tokens with labels in [0, ..., config.vocab_size]
即,不打算预测的,label设置为-100。一般只设置[MASK]位置对应的label,其它位置设置成-100。这样只计算了[MASK]待预测位置的token对应的loss。-100实际上是CrossEntropyLos
的ignore_index
参数的默认值。
和BertForMaskedLM类似,多了一个next sentence prediction预训练任务。Bert Model with two heads on top as done during the pre-training: a masked language modeling head and a next sentence prediction (classification) head.
此部分对应的heads的核心代码为:
1 | class BertPreTrainingHeads(nn.Module): |
其中,BertLMPredictionHead和BertForMaskedLM中的BertLMPredictionHead一样,通过这个来得到MLM loss。另外,多了一个seq_relationship,即拿pooled encoding接一个线性二分类层,判断是否是next sentence,因此可以构造得到next-sentence loss。二者Loss相加。
Bert Model with a next sentence prediction (classification) head on top。只有上述的seq_relationship head来构造next-sentence loss,不作赘述。
下面将介绍利用预训练好的Bert对下游任务进行Fine-tuning的方式。下文介绍的fine-tuning任务对应的model,已经在BERT基础上加了task-specific parameters,只需要利用该model,输入task-specific data,然后optimization一下,就能够得到fine-tuned model。
句子级别的任务,sentence-level task。Bert Model transformer with a sequence classification/regression head on top (a linear layer on top of the pooled output) e.g. for GLUE tasks.
1 | class BertForSequenceClassification(BertPreTrainedModel): |
看上述代码,非常清晰。先经过BertModel得到encoding,由于是sentence-level classification,直接拿第一个[CLS] token对应的hidden state过一个分类层得到类别的预测分数logits。再基于logits和labels来构造损失函数。这个任务主要用于sentence-level的分类任务,当然也能够用于sentence-pair-level的分类任务。
句子对级别的任务,sentence-pair-level task。Bert Model with a multiple choice classification head on top (a linear layer on top of the pooled output and a softmax) e.g. for RocStories/SWAG tasks.
给一个提示prompt以及多个选择choice(其中有1个是对的,其它是错的),判断其中哪个选择是对的。输入格式会整成[[prompt, choice0], [prompt, choice1]…]的形式。bertModel得到的pooled基础上接一个全连接层,输出在每个“句对“[prompt, choice i]上的logits,然后过一个softmax,构造交叉熵损失。
token级别的下游任务,token-level task。Bert Model with a token classification head on top (a linear layer on top of the hidden-states output) e.g. for Named-Entity-Recognition (NER) tasks.
1 | def forward(self, input_ids=None, attention_mask=None, |
上述代码一目了然。不作赘述。主要应用于token-level的分类任务,如NER等。
句子对级别的任务,sentence-pair-level task,具体而言,即抽取式问答任务。Bert Model with a span classification head on top for extractive question-answering tasks like SQuAD (a linear layers on top of the hidden-states output to compute span start logits and span end logits).
1 | class BertForQuestionAnswering(BertPreTrainedModel): |
上述代码主要就是拿sequence-token-level hidden states接两个全连接层,分别输出start_position预测的logits和end_position预测的logits。
本部分进行Bert的实践,包括3个部分:
目前该库实现的预训练模型如下:
上述预训练好的模型的主要差异在于:
接下来主要采用’bert-base-cased’。在QA部分还会使用上述预训练模型‘bert-large-uncased-whole-word-masking’在SQUAD上的fine-tuning好的模型进行推断。
首先加载切割器和模型:
1 | MODEL_NAME = "bert-base-cased" |
预览下tokenizer (transformers.tokenization_bert.BertTokenizer):
1 | # 共28996词,包括特殊符号:('[UNK]', 100),('[PAD]', 0),('[CLS]', 101),('[SEP]', 102), ('[MASK]', 103)... |
看下model的网络结构:
1 | BertModel( |
模型结构参考BertModel源码介绍部分。
1 | text = "This is an input example" |
1 | from transformers import BertForMaskedLM |
可以看出,meet的概率最大,且达到了0.97,非常显著。
展示sentence-pair level的下游任务。
1 | from transformers import BertTokenizer, BertForQuestionAnswering |
可以看出,模型能准确预测出答案,a nice puppet。
之前一直没有机会阅读BERT源码。这篇文章也算是对BERT源码的一次粗浅的阅读笔记。想要进一步学习的话,可以参考文章,進擊的 BERT:NLP 界的巨人之力與遷移學習。总之,基于huggingface提供的transfomers进行二次开发和fine-tune还是比较方便的。下一次会尝试结合AllenNLP,在AllenNLP中使用transformers来解决NLP tasks。
Transformers: State-of-the-art Natural Language Processing
深入理解NLP Subword算法:BPE、WordPiece、ULM
huggingface transformers source code
BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding
]]>方案解析也可参考我的知乎:https://zhuanlan.zhihu.com/p/149061129
目前代码已开源:https://github.com/xuetf/KDD_CUP_2020_Debiasing_Rush
赛题介绍:KDD Cup 2020 Challenges for Modern E-Commerce Platform: Debiasing
主要包括了4个数据集:
目标是基于用户历史点击行为,来预测下一次用户会点击的item,即next-item prediction。
根据赛题介绍和对数据集的观察,可以推测主办方是从全量数据里头随机采样部分用户,将这些用户的点击数据作为赛题的数据。在进行数据划分的时候,选取了部分用户的数据作为测试集test,其他用户的数据作为训练集train。对于测试集,将每个用户行为序列的最后一次交互item作为线上测试answer,行为序列去除掉最后一个交互item以外的作为test用户的历史行为数据公开给我们,同时将answer中的user id和query time也公开给我们,即,test_q_time。具体如下图所示:
显然,这是典型的序列推荐场景,即next-item-prediction。模型构建的过程中要重点考虑行为序列和蕴含在序列中的时间信息,位置信息和长短期偏好等。
为了保证线上线下数据分布的一致性,验证集划分思路可参考线上数据的划分方式。即,利用线上train训练集进行划分,从train数据集中随机采样1600个用户,将这1600个用户的最后一次交互item作为验证集answer,其它数据作为验证集用户的历史行为数据。具体如下图所示:
这样的划分,保证了离线环境和线上环境的一致性。上述操作对每个phase都会进行这样的划分过程。
几个重要的数据分析观察和结论如下:
经过统计分析,每个阶段的时间范围一致,不同阶段按照时间推移,且不同阶段的时间重叠部分占到了阶段时间区间的3/4,因此会出现当前阶段记录不完全的情况,所以训练模型时需要考虑使用联合多个phase的全量数据训练模型。推测可能是线上打点日志系统的延迟上报,或者主办方对每个阶段的数据,都是从某个较大的时间区间内通过滑动窗口的方式随机采样得到的,因此样本存在较大的时间重叠。
经过验证集上的统计,每个用户的最后一次点击有99%以上是在当前阶段出现过的item,因此利用全量数据时需要将不属于当前phase的item过滤掉,防止item的穿越。
一条相同的点击数据可能会分布在各个阶段之中,重复率占比非常高,因此需要对记录进行去重处理。
item出现的次数呈现典型的长尾分布,在重排阶段需要挖掘长尾物品,如结合物品出现的频次进行纠偏。
其它的一些分析包括,最后一次点击和倒二次点击之间的内容相似性、基于w2v嵌入的行为相似性等分析。不一一列举。
我们的方案遵循了推荐系统的主流架构,即召回+粗排+精排。召回方案主要包括了多种改进后的协同过滤方法,即:user-cf、item-cf、swing、bi-graph。以及改进的基于序列的图神经网络SR-GNN方法。对每种召回方法,粗排阶段会基于物品的流行度等因素对每个用户的推荐结果进行初步重排,然后将不同方法的Recall的结果初步融合起来。精排方案主要采用了GBDT和DIN方法,会重点挖掘召回特征,内容特征和ID类特征。最终产生的结果是GBDT和DIN的集成。
经过数据分析,我们发现不同阶段的数据存在明显的交叉,说明了不同阶段之间不存在明确的时间间隔。因此,我们希望充分利用所有阶段的数据。但是直接利用所有阶段的数据会造成非常严重的数据穿越问题。为了保证数据不穿越,我们对全量数据做了进一步的筛选。这是本方案的key points之一。具体包括两点:
1) 对每个用户,根据测试集中的q-time,将q-time之后的数据过滤掉,防止user的行为穿越。
2) 对1) 中过滤后的数据,进一步,把不在当前阶段出现的item的行为数据过滤掉,防止item穿越。
1 | def get_whole_phase_click(all_click, click_q_time): |
对每个阶段,经过上述步骤后得到筛选后的针对该阶段的全量训练数据,会作为多路召回模型的输入进行训练和召回。
多路召回包括了4种改进的协同过滤方法以及改进的图神经网络SR-GNN方法。
参考item-cf [7, 8]的实现,考虑了交互时间信息,方向信息、物品流行度、用户活跃度等因素对模型的影响对模型的影响。
$$
sim(i,j) = \frac{1}{\sqrt{|U_i||U_j|}} \sum_{u \in U_i \cap U_j} \frac{\left(exp(-\alpha * |t_i - t_j|)\right) \times (c \cdot \beta^{|l_i-l_j|-1})}{\log(1+|I_u|)} \tag{1}
$$
其中,
上述改进能够有效进行纠偏。
1 | def get_time_dir_aware_sim_item(df): |
在原始user-cf基础上考虑了用户活跃度、物品的流行度因素。
$$
sim(u,v) = \frac{1}{\sqrt{|I_u||I_v|}} \sum_{i \in I_u \cap I_v} \frac{1}{log(1+|U_i|)} \tag{2}
$$
1 | def get_sim_user(df): |
基于图结构的推荐算法Swing [9],将物品的流行度因素也考虑进去。
$$
Sim(i,j)=\frac{1}{\sqrt{|U_i||U_j|}} \sum_{u \in U_i \cap U_j} \sum_{v \in U_i \cap U_j} \frac{1}{\alpha+|I_u \cap I_v|} \tag{3}
$$
1 | def swing(df, user_col='user_id', item_col='item_id', time_col='time'): |
Bi-Graph [3, 10] 核心思想是将user和item看做二分图中的两个集合,即:用户集合和物品集合,通过不同集合的关系进行单模式投影得到item侧的物品之间的相似性度量。改进方式:将时间因素、商品热门度、用户活跃度三因素考虑进去。
$$
Sim(i,j)= \sum_{u \in U_i} \sum_{j \in I_u} \frac{\left(\exp(-\alpha * |t_i - t_j|)\right)}{\log(|I_u|+1) \cdot \log(|U_j|+1)} \tag{4}
$$
1 | def get_bi_sim_item(df): |
SR-GNN [1] 是将GNN用于序列推荐的一种模型,原论文的方法在多个数据集上都表现出较好的性能。SR-GNN通过GGNN能够捕捉序列中不同item之间的多阶关系,同时会综合考虑序列的长短期偏好,尤其是短期的最后一次交互item,天然适用于该比赛的场景。但是直接使用原始论文开源的代码[13],在我们的比赛场景中,召回效果不佳,还不如单个CF方法来的好,因此需要进行改进。
我们将用户的行为记录按时间戳排序,然后对用户序列进行数据增强操作,得到增强后的行为序列后,使用改进的SR-GNN实施召回。具体改进如下:
由于训练样本较少,难以对物品嵌入矩阵进行充分的学习,因此不宜使用随机初始化。考虑到比赛提供的数据中包含了物品特征,为此我们使用物品的文本描述和图片描述向量(共256维)对嵌入矩阵进行初始化。这是本方案的重要trick之一。 这个方法能够显著解决某些长尾item的嵌入学习不充分的问题。
1 | # obtain item feat |
这里头有一个小细节,点击数据里存在一些特征缺失的items(未出现在item_feat.csv中),这些items的特征需要做填充。我们采用了局部上下文统计item-item共现关系,并基于共现item的特征做特征填充的方法,这种方式得到的完整item feat对排序过程的提升作用也非常大。
1 | def fill_item_feat(processed_item_feat_df, item_content_vec_dict): |
在SR-GNN中,得到物品序列后,将序列中的物品作为图节点,序列中相邻的物品之间通过有向边连接,最终分别得到入边和出边的邻接矩阵并按行归一化。例如,物品序列$s=[v_1, v_2, v_3, v_2, v_4]$对应的有向图及邻接矩阵$\boldsymbol{M}_{s, out}, \boldsymbol{M}_{s, in}$, 如下所示:
得到序列的图表示后,之后进行GNN处理的,遵循GNN信息传递架构 [12],即:信息构造—传播—更新三个步骤:
1)、 信息构造:针对全部物品设置嵌入矩阵,每个节点对应的物品可用嵌入矩阵的一个行向量$\boldsymbol{e}_i \in \mathbb{R}^d$表示。由于训练集中物品呈长尾分布,对于出现次数较多的物品,我们希望降低它的影响,因此我们设置节点$i$(即对应的物品$i$)的初始权重,
$$
w_i = \frac{1}{\sqrt{\#i / \text{median}}+1} \tag{5}
$$
$\#i$为物品$i$在训练集中出现的次数,$\text{median}$为全部物品出现次数的中位数,最终权重位于(0,1)之间,出现次数较多的物品权重较小,而出现次数较少的物品权重接近1。我们设置权值$w_i$为可学习的参数,因此节点$i$待传播的信息为$w_i \boldsymbol{e_i}$。
2)、 传播:按照连接矩阵进行传播,
$$
o_{s,i}^t = \text{concat}(\boldsymbol{M}_{s, in}^i \boldsymbol{E}^{t-1} \boldsymbol{W}_{in}, \boldsymbol{M}_{s, out}^i \boldsymbol{E}^{t-1} \boldsymbol{W}_{out})+b \tag{6}
$$
此处,$\boldsymbol{E}^{t-1}=[w_1 \boldsymbol{e}_1^{t-1}, …, w_n \boldsymbol{e}_n^{t-1}]$为图中全部节点的信息矩阵,$\boldsymbol{M}_{s, in}, \boldsymbol{M}_{s, out} \in \mathbb{R}^{1 \times n}$分别表示入度矩阵和出度矩阵的$i$行, 我们从入边和出边两个方向传播信息,$o_{s,i}^t \in \mathbb{R}^{2d}$为节点$i$在第$t$步时从邻居节点汇聚得到的信息。$\boldsymbol{W}_{in}, \boldsymbol{W}_{out}, b$为模型可学习的参数。
3)、 更新:根据节点自身的信息和来自邻居的信息,更新节点的信息。这里使用GRU进行结点信息的更新:$\boldsymbol{e_i}^t=GRU(o_{s,i}^t, \boldsymbol{e}_i^{t-1}) + \boldsymbol{e}_i^0$,此处,我们采用了残差连接。
以上过程可循环进行$R$步,最终每个节点可获取到它的$R$阶邻居的信息。我们的方案中,$R=2$。
用户的行为受最后一次交互影响较大,为了强化交互顺序的影响,我们增加了位置编码矩阵$P \in \mathbb{R}^{k \times d}$,$k$为位置数量,我们从后向前编码,最后一次交互的物品位置为1,上一次为2,以此类推。通过GNN更新后的节点向量和位置编码向量相加:
$$
\boldsymbol{e_i} \leftarrow \boldsymbol{e}_i + \boldsymbol{p}_i \tag{7}
$$
$\boldsymbol{p}_i$为节点$i$的位置编码向量。我们设置$k=5$,对于倒数第5个物品之前的物品,它们的位置均为5。
这里需要汇聚图中全部节点向量,得到一个图级别的输出作为序列的嵌入表征。考虑到最后一次行为的重要性,我们使用了加权平均池化的汇聚方式,即:
$$
\boldsymbol{s}_h = w \boldsymbol{e}_T + (1-w) \sum_{i=1}^{T-1} \frac{\boldsymbol{e_i}}{T-1} \tag{8}
$$
$\boldsymbol{e}_T$为序列最后一个item的嵌入表示,这里我们对序列中最后一个物品之前的物品向量进行平均池化,之后和最后一个物品向量按照权重$w$进行加权,得到序列的表示。$w$是可学习的参数。
我们对序列向量及物品向量进行L2归一化:
$$
\boldsymbol{s}_h = \frac{\boldsymbol{s}_h}{||\boldsymbol{s}_h||_2}, \boldsymbol{e}_i = \frac{\boldsymbol{e}_i}{||\boldsymbol{e}_i||_2} \tag{9}
$$
之后通过点积对物品进行打分:
$$
\hat{y}_i = \text{softmax}(\sigma \boldsymbol{s}_h^T \boldsymbol{e}_i) \tag{10}
$$
$\sigma$为超参数,我们设为10,来进一步拉大高意向item和低意向item之间的差距。这实际上是通过余弦相似度对物品进行打分,这些在参考文献[2]中有具体描述。模型的损失为预测概率的多分类交叉熵损失。
上述协同过滤方案实际上分为了Item-based,即:item-cf、swing、bi-graph和User-based,即user-cf。在具体进行推荐时,我们封装了基于item的产生召回结果的流程和基于user的产生召回结果的流程。
item-based的方法在进行推荐的时候,会利用用户的历史行为item,计算历史行为item最相似的Top-K个item推荐给用户。在计算相似性时,同样会利用前文提到的策略,即:根据交互时间进行指数衰减;根据交互方向进行幂函数衰减。同时,我们还利用了物品的内容特征,即,利用Faiss [11] 计算了item-item之间的内容相似性权重,最后,每个item的得分=召回方法的分数 $\times$ 时间权重 $\times$ 方向权重 $\times$ 内容权重。每种方法产生Top-200个召回结果。
1 | def item_based_recommend(sim_item_corr, user_item_time_dict, user_id, top_k, item_num, alpha=15000, |
User-based进行推荐时,会将相似用户的历史感兴趣item推荐给目标用户。但是这里面的一个问题是,没有利用到目标用户本身的行为序列信息。我们做了改进,会计算相似用户历史感兴趣item和目标用户本身行为序列中的item之间的相似性,计算相似性时,同样会利用时间权重和方向权重进行衰减。产生Top-200个召回结果。
1 | def user_based_recommend(sim_user_corr, user_item_time_dict, user_id, top_k, item_num, alpha=15000, |
我们还对数据进行了增强操作。对每个用户的交互序列进行截断,变成多条的交互序列。然后使用模型进行训练并产出结果。具体使用时,我们使用了两套参数(原始论文实现+改进版实现)训练SR-GNN,每套参数对应的模型根据公式(10)各产生Top-100个召回结果,共Top-200个召回结果。
1 | # Train |
在A榜中,单模型的SR-GNN效果已超过4种改进后的CF融合后的效果。
最终,每个用户产生了1000个召回结果。
粗排阶段主要基于这样的观察,我们的模型Top 100的hit-rate指标远高于Top 50,说明可能很多低流行度的物品被我们的模型召回了,但是排序较靠面,因此需要提高低频商品的曝光率,以消除对高频商品的偏向性。具体而言,对每个阶段进行召回时,本方案会统计该阶段内的物品出现的频次,然后根据该频次以及召回方法计算的item-item相似性分数,对相似性分数进行调整。这是本方案的key points之一,能够在基本不影响full的情况下,有效提高half。不同于其他开源的方案,我们在召回后进行re-rank,而不是在精排后进行re-rank。
本方案考虑加入频率因素,具体方法包括:
(1) 首先将频率作为一个单独的考量标准,为了初步鉴定频次的打压效果并尽量排除其他权重对其干扰,直接将召回分数除以物品出现的频次,初步鉴定对half有比较明显的提升,但是会显著降低full指标。
(2) 进一步,经过对item频次进行数据分析,item频率的分布呈现长尾效应,因此对于这些高频但极少数的item,考虑使用幂函数削弱打击的效果。采用的打压函数分段函数如下所示:
$$
\begin{split}
f(c) &= \log(c + 2), c < 4 \\
f(c) &= c, 4 \leq c < 10 \\
f(c) &= c^{0.75} + 5.0, c > 10
\end{split}
$$
其中,$c$为item出现在目标pahse中的频次,则新的分数为,$s_i^{*} = s_i / f(c_i)$。
(3) 考虑到不同活跃度的用户对于不同频率的物品的倾向性不同,越活跃的用户越倾向于点击低频的商品,因此对高活跃度的用户,需要提高高频item打压程度;对低活跃度的用户,提高对于低频率物品的打压程度。对于不同用户进行区分的策略在几乎不影响ndcg-full同时,有效提高了ndcg-half。
1 | def re_rank(sim, i, u, item_cnt_dict, user_cnt_dict, adjust_type='v2'): |
不同的召回方法得到的分数会经过上述步骤进行分数调整粗排,然后需要将不同召回模型初步融合在一起,我们的方法是,每种方法对每个用户产生的推荐结果先进行打分的最小最大归一化;然后求和合并不同方法对同一个用户的打分结果。
注:实际上,我们临近截止日期的时候对召回做了小修改,full指标上升了一些,half下降了一些,导致覆盖了原本最好的half结果,没来的及对改进后的召回重排策略进行精排。最终导致目前线上最终的成绩是仅通过上述召回方案得到的。而在我们所有的提交记录中,我们最好的half指标的成绩是该召回方案和下文即将描述的排序方案产生的。笔者认为,如果对改进后的重排策略进行精排的话,我们的分数应该还会更高。
到目前为止,B榜的最终成绩(full rank 3rd, half rank 10th)仅由上文提到的召回+粗排即可得到。精排方案在A榜的时候会有full会有0.05+的提升;half会有0.01+的提升。B榜由于时间问题没来得及对改进后的召回方案做排序并提交。如果你有兴趣可以接着往下阅读。
精排方案主要由GBDT和DIN方法组成。这里面最重要的步骤来自于训练样本的构造和特征的构造。其中,训练样本的构造是重中之重,个人认为也是本次比赛排序阶段最大的难点所在。
排序方案的训练样本构造我们采用了序列推荐的典型构造方案,即:滑窗方式构造训练样本。为了保证训练时和线上预测时的数据一致性,我们以行为序列中的1个item为滑窗步长,共滑动了10步。具体步骤即:对每个用户的行为序列$s=[i_1, i_2, …, i_n]$,从倒数第1个item开始,即:$i_n$为ground truth item, $i_1 \sim i_{n-1}$的通过我们的召回模型来计算item pair相似性,并为第$n$个位置的next-item产生召回结果;滑动窗口往左滑动1步,即:$i_{n-1}$为ground truth item, $i_1 \sim i_{n-2}$的通过我们的召回模型来计算item pair相似性,并为第$n-1$个位置的next-item产生召回结果;以此类推,共滑动10步。这种方式的缺点在于,计算复杂度非常高。因为每次滑动,都需要进行相似性的计算,并用训练集中所有的用户进行召回。目前笔者还不清楚这种方式是否是最优的构造方法(应该不是最优的),希望后面看看其他队伍的开源开案,学习学习。
1 | def sliding_obtain_training_df(c, is_silding_compute_sim=False): |
构造样本标签时,将召回结果中,命中了的用户真实点击的item作为正样本(即:不包括召回结果中未命中,但是用户真实点击的item,好处是能够把召回分数特征等送到模型中进行排序),然后随机负采样部分item作为负样本,负样本的策略以user和item侧分别入手,按照比例进行负采样,最终采样到的负样本: 正样本比例 约等于 10:1。
具体实现时,我们会对每个阶段的数据中的所有用户,分别进行召回并构造样本和标签。上述得到的数据格式即:user id, item id, hist item sequence, label,即: 用户id,目标物品id,用户历史交互item序列,标签。
重要的特征主要涉及召回时的特征以及目标item和用户历史item之间的各种关联性,如内容关联性、行为关联性等。
召回特征主要包括了:
待预测的目标物品原始的内容特征。
用户历史交互序列中的item的内容特征,根据交互位置顺序进行加权计算后的兴趣向量。
这部分特征主要供深度学习模型DIN使用。包括:
比较遗憾的是,本次比赛user侧的特征由于缺失值过多,我们没有花太多时间在user侧的特征提取,比如像item侧的特征一样,进行缺失值预测、补全等。
排序模型包括了两个,1个是GBDT,这里我们采用了LightGBM [5] 中的learning to rank方法LGBMRanker进行排序。另一个是DIN,这里采用了DeepCTR [6] 库中的DIN实现版本。对于DIN,我们利用了物品的内容特征对item的嵌入进行了初始化;利用用户历史行为序列中的item的加权后的兴趣向量对user的嵌入进行了初始化。
1 | def lgb_main(train_final_df, val_final_df=None): |
1 | def din_main(target_phase, train_final_df, val_final_df=None): |
最后,我们将GBDT预测的分数和DIN预测的分数融合起来。具体而言,每个方法的预测概率会先进行user-wise的归一化操作;然后两个方法归一化后预测的概率值进行相加融合。最后按照融合后的分数进行排序,并产生最终的Top 50结果。在A榜的时候,lgb对召回结果对full指标的提升效果大概都在0.02+;但是融合后的LGB+DIN,提升效果可达到0.05+。对half指标的提升略微少了一些,可能原因在于模型过于关注召回得到的sim等特征,对debiasing相关的特征挖掘比较少。
1 | def norm_sim(sim_df, weight=0.0): |
对本文方案的key points作一个总结:
[1] Wu S, Tang Y, Zhu Y, et al. Session-based recommendation with graph neural networks[C]//Proceedings of the AAAI Conference on Artificial Intelligence. 2019, 33: 346-353.
[2] Gupta P, Garg D, Malhotra P, et al. NISER: Normalized Item and Session Representations with Graph Neural Networks[J]. arXiv preprint arXiv:1909.04276, 2019.
[3] Zhou T, Ren J, Medo M, et al. Bipartite network projection and personal recommendation[J]. Physical review E, 2007, 76(4): 046115.
[4] Zhou G, Zhu X, Song C, et al. Deep interest network for click-through rate prediction[C]//Proceedings of the 24th ACM SIGKDD International Conference on Knowledge Discovery & Data Mining. 2018: 1059-1068.
[5] Ke G, Meng Q, Finley T, et al. Lightgbm: A highly efficient gradient boosting decision tree[C]//Advances in neural information processing systems. 2017: 3146-3154.
[6] DeepCTR, Easy-to-use,Modular and Extendible package of deep-learning based CTR models, https://github.com/shenweichen/DeepCTR
[7] A simple itemCF Baseline, score:0.1169, https://tianchi.aliyun.com/forum/postDetail?postId=103530
[8] 改进青禹小生baseline,phase3线上0.2, https://tianchi.aliyun.com/forum/postDetail?postId=105787
[9] 推荐系统算法调研, http://xtf615.com/2018/05/03/recommender-system-survey/
[10] A Simple Recall Method based on Network-based Inference, score:0.18 (phase0-3), https://tianchi.aliyun.com/forum/postDetail?postId=104936
[11] A library for efficient similarity search and clustering of dense vectors, https://github.com/facebookresearch/faiss
[12] CIKM 2019 tutorial: Learning and Reasoning on Graph for Recommendation, https://next-nus.github.io/
[13] Source code and datasets for the paper “Session-based Recommendation with Graph Neural Networks” (AAAI-19), https://github.com/CRIPAC-DIG/SR-GNN
也欢迎关注我的公众号”蘑菇先生学习记“,更快更及时地获取推荐系统前沿进展!
]]>KDD2018: Graph Convolutional Matrix Completion
这是一篇发表在KDD2018(二作T.N.Kipf是著名的 GCN 的一作)的文章。将矩阵补全问题看做是关于user-item 二分图的链接预测问题(a bipartite user-item graph with labeled edges),每种链接边可以看做是一种label(例如多种交互行为:点击,收藏,喜欢,下载等;在评分中,1~5分可以分别看做一种label)。有点像multi-view bipartite graph。作者提出了一个信息传递(differentiable message passing)的概念,通过在bipartite interaction graph上进行信息传递来学习结点的嵌入,再通过一个bilinear decoder进行链接预测。
给定关于用户-物品交互数据的二分图,$G=(\mathcal{W}, \mathcal{E}, \mathcal{R})$,其中$\mathcal{W}$是结点,包括用户结点$u_i \in \mathcal{W}_u, i=\{1,…,N_u\}$和物品结点$v_j \in \mathcal{W}_v, j=\{1,…,N_v\}$,$\mathcal{W}=\mathcal{W}_u \cup \mathcal{W}_v$. 边$(u_i ,r,v_j ) \in \mathcal{E}$代表了用户$u_i$和$v_j$的交互行为类型为$r$,$r \in \mathcal{R}=\{1,…,R\}$.其中$R$是总的交互类型种数。这里的交互行为原文中使用的是评分level来代表,如1~5分,则代表5种rating level,即:$R=5$。
可以看做是一个graph auto-encoders。Graph Encoder Model形如:$[Z_u ,Z_v ] = f (X_u ,X_v , M_1 , . . . , M_R)$。其中,$X_u, X_v$是用户或物品的Feature矩阵。$M_r \in {0, 1}^{N_u \times N_v}$是和交互类型$r$相关的邻接矩阵。$Z_u, Z_v$是输出的结点嵌入。Decoder形如:$\hat{M} = (Z_u ,Z_v)$用于预测$u$和$v$的链接类型或评分矩阵的评分值。然后使用重构误差最小化来训练模型,如RMSE或交叉熵。
作者首先提出了一种针对不同rating level的sub-graph分别进行局部图卷积,再进行汇聚的encoder模型。这种局部图卷积可以看做是一种信息传递(message passing),即:向量化形式的message在图中不同的边上进行传递和转换。每种边特定的信息传递过程如下(edge-type specific message),以item $j$ 传递到 user $i$为例:
$$
\mu_{j \rightarrow i, r}= \frac{1}{c_{ij}} W_r x_j^v \tag{1}
$$
其中,$c_{ij}$是归一化常数因子,如$|\mathcal{N}(u_i)|$或$\sqrt{|\mathcal{N}(u_i) \mathcal{N}(v_j)|}$。$W_r$是 edge-type specific parameter matrix。$x_j^v$是item $j$初始的特征,作者采用的是unique one-hot vector作为特征。相当于把$x_j^v$这一信息传递到了用户结点$i$上。这样针对每种类型的边,可以把所有$i$的邻域节点传递过来的信息做个累加操作,$\sum_{j \in \mathcal{N}_r(u_i)}{\mu_{j \rightarrow i, r}}$, $\text{for } r = 1,2,…,R$.
接着需要将不同edge-type采集到的信息进行一个汇聚,
$$
h_i^v = \sigma \left[\text{accum}\left(\sum_{j \in \mathcal{N}_1(u_i)}{\mu_{j \rightarrow i, 1}},…,\sum_{j \in \mathcal{N}_r(u_i)}{\mu_{j \rightarrow i , r}},…, \sum_{j \in \mathcal{N}_R(u_i)}{\mu_{j \rightarrow i, R}}\right)\right] \tag{2}
$$
上式的$\text{accum}$是一个汇聚操作,例如可以采用连接操作或求和操作,$\sigma$ 是激活函数,例如Relu。 完整的式(2)称为
graph convolution layer,可以叠加多个graph convolution layer。
为了得到用户$u_i$最终的embedding,作者加了个全连接层做了个变换:
$$
z_{i}^u = \sigma(W h_i^u) \tag{3}
$$
物品$v_i$的embedding和用户$u_i$的求解是对称的,只不过使用的是两套参数。
作为拓展,值得一提的是,很多人忽略了归一化因子$c_{ij}$的重要性。一种观点是随着GCN层数的叠加,$c_{ij}$起着embedding平滑的作用(Embedding Smoothness)。我们以二层GCN为例,从协同过滤角度来阐述这一归一化因子的重要性(源自另一篇文章的观点LightGCN)。此处忽略多视图$r$以及非线性$\sigma$。令,$c_{ij}=\sqrt{|\mathcal{N}(u_i) \mathcal{N}(v_j)|}$为例,记$\boldsymbol{e}_j^{(1)}=W x_j^v$,当$x_j$为id one-hot vector时,可以认为就是item的嵌入;user同理。
根据式子2,neighbor aggregation操作。我们观察用户$u, v$是如何产生协同过滤效果的。
$$
\begin{aligned}
\boldsymbol{e}_u^{(2)} &= \sum_{j \in \mathcal{N}_u} \frac{1}{\sqrt{|\mathcal{N}_u| \cdot |\mathcal{N}_j}|} \boldsymbol{e}_j^{(1)}= \sum_{j \in \mathcal{N}_u} \frac{1}{\sqrt{|\mathcal{N}_u| \cdot |\mathcal{N}_j}|} (\sum_{v \in \mathcal{N}_j} \frac{1}{\sqrt{|\mathcal{N}_j| \cdot |\mathcal{N}_v|}}\boldsymbol{e}_v^{(0)}) \\
&=\sum_{j \in \mathcal{N_u}} \frac{1}{|\mathcal{N}_j|} \sum_{v \in \mathcal{N}_j} \frac{1}{\sqrt{|\mathcal{N}_u| \cdot |\mathcal{N}_v|}} \boldsymbol{e}_v^{(0)}
\end{aligned}
$$
可以看出如果$u$和$v$存在共同交互过的item $j$ (从公式看,$j$是$u$的邻居,$v$是$j$的邻居,故$j$ 是$u, v$的co-interacted item),则$v$对$u$的平滑强度可以使用下述系数来表示 (the smoothness strength of v on u is measured by the coefficient),
$$
c_{v \rightarrow u} = \frac{1}{\sqrt{|\mathcal{N}_u| \cdot |\mathcal{N}_v|}} \sum_{j \in \mathcal{N}_u \cap \mathcal{N}_v} \frac{1}{|\mathcal{N}_j|}
$$
非co-interacted items对上式不起作用,故可以直接去掉,重新整理得到该系数。这个系数具备很强的可解释性,可以从协同过滤角度来阐述second-order的近邻$v$对$u$嵌入表示的影响。
上述系数从衡量user similarity的协同过滤角度提供了完美的可解释性。
为了重构二分图上的链接,作者采用了bilinear decoder,把不同的rating level分别看做一个类别。bilinear operation后跟一个softmax输出每种类别的概率:
$$
p(\hat{M}_{ij}=r)=\text{softmax}((z_i^u)^T Q_r z_j^v) \tag{4}
$$
$Q_r$是可训练的edge-type r特定的参数。
则最终预测的评分是关于上述概率分布的期望:
$$
\hat{M_{ij}} = g(u_i ,v_j) = E_{p(\hat{M}_{ij}=r)}[r] = r p(\hat{M}_{ij}= r) \tag{5}
$$
最小化 negative log likelihood of the predicted ratings $\hat{M}_{ij}$.
$$
\mathcal{L} = − \sum_{i,j;Ω_{ij}=1} \sum_{r=1}^R I[M_{ij}=r] \log p(\hat{M}_{ij}=r) \tag{6}
$$
作者在训练过程中,还使用了一些特殊的优化点。
Node dropout
对特定的某个节点,随机地将outgoing的信息随机drop掉。这能够有效的提高模型的鲁棒性。例如:去除掉某个结点时,模型性能不会有太大的变化。
Weight sharing
不是所有的用户或物品在不同rating level上都拥有相等的评分数量。这会导致在局部卷积时,$W_r$上某些列可能会比其他列更少地被优化。因此需要使用某种在不同的$r$之间进行参数共享的方法。
$$
W_r = \sum_{s=1}^r T_s \tag{7}
$$
$T_s$是基础矩阵。也就是说越高评分,$W_r$包含的$T_s$数量越多。
作者采用了一种基于基础参数矩阵的线性组合的参数共享方法:
$$
Q_r = \sum_{s=1}^{n_b} a_{rs} P_s \tag{8}
$$
其中,$n_b$是基础权重矩阵的个数,$P_s$是基础权重矩阵。$a_{rs}$是可学习的系数。
为了建模结点的辅助信息,作者在对$h_i^u$做全连接层变换时,考虑了结点的辅助信息:
$$
z_{i}^u = \sigma(W h^u_i +W_2^{u,f} f_i^u), f_i^u = σ(W_1^{u,f} x_i^{u,f} + b^u) \tag{9}
$$
即:先对特征$x_i^{u,f}$做一个变换得到$f_i^u$。与$h^u_i$分别经过线性变换后加起来并激活,最终得到结点的嵌入表示。
总结一下整体的过程,模型的核心过程形式化如下:
$$
\boldsymbol{z}_i^u, \boldsymbol{z}_j^v = \text{GNN-Encoder}(\mathcal{G}_{u,i}) \tag{10}
$$
$$
p(\hat{M}_{ij}=r)= \text{softmax}\left(\text{Bilinear-Decoder}(\boldsymbol{z}_i^u, \boldsymbol{z}_j^v)\right) \tag{11}
$$
$$
\mathcal{L} = − \sum_{i,j;Ω_{ij}=1} \sum_{r=1}^R I[M_{ij}=r] \log p(\hat{M}_{ij}=r) \tag{12}
$$
$$
\hat{M_{ij}} = g(u_i ,v_j) = E_{p(\hat{M}_{ij}=r)}[r] = r p(\hat{M}_{ij}= r) \tag{13}
$$
先经过GNN-Encoder输出user和item的嵌入表示(公式10),再经过Bilinear Decoder输出属于不同评分值的概率(公式11),最后公式(12)是关于评分多分类问题的交叉熵损失。具体预测的时候使用公式(13)预测评分,进行topk推荐。
SIGIR2019: Neural Graph Collaborative Filtering
这是何向南教授团队在SIGIR2019发表的一篇文章,主要针对隐式反馈行为数据。为了解决传统的方法主要通过user或item的pre-existing fetures的映射得到user和item的embedding,而缺乏了user和item之间重要的协同信息(collaborative signal)这一问题,作者提出了一种新的推荐框架——神经图协同过滤。这篇文章核心的目标问题在于如何更好的将user-item之间的协同信息建模到user和item的emebdding表示中。1
2
3
4We develop a new recommendation framework Neural Graph Collaborative Filtering (NGCF),
which exploits the user-item graph structure by propagating embeddings on it.
This leads to the expressive modeling of high-order connectivity in user-item graph,
effectively injecting the collaborative signal into the embedding process in an explicit manner.
传统的方法无法学到很好的Embedding,归咎于缺乏对于重要的协同信息显示地进行编码过程,这个协同信息隐藏在user-item交互数据中,蕴含着users或者items之间的行为相似性。更具体地来说,传统的方法主要是对ID或者属性进行编码得到embedding,再基于user-item interaction定义重构损失函数并进行解码。可以看出,user-item interaction只用到了解码端,而没有用到编码端。这样会导致,学习到的embedding的信息量不够,为了更好的预测,只能依赖于复杂的interaction (decoder) function来弥补次优的embedding在预测上的不足。1
2
3
4
5
6
7The key reason is that the embedding function lacks an explicit encoding of the crucial collaborative signal,
which is latent in user-item interactions to reveal the behavioral similarity between users (or items)
To be more specific, most existing methods build the embedding function with the descriptive features only (e.g., ID and attributes),
without considering the user-item interactions which are only used to define the objective function for model training.
As a result, when the embeddings are insufficient in capturing CF,
the methods have to rely on the interaction function to make up for the deficiency of suboptimal embeddings.
难就难在如何将interaction中的collaboritive signals建模到embedding的表示中。由于原始的interaction数据规模通常比较庞大,使得难以发掘出期望的collaboritive signals(distill the desired collaborative signal)。
作者在这篇文章中提出基于user-item intractions中的high-order connectivity来解决collaboritive signals的发掘和embedding的建模,做法是在user-item interaction graph structure图结构中进行collaborative signal的编码。1
2we tackle the challenge by exploiting the high-order connectivity from useritem interactions,
a natural way that encodes collaborative signal in the interaction graph structure.
关于high-order connectivity含义的可视化如下,$u_1$的两种视角:二分图 和 树
作者设计了一个神经网络来迭代地在二部图上进行embeddings的传播,这可以看做是在embedding空间构建信息流。1
2We design a neural network method to propagate embeddings recursively on the graph,
which can be seen as constructing information flows in the embedding space.
特别地,作者设计了一种embedding传播层(embedding propagation layer),通过汇聚交互过的items或users来提炼出users或items的embeddings。进一步,通过叠加多个embedding propagation layer,可以使得embeddings来捕获二部图中high-order connectivities所蕴含的协同信息。1
2
3Specifically, we devise an embedding propagation layer, which refines a user’s (or an item’s) embedding
by aggregating the embeddings of the interacted items (or users). By stacking multiple embedding propagation layers,
we can enforce the embeddings to capture the collaborative signal in high-order connectivities.
模型的结构如下:
嵌入层,offers and initialization of user embeddings and item embeddings。
$$
\boldsymbol{E}=[\boldsymbol{e}_{u1},…,\boldsymbol{e}_{uN} , \boldsymbol{e}_{i1},…,\boldsymbol{e}_{iM}] \tag{1}
$$
传统的方法直接将$E$输入到交互层,进而输出预测值。而NGCF将$E$输入到多层嵌入传播层,通过在二部图上进行嵌入的传播来对嵌入进行精炼。
嵌入传播层,refine the embeddings by injecting high-order connectivity relations。
包括两个步骤,Message construction和Message aggregation。这个部分和KDD2018的GCMC那篇文章是类似的描述方式。
对于每个user-item pair $(u,i)$, 定义从$i$到$u$传递的message如下:
$$
\boldsymbol{m}_{u \leftarrow i}=f(\boldsymbol{e_i}, \boldsymbol{e_u}, p_{ui}) \tag{2}
$$
其中,$\boldsymbol{m}_{u \leftarrow i}$定义为message embedding。$f(\cdot)$是message encoding function,将user和item的 embedding $\boldsymbol{e}_u, \boldsymbol{e}_i$作为输入,并使用$p_{ui}$来控制每条边edge $(u,i)$在每次传播中的衰减系数。
具体的,作者使用如下message encoding function:
$$
\boldsymbol{m}_{u \leftarrow i} = \frac{1}{\sqrt{|\mathcal{N}_u||\mathcal{N}_i|}}(\boldsymbol{W}_1 \boldsymbol{e}_i + \boldsymbol{W}_2(\boldsymbol{e}_i \odot \boldsymbol{e}_u)) \tag{3}
$$
可以看出作者不仅考虑了message的来源$\boldsymbol{e}_i$(传统图卷积方法只考虑这个),还考虑了信息来源和信息目的地之间的关系,即$\boldsymbol{e}_i \odot \boldsymbol{e}_u$,这个element-wise product是典型的特征交互的一种方式,值得学习。$p _u=\frac{1}{\sqrt{|\mathcal{N}_u||\mathcal{N}_i|}}$,$\mathcal{N}_u$是用户$u$的1-hop neighbors。从表示学习角度:$p_{ui}$反映了历史交互item对用户偏好的贡献程度。从信息传递角度,$p_{ui}$可以看做是折扣系数,随着传播路径长度的增大,信息慢慢衰减(这个可以通过叠加多层,并代入到式子,会发现前面系数也是连乘在一起了,说明路径越长,衰减越大)。
这个阶段,我们将从用户$u$的邻居传递过来的信息进行汇聚来提炼用户$u$的嵌入表示。
$$
\boldsymbol{e}_u^{(1)} = \text{LeakyReLU}\left(\boldsymbol{m}_{u \leftarrow u} + \sum_{i \in \mathcal{N}_u} \boldsymbol{m}_{u \leftarrow i} \right) \tag{4}
$$
$\boldsymbol{e}_u^{(1)}$是经过一层嵌入传播层得到的提炼后的用户$u$嵌入表示。LeakyReLU允许对于正反馈信息和少部分负反馈信息的编码。$\boldsymbol{m}_{u \leftarrow u} = \boldsymbol{W}_1 \boldsymbol{e}_u$则考虑了self-connection,$\boldsymbol{W}_1$和Equation(2)中的$\boldsymbol{W}_1 $是共享的。
item的嵌入表示同理可得。embedding propagation layer的好处在于显示地挖掘 first-order connectivity信息来联系user和item的表示。
得到的$\boldsymbol{e}_u^{(1)}$可以作为下一个embedding propagation layer的输入,通过叠加多层,可以挖掘multi-hop的关联关系。迭代式如下:
$$
\boldsymbol{e}_u^{(l)} = \text{LeakyReLU}\left(\boldsymbol{m}^{(l)}_{u \leftarrow u} + \sum_{i \in \mathcal{N}_u} \boldsymbol{m}^{(l)}_{u \leftarrow i} \right) \tag{5}
$$
其中,
$$
\boldsymbol{m}^{(l)}_{u \leftarrow i} = p_{u,i}(\boldsymbol{W}^{(l)}_1 \boldsymbol{e}^{(l-1)}_i + \boldsymbol{W}_2^{(l)}(\boldsymbol{e}_i^{(l-1)} \odot \boldsymbol{e}_u^{(l-1)})) \tag{6}
$$
$$
\boldsymbol{m}^{(l)}_{u \leftarrow u} = \boldsymbol{W}^{l}_1 \boldsymbol{e}_u^{(l-1)}
$$
进一步,作者给出了上述Equation(5), (6) 过程的矩阵表示形式,有助于实现layer-wise propagation。
$$
\underbrace{\boldsymbol{E}^{(l)}}_{\mathbb{R}^{(N+M) \times d_l}} = \text{LeakyReLU} \left( \underbrace{(\boldsymbol{\mathcal{L}} + \boldsymbol{I})}_{\mathbb{R}^{(N+M)\times (N+M)}} \overbrace{\boldsymbol{E}^{(l−1)}}^{\mathbb{R}^{(N+M) \times d_{l-1}}} \underbrace{\boldsymbol{W}_1^{(l)}}_{\mathbb{R}^{d_{l-1} \times d_l}} + \boldsymbol{\mathcal{L}} \underbrace{\boldsymbol{E}^{(l−1)}}_{(N+M) \times d_{l-1}} \odot \overbrace{\boldsymbol{E}^{(l−1)}}^{(N+M) \times d_{l-1}} \underbrace{\boldsymbol{W}_2^{(l)}}_{\mathbb{R}^{d_{l-1} \times d_l}} \right) \tag{7}
$$
其中,$E^{(l)} \in \mathbb{R}^{(N +M)×d_l}$,即:把user, item的embeddings矩阵concat在一起,一起进行传播。也就是说,上述是user,item共同进行传播的表示形式,因此所有的矩阵都是concat在一起的形式。
作者说,$\boldsymbol{\mathcal{L}}$表示user-item interaction graph的拉普拉斯矩阵,$\boldsymbol{\mathcal{L}}=\boldsymbol{D}^{-1/2} \boldsymbol{A} \boldsymbol{D}^{-1/2}$,其中,$\boldsymbol{A} \in \mathbb{R}^{(N+M) \times (N+M)}$是邻接矩阵,是user-item 交互矩阵和item-user交互矩阵构成的,即:$\boldsymbol{A} = \left[ \begin{array}{ccc}
\boldsymbol{0} & \boldsymbol{R} \\
\boldsymbol{R}^T & \boldsymbol{0} \\
\end{array} \right] $。(但是我个人记得拉普拉斯矩阵三种方式都不是长这个样子的,有可能这些定义之间差异很小,可能特征根是一样的,故也叫拉普拉斯矩阵吧,虽然和标准的拉普拉斯矩阵之间有一丝差异。本质都是一种graph operator。可参考从 Graph Convolution Networks (GCN) 谈起,讲的非常到位!)
这个矩阵表示形式很好理解,主要点在于,和$\boldsymbol{\mathcal{L}}$的乘法就对应于公式(5)中$\sum_{i \in \mathcal{N}_u} \boldsymbol{m}^{(l)}_{u \leftarrow i}$对邻域节点的汇聚求和操作,其它的一目了然。
预测层,aggregates the refined embeddings from different propagation layers and outputs the affinity score of a user-item pair.
最终的嵌入表示是原始的embedding和所有嵌入传播层得到的embedding全部concat在一起的结果。即:
$$
\boldsymbol{e}_u^{*}= \text{concat}(\boldsymbol{e}_u^{(0)},\boldsymbol{e}_u^{(1)},…,\boldsymbol{e}_u^{(L)}) \tag{8}
$$
$\boldsymbol{e}_u^{(0)}$是初始化的embeddings。$\boldsymbol{e}_i^{*}$同理可得。
最后预测user-item交互的时候使用点乘:
$$
\hat{y}_{\text{NGCF}}(u,i) = {\boldsymbol{e}_u^{*}}^T \boldsymbol{e}_i^{*}
$$
最后作者采用的是pairwise BPR loss进行优化。
$$
Loss = − \sum_{(u,i,j) \in O}\ln \sigma(\hat{y}_{ui} − \hat{y}_{uj}) + \lambda||\Theta||_2^2
$$
其中,$O = \{(u,i, j)|(u,i) \in R^+ , (u, j) \in R^- \}$, $R^+$是观测数据,$R^-$是未观测数据,$\Theta= \{ \boldsymbol{E}, \{ {\boldsymbol{W}_1^{(l)} , \boldsymbol{W}_2^{(l)}\}}_{l=1}^L \}$是所有的可训练参数。
MM2019: MMGCN: Multi-modal Graph Convolution Network for
Personalized Recommendation of Micro-video
这篇也是何向南团队(可能是co-author)在顶会ACM Multimedia 2019上发表的文章。为了给内容分享平台提供高质量的推荐,我们不仅要考虑用户和物品的交互 (user-item interactions),还要考虑内容本身多模态的特征 (various modalities (e.g., visual, acoustic, and textual)。目前的多模态推荐方法主要是利用物品本身的多模态内容来丰富item侧的表示;但是很少会利用到users和items之间的信息交互来提升 user侧的表示,进而捕获用户对不同模态特征的细粒度偏好。在这篇文章中,作者主要是想利用user-item interactions来引导每种模态下的表示学习,主要是利用了GNN的message-passing思想,来学习modal-specific representations of users and items。具体而言,作者将user-item interaction graph依据item的多模态特征:图像,文本,语音切分为三个子图,汇聚的时候不仅考虑了邻域的拓扑结构 (可以认为是item id来表征),还考虑了邻域的模态特征 (可以认为是item的feature id来表征)。作者没有将所有的特征一视同仁,而是每个子图对应一种模态特征。
对多模态特征的进行区分对于深入理解用户的preferences有帮助:
遗憾的是,目前的工作都主要把不同的模态特征作为整体来统一对待 (multimodal features of each item are unified as a single representation, reflecting their content similarity),缺乏对特定模态的用户偏好的建模(modeling of modal-specific user preferences)。
作者希望能够通过关注users和items在不同模态空间下的信息交互 (focus on information interchange between users and items in multiple modalities),借鉴GNN的信息传播机制(information-propagation mechanism)来编码用户和短视频在不同模态下的high-order connectivity,进而捕获特定模态内容下用户的偏好 (user preference on modal-specific contents)。
为此,作者提出了a Multi-modal Graph Convolution Network (MMGCN),在不同模态下构造user-item二分图(modality-aware bipartite user-item graph)。
具体而言,MMGCN各自地在不同的模态子图(e.g, visual)下,从交互过的items聚合相应的模态特征(e.g., frames)到user representation,同时利用user group来提升item representation。也就是说不同模态的aggregation操作是每个子图分开单独进行的。然后每个子图下,都会有个combination操作来combine不同模态下的user和item representation,也就是说每个子图下的combined representation都融合了所有模态的特征,combined representation又会作为该子图的下一个GNN aggregation层的输入,然后继续进行combination。总之,aggregation和combination操作迭代执行多次,就能捕获user和item之间多跳的邻居信息。最终,预测的时候可以分别concat user和item在所有子图下的representation,并计算concat后的user和item的representations之间相似性,并进行推荐。
作者不是把所有模态的信息作为整体来统一对待,而是每种模态进行区分对待。首先基于user-item交互数据来构造二分图,$\mathcal{G} = \{(u,i)|u \in \mathcal{U},i \in \mathcal{I}\}$,每条边$y_{ui} = 1$对应一条user-item观测数据。除此之外,对于每个item $i$,都有多种模态特征,即:视觉 (visual) 、声觉 (acoustic)、文本 (textual)。具体的,使用$m \in M = \{v,a,t\}$作为模态的indicator,$v, a, t$分别表示视觉、声觉、文本。为了正确捕获特定模态下的用户偏好,作者将$\mathcal{G}$切分为三个子图$\mathcal{G}_m, m \in M$。相比于原图,子图只改变了每个item结点的属性特征,只保留其相对应的模态的特征,而整体的拓扑结构和原图$\mathcal{G}$是一致的。例如$\mathcal{G}_v$下,只有对应的视觉模态特征可以在该子图下使用。
整体的模型结构如下所示,不同模态域的aggregation和combination分别进行,最后相加不同模态域得到的表示作为最终的表示,并通过点乘进行预测。
对于用户来说,用户历史interacted item能够反映用户的兴趣,故可以对items进行aggregate操作来丰富user representation;对于物品来说,交互过item的user group可以作为item除自身模态特征之外的补充信息,故可以对users进行aggregate来提升item representation。
基于message-passing机制,对模态子图$\mathcal{G}_m$中,任意一个user或item结点,我们采用一个汇聚函数$f(\cdot)$来量化从邻域结点传播来的信息(representation being propagated)的影响。以user为例,汇聚得到的modal-specific表示如下:
$$
\boldsymbol{h}_m = f(\mathcal{N}_u) \tag{1}
$$
$\mathcal{N}_u = {j|(u, j) \in \mathcal{G}_m }$表示子图$\mathcal{G}_m$ user结点$u$的邻域item结点。$\boldsymbol{h}_m$捕获了结构化特征 (structural information)。
$f(\cdot)$作者采用了两种形式。
Mean Aggregation: 采用average pooling操作来汇聚modal-specific features,再加一个非线性变换。
$$
f_{avg}(\mathcal{N}_u)=\text{LeakyRelu}(\frac{1}{|\mathcal{N_u}|}\sum_{j \in \mathcal{N_u}} \boldsymbol{W}_{1, m} \boldsymbol{j}_m) \tag{2}
$$
$\boldsymbol{j}_m \in \mathbb{R}^{d_m}$ 是模态$m$下item $ j$ 的表示。$\boldsymbol{W}_{1,m} \in \mathbb{R}^{d_m^{\prime} \times d_m}$是线性变换矩阵 (下标1只是编号,代表本文中使用的第一个参数矩阵)。平均池化操作假设了所有邻域结点的影响是等价的。
目前的问题是,item $j$在每种模态下都有一种初始表示,究竟是根据item的模态特征得到 (visual下根据帧图像卷积得到特征表示;text下根据文本描述提取特征表示),还是直接指定$|M|$个随机的modal-specific嵌入呢?
答案应该是前者。对于item侧,$\boldsymbol{j}_m$这个实际上就是后文提到的初始化的item intrinsic information $\boldsymbol{i}_m$,是modal pre-extracted feature。(后文实际上没有讲清楚,我是如何知道的?我是看开源的代码实现知道的。一开始我的理解是后者)
Max Aggregation: 使用max pooling操作来进行dimension-aware特征选择,
$$
f_{max}(\mathcal{N}_u) = \text{LeakyReLU}(max_{j \in \mathcal{N}_u} \boldsymbol{W}_{1,m} \boldsymbol{j}_m) \tag{3}
$$
这样的好处是不同的邻域结点的影响力不同。
item结点的aggregate操作同理。同样的,目前的问题是每个用户在每种模态下的初始表示是什么?是直接指定$|M|$个随机的modal-specific嵌入吗?答案是的,modal-specific嵌入,但是这里也是指后文提到的user intrinsic information $\boldsymbol{u}_m$,只不过作者用的随机初始化的向量来表示(可能是因为缺乏user profile信息)。
这个层的目标是融合aggtegation layer得到的来自邻域结点的结构化信息 (structural information) $\boldsymbol{h}_m$,结点自身内在信息 (intrinsic information) $\boldsymbol{u}_m$ 以及沟通不同模态的联系信息 (modality connection information) $\boldsymbol{u}_{id}$。形式化为:
$$
\boldsymbol{u}_m^{(1)} = g(\boldsymbol{h}_m, \boldsymbol{u}_m, \boldsymbol{u}_{id}) \tag{4}
$$
$\boldsymbol{u}_m \in \mathbb{R}^{d_m}$和上述提到的$\boldsymbol{j}_m$同理,是user的初始modal-specific表示,只不过作者实际上采用的是随机初始化方式,而$\boldsymbol{j}_m$是pre-extracted item modal-features。$\boldsymbol{u}_{id} \in \mathbb{R}^d$是$d$维user ID的嵌入表示,是所有模态间共享的,作为沟通不同模态信息的桥梁。
对于$g$函数的设计,
作者首先将$\boldsymbol{u}_m$和$\boldsymbol{u}_{id}$融合起来,即将$\boldsymbol{u}_m$通过非线性变换映射到$d$维空间,再加上$\boldsymbol{u}_{id}$。
$$
\hat{\boldsymbol{u}}_m=\text{LeakyRelu}(\boldsymbol{W}_{2,m} \boldsymbol{u}_m) + \boldsymbol{u}_{id} \tag{5}
$$
$\boldsymbol{W}_{2,m} \in \mathbb{R}^{d \times d_m}$。这样子变换完后,不同的模态信息在同一个超平面上了,是可比的。$\boldsymbol{u}_{id}$的好处是沟通了不同模态表示之间的差距,同时在反向传播的过程中,信息可以跨模态进行传播(the ID embedding $\boldsymbol{u}_{id}$ essentially bridges the gap between modal-specific representations, and propagates information across modalities during the gradient back-propagation process.)。形象的说,例如,视觉模态$v$下的反向传播误差能影响$\boldsymbol{u}_{id}$,$\boldsymbol{u}_{id}$又能进一步影响模态$t$下的modal-specific参数。这样就达到了不同模态之间互相联系。
接着将$\hat{\boldsymbol{u}}_m$和$\boldsymbol{h}_m$融合起来,进一步分为了两种:
Concatenation Combination:
$$
g_{co} (\boldsymbol{h}_m , \boldsymbol{u}_m , \boldsymbol{u}_{id}) = \text{LeakyReLU} \left(\boldsymbol{W}_{3,m} (\boldsymbol{h}_m || \hat{\boldsymbol{u}}_m)\right) \tag{6}
$$
$||$是concat操作,$\boldsymbol{W}_{3,m} \in \mathbb{R}^{d_m^{\prime} \times (d_{m}^{\prime} +d)}$。
Element-wise Combination:
$$
g_{ele}(\boldsymbol{h}_m , \boldsymbol{u}_m , \boldsymbol{u}_{id}) = \text{LeakyReLU}(\boldsymbol{W}_{3,m} \boldsymbol{h}_m + \hat{\boldsymbol{u}}_m) \tag{7}
$$
$\boldsymbol{W}_{3,m} \in \mathbb{R}^{d \times d^{\prime}_m}$。加法即element-wise feature interaction between two representation。而concat中两种表示之间独立。
第$l$层的combination layer的输出,即$g$的输出,对于user,作者用$\boldsymbol{u}_m^{(l)}$表示;对于item,作者用$\boldsymbol{i}_m^{(l)}$表示。
叠加多层aggregation layer和combination layer,递推式子如下:
$$
\boldsymbol{h}_m^{(l)}=f(\mathcal{N}_u), \boldsymbol{u}_m^{(l)} = g(\boldsymbol{h}_m^{(l)} , \boldsymbol{u}_m^{(l-1)} , \boldsymbol{u}_{id}) \tag{8}
$$
此处有个关键性的描述段落,指明了每个变量的含义,尤其是$\boldsymbol{u}_m$,原文讲的比较清楚,由于很重要,先摘录下来。
where $\boldsymbol{u}_m$ is the representation generated from the previous layer, memorizing the information from her $(l − 1)$-hop neighbors. $\boldsymbol{u}_m^{(0)}$ is set as $\boldsymbol{u}_m$ at the initial iteration. Wherein, user $u$ is associated with trainable vectors $\boldsymbol{u}_m$ , $\forall m \in M$, which are randomly initialized; whereas, item $i$ is associated with pre-extracted features $\boldsymbol{i}_m$ , $\forall m \in M$. As a result, $\boldsymbol{u}_m^{(l-1)}$ characterizes the user preferences on item features in modality $m$, and considers the influence of modality interactions that reflect the underlying relationships between modalities.
注意上述加粗的部分,对于user来说,初始化的intrinsic information $\boldsymbol{u}_m^{(0)}$使用随机初始化的modal-specific $\boldsymbol{u}_m$;对于item来说,初始化的intrinsic information $\boldsymbol{i}_m^{(0)}$使用预先提取的模态特征$\boldsymbol{j_m}$(原文写的是$\boldsymbol{i_m}$,我结合了开源代码,个人认为是笔误)。
$\boldsymbol{u}_m^{(l)}$构成:
因此作者说$\boldsymbol{u}_m^{(l-1)}$不仅刻画了用户对于模态$m$下item特征的偏好,还考虑了跨模态之间的交互信息的影响力。
以user为例,可以看出,随着GNN层数的增加,$\boldsymbol{h}_m^{(l)} , \boldsymbol{u}_m^{(l-1)}$是迭代的形式,$\boldsymbol{u}_{id}$是共享不变的。$\boldsymbol{u}_m^{(l)}$的迭代形式公式8交代的很清楚。而$\boldsymbol{m}^{(l)}$的迭代形式,作者没有说明清楚,实际上$\boldsymbol{h}_m^{(l)}$是关于$\boldsymbol{i}_m^{(l-1)}$的函数,即item侧第$l-1$的combination layer的输出,更准确的递推式,$\boldsymbol{h}_m^{(l)}=f(\mathcal{N}_u, \boldsymbol{i}_m^{(l-1)})$。
进一步可以观察下作者在github的代码实现,核心forward,
可以重点关注下$x$,初始是features;第一层输出的$x$作为第二层的输入,以此类推。
上述总共叠加了$L$层。最后,作者累加了所有模态下最后一个GNN层的输出,作为user或item最终的表示,
$$
\boldsymbol{u}^{\star} = \sum_{m \in M}\boldsymbol{u}_m^{(L)}, \boldsymbol{i}^{\star} = \sum_{m \in M}\boldsymbol{i}_m^{(L)} \tag{9}
$$
预测user-item pair的话,使用二者点乘形式进行预测,${\boldsymbol{u}^{\star}}^T \boldsymbol{i}^{\star}$。
最后作者使用和NGCF一样的BPR Loss进行优化。不再累赘。
在实验部分作者使用了头条数据集tiktok,快手数据集Kwai,movie-lens进行实验。头条数据集3种模态都有,快手只有文本和图像。movie-lens作者手动爬取了youtube的预告片,并用resnet50提取关键帧的特征,使用FFmpeg抓取声音片断并用VGGish提起声音特征,使用Sentence2Vector从文本描述中提取特征。这个工作量是真大。
另外,作者评估的时候,对于测试集中每个正样本observed user-item pair,随机抽了1000个unobserved user-item pairs作为负样本,然后用precision@k, recall@k, ndcg@k进行评估。这个是可取的,但是很多方法都是在全域进行评估,即,所有的unobserved user-item pairs全部作为负样本,这样的评估显然更客观,也更有说服力。
作者可视化用户对同1个item的不同模态的特征的偏好不一致性也值得学习。通过分析学习到的item的多模态降维表示,并抽取部分用户交互过的item,看交互过的item的降维表示的分布情况,例如,在视觉模态下,交互过的item比较分散,说明这些items的封面/帧/图像差异较大;而文本模态下,交互过的item表示向量点比较集中。则说明了用户对视觉模态没有太多的偏好,不是对其兴趣起决定性作用;而对文本域的模态有典型的偏好,例如喜欢看浪漫主题的电影。如下图中的user 1,左图视觉域点分布很分散;右图文本域集中在war和romance主题。相反,有的人可能很关注视觉模态,比如爱看封面美女的电影,那么其视觉模态下的表示就很集中;而可能这些电影主题差异很大,即文本模态下很分散。
作者没有讨论参数复杂度。这里面有非常多的参数。尤其是针对每个user和item的modal-specific参数,即带$m$下标的参数,尤其是user侧,如$\boldsymbol{u}_m^{0}$,全局的$\boldsymbol{u}_{id}$ 。我个人对此保持疑惑,因为在大规模的推荐系统中,user的数量非常多,而交互数据又非常稀疏。给每个user都分配如此多的参数,很多参数估计都得不到很好的学习,同时训练速度也很慢。可能user侧也需要引入profile信息比较好。另外,不是所有的items都有丰富的模态特征,大部分items可能缺乏模态特征,即,不同子图的拓扑结构可能会因为结点缺失相应的特征而导致不相同,这种情况下如何处理呢?
除了上述三个工作,关于二分图表示学习的最新工作还包括:
这两个工作主要借鉴了ICML2019: Simplifying Graph Convolutional Networks,讨论了如何简化GCN,使得更好的应用在推荐系统中二分图的表示学习。
关于图二分图的挖掘,是推荐系统中的核心问题之一。传统的图表示学习直接对二部图进行挖掘是有问题的。个人认为传统的graph embedding在建模时实际上很依赖于graph的手动构造,连边权重的合理设置,且没有把二分图中的collaborative signals直接建模到结点的embedding表示中,而只是通过目标函数来间接引导。而二分图的构建是基于原始数据的,没有连边权重,且数据过于稀疏,蕴含在二分图中的协同信息是非常隐晦的和难以挖掘的,故传统的图表示学习方法很难处理。本篇文章中介绍的三个工作基于message passing范式的GNN来挖掘二分图,将collaborative signals直接建模到embedding中,这是非常值得借鉴的。另外,这几篇文章的github都有源码,值得学习和实践。
KDD2018,GCMC:Graph Convolutional Matrix Completion
SIGIR2019,NGCF:Neural Graph Collaborative Filtering
MM2019,MMGCN: Multi-modal Graph Convolution Network for
Personalized Recommendation of Micro-video
Github, GCMC, Source Code
Github, NGCF, Source Code
从 Graph Convolution Networks (GCN) 谈起
LightGCN: Simplifying and Powering Graph Convolution Network for Recommendation
]]>2017: Representation learning on graphs: Methods and applications
下面主要围绕graph表示学习的问题定义,主流方法分类,encoder-decoder框架展开来介绍这篇调研paper.
目前主流的Graph Embedding方向是Node Embedding,包含了3大类主流方法:Matrix Factorization、Random Walk、Graph Convolution Networks。
作者针对Node Embedding,提出了一个统一的Encoder-Decoder编程框架来设计和实现Graph Embedding算法,上述所述目前主流的Graph Embedding算法都可以使用该框架来重新组织代码结构。
这一框架的核心思想在于,如果我们能够基于编码得到的低维embeddings,来学习高维Graph结构信息的解码,这些信息包括节点的全局位置或节点的局部近邻结构等,那么,原则上,这些低维emebdding包含了所有下游机器学习任务所需要的全部信息。
形式化地,Encoder是如下映射函数:
$$
ENC: \mathcal{V} \rightarrow \mathbb{R}^d
$$
即,将节点 $i \in \mathcal{V}$ 映射成embedding $\boldsymbol{z}_i \in \mathbb{R}^d$。
Decoder是这样一个函数,函数的输入是上述node emebddings集合,输出是要解码的、用户自定义的Graph结构信息。例如:Decoder目标可能是预测在给定节点embedding条件下,节点之间的连边是否存在;或给定embeddings下,预测节点所属的社区类别。Decoder的形式是多样化的,但是最常用的是pairwise decoder,
$$
DEC: \mathbb{R}^d \times \mathbb{R}^d \rightarrow \mathbb{R}^+
$$
即,Decoder的输入是Node Pair的embeddings,输出是一个实数,衡量了这两个Node在原始Graph中的相似性。
为了学习emebdding,我们的目标是重构节点低维emebddings的相似性,以反映二者在原始Graph中的相似性。即给定Node Pair $(v_i,v_j)$,
$$
DEC(ENC(v_i), ENC(v_j)) = DEC(\boldsymbol{z}_i,\boldsymbol{z}_j) \approx s_{\mathcal{G}}(v_i, v_j)
$$
其中,$DEC(\boldsymbol{z}_i,\boldsymbol{z}_j)$是模型基于编码的embedding,解码得到的二者的相似性(Estimated);而$s_{\mathcal{G}}$是用于定义的、原始图中,顶点之间的相似性(Ground Truth),例如可以使用邻接矩阵$A$来表示。那么,学习的目标就是所有训练集Node Pairs上,上述重构误差最小化,
$$
\mathcal{L} = \sum_{(v_i,v_j) \in \mathcal{D}} \ell (DEC(\boldsymbol{z_i}, \boldsymbol{z_j}), s_{\mathcal{G}}(v_i,v_j))
$$
$\ell: \mathbb{R} \times \mathbb{R} \rightarrow \mathbb{R}$是用于定义的损失函数,衡量了两个输入之间的差异。例如可以使用平方损失或交叉熵损失等。其中,$DEC(z_i, z_j)$可以看做是估计的(相似)值;$s_{\mathcal{G}}(v_i,v_j)$可以看做是真实的(相似)值。
上述框架涉及到4大组件:
目前基于矩阵分解,随机游走的方法都可以使用上述框架来抽象,并且其encoder都是浅层的embedding,即,使用embedding lookup,每个节点学习一个自己的emebdding,不同节点不进行参数共享,如下表:
例如:Laplacian Eigenmaps(谱聚类用的方法)的Decoder使用的是欧式距离,相似性度量可以使用任何方法(例如邻接矩阵,每个元素为$w_{ij}$),损失函数形如$\ell=w_{ij}(z_i-z_j)^2$,即两个节点相似性越大,施加大的权重,使得模型学习到的二者embedding更近。再比如DeepWalk使用$\text{softmax}(z_i^T z_j)$作为Decoder,而相似性度量是基于条件概率分布$P_{\mathcal{G}}(v_j|v_i)$,这个分布是指以$v_i$为起点,访问到$v_j$的概率,通过采样节点序列并构造共现对来近似的,而损失函数使用的是交叉熵损失。具体实现时,通常使用$\mathcal{L}=\sum_{(v_i, v_j) \in \mathcal{D}} -\log(\text{DEC}(\boldsymbol{z}_i, \boldsymbol{z}_j))$,其中, $(v_i,v_j) \sim P_{\mathcal{G}}(v_j|v_i)$,是通过随机游走在Graph采样得到的。
此外,GNN的方法实际上也能用上述框架来抽象,将在拓展一节介绍。
上述浅层的embedding的缺点:
为了解决上述问题,目前有几种方案:
Structural Deep Network Embeddings (SDNE) 把graph的structure在节点encoder的时候使用到。使用的是AutoEncoder,节点的原始输入经过encoder后再decoder,decoder的结果与原始输入越接近越好,原始输入通常使用某个节点和其邻居节点的相似度值集合来表示。此时SDNE的解码器是unary decoder,即不是上文提到的pairwise decoder。$DEC ( ENC (s _i )) = DEC (z_i ) ≈ s_i$。$s_i$即节点$i$和邻居节点的相似值。Loss为:$\mathcal{L}=\sum_{v_i \in \mathcal{V}} ||DEC(z_i) - s_i||_2^2$。该Loss的目标其实就是为了压缩节点的邻居结构信息($O(|V|)$)到低维空间$z_i$。
目前广泛使用的方法是Graph Convolutional Networks(GCN)。GCN中,每个节点单独encoder,但encode的时候,会利用卷积操作来汇聚Local Neighborhoods的节点的属性信息,并叠加多层网络,形成节点的embedding表示。而卷积核参数或网络的参数是所有之间之间共享的,因此能够有效减少参数量,同时能够泛化到新的节点,只要新的节点有属性信息以及节点的Local Neighborhoods结构化信息即可。而Decoder和Loss可以使用前面提到的任意方法。关于GCN的介绍参见我的另一篇博客。
引入特定任务的监督信息。上述方法都是无监督学习目标。我们可以使用监督学习目标。例如针对一个二分类问题,将embedding经过一层MLP($\boldsymbol{\theta}$)参数为输出一个预测值,即逻辑回归的损失函数。即:
$\mathcal{L} =\sum_{v_i \in \mathcal{V}} y_i \log(\sigma(ENC(v_i)^T\boldsymbol{\theta})) + (1-y_i)\log(1-\sigma(ENC(v_i)^T \boldsymbol{\theta}))$
从上述框架可以看出,Decoder,Loss,Similarity通常情况下是可以复用的。近年来的文章其实落脚点都主要在Encoder的改进上。如:如何融入节点的辅助信息;如何建模graph的structure;如何建模结点的local neighborhoods等。然后再通过Decoder和Loss来学习出结点的embedding。
本节将作为上述survey的拓展。我将引入Encoder-Decoder框架,围绕现有的代表性的Graph表示学习工作,总结和抽象出不同方法中的各大组件的具体表现形式。注,读本节前,请详细阅读上述关于Encoder-Decoder框架的介绍。
KDD 2014: DeepWalk: Online Learning of Social Representations
每个节点根据id进行embedding,节点的encoder就是Embedding Lookup操作。记做:$\boldsymbol{z}_i=\text{ENC}(v_i) = \text{Embedding-Lookup}(v_i, \boldsymbol{W})$,$\boldsymbol{W} \in \mathbb{R}^{N \times k}$是所有节点的Embedding矩阵,$N$是节点数量,$k$是向量维数。
如何衡量原始图空间中的Ground Truth结构信息呢?DeepWalk采用的是随机游走策略。观察某个节点$v_j$出现在以$v_i$为起始节点的游走路径上的概率。$s_{\mathcal{G}}(v_i, v_j) = P_{\mathcal{G}}(v_j | v_i)$。这个概率通过在带权图上进行随机游走采样路径序列,并在序列上使用滑动窗口来构造共现节点pair来近似。$(v_i, v_j) \sim P_{\mathcal{G}}(v_j | v_i)$。
如何衡量低维嵌入空间中的Estimated Information?DeepWalk希望上述采样到的共现节点pair的embedding越相近越好。采用的是点乘操作接softmax,即:$\text{DEC}(\boldsymbol{z_i}, \boldsymbol{z_j})=\text{softmax}(\boldsymbol{z}_i^T \boldsymbol{z}_j)$。
DeepWalk真正意义上的损失是交叉熵损失函数,即所有节点对上的交叉熵损失,$s_{\mathcal{G}}(v_i,v_j)$是ground truth,$\mathcal{L}(\boldsymbol{W}) = -\sum_{(v_i, v_j) \in \mathcal{R}^{|V| \times |V|}}s_{\mathcal{G}}(v_i,v_j) \log(\text{DEC}(\boldsymbol{z_i}, \boldsymbol{z_j}))$。具体实现时,无法把所有的节点对都配对,故基于采样的方式,$(v_i,v_j) \sim P_{\mathcal{G}}(v_j|v_i)$,优化目标转化为负对数似然损失函数,即:$\mathcal{L}(\boldsymbol{W})=\sum_{(v_i, v_j) \in \mathcal{D}} -\log(\text{DEC}(\boldsymbol{z}_i, \boldsymbol{z}_j))$。进一步,为了加速softmax配分函数的计算,使用层次softmax来优化。
KDD 2016: node2vec: Scalable Feature Learning for Networks
和DeepWalk唯一不同点在于Similarity Function,更准确的说,是衡量哪些node pair是相似的方法不同,体现在随机游走的规则上。
设计了有偏的游走策略来采样共现pair。考虑目前刚从节点$t$游走到某个节点$v$,准备从$v$游走到下一个节点$x$,Node2Vec会考虑$t$和$x$的关系,来约束$v$的游走规则。DeepWalk中,$P_{\mathcal{G}}(x | v) \propto w_{vx}$,即:游走概率正比于从$v$到$x$的连边权重,和怎么到达$v$的上一步$t$无关。但是在Node2Vec中,会判断下一步$x$和$t$的关系,设置一个系数$\alpha_{p,q}(x,t)$,则:
$$
P_{\mathcal{G}}(x | v) \propto \alpha_{p,q}(x,t) \cdot w_{vx}, \text{其中t是到达v的上一步节点}
$$
其中,
$$
\alpha_{p,q}(x,t) =
\begin{cases}
\frac{1}{p} & , & d_{tx}=0 \\
1 & , & d_{tx}=1 \\
\frac{1}{q} & , & d_{tx}=2
\end{cases}
$$
$d_{tx}=0$ 代表下一步$x$又回到了上一个点$t$,即同一个点。代表了回溯到上一个节点的概率。
$d_{tx}=1$代表下一步$x$和当前节点$v$同属于节点$t$的邻居节点,代表了BFS宽度优先遍历,作者认为BFS通过发现节点的局部近邻相似性能够在全图上探索出结构等价性节点。也就是说,BFS将某个节点游走限制在邻居节点,能够使得该节点获取到微观的邻居结构view。这样若在全图上存在某两个相似的、但距离较远的节点,说明这两个节点的邻居很相似,这进一步能够表明这两个节点存在结构等价性。
$d_{tx}=2$代表下一步$x$和上一步节点$t$没有直接连边,代表了DFS深度优先遍历。某个节点通过DFS游走到的节点,更多的是反映该节点在全图上的宏观view下的其邻居结构特点。即:虽然没有直接连边,但是存在潜在的相似性。这很适合用于进行社区发现。
$p$和$q$是超参数,代表了DFS和BFS之间的权衡,当都等于1时,Node2Vec退化成DeepWalk。
示意图如下:
和DeepWalk一样,只不过在优化softmax时,采用的是负采样方法。
$$
J_{\mathcal{G}}(\boldsymbol{z}_i)=-\log \left(\sigma(\boldsymbol{z}_i^T \boldsymbol{z}_j)\right) - \sum_{v_{j_n} \in W_j^{‘}} \log\left(\sigma(-\boldsymbol{z}_i^T \boldsymbol{z}_{j_n})\right)
$$
WWW 2015: LINE: Large-scale Information Network Embedding
和Deepwalk的不同点主要体现在Similarity Function,Decoder,Loss上,即如何定义哪些node pair是在原始空间是相似的?如何定义embedding空间中node pair之间的相似性?
Line定义了两种相似性node pair,一阶相似性(First-order Proximity)和二阶相似性(Second-order Proximity)。其中,
一阶相似性只针对无向图而言,是图中每一条边所对应的两个顶点之间存在相似性。即:对于每条无向边,$(i, j)$,其similarity function是$s_{\mathcal{G}}(v_i,v_j)=\hat{w}_{ij}$,其中归一化边权重$\hat{w}_{ij}=\frac{w_{ij}}{\sum_{(i,j) \in E}w_{ij}}$,即:使用所有边的权重和来归一化。如下图,6,7之间属于一阶相似性。
二阶相似性和deepwalk中类似,$s_{\mathcal{G}}(v_i, v_j) = P_{\mathcal{G}}(v_j | v_i)$。只不过Line中把每个节点的两个角色说的更清楚一些,即:target角色和context角色(deepwalk中也是有的)。context角色的意义在于,如果两个节点各自的上下文邻居很相似,那么这两个节点也相似,所以能够学习到Graph上远距离的结构相似性,如下图所示,节点5,6之间属于二阶相似性,因为5,6的上下文节点相似性(1,2,3,4)。在我看来,从生成概率角度而言,整个graph是通过若干个target节点(如社区)不断生成context节点;context节点再充当target节点,生成新的context节点而产生的。
DeepWalk中,$P_{\mathcal{G}}(v_j | v_i)$是通过随机游走+构造滑动窗口来近似,一次性能够采样到multi-hop多跳距离的节点;而在Line中,$P_{\mathcal{G}}(v_j | v_i)=\frac{w_{ij}}{d_i}$,$d_i$是节点的出度和,一次只能采样到相连接的上下文顶点$v_j$。通过context的桥梁作用(5和1相似,6和1相似,则5和6会慢慢相似;5和6相似了,因为7和6相似,则5和7可能也会慢慢相似),在不断迭代过程中,节点’感受野’会慢慢在graph中拓展开,因此会学习到这种多跳的节点之间的相似性。所以相比于DeepWalk,Line的收敛速度可能相对比较慢(作者提到,一般迭代步数正比于$O(E)$,In practice, we find that the number of steps used for optimization is usually proportional to the number of edges $O(|E|)$. 很多人忽视这一点,导致实际使用时性能很差)。
对于一阶相似性,节点$(v_i, v_j)$在embedding空间的解码相似性定义为,$DEC(v_i, v_j)=\text{sigmoid}(z_i^Tz_j)=\frac{1}{1+\exp(-\boldsymbol{z}_i^T \boldsymbol{z}_j)}$,其中,$\boldsymbol{z}_i, \boldsymbol{z}_j$分别是节点$v_i,v_j$的encoder。
对于二阶相似性,节点$(v_i, v_j)$在embedding空间的解码相似性定义为,
$DEC(v_i,v_j)=p(v_j|v_i)=\text{softmax}(\boldsymbol{z}_i^T \boldsymbol{z}_j))$。如上图,$v_i$为目标结点5时,$p(\cdot |v_i)$定义了$v_i$产生上下文节点1, 2, 3, 4的概率。
对于一阶相似性,基于KL散度,实际上去掉常数,化简完就是交叉熵,$\mathcal{L}(\boldsymbol{W}) = -\sum_{(v_i, v_j) \in E} s_{\mathcal{G}}(v_i,v_j) \log(\text{DEC}(\boldsymbol{z_i}, \boldsymbol{z_j}))= -\sum_{(v_i, v_j) \in E} w_{ij} \log(\text{DEC}(\boldsymbol{z_i}, \boldsymbol{z_j}))$。
对于二阶相似性,基于KL散度,实际上化简完也是交叉熵。为了化简完的形式更优雅,作者引入了每个target node的重要性$\lambda_i$,得到加权的KL散度损失,即$\mathcal{L}(W)=\sum_{(i,j) \in E} \lambda_i \text {KL}(s_{\mathcal{G}}(v_i, v_j), \text{DEC}(v_i,v_j))$;使用的是节点的度$d_i$来衡量,把这几个代入并去掉常数项,很容易得到:
$$
\mathcal{L}(\boldsymbol{W}) = -\sum_{(i,j) \in E} w_{ij} \log(\text{DEC}(v_i, v_j))
$$
注意到,和DeepWalk不同的是,不管是一阶还是二阶,这里头的node pair样本对只使用每条边对应的两个顶点;而DeepWalk实际上是任意两个顶点对(全图随机游走采样,只要游走距离够长,窗口够大,任意两个节点都有可能成为相似节点对)。具体实现时,使用alias sampling,每个迭代步依$w_{ij}$分布采样节点$i$的若干个邻居$j$,优化负对数似然$ -\sum_{(i,j) \in E} \log(\text{DEC}(v_i, v_j))$。(实际上,作者实现时,是采用边采样的策略,相当于把边的权重拍扁,然后随机采边,为了更好的收敛,迭代步数要正比于边的数量(paper里头说的);如果按照deepwalk那种方式,以点为主的话,也是可以的,只不过迭代步数要够,才好收敛,因为通常情况下,边的数量是大于点的)。
KDD2017: metapath2vec: Scalable Representation Learning for Heterogeneous Networks
这篇文章将DeepWalk拓展到异构图场景。主要的改进包括:引入了meta-path based random walk,Heterogeneous Skip-Gram和Heterogeneous negative sampling。其中,meta-path based random walk属于similarity function的范畴;Heterogeneous Skip-Gram和Heterogeneous negative sampling属于Loss Function的范畴。
meta-path based random walk制定一个游走规则,好处是能把节点之间的语义关系纳入到随机游走中。比如:U-I-U,I-U-I。通过该游走规则采样到的样本,可以认为是:$p(v_j |v_i, \mathcal{P})$的近似。其中,$\mathcal{P}$即为meta-path。实际上就是通过meta-path来限定转移概率分布。
注意,作者还提到,一般meta-paths都是对称的。
Loss形式如下:
$$
\arg \max_{\theta} \sum_{v \in V} \sum_{t \in T_V} \sum_{c_t \in N_t(v)} \log p(c_t|v;\theta)
$$
实际上就是把结点的类型纳入到损失中。$T_V$是所有的节点类型。$N_t(v)$是$v$的类型为$t$的邻居节点,即要为$v$节点采样所有类型的上下文节点$c_t, t \in T_V$。
$p$是softmax的形式的,故为了优化,作者引入了Heterogeneous Skip-Gram和Heterogeneous negative sampling。引入Skip Gram With negative sampling方法对上述Loss进行近似,即可得到:Heterogeneous Skip-Gram with negative sampling Loss:
$$
\log \sigma(\boldsymbol{z}_{c_t} \boldsymbol{z}_v) + \sum_{m=1}^M \mathbb{E}_{u^m \sim P(u)}[\log \sigma(-\boldsymbol{z}_{u^m} \cdot \boldsymbol{z}_v)]
$$
实际上和常规的Skip Gram是一样的,只不过上下文节点的类型$c_t$是基于meta-path random walk得到的。
同理,heterogeneous negative sampling也没有什么大的改动,对softmax分母的配分函数使用属于类型$t$的所有节点,而不是全部类型的节点:
$$
p(c_t|v;\theta) = \frac{\exp(\boldsymbol{z}_v^T \boldsymbol{z}_{c_t})}{\sum_{u_t \in V_t} \exp(\boldsymbol{z}_{u_t}^T\boldsymbol{z}_v)}
$$
上式重点在分母的求和项$\sum_{u_t \in V_t}$。则相应的,heterogeneous negative sampling改成使用该类型的节点上的分布$P_t(u)$即可。则对应的最终loss如下:
$$
\log \sigma(\boldsymbol{z}_{c_t} \boldsymbol{z}_v) + \sum_{m=1}^M \mathbb{E}_{u_t^m \sim P_t(u)}[\log \sigma(-\boldsymbol{z}_{u_t^m} \cdot \boldsymbol{z}_v)]
$$
KDD 2018: Billion-scale Commodity Embedding for E-commerce Recommendation in Alibaba
阿里KDD2018的文章,也是最早将graph embedding应用于推荐系统的工作之一。这篇文章主要是在DeepWalk基础上改进了节点的Encoder结构。
除了节点的id的embedding之外,还融入了节点的稀疏特征的embedding。
$$
\boldsymbol{H}_v =\frac{\sum_{j=0}^n e^{a_v^{j}}\boldsymbol{w}_v^j}{\sum_{j=0}^{n}e^{a_v^{j}}}
$$
上述,$v$代表结点,$\boldsymbol{a}_{v} \in \mathbb{R}^{n+1}$,$n$是稀疏特征的数量,+1代表的是id特征(j=0是id的索引)。对于每个结点$v$,有1个$n+1$维的向量$\boldsymbol{a}_v$,向量的每个取值$a_v^j$代表第$j$个特征的权重。若结点有$N$个,则有N个$\boldsymbol{a}_{v} \in \mathbb{R}^{n+1}$向量。
$\boldsymbol{w}_v^{j}$是该结点$v$第$j$个特征的embedding,可以看出结点最终的embedding就是每个特征embedding的指数加权和,权重系数向量$\boldsymbol{a}_v$也是要学习的。上式重写一下:
$$
\boldsymbol{H}_v =\sum_{j=0}^n \frac{e^{a_v^{j}}}{\sum_{j=0}^{n}e^{a_v^{j}}} \boldsymbol{w}_v^j = \sum_{j=0}^n \text{softmax}(a_v^j) \cdot \boldsymbol{w_v^j}
$$
NIPS 2017: Inductive Representation Learning on Large Graphs
基于邻域节点的特征汇聚。单个节点的Encoder过程如下图所示:
形式化表示为:$\boldsymbol{z}_i=\text{ENC}(v_i, \mathcal{N}(v_i))$,即:每个节点的encoder除了融入了自身节点的信息以外,还汇聚了局部的邻域节点的特征信息。汇聚的过程是个多层的网络。
初始的时候,节点使用辅助信息来表示(节点特征;节点本身的id embedding;graph上的节点拓扑结构信息,如:度)。接着对第$k$层网络,首先使用AGGREGATE函数汇聚节点$i$的邻居$\mathcal{N}(v)$的$k-1$层的表示,得到汇聚后的邻域 hidden vector,然后和自身的vector连接在一起,经过一个全连接层,再sigmoid激活,得到该节点$v_i$第$k$层的表示,可以认为该表示融入了节点$v_i$的k-hop范围内的节点的特征信息,例如:第1层的时候,融入了1-hop,即邻域节点的特征信息;同理,在第$k+1$层时,AGGREGATE函数的输入变为了第$k$层的输出表示,$k+1$层的节点表示融入了节点k+1 hop范围内的节点信息,重复该过程$K$次,就能够学习到节点在graph上K-hop的拓扑结构信息,节点的”感受野”随着迭代的进行不断扩大。注意,每次迭代完,作者还进行了一个范数归一化的操作(这个操作在层数比较大的时候应该还是必要的,还可以使用layer normalization替代)。
具体实现的时候,3~6行不需要使用所有的顶点进行更新。对于某个min-batch节点集合,只需要依次采样节点1-hop 邻居; 1-hop 邻居的邻居,即节点的2-hop 邻居;依次类推,采样到K-hop 邻居。则3~6行,只需要对这些采样到的K-hop执行操作即可,即:只要从1-hop~K-hop依次向外aggregate迭代执行即可。3~6的时间复杂度为:$O(\prod_{i=1}^K S_i)$, 其中$S_i$为第$k$层采样的邻居的个数。作者在paper中使用的$K=2$,且$S1*S2 \leq 500$就能达到很好的性能。也就是说平均每个节点大概采样20个邻居。
这里头最主要的是AGGREGATE汇聚函数的设计:
Mean Aggregator: $\text{MEAN}(\boldsymbol{h}_u^{k-1}, \forall u \in \mathcal{N}(v))$, element-wise mean of the vectors.
GCN Aggregator: 4-5步合并起来,并用如下式子替换
$$
\boldsymbol{h}_v^k \leftarrow \sigma \left(\boldsymbol{W} \cdot \text{MEAN}\left({\boldsymbol{h}_v^{k-1}} \cup {\boldsymbol{h}_u^{k-1}, \forall u \in \mathcal{N}(v)}\right)\right)
$$
这个怎么理解呢?此处实际上是第三代的GCN(参考我的另一篇博客)。第三代GCN形式化:
$$
\underbrace{\boldsymbol{Z}}_{\mathbb{R}^{N \times F}} = \underbrace{\tilde{\boldsymbol{D}}^{-1/2}\tilde{\boldsymbol{W}} \tilde{\boldsymbol{D}}^{-1/2}}_{\mathbb{R}^{N \times N}} \underbrace{\boldsymbol{X}}_{\mathbb{R}^{N \times C}} \ \ \underbrace{\boldsymbol{\Theta}}_{\mathbb{R}^{C \times F}} \\\\
\boldsymbol{I_n} + \boldsymbol{D}^{-1/2} \boldsymbol{W} \boldsymbol{D}^{-1/2} \rightarrow \tilde{\boldsymbol{D}}^{-1/2}\tilde{\boldsymbol{W}} \tilde{\boldsymbol{D}}^{-1/2}
$$
$\boldsymbol{\Theta}$类比于此处的$\boldsymbol{W}$,$X$类比于$\boldsymbol{h}$。第二个式子指的是加了skip-connection(原本W的对角元素为0),是一个renormalization trick,即:把结点自身的信息也考虑了。那么代入2式,并乘上常数$\boldsymbol{D}^{-1/2}$,可得:
$$
\boldsymbol{Z} = (\boldsymbol{I}_n + \boldsymbol{D}^{-1/2} \boldsymbol{W} \boldsymbol{D}^{-1/2})\boldsymbol{X} \boldsymbol{\Theta} = (\boldsymbol{X}+ \boldsymbol{D}^{-1/2} \boldsymbol{W} \boldsymbol{D}^{-1/2} \boldsymbol{X})\boldsymbol{\Theta} \\
\leftrightarrow \\
\boldsymbol{D}^{-1/2} \boldsymbol{Z} = (\boldsymbol{D}^{-1/2} \boldsymbol{X} + (\boldsymbol{D}^{-1} \boldsymbol{W}) (\boldsymbol{D}^{-1/2} \boldsymbol{X}))\boldsymbol{\Theta} \\
= (\tilde{\boldsymbol{X}} + \tilde{\boldsymbol{W}} \tilde{\boldsymbol{X}}) \boldsymbol{\Theta}
$$
$\boldsymbol{W}$是对角为0的邻接矩阵,故$\tilde{\boldsymbol{W}} \tilde{\boldsymbol{X}}$实际上获取的就是节点的邻居的特征,因此,实际上也是对节点的邻居做了汇聚操作,再加上自身的节点特征(通过skip-connection实现的,和concat是异曲同工!)。故,GCN Aggregator 和 Mean Aggregator+Concat实际上异曲同工,二者是线性近似的关系。
LSTM aggregator: 直接对邻域节点随机扰动permutation,然后将扰动后的序列使用LSTM来聚合。感觉有点简单粗暴了。
Pooling aggregator:
$$
\text{AGGREGATE}_k^{pool}=\max({\sigma(\boldsymbol{W}_{pool}\boldsymbol{h}_{u_i}^k + \boldsymbol{b}), \forall u_i \in \mathcal{N}(v)})
$$
即:每个邻居节点的表示先经过一个MLP,然后进行sigmoid激活;最后应用element-wise max pooling策略,此处的max pooling,作者提到用mean pooling也是可以的。内部的MLP也可以改成多层的MLP。
另外,similarity function作者采用的相似性函数和deepwalk一样,$s_{\mathcal{G}}(v_i, v_j) = P_{\mathcal{G}}(v_j | v_i)$,并通过基于graph的随机游走来构造共现对来近似(原paper: where $v$ is a node that co-occurs near $u$ on fixed-length random walk)。为了佐证这点,笔者特地读了原作者实现的代码,其中:
1 | # link: https://github.com/williamleif/GraphSAGE/blob/a0fdef95dca7b456dab01cb35034717c8b6dd017/graphsage/unsupervised_train.py#L143 |
除此之外,Loss Function中,无监督的损失函数和Node2Vec一样,采用的是skip-gram with negative sampling。Decoder和DeepWalk/Node2Vec也一样。
ICLR 2018:Graph Attention Networks
ICLR 2018的文章,在GraphSAGE基础上,引入了self-attention机制对aggregator进行了改进。
基于邻域节点的特征汇聚。只不过引入了self-attention机制,每个节点attend到自身的邻域节点上。不同于GraphSAGE采用Mean/Pooling Aggregator,GATs采用了基于self-attention机制的Aggregator。也就是说,把目标节点的表示和邻域节点的表示通过一个attention网络,计算注意力值,再依据该注意力值来aggregate邻域节点。对于节点$i$及其邻域节点$j$。我们要计算$i$节点attend到$j$的注意力值,attention score计算如下:
先对$i$和$j$的node feature分别做一个线性变换 (即multi-head attention的特例,1-head attention),$\boldsymbol{W} \boldsymbol{h}_i$
再把变换后的表示送到attention网络并进行softmax得到注意力值,$\alpha_{ij} = \text{softmax}(\text{attention}(\boldsymbol{W} \boldsymbol{h}_i, \boldsymbol{W} \boldsymbol{h}_j))=\text{softmax}(e_{ij})$,这个attention网络就可以随便设计和尝试了。作者使用的是:
$$
e_{ij}=\text{LeakyReLU}(\boldsymbol{a}[\boldsymbol{W}\boldsymbol{h}_i ,\boldsymbol{W}\boldsymbol{h_j}])
$$
即:二者Concat到一起后,经过一个线性变换$\boldsymbol{a}$ (attention网络的参数),再LeakyReLU激活。另外,对于节点$i$和自身的attention score,作者提到直接代入$j=i$即可。
则Aggregator直接依注意力值对线性变换后的vector加权并激活即可:
$$
\boldsymbol{h}^{\prime}_i = \sigma(\sum_{j \in \mathcal{N}_i}\alpha_{ij} \boldsymbol{W} \boldsymbol{h}_j)
$$
另外,作者提到,可以采用multi-head attention来拓展,即:attention score计算的第一步中,将node feature变换到不同的语义子空间,再进行attention score计算并aggregate。每个head输出一个$\boldsymbol{h}_i^{\prime}$,将所有的输出concat到一起;或者做mean pooling,作为节点的最终表示。
示意图如下:
上述描述的是单层的GAT。实际上,可以像GraphSAGE那样,设置多层。作者在实验中,采取的是2层以及3层的GAT。
KDD2018: Graph Convolutional Neural Networks for Web-Scale Recommender Systems
encoder结构非常简单,伪代码如下:
主要步骤和GraphSAGE几乎是一样的。$\gamma$就是Aggregation Function。作者提到,步骤2中的concat操作比average操作效果要好很多;步骤3中的归一化操作使得训练更稳定,且对后面基于embedding的相似性搜索更加高效。实际上,作者采用的$\gamma$是weighted mean pooling aggregator(important pooling aggregator)。其中,weight根据下面介绍的基于重要性的领域节点采样方法。
关键点在于,
传统的方法从目标结点$u$开始采样K-hop的邻居。作者采用了从$u$起始的随机游走的方式,并计算随机游走过程中每一个路径上的节点的L1-normalized visit count;则邻域节点定义为:最大的Top $T$ L1-normlized visit count。则每个邻域节点的weight也根据L1-normalized visit count来计算。作者称这种方法为important pooling。
实际上指的就是使用多层的卷积操作,前一层的结果作为下一层的输入。跟GraphSAGE中也是一样的,只不过作者换了个名字。
作者接着将卷积得到的结果通过2个全连接层得到最终节点的embedding。
作者采用了最大间隔损失函数(类似pairwise SVM Loss)。对某个正样本对$(q, i)$,其损失为:
$$
J_{\mathcal{G}}(\boldsymbol{z}_q \boldsymbol{z}_i) = \mathbb{E}_{n_k \sim P_n(q)}\max \{0, \boldsymbol{z}_q \cdot \boldsymbol{z}_{n_k} - \boldsymbol{z}_q \boldsymbol{z}_i + \Delta \}
$$
其中,$n_k$是采样的负样本,即,和$q$不相关的样本。$\Delta$是间隔参数,例如一般设置为1。
多说几句,个人认为这个文章的亮点主要在工程实现,作者提到了很多部署模型的细节,例如多GPU训练;生产消费者模式来产生训练样本等。尤其是生产消费者模式这个值得借鉴:由于graph图数据和节点的特征数据非常大,只能存储在CPU中,训练的时候如果让TF把数据从CPU搬到GPU来计算的话,代价是非常庞大的。作者的思路是,使用re-indexing技术,构造包括节点以及其邻域的子图,并把其纳入到mini-batch数据产生器中,使得子图在每次mini-batch 迭代开始前就已经送到GPU中了。个人认为就是利用了TF自带的喂数据的接口,并封装了一下generator。CPU中提取节点特征,re-indexing,负采样产生训练样本的操作可以认为是生产者;GPU中消费数据来训练样本可以认为是消费者。
对于负采样,作者为每个子图一次性采样了500个共享的负样本,可以有效的减少训练时间。如果每个节点都采样本的话,训练的时候,需要为每个负样本都计算embedding,非常耗时(感同身受)。
对于负样本采样个数,作者也有比较深入的讨论(非常值得学习)。Pinterest需要从20亿多个Item中,为每个Item找到最相关的1000个Item(1:2,000,000,相当于200万个Item中得找到1个相关Item);如果使用均匀分布随机采样500个负样本的话,相当于从500个Item中找到1个相关Item,显然是不够的。为了解决这个问题,作者引入了hard negative samples的概念,除了负采样easy negative samples,作者还采样了hard negative samples。用的是相对于正样本$q$,Personalized PageRank取值最高的若干负样本。具体训练时,交替执行,1轮不用hard samples,1轮使用hard samples(作者称这种方式为:curriculum training scheme)。
最后,作者还提到对于重复计算embedding的问题。每个节点的邻居可能存在交叉,即:某个节点是多个其他目标结点的邻居,此时这个节点只需要计算一次embedding即可。作者采用了Map-Reduce架构来防止重复的计算问题。
KDD 2019: Representation Learning for Attributed Multiplex Heterogeneous Network
作者在这篇文章中想要解决的是一种多类型节点,多类型连边关系的异构图网络的表示学习。这种网络称作AMHEN(Attributed Multiplex Heterogeneous Network),可以翻译做复合异构属性网络。
作者提出了一种叫做GATNE(General Attributed Multiplex HeTerogeneous Network Embedding)的模型,能够建模丰富的属性信息,并从不同类型的节点中捕捉复合拓扑结构(capture both rich attributed information and to utilize multiplex topological structures from different node types)。
看到这里,我们对作者的思路其实已经略知一二了。作者主要的创新点在于把节点之间多种多样的连边关系融入到节点的Encoder中。Multiplex在其他文章可能叫做Multi-View,即多视图。直觉上而言,节点之间的连边关系的层次是不同的,例如U-I交互中的click和conversion关系,显然是不等的。把这种交互关系的层次区分开,确实值得借鉴。下面就要看作何如何设计Encoder架构来建模多种连边关系,区分开不同level的interaction关系,并统一到Encoder中。
首先给出AMHEN的形式化表述:
作者实际上仍然是把Multi-View Graph拆分开为多个1-View Sub-Graph。
$$
\boldsymbol{u}_{i,r}^k=\text{aggregator}(\{\boldsymbol{u_{j,r}}^{k-1}, \forall v_j \in \mathcal{N}_{i,r} \})
$$
即:使用r-view sub-graph下,$i$的邻域节点汇聚得到$u_{i,r}$。对于transductive learning,初始化的$\boldsymbol{u}_{i,r}^0$随机初始化(也就是每个节点在每种view下都有唯一的 id embedding)。最终$\boldsymbol{u}_{i,r}^K$作为$\boldsymbol{u}_{i,r}$。此处,只用到r-view下,邻域节点的edge embeddings,未用到自身的edge embedding。aggregator可以使用mean pooling或者max pooling。
$$
\boldsymbol{U}_i = (\boldsymbol{u}_{i,1}, \boldsymbol{u}_{i,2},…,\boldsymbol{u}_{i,m})
$$
$\boldsymbol{U_i} \in \mathbb{R}^{s \times m}$矩阵,$s$是$\boldsymbol{u}_{i,r}$的维度数,$m$是连边类型的数量。
为此,引入了self-attention网络,可以把$\boldsymbol{U}_i$类比作word序列,每个word都要focus到句子的每个word上。同理,每个edge embedding都要focus到所有的edge embeddings上。对于某个edge type $r$,首先计算focus到所有edge embedding上的权重向量:
$$
\boldsymbol{a}_{i,r}=\text{softmax}(\boldsymbol{w}_r^T \text{tanh}(\boldsymbol{W}_r \boldsymbol{U}_i))^T
$$
其中,$\boldsymbol{a}_{i,r} \in \mathbb{R}^m$,$W_r \in \mathbb{R}^{d_a \times s}, \boldsymbol{w}_r \in \mathbb{R}^{d_a}$。衡量了r-view下,节点$i$和所有edge emebddings的关联程度。怎么从直觉上,或者从attention的范式上(Query, Key, Value)理解该self-attention网络呢?
$\boldsymbol{W}_r, \boldsymbol{w}_r$是r-view specific权重参数,可以认为是Query,$\boldsymbol{U}_i$是all-view下节点$i$的edge embeddings,可以认为是Key,即:探讨r-view和$i$的all-view的关联关系(Query和Key的关联关系),得到的就是$i$的r-view和all-view的关联关系。
再依据关联关系对Value ($\boldsymbol{M}_r^T \boldsymbol{U}_i$) 做聚合得到最终的节点$i$在edge type $r$下的overall embedding。
$$
\boldsymbol{v_{i,r}}=\boldsymbol{b_i} + \alpha_r (\boldsymbol{M_r}^T \boldsymbol{U}_i) \boldsymbol{a}_{i,r}
$$
$b_i$是节点的base embedding(node-specific,所有view共享);$\boldsymbol{M}_r^T \boldsymbol{U}_i$其实就是对Key $\boldsymbol{U}_i$做了个r-view specific transformation,最简单的情况下,$\boldsymbol{U}_i$既是Key,又是Value,此处额外做了个线性变换。然后基于self-attention向量$\boldsymbol{a}_{i,r}$做加权。$\alpha_r$是个可学习的常量系数,衡量了相比于base embedding,edge embeddings对overall embedding的重要性。
上述是transductive learning,为了实现inductive learning,只需要把$\boldsymbol{b}_i=h_z(\boldsymbol{x}_i)$ , 且$\boldsymbol{u}_{i,r}^0=g_{z,r}(\boldsymbol{x}_i)$, $\boldsymbol{x_i}$是节点的attribute向量,$z$是节点的类型,$h_z$,$g_{z,r}$是映射函数,如线性变换。除此之外,作者还加了一项关于节点本身attribute关于节点类型的线性变换项,最终形成如下的embedding:
$$
\boldsymbol{v_{i,r}}=h_z(\boldsymbol{x}_i) + \alpha_r (\boldsymbol{M_r}^T \boldsymbol{U}_i) \boldsymbol{a}_{i,r} + \beta_r \boldsymbol{D}_z^T \boldsymbol{x}_i
$$
作者为每个节点学习了$m$种embedding,$\boldsymbol{v}_{i, 1},…,\boldsymbol{v}_{i, m}$,并没有把$m$种aggregate到一起。说明在Similarity Function或者Loss Function上有一定的设计。
作者使用的和metapath2vec方法差不多的similarity function,由于是异构网络,作者引入了meta-based random walk来得到similarity function,$p(v_j |v_i , \mathcal{T})$。对于某个r-view sub-Graph $\mathcal{G}_r = (\mathcal{V}, \mathcal{E}_r , \mathcal{A})$, meta-path scheme $\mathcal{T}: \mathcal{V}_1 \rightarrow \mathcal{V}_2 \rightarrow … \rightarrow \mathcal{V}_t \rightarrow … \rightarrow \mathcal{V}_l$,其中$l$是meta-path scheme的长度。每个sub-graph分别按照这种方式采样训练样本。作者采用的meta-path其实就是U-I-U, I-U-I。
作者采取的损失为Skip Gram with negative sampling。对于某个node pair $(v_i,v_j)$,损失为:
$$
E = − \log \sigma(\boldsymbol{c}_j^T \cdot \boldsymbol{v}_{i,r}) − \sum_{l=1}^L \mathbb{E}_{v_k \sim P_t(v)}[\log \sigma(-\boldsymbol{c}_k^T \boldsymbol{v}_{i,r})]
$$
会根据该node pair的连边类型$r$,选择对应的$\boldsymbol{v}_{i,r}$。这样相当于每个节点可以学到$m$种embedding。
遗憾的是,作者没有对$m$种embedding做一个aggregator。看了下实验,可能对于node-node之间多种的interaction关系进行链接预测时,使用对应的$\boldsymbol{v}_{i,r}$。但是实际进行推荐的时候,是不是聚合一下得到唯一的embedding更好呢?
本文介绍了一种Encoder-Decoder框架,用于抽象和组织关于Representation Learning on Graph的方法。对于发现方法中的核心思想和核心组成部分有非常好的辅助作用。同时,该框架可以用于指导关于图表示学习的编程实践。据我所知,Alibaba开源的图表示学习框架 Euler 中,核心模型层的代码就是使用该Enocder-Decoder结构来组织的。这是一个非常好的实践,对于定义Encoder和Decoder的定制非常方便,笔者一直在用。后续有机会会分享一下关于Euler的实践经验。
Euler: A distributed graph deep learning framework (Alibaba)
]]>生成对抗网络(GAN,Generative Adversarial Network)是一种生成模型,由Generator和Discriminator构成。首先需要明确,虽然GAN是一种生成模型,理论上能针对特定的领域生成任何东西。但是随机生成不是我们想要的(即使生成的东西很逼真)。重要的是,我们能够控制生成control what to generate,这也是生成的意义所在。这种方式的生成,我们称作Conditional Generation。
Generator:实际上是一个neural network or a function。input: vector -> Generator -> output: image(matrix)
其中,input向量每个维度代表了某些特定的特征。比如第一维数值代表头发的长短;第二维数值代表头发的颜色;第三维代表嘴巴张开还是闭合。output的图像,实际就是Generator最后一层隐藏层输出的高维向量(reshape一下就成matrix)。
Discriminator:实际上也是一个neural network or function。input: image -> Discriminator -> scalar。
其中,output数值越大代表输入的图像越真实,越小代表输入的图像越假。
Adversarial的理解:多种多样的方式。
适者生存:Generator像是一种普通的生物(e.g., 枯叶蝶),Discriminator是Generator的天敌(e.g., 鸟)。Generator为了生存,不能轻易被天敌发现,故在自然选择的条件下,不断进化(e.g, 自身颜色变化),使得自己外表有更好的隐蔽性,能够迷惑天敌。Discriminator同样需要生存(e.g., 捕食),需要不断进化。使得自己有更好的辨别目标的能力。
作为类比,为了Fool Discriminator,Generator不断进化,生成更加真实的fake image。这些fake image作为Discriminator的输入,Discriminator要能识别出这些输入是fake的,不管Generator生成的多真实。
名师出高徒:Generator像是学生,Discriminator像是老师,我们希望学生不断进步。学生一年级时,画画较差,画的图没有眼睛,一年级老师不满意;到二年级时,该学生学会画眼睛,但是没有画嘴巴,二年级的老师更严格,也不满意。随着年级的增长,在老师的指导下,学生的能力不断增强,画画越来越好。
可以说,Discriminator leads the Generator。Discriminator有大局观,会懂得鉴赏,而不会亲手动笔画;而Generator会一笔一画,落到细处,但缺少大局观。
GAN:Generative Adversarial Network。从名称上,不言而喻,目的是希望得到一个生成网络。为了能够很好的生成目标对象,例如,image/sentence等,引入了对抗(adversarial)学习的概念,使用Discriminator承担对抗的任务,引导着Generator不断学习和进步。Discriminator体现着top-down的思想,能够从全局上对一个完整的输入图片进行真假判断,但自己生成目标对象较困难(穷举);Generator体现着bottom-up的思想,从细粒度的组成单元(pixel/word)的级别,one-by-one的生成目标对象(image/sentence),但是无法把握组成单元之间的依赖关系(pixel之间,word之间,实际上是结构化预测的核心问题),没有大局观。二者结合,迭代学习,能够发挥二者的长处,同时互相弥补二者的短处。
结构化学习(Structured Learning):是machine learning中有别于分类/回归之外的另外一种问题。主要区别在于其输出的是结构化的对象,如序列,矩阵,图,树等,且结构化输出每个components之间是存在依赖关系的。
常见的结构化学习问题包括:Seq2Seq机器翻译(输出序列)、Image to Image图像变换/上色(输出矩阵)、Text to Image/Image to Text图像描述(输出矩阵或序列)、连续决策或控制(输出是决策序列)。关键点在于,上述结构化学习的输出的组成成分之间是有明显的依赖关系的(例如句子中word-by- word关系,图像中pixel-by-pixel关系,决策中action-by-action关系)。
结构化学习的难点还在于,输出空间是巨大无比的,如果把每个可能的输出都看做一个类别的话,大部分类别缺乏足够的训练样本,因此在测试的阶段,模型需要具备创造能力/泛化能力,这种问题实际上就是one-shot/zero-shot learning的体现。其次,结构化学习需要模型学会计划。也就是说,模型可以按照component-by-component的方式来生成目标对象,但是需要模型在脑海里有一个大局观在指导。因为components之间有很强的依赖关系,需要全局的进行考虑(比如说,前一个是主语类型的单词,接下来生成的更可能是谓语类型的单词,这是大局观)。
GAN是一种用于做Structured Learning的具体方法。其中,Generator能够在component-level来component-by-component的生成目标对象(Bottom Up);Discriminator能够学会计划,从全局上评估整个目标对象(Top Down),不断引导(Leads)Generator的学习。
因此回到问题本身,GAN可以用于做结构化学习。
Generator的任务是给定输入向量(我们称之为code,通常是低维的),生成目标对象,如图片,句子等(高维向量)。这里有了输入输出pair,实际上就变成了回归问题。我们知道,输出就是具体的目标对象,如图片/句子。因此,这里的关键是输入code如何选取?code的每一维实际上都隐含着描述目标对象的特征信息。如果为每个目标对象随机地选择code,那么训练就会存在很大的困难。因为,可能两个目标对象很像,但是随机生成的code差异很大,这样的话,想让网络生成很像的两个目标对象是比较困难的。我们希望,两个code比较相似的时候,生成的两个目标对象也有很多相似之处。这个问题可以借助Auto-Encoder或Variation Auto-Encoder,通过最小化重构误差,学习目标对象的低维表示。顺便提一下,Auto-Encoder的假设是,即使目标对象的向量维度数是很高的,但是实际上存在一个低维的表示就能够很好的描述它(流形假设)。
目标对象经过NN Encoder提取到的$c$就是此处的code。而Code -> Decoder -> Image这三部分就可以看做是一个generator。
但问题在于,NN Decoder输出的时候,没有考虑目标对象组成单元之间的依赖关系(虽然这种依赖关系可以通过多层网络间接考虑到,但是还是比较弱)。这会导致诸多问题,例如,不同生成的图片和实际的目标图片同样是相差1个像素点,但是重要性却不同,有些像素点缺少无所谓,有些像素点却不能缺少。比如下图:
第一幅图多了个像素点,第二幅图少了个像素点,影响都非常大;第三幅和第四幅尽管相差了6个像素点的误差,但是仍然影响不大。像素直接的依赖关系非常重要,对于第一幅图,我们不是说一定不能够多出图中的那个像素点,但关键是没有考虑该像素点周围的像素点的影响,如果改成下图,把多出来的那个像素点周围的像素点都填充了,那么也OK。
也就是说,像素点之间的关系是非常重要的。但是,generator最后一层是独立地生成各个像素点,无法从全局上把握不同像素点的依赖关系(虽然通过深度网络架构能够在一定程度上间接捕捉依赖关系,但仍然不够)。因此,回到问题本身,这也是不能单独使用generator进行自我学习且期望生成较高质量的目标对象的原因。
Discriminator又称作Evaluation Function或Potential Function,是一个函数,将高维输入对象映射成一个scalar值,该数值代表了输入对象“多好”。Discriminator的好处在于能够以top-down全局的评估方式来考察componets之间的依赖关系。例如以上文的例子为例,使用下述右侧的1个CNN filter,如果提取到了游离像素点特征,那么就能够很方便的从全局上分析该输入不是2(左侧第一个2)。
那么Discriminator既然这么会分析输入对象的好坏,那么能否用于生成呢?答案是可以。
假设我们已经有个一个足够好的Discriminator $D(\boldsymbol{x})$,那么生成目标对象$\tilde{x}$的任务为:
$$
\tilde{\boldsymbol{x}} = \arg \max_{\boldsymbol{x} \in \boldsymbol{X}} D(\boldsymbol{x})
$$
上述任务就是穷举所有可能的$\boldsymbol{x}$,选出模型认为好的作为生成的目标对象。
关键问题转成了如何训练处一个足够好的Discriminator以及如何求$\arg \max$。
对于第一个问题,Discriminator实际上就是一个二分类判别模型,因此需要正样本和负样本。其中,正样本由我们的数据集提供,我们需要考虑负样本的生成。负样本是问题的关键所在,那我们应该如何生成realistic negative examples呢?我们可以采取迭代学习的方式来训练判别模型,每轮迭代完,使用判别模型本身来产生negative examples,再接着下一轮迭代。使用Discriminator来解Generation问题的通用算法如下:
首先给定正样本以及随机抽取的负样本,训练模型来最大化区分正负样本(如二分类交叉熵损失);接着使用上一轮训练好的模型通过解$\arg \max$生成负样本,然后作为下一轮训练的输入。
学习的过程可以使用下述图来形象刻画:
上述假设输入$\boldsymbol{x}$是一维的。1图中,假设最开始正样本是绿色球区域,随机抽取的负样本是蓝色球区域,第一轮迭代完,$D(x)$曲线在绿色样本区域预测得分高,在蓝色样本区域预测得分低,但是在最右侧大部分区域,模型还不得而知是该预测得分高还是低,图中可以看出右侧还有更高得分区域(实际上除了绿色球区域,其他区域都是负样本,得分都应该低,但是目前来看右侧高了,说明模型存在弱点);第二轮迭代前,通过求解arg max(通常通过采样来近似求解,如Gibbs Sampling)生成了目前模型认为高置信的样本(模型当前弱点所在)作为负样本,也就是图2中右侧蓝色球部分,第二轮迭代后,如图3所示,$D(x)$曲线在右侧区域得分值降低,也就是说纠错了当前的弱点。一直不断迭代,不断纠错后,最终模型采样的结果和真实的样本会非常接近,如图4所示。因此,$D(x)$本身学习到了数据某种潜在的分布,可以通过采样等方式,泛化到未知的数据上。实际上,很多结构化学习/无监督学习都是采用这种方式进行生成学习的,其学习后的模型本身是可以用于生成新样本的,也就是说学习到数据潜在的真实分布。
如上图,我们熟悉的很多图模型都是根据上述方式进行学习的,即不断根据$\arg \max$进行负采样,来纠错并更新模型,提高模型的生成能力,只不过有的模型$\arg \max$可以显示精确求解,有的模型$\arg \max$需要使用Gibbs采样等方式近似求解。例如,RBM只使用无标签的样本本身进行无监督学习,使用基于能量的方式来构建似然损失,每步迭代时,都需要RBM模型本身进行负采样(Gibbs Sampling),并进行模型参数的学习。在CRF中 ,当要预测给定输入序列的标签序列时,需要求解$\arg \max$,即给定$X$,求似然(X和Y联合概率)最大的$Y$,$\arg \max\limits_{Y} P(Y,X)$(等价于$P(Y|X)$最大,使用维特比算法或Beam-Search近似算法;注意CRF训练时不需要求argmax,因为是监督学习,用了下一时刻真实的标签y即可)。
Discriminator生成目标对象的问题在于复杂度较高,需要求解$\arg \max$问题。
总结一下:
集大成,取长补短。使用Generator进行负采样,产生负样本;使用Discriminator根据真实样本和产生的负样本进行学习,从全局上把握components之间的关系,指导Generator不断进化,生成更逼真的目标对象。
关键:也就是说除了min-max博弈方式来通俗的理解GANs之外,也能够按照上述方式理解,即:Generator是Discriminator的负采样器,功能上等价于arg max discriminator;Discriminator通过区分负采样的样本和真实样本,来不断提升Generator的负采样能力,直到负样本和真实样本几乎服从于同一个分布为止!此时,Generator能够用于生成新样本!!
上图是两侧非真实样本所在区域的fake样本(D(x)很低),在Discriminator的指导下,都不断往真实的样本所在的区域靠(D(x)很高)。最终,Generator输出的Fake样本和Real样本几乎重叠,D(x)无法区分是真实样本还是假样本。
学习算法统一起来,如下:
每次迭代,
演算法如下:
GAN的好处在于:
From Discriminator’point of view
前面我们喂给Generator的输入都是随机的噪声,这样产生的都是随机的东西。而在Conditional GAN当中,我们不仅要喂给Generator随机的噪声,还要喂Conditions,这样产生的东西是基于输入的条件的。比如Caption Generation,给定输入条件为图片,输出文字描述;Chat-bot中,给定输入条件是问题,输出回答;Image Generation中,给定输入条件是文字描述,输出图片;Video Generation中,给定输入条件是前几帧的画面,输出是下一帧的画面。此时,这些输出连同conditions作为Discriminator的输入,Discriminator判断时,不仅要判断输入的stuff是否逼真,同时还要判断输入的stuff是否和conditions相匹配。
有监督条件GAN是指用于训练的数据集中,包含了real stuff和其对应的condition,记做,$(c^{i}, x^{i})$,$c^{i}$是condition,$x^{i}$是real stuff。
首先训练Discriminator,固定Generator。Discriminator的学习目标不仅是判断输入图像是否真实,还要判断输入的stuff和condition相匹配。condition给定的前提下,前者的学习的目标是最小化(fake stuff, condition)得分;后者的学习目标是,最小化(not matched real stuff, condition)的得分,前后者共同的学习目标是,最大化(real stuff, condition)得分。具体而言,
前者根据最小化generator生成的样本$\tilde{x}^{i}$的得分$D(c^i, \tilde{x}^i)$,后者从数据集中真实的样本随机抽样部分样本$\hat{x}^{i}$,作为和condition不匹配的样本,最小化$\hat{x}^{i}$的得分$D(c^{i}, \hat{x}^i)$;二者共同目标是,最大化数据集中该condition对应的真实样本$x^{i}$的得分$D(c^i, x^i)$进行学习。
接着训练Generator,固定最后几层的Discriminator。目标是最大化Generator输出的得分(Discriminator打分的)。Generator输入是(noise, condition) pair(noise的含义见下文理论部分),输出是fake stuff,$G(c^i, z^i)$。
演算法如下:
前面有监督条件GAN使用的训练集是(real stuff, condition) pairs,二者是一一对应的。无监督条件GAN使用的训练集,real stuff和condition不是一一对应的。相反,使用的数据集是x domain(conditions)和y domain(real stuffs)两个分开的集合,没有对应关系。希望实现由x domain直接转成y domain。例如,图像风格转换,x domain是原始图,y domain是梵高的图,训练集中只包含一堆原始图,一堆梵高的图作,二者没有对应关系,目标是将原始图转成梵高的画作风格,例如将日月潭转成梵高的图,显然日月潭和梵高画作不能对应,因为梵高没有画过日月潭,但我们希望模型能够将原始日月潭渲染成梵高的画作风格类型。
学习时要考虑两个因素,x domain通过Generator转化成的fake y domain能够符合y domain,使用Discriminator来判断是否符合y domain;还要考虑约束fake y domain必须和输入x domain存在一定的相似性,否则fake y domain每次都输出固定的某张y domain,完全无视input x domain的话,Discriminator会认为fake y domain很逼真,但是完全没达到我们的目的,因为fake y domain和输入x domain完全不相关了。
因此,有大量的研究工作是针对如何使得fake y domain和x domain产生关联,即依赖于条件x domain的条件生成模型。
添加输入x domain stuff和输出fake y domain stuff之间的相似性约束。
最粗暴的方法,不考虑相似性约束,但必须保证Generator的网络是Shallow的,这样不会改变太多,间接的达到x domain stuff和fake y domain stuff相似的目的。
DTN
x Domain 和 Generator生成的 fake y domain 都经过Encoder Network提取特征后,约束二者之间的相似性。
Cycle GAN
添加俩Generator,正反向,domain x -> fake y domain -> recovered domain x。反向恢复后的domain x和原始的domain x越近越好(cycle consistency loss)。
double cycle gan:
问题是,存在隐藏信息的可能(隐写术);generator出来的fake y domain存在问题,但是recovered domain x没问题,这说明模型通过其他方式绕过了cycle consistency loss,generator会隐藏信息,且善于恢复(cycle consistency loss很小),但是generator输出的stuff可能就和原始stuff差距很大了,这不是我们想要的。
如上图所示:中间generator输出的fake y domain的质量很差,但是generator却比较擅长恢复x domain,导致虽然cycle consistency loss很小,但是fake y domain却达不到我们的预期。
StarGAN
多个domain间互相转换,正常需要$C_n^2$个generator,但StarGAN只需要1个generator。
Demo如下:
每个Domain(可能是组合,金色头发+年轻)有一个label。
VAE-GAN
问题是,尽管得到了两个Encoder和两个Decoder。实际转换时,人脸照片作为Encoder X的输入,获取Decoder Y的输出,作为人脸照片的卡通画形象。如果训练时,输入数据是对应的数据pair对(人脸照片,对应的卡通化照片),那么中间的latent vector表达的语义在Encoder X中和Enocder Y中是一样的。但是,由于不是pairs数据进行训练,中间的latent space在Encoder X中和Enocder Y中的语义是不一样的,二者没有关系,是不同空间的。例如,在Encoder X中,latent vector第一维代表戴眼镜,在Enocder Y中,latent vector第一维可能代表长头发。这样,从Decoder Y输出的stuff,可能和Encoder X的输入stuff完全没有关系。我们必须保证latent vector对于Encoder X和Encoder Y来说,是位于common space的。上述的原因是,两个auto-encoder是分开训练的,除了中间共用了latent vector以外,优化时分开的,但是latent vector对于二者而言,语义可能完全不一样,即The image with the same attribute may not project to the same position in the latent space。
Couple GAN
Sharing the parameters of encoders and decoders.
encoder最后几层的参数共用;decoder最前几层的参数共用。这样可以使得latent vector在两个encoder中的语义相似,在两个decoder的语义相似。极端情况下,两个encoder完全一样,只是输入的时候给不同domain的flags。
VAE-GAN + Domain Discriminator
判断latent vector是从哪个domain的image转化来的。学习时,两个Auto-Encoder轮流骗Domain Discriminator。例如,Encoder X得到的fake latent vector作为负样本输入Discriminator,Encoder Y得到的real latent vector作为正样本输入Discriminator,不断更新Encoder X,来最大化Discriminator识别fake latent vector(X)为domain y的得分。反之,Encoder Y得到的fake latent vector作为负样本输入Discriminator,Encoder X得到的real latent vector作为正样本输入Discriminator,不断更新Encoder Y,来最大化Discriminator识别fake latent vector(Y)为domain x的得分。最终导致,Domain Discriminator无法识别latent vector是来自于Domain X还是Domain Y,此时意味着学习到的latent vector在Domain X和Domain Y中位于同一个语义空间。
ComboGAN: VAE-GAN + Cycle Consistency
数据流入图中序号所示。
XGAN: VAE-GAN+Semantic Consistency
和ComboGAN类似,只不过重构误差加在latent vector上。经过Encoder X第一次得到的latent vector和经过Encoder X -> Decoder Y -> Encoder Y得到的latent vector之间误差最小,这是语义一致性,因为latent vector表征了学习到的语义。
Find data distribution $P_{\text{data}}(x)$。
GAN之前的做法:MLE(maximum likelihood Estimation)
最大似然估计等同于最小化生成模型$P_G$和潜在数据分布$P_{data}$(我认为更准确的应该是经验分布)之间的KL divergence。注意下图推导中,$arg max_{\theta}$中的第二项$\int_x p_{data}(x)log p_{data}(x)dx$是与$\theta$无关的常数,故可以添加该项。
以往做法通常使用GMM作为$P_G$,然后在高维空间拟合样本$x$。但是训练完,通过GMM生成的图往往很糊,因为是直接在高维空间做的,但是很多高维空间的样本实际上是位于低维的语义空间,即Manifolds流形区域的,因此如果直接拟合高维空间的样本,往往学习到的东西是存在很多冗余和噪声的。
GAN的做法:
A network which defines a probability distribution $P_G$.
问题是Div很难算,$P_{data}$和$P_G$的Formulation是未知的。如果形式已知,那么Div能算,就可以直接通过梯度下降优化了。
GAN的做法很神奇,即使$P_{data}$和$P_{G}$的Distribution Formulation未知,但是二者都可以通过【采样】来近似。
那么采样完数据后,如何计算二者之间的Divergence呢?
GAN利用Discriminator来计算二者之间的Divergence。实际使用时,就是选择某种关于二者的目标函数进行优化,来近似等同于优化二者之间的Divergence。
重要结论:目标函数的最优值和JS divergence密切相关(目标函数的上界是JS)。
$$
\max V = \text{JS}\ \\
\arg \min \text{JS} \leftrightarrow \arg \min \max V
$$
看出端倪了。Discriminator的目标是最大化real stuff的得分以及最小化fake stuff的得分,等价于最大化V(G,D),其中G是固定的,V的第一项是real stuff的得分$D(x \sim p_{data})$要最大化,第二项是fake stuff的得分$D(x \sim p_{generator})$要最小化,即$1-D(x \sim p_{generator})$最大化,也就是最大化V函数。而最大化V函数的结果正好衡量了real stuff数据分布和generator生成的fake stuff数据分布之间的JS!!那么,轮到generator优化时,顺理成章就是最小化二者的JS,等价于$\arg \min \max V$, 最终变成了一个max-min博弈问题。
直观解释:
理论证明:
积分最大化,转成每个样本都最大化,那么所有样本相加也是最大化。
求导得到最优的$D^{*}(x)$。代入原来的目标函数得到:
优化目标转换:
代入$\max V= \text{Div}$:
变成了一个MIN-MAX的问题。
举个例子进行形式化解释。
假设候选的Generator只有3个,G1,G2,G3。Discriminator只由1个参数(横坐标)决定,曲线D上任意一点代表不同的Discriminator。
在给定Generator条件下,优化D。选择D使得$V(G,D)$最大化,也就是下图每幅图中的最高点对应的D,得到3个点。
在给定Discriminator条件下,优化G。选择G使得$\max V(G,D)$最小,因此在上述得到的3个D中,选择最小的点对应的Generator,即G3。
演算法如下:
G固定,更新D。直接$\arg \max_D V(G,D)$,即可。Evaluate JS Divergence.
D固定,更新G。Minimize JS Divergence.
主要难点在于max operation的求导。
梯度下降:如果从整体上来看,$max V(G,D)$等价于JS目标,那么第二步就是最小化JS目标,因此用梯度下降。
从细节来看,前面我们说优化G时,希望更新后的G产生的样本,D能给更高的分,等价于V(G,D)的第二项越小越好($1-D(x \sim P_{generator})$越小,$D(x \sim P_{generator})$越大),而第一项与G无关,则相当于整体上V(G,D)越小越好,因此用梯度下降。
max operation求导:实际上就是不同的G(类比输入$x$),对应不同的V(G,D)(类比$f_i(x)$,可以看做分段函数)曲线。把所有不同G对应的V(G,D)曲线求max operation整合在一起,得到一个总的曲线就是$L(G)$。从另一个角度理解,V(G,D)越大,$G$越不喜欢,而$G$倾向于减小$V(G,D)$,因此选择最大的$V(G,D)$能够提供最大的梯度。
但这里有个问题,迭代过程中,每轮迭代之间JS divergence都会下降吗?我们不妨来看下图,
究其原因是,G的更新幅度太大,导致V(G,D)曲线变化太大。如果G的更新幅度很小,两幅曲线基本一致的话,则,$D_0^{*} \approx D_1^{*}$,即两幅曲线的最高点都在相同的位置取到,此时梯度下降更新G的结果就像稍微把曲线往下挪,仍然在同一个位置取到JS最大值,但是此时JS divergence相比于前一轮迭代是下降的。
因此,实际更新模型时,每轮迭代时,对Discriminator必须要使劲训练,Train到收敛,因为V的最大值才能用来衡量JS Divergence;而对Generator不能更新太多,稍微训练即可,防止V(G,D)曲线变动。另外,优化目标函数中存在期望,实际优化时,使用抽样的方式求平均值来近似期望。
注意,在更新G时,V的第一项和G没关系。
另外,在更新G的时候,要最小化V的第二项,即$\log(1-D(x))$。然而,由于$\log(1-D(x))$在D(x)很小时(比如:一开始训练),导数很小,导致收敛非常慢。因此,实际实现时,通常改成优化minimize: $-\log D(x)$(最小化$\log(1-D(x))$,即最大化$\log(D(x))$,也即最小化$-\log D(x)$),二者趋势一致,但是导数大,收敛快。如下图:
而从另一个角度,在最小化$-\log D(x)$时,完全可以复用更新Discriminator的代码来更新Generator。只需要将标签反过来,即:generator输出的作为正样本,数据集中的作为负样本,然后运行Discriminator更新的代码即可。即,
$$
\begin{split}
& \underbrace{\max E_{x \sim P_{\text{data}}}[\log D(x)] + E_{x \sim P_{\text{G}}}[\log(1-D(x))]}_{\text{object function of Discriminator}} \\
& \leftrightarrow \\
& \underbrace{\max E_{x \sim P_{\text{data}}}[\log (1-D(x))] + E_{x \sim P_{\text{G}}}[\log(D(x))]}_{\text{object function of Generator}}
\end{split}
$$
第一个式子是Discriminator的更新代码;第二个式子是Generator的更新代码,可以看出是直接将V的第一项real data的预测标签从$D(x)$改为$1-D(x)$, 第二项fake data的预测标签从$1-D(x)$改为$D(x)$。
在更新Generator时,第二个式子的第一项在更新Generator时是常数,可以忽略;而max第二项就等价于min $-\log D(x)$,也即Generator的目标。
不得不说李老师的教学视频非常棒!受益匪浅!比大多数网上讲解GAN的资料好太多。再次致谢!
卷积和傅里叶变换有着密不可分的关系。在数学上,两个函数的卷积等于各自求傅里叶变换转成频域后乘积的逆傅里叶变换。即:Convolution —— Fourier
傅里叶变换又可以通过谱图理论推广到Graph上进行变换。Fourier —— Spectral Graph
因此自然而然,Convolution —— Fourier —— Spectral Graph,Convolution通过傅里叶变换和Graph发生了联系。
从整个的研究进程来看,首先是研究GSP(Graph Signal Processing)的学者提出了Graph上的Fourier Transformation,进而定义了Graph的Convolution,最后与深度学习结合起来,发展出来GCN。
下文主要先介绍数学中的傅里叶变换,再介绍Graph上的傅里叶变换。最后介绍卷积如何应用在Graph上。
傅里叶变换可以从多种角度进行表述。
从数学角度,傅立叶变换就是将周期函数转化为一组正交基下的坐标表示,这个坐标表示就是傅立叶变换的结果。换句话说,周期函数是这些正交基的线性组合(向量的叠加), 线性组合系数构成的向量就是傅立叶变换的结果。
从信号处理领域角度,傅里叶变换将一个周期函数从时域(时间与振幅的关系)转化为频域(频率与振幅的关系)。做个类比,正交基选择的是正弦函数,每个正弦函数有个频率参数值,而每个正弦函数的振幅参数就是该基下对应的坐标值。所有正弦函数的振幅构成的向量就是傅立叶变换的结果。
下面以信号处理领域为例,来进一步理解傅里叶变换。
理解傅里叶变换,需要理解两个核心概念:
任何周期(T)函数,都可以使用傅立叶级数展开法将它们分解为有限或无限个不同频率不同振幅的正弦函数的叠加。傅里叶级数展开公式如下:
$$
f(x)=\sum_{n=1}^{\infty} \left(a_n \cos (\frac{2\pi n}{T}x) + b_n \sin (\frac{2\pi n}{T}x)\right) + C, C \in \mathbb{R}
$$
振幅$a_n, b_n$有具体的计算公式。$\frac{2\pi n}{T}$是频率。求和叠加就是线性组合。如果把函数$f$看成离散点构成的向量,那么就是这些正弦函数基向量的线性组合。
举例:分解动图如下:
某个周期函数$s_6(x)$, 可以分解为一系列正弦函数的和:
$$
f(t) = A_0 + A_1 \sin wt + A_2 \sin 2wt + … + A_{\infty} \sin(\infty) wt
$$
其中各个分量的振幅$A_i$(有正有负)的确定有专门的公式,此处不详述。而各个分量的频率$aw$($w$是角频率,$f=\frac{w}{2\pi}$)恰好是原来函数频率的整数倍(公式中$2\pi n/T$为整数),是确定的。
经过分解后的公式完全可以用另一幅图来表示,横坐标为各个分量的频率(不断递增的整数),纵坐标为对应振幅。即图中,侧面观看到的$S(f)$。也就是说,频域图中每个点(频率,振幅) 对应的就是一个正弦函数中的频率和振幅参数。所有正弦函数的频率和振幅参数点组成整幅频域图。
故,周期函数可以通过傅立叶级数画出频域图。
进一步欣赏下列图:
首先,我们一般描述向量的时候,都有对应的基,即在某组基下的坐标表示构成了向量。默认是单位基时,则不显示提到。
我们发现,给定周期函数$T$, 频域图中的横坐标频率值实际上可以确定了,即$\frac{2\pi n}{T}$。进一步,横坐标频率代表的正弦函数实际上就是傅里叶级数的基,即:$[1, cos(\frac{2\pi n}{T}), sin(\frac{2 \pi n}{T})]$,可以证明这些基相互正交。而系数$(C, a_n, b_n)$构成的向量就是傅里叶级数。因此,傅里叶级数是向量。
也就是说,频域下,某个曲线是表示成了关于正弦函数正交基下的傅里叶级数向量。而在时域下,某个曲线是表示成了关于时间的周期函数。不管时域还是频域,其实反映的都是同一个曲线,只是一个是用函数的观点,一个是用向量的观点。
首先介绍欧拉公式。我们知道,根据欧拉公式有:(参考如何通俗地解释欧拉公式 )
$$
e^{i\theta} = \cos \theta + i \sin \theta
$$
欧拉公式可以根据泰勒展开推出。通常的理解,我们可以把$e^{i\theta}$看做是单位圆的圆周运动来描述单位圆上的点,$\cos \theta + i \sin \theta$通过复平面的坐标来描述单位圆上的点,是同一个点不同的描述方式,所以有$e^{i\theta} = \cos \theta + i \sin \theta$.
接着,根据欧拉公式,重新表示$\sin(t)$
在我们的例子中,$\theta \rightarrow t$, $e^{i\theta} \rightarrow e^{i \boldsymbol{t}}$。有:
$$
e^{it} = \cos t + i \sin t
$$
随着时间流逝,t从0开始增长,$e^{it}$这个向量就会旋转起来,$2\pi$会转1周,也就是$T=2\pi$。随着圆周的运动,我们把$e^{it}$向量的虚部记录下来(也就是纵坐标),得到的就是$\sin t$;在时间轴$t$上,把$e^{i2t}$的虚部记录下来就是$\sin 2t$。以此类推。
同理,在时间轴t上,把$e^{it}$的实部记录下来,就是$\cos t$。
更一般的我们认为,我们具有两种看待$\sin (x), \cos(x)$的角度:
$$
e ^{i w t} \Leftrightarrow
\begin{cases}
sin (wt) \\
cos (wt)
\end{cases}
$$
可以用下图来形象化刻画:
这两种角度,一个可以观察到旋转的频率($w$),所以称为频域;一个可以看到流逝的时间($t$),所以称为时域。
实际上,周期越大,画出的频域图越密集,当$T \rightarrow \infty$时,傅里叶级数就为傅里叶变换,此时频域图是连续的曲线。如下图:
傅里叶级数展开公式中有正弦波,也有余弦波,画频域图也不方便,通过欧拉公式,可以修改为复数形式:
$$
f(x) = \sum_{n = -\infty}^{\infty} c_n \cdot e^{i \frac{2\pi n}{T}x}
$$
复数形式也可以理解为向量,$e^{i \frac{2\pi n}{T} x}$是基,$c_n$是该基下的坐标。不过$c_n$也是复数,不太好画频域图。
当周期$T$无穷大时,
$$
f(x) = \int_{-\infty}^{\infty} F(w) e^{i w x} dw = \sum_w F(w) e^{iwx}
$$
上面简化了一下,用$w$代表频率。这个公式也叫做逆傅里叶变换。
从数学角度,$f(x)$是函数$f$在$x$处的取值,所有基都对该处取值有贡献,即把每个$F(w)$投影到$e^{iwx}$基方向上分量累加起来,得到的就是该点处的函数值。
其中可以计算,
$$
F(w) = \frac{1}{2\pi}\int_{-\infty}^{\infty} f(x) e^{-i wx} dx
$$
$F(w)$就是傅里叶变换,得到的就是频域曲线。每个频率$w$下都有对应的振幅$F(w)$。
从数学角度,$F(w)$就是每个基下对应的坐标值,所有的$x$对该基都有贡献,即把每个$f(x)$投影到$e^{-iwx}$基方向上的分量全部累加起来,得到的就是该基方向的坐标值。
下面两者称为傅立叶变换对,可以相互转换:
$$
f(x) \Leftrightarrow F(w)
$$
正如之前说的,这是看待同一个数学对象的两种形式,一个是函数,一个是向量(频域曲线纵坐标构成的向量,基为频域曲线横坐标对应的的基函数)。
图上的傅里叶变换是通过下述联系实施的:
根据4,可以证明,Fourier basis = Laplacian eigenfunctions,即Fourier的基(和频率一一对应)是拉普拉斯算子的特征函数 (满足特征方程)。根据1,在Graph上,拉普拉斯算子为拉普拉斯矩阵。根据2,拉普拉斯矩阵的谱分解得到的特征向量(和特征值一一对应)类比特征函数。因此,传统傅里叶变换在Graph的拓展就是将正弦函数基替换换成Graph拉普拉斯矩阵的特征向量,正弦函数与频率一一对应,特征向量与特征值一一对应。而根据3,这一的替换的根源意义在于,Graph拉普拉斯矩阵的特征向量作为一组基的话,这组基是Graph上Dirichlet Energy最小的基。
因此,可以通过这一系列类比/桥接,实现在图上的傅里叶变换。
首先是标准的拉普拉斯算子定义:
$$
\Delta f = \sum_i \frac{\partial f}{\partial x^2}
$$
即,非混合二阶偏导数的和。$f$是拉普拉斯算子作用的函数,求函数各向二阶导数再求和,定义为$f$上的拉普拉斯算子。注意这个是其严谨的数学定义,所有的xxx拉普拉斯算子都是其一个特例,或是某种情况下(比如离散情况下)的一种近似。由于拉普拉斯算子和二阶偏导数密切相关,而二阶偏导数能够衡量函数的smoothness(不变化或缓慢变化时二阶导为0;突变或噪声,则数值不为0。因此容易检测出突变点)。
接着看图像上的处理。图像是一种离散数据(看做是函数的一种特殊形式),那么其拉普拉斯算子必然要进行离散化。
从一阶导数定义说起:(一阶差分近似)
$$
f^{\prime}(x) = \frac{\partial f(x)}{\partial x} \approx f(x+1) - f(x)
$$
则二阶导数近似等于其二阶差分。
$$
\begin{aligned}
f^{\prime \prime}(x) = \frac{\partial^2 f(x)}{\partial x^2} &= f^{\prime}(x)-f^{\prime}(x-1) \\
&= f(x+1) - f(x) - (f(x) - f(x-1)) \\
&= f(x+1) + f(x-1) - 2f(x) \\
&= [f(x+1) - f(x)] + [f(x-1) - f(x)]
\end{aligned}
$$
某个二阶导数等于其在所有自由度上微扰之后获得的增益。一维函数其自由度可以理解为2,分别是+1方向和-1方向,增益分别为:$f(x+1) - f(x)$ 和 $f(x-1) - f(x)$。总增益为所有方向增益的和。
同理对于图像而言,
$$
\begin{aligned}
(\Delta f)_{x,y} &= \frac{\partial f(x,y)}{\partial x^2} + \frac{\partial f(x,y)}{\partial y^2} \\
&\approx f(x+1,y) + f(x-1,y) - 2f(x,y) + f(x, y+1)+f(x,y-1)-2f(x,y) \\
& = f(x+1,y) + f(x-1,y) + f(x, y+1)+f(x,y-1)-4f(x,y) \\
&= [f(x+1,y) - f(x,y)]+[f(x-1,y) - f(x,y)]+[f(x,y+1) - f(x,y)]+[f(x,y-1) - f(x,y)]
\end{aligned}
$$
上下左右共4个自由度$(1, 0), (-1,0), (0, 1), (0, -1)$(当然还可以任意的定义自由度,比如对角线也算的话,就是8个自由度。在卷积时,使用的拉普拉斯模板就对应着1种方式的自由度定义)。在图像上某一点$(x,y)$,其拉普拉斯算子的值$(\Delta f)_{x,y}$,即为对其进行扰动,使其变化到相邻像素后得到的增益。
这给我们一种形象的结论:拉普拉斯算子就是在所有自由度上进行微小变化后获得的增益 (另一种说明,Informally, the Laplacian measures how different the value of f at p is from the average value of the neighbors)。
那么推广到Graph, 对于有$N$个节点的Graph, 其邻接矩阵为$W$。这个Graph的自由度为$N$。因为如果该图是一个完全图,即任意两个节点之间都有一条边,那么对一个节点进行微扰,它可能变成任意一个节点。
那么上面的函数$f$就理所当然是一个$N$维的向量,即:
$$
\boldsymbol{f} = (f_1, …, f_N)
$$
其中,$f_i$表示函数在节点$i$的值(跟节点相关的信息,如节点属性等,可以是标量或向量,最基本的向量信息就是节点编号one-hot向量,这里先用标量),类比$f(x,y)$在$(x,y)$的值。$\boldsymbol{f}$可以表示Graph (权重还没考虑)。
对于任意节点$i$,对$i$节点进行微扰,它可能变为任意一个与他相邻的节点$j \in N_i$。
前面提到,拉普拉斯算子就是在所有自由度上进行微小变化后获得的增益。对于图而言,从节点$i$变化到节点$j$增益是$f_j-f_i$。不过通常这里头写作取负数的形式(无非就是L=D-W还是W-D的问题),即$f_i-f_j$。再考虑边的权重,可以认为增益是:$w_{ij} (f_i - f_j)$。那么对于节点$i$,总的增益即为拉普拉斯算子在节点$i$的值:
$$
\begin{aligned}
(\Delta \boldsymbol{f})_i &= \sum_{j} \frac{\partial f_i}{\partial j^2} \\
& \approx \sum_{j \in N_i} w_{ij} (f_i - f_j) \\
&= \sum_{j} w_{ij} (f_i - f_j) \\
&= (\sum_{j} w_{ij}) f_i - \sum_j w_{ij} f_j \\
&=(\boldsymbol{D} \boldsymbol{f})_i - (\boldsymbol{W} \boldsymbol{f})_i \\
&= [(\boldsymbol{D} - \boldsymbol{W}) \boldsymbol{f}]_i
\end{aligned}
$$
上述$j \in N_i$去掉是因为非邻接点$w_{ij}=0$。粗体代表矩阵或向量。
对于任意的$i$, 都有上述的结论。故:
$$
\Delta \boldsymbol{f} = (\boldsymbol{D}- \boldsymbol{W}) \boldsymbol{f}
$$
这个公式全称:图拉普拉斯算子作用在由图节点信息构成的向量上$\boldsymbol{f}$得到的结果等于图拉普拉斯矩阵和向量$\boldsymbol{f}$的点积。
左式$\Delta \boldsymbol{f} $要看成一个整体(而不是乘法),即,图拉普拉斯算子作用在由图节点信息构成的向量上$\boldsymbol{f}$得到的结果。右边是矩阵乘法,即$\boldsymbol{L}=\boldsymbol{D}- \boldsymbol{W}$ 拉普拉斯矩阵和向量$\boldsymbol{f}$乘法(当节点的信息为向量时,$\boldsymbol{f}$为矩阵)。通常,$\boldsymbol{L}=\boldsymbol{D}- \boldsymbol{W}$ 图拉普拉斯矩阵也直接称作图拉普拉斯算子,即$\Delta= \boldsymbol{L}=\boldsymbol{D}-\boldsymbol{W}$,此时就可以认为,$\Delta \boldsymbol{f}$ 是乘法,只不过实际上这种写法是等式右边的式子,而不是左边的式子。
我们可以发现,图拉普拉斯算子作用在节点信息$f_i$上,并不会改变$f_i$的形状。当$f_i \in \mathbb{R}^{h}$, 则$(\Delta f)_i \in \mathbb{R}^{h}$ 。只不过上述讨论都是基于$f_i$为标量展开的。
拉普拉斯矩阵的谱分解就是特征分解。由于拉普拉斯矩阵时半正定对称矩阵的,因此拥有诸多优秀性质:
谱分解:
$$
\boldsymbol{L} \boldsymbol{\phi}_k = \lambda_k \boldsymbol{\phi_k}, k=1,2…,n
$$
由于半正定对称矩阵,故有:
$$
\boldsymbol{L} = \boldsymbol{\Phi} \boldsymbol{\Lambda} \boldsymbol{\Phi}^T
$$
$\boldsymbol{\Phi}=(\boldsymbol{\phi_1}, \boldsymbol{\phi_2},…,\boldsymbol{\phi_n}) \in \mathbb{R}^{n \times n}$ 是列向量为单位特征向量构成的正交矩阵。$\boldsymbol{\Lambda}=diag(\lambda_1,…,\lambda_n)$是由对应特征值构成对角阵。
Dirichlet Energy衡量了函数的平滑性Smoothness。Dirichlet Energy定义为:
$$
E_{Dir}(\boldsymbol{f})= \boldsymbol{f}^T \boldsymbol{\Delta} \boldsymbol{f}
$$
$\boldsymbol{f}$是函数,$\boldsymbol{\Delta}$是拉普拉斯算子。
我们的目标是寻找Graph上Dirichlet Energy最小一组单位正交基(每个基都可以看出函数)。
巧合的是,这样的正交基正好就是对拉普拉斯矩阵$\boldsymbol{L}$进行谱分解得到的特征向量${\boldsymbol{\phi_1}, …, \boldsymbol{\phi_n}}$。
因此,这也是下文从传统傅里叶变换推广到Graph上傅里叶变换时,进行类比和替换的理论解释。
回顾下传统的傅里叶变换,
$$
F(k) = \frac{1}{2\pi}\int_{-\infty}^{\infty} f(x) e^{-i kx} dx \approx \langle f,e^{-ikx} \rangle
$$
$F(k)$是傅里叶系数(即频率为$k$时的振幅值)。约等号去掉了常数系数,同时$x$为离散变量时,离散积分等于内积。
$e^{-ikx}$为Fourier Basis。可以证明$e^{-ikx}$是拉普拉斯算子的特征函数(满足特征方程$AV=\lambda V$),证明:
$$
\Delta e^{-ikx} = \frac{\partial e^{-ikx}}{\partial x^2} = - k^2 e^{-ikx} \\
$$
在Graph上作类比,$\boldsymbol{\phi}_k$是图拉普拉斯算子$\boldsymbol{L}$的特征向量(满足$\boldsymbol{L} \boldsymbol{\phi_k} = \lambda_k \boldsymbol{\phi_k}$)。即,在Graph中,$\Delta=\boldsymbol{L}, e^{-ikx}= \boldsymbol{\phi_k}$,而$k$和特征值$\lambda_k$有关。
因此,为了在Graph上进行傅里叶变换,可以把传统傅里叶变换中的$e^{-ikx}$换成$\boldsymbol{\phi_k}$。(换了种基)
传统傅里叶变换 | 图傅里叶变换 |
---|---|
频率($k$) | 特征值($\lambda_k$) |
正弦函数($e^{-ikx}$) | 特征向量($\boldsymbol{\phi}_k$) |
振幅($F(k)$) | 振幅($F(\lambda_k)$) |
则,图上的傅里叶变换写作:
$$
F(\lambda_k) =\hat{f}_k= \left< \boldsymbol{f}, \boldsymbol{\phi_k}\right>
$$
$\boldsymbol{f}=(f_1,…,f_n)$是由节点信息构成的n维向量。做个类似的解释,即特征值$\lambda_k$(频率)下,$\boldsymbol{f}$的Graph傅里叶变换(振幅)等于$\boldsymbol{f}$与$\lambda_k$对应的特征向量$\boldsymbol{\phi_k}$的内积。
推广到矩阵形式,图傅里叶变换:
$$
\hat{\boldsymbol{f}} = \boldsymbol{\Phi}^T \boldsymbol{f}
$$
其中,$\hat{\boldsymbol{f}}=(\hat{f}_1, \hat{f}_2,…, \hat{f}_n)$,即图傅里叶变换,即不同特征值(频率)下对应的振幅构成的向量。$\boldsymbol{f}=(f_1,..,f_n)$是由节点信息构成的n维向量。
类似的,传统逆傅里叶变换:(n个正弦波的叠加)
$$
\mathcal{F}^{-1}[F(k)] = f(x) = \sum_k F(k) e^{ikx} = \sum_k \underbrace{\frac{1}{2\pi}\int_{-\infty}^{\infty} f(x^{\prime}) e^{-i kx^{\prime}} dx^{\prime}}_{\text{Fourier Coefficient}} e^{ikx}
$$
迁移到Graph上的逆傅里叶变换:$e^{ikx} e^{-ikx}=1$,两个基正交,类比于$(\boldsymbol{\phi}_{k}^T \boldsymbol{\phi}_{k})_i=1$。
$$
f_i= \sum_{k=1}^n \hat{f}_k (\boldsymbol{\phi_{k}}^T )_i
$$
推广到矩阵形式,
$$
\boldsymbol{f} = \boldsymbol{\Phi} \boldsymbol{\hat{f}}
$$
个人理解,Graph傅里叶变换是为了将Graph从Spatial Domain转换到Spectural Domain,使得Graph在Spectural Domain有向量化表示,卷积更方便。这就类比于,传统傅里叶变换为了将Function从Time Domain转换到Frequency Domain,使得Function在Frequency Domain有向量化表示。
卷积定理:函数卷积的傅里叶变换是函数傅立叶变换的乘积,即对于函数$f$与$h$两者的卷积是其函数傅立叶变换乘积的逆变换。
$$
\boldsymbol{f} * \boldsymbol{h} = \mathcal{F}^{-1}[\hat{\boldsymbol{f}} \circ \hat{\boldsymbol{h}}]= \sum_k (\hat{f}(k) \cdot \hat{h}(k)) e^{ikx}
$$
类比到Graph上并把傅里叶变换的定义带入,$\boldsymbol{f}=(f_1…,f_n)$为Graph节点信息向量,$h$为卷积核,则$f$和$h$在Graph上的卷积可按下列步骤求出:
卷积核$\boldsymbol{h}$的Graph傅里叶变换为:$\hat{\boldsymbol{h}}=(\hat{h}_1,…,\hat{h}_n)$,其中,$\hat{h}_k=\langle h, \phi_k \rangle, k=1,2…,n$。实际上,$\hat{\boldsymbol{h}}=\boldsymbol{\Phi}^T \boldsymbol{h}$.
求图傅里叶变换向量$\hat{\boldsymbol{f}} \in \mathbb{R}^{N \times 1}$和$\hat{\boldsymbol{h}} \in \mathbb{R}^{N \times 1}$ 的element-wise乘积,等价于将$\hat{\boldsymbol{h}}$组织成对角矩阵的形式,即$diag[\hat{h}(\lambda_k)] \in \mathbb{R}^{N \times N}$,再求$diag[\hat{h}(\lambda_k)] $和$\hat{\boldsymbol{f}}$矩阵乘法(稍微想一下就可以知道)。
则:图上的卷积定义为:
$$
(\boldsymbol{f} * \boldsymbol{h})_\mathcal{G}=\boldsymbol{\Phi} \text{diag}[\hat{h}(\lambda_1),…,\hat{h}(\lambda_n)] \boldsymbol{\Phi}^T \boldsymbol{f} \tag{1}
$$
Deep Learning中的Convolution就是要设计含有trainable共享参数的kernel。从公式1看很直观:graph convolution的参数就是$\text{diag}[\hat{h}(\lambda_1),…,\hat{h}(\lambda_n)]$,也就是说,简单粗暴的将其变成了卷积核 $diag [\theta_1,…,\theta_n]$。这也是为什么我们前面不把卷积核$\boldsymbol{h}$的Graph傅里叶变换表示为$\hat{\boldsymbol{h}}=\boldsymbol{\Phi}^T \boldsymbol{h}$的原因,我们要把$\boldsymbol{h}$变换后的结果$\boldsymbol{\hat{h}}$直接作为参数向量$\boldsymbol{\theta} \rightarrow \boldsymbol{\hat{h}}$进行学习。
可以得到第一代的GCN,(Spectral Networks and Locally Connected Networks on Graphs):
$$
\boldsymbol{y}_{output} = \sigma(\boldsymbol{\Phi} \boldsymbol{g}_{\theta} \boldsymbol{\Phi}^T \boldsymbol{x})=\sigma(\boldsymbol{\Phi} \text{diag}[\theta_1,…,\theta_n] \boldsymbol{\Phi}^T \boldsymbol{x})
$$
$\boldsymbol{x}$就是graph上对应于每个顶点的feature构成的向量$\boldsymbol{x}=(x_1,x_2,…,x_n)$,目前仍然是每个节点信息是标量(即单通道),后续推广到向量很方便(多通道)。 $\boldsymbol{y}_{output}$是该节点卷积后的输出。所有的节点都要经过该操作,得到各自的输出。再$\sigma$激活后,传入下一层。$\boldsymbol{g}_{\boldsymbol{\theta}}=\text{diag}[\theta_1,…,\theta_n]$。相当于拿这个卷积核每个节点卷一遍。
这个问题在于,
复杂度太高,需要对拉普拉斯矩阵进行谱分解求$\boldsymbol{\Phi}$,Graph很大时复杂度较高。每次前向传播都要计算矩阵乘积,复杂度$O(n^2)$, $n$为Graph节点数。
卷积核的参数为$n$,当Graph很大时,$n$非常大。
第二代的GCN,Convolutional Neural Networks on Graphs with Fast Localized Spectral Filtering
为了解决上述问题,首先回顾一下,图傅里叶变换是关于特征值(频率)的函数$F(\lambda_1), …,F(\lambda_n)$, 即,$F(\boldsymbol{\Lambda})$,因此可以将上述卷积核$\boldsymbol{g}_{\theta}$写作$\boldsymbol{g}_{\boldsymbol{\theta}}(\boldsymbol{\Lambda})$。接着,将$\boldsymbol{g}_{\boldsymbol{\theta}}(\boldsymbol{\Lambda})$定义成如下k阶多项式形式:
$$
\boldsymbol{g}_{\boldsymbol{\theta^{\prime}}}(\boldsymbol{\Lambda}) \approx \sum_{k=0}^K \theta_k^{\prime} \boldsymbol{\Lambda}^k
$$
代入可以得到:
$$
\begin{aligned}
\boldsymbol{g}_{\boldsymbol{\theta^{\prime}}} * \boldsymbol{x} &\approx \boldsymbol{\Phi} \sum_{k=0}^K \theta_k^{\prime} \boldsymbol{\Lambda}^k \boldsymbol{\Phi}^T \boldsymbol{x} \\
&= \sum_{k=0}^K \theta_k^{\prime} (\boldsymbol{\Phi} \boldsymbol{\Lambda}^k \boldsymbol{\Phi}^T) \boldsymbol{x} \\
&= \sum_{k=0}^K \theta_k^{\prime} (\boldsymbol{\Phi} \boldsymbol{\Lambda}\boldsymbol{\Phi}^T)^k \boldsymbol{x} \\
& = \sum_{k=0}^K \theta_k^{\prime} \boldsymbol{L}^k \boldsymbol{x}
\end{aligned}
$$
上述推导第三步应用了特征分解的性质。
上式为第二代的GCN。不需要做特征分解了,直接对拉普拉斯矩阵进行变换。可以事先把$\boldsymbol{L}^{k}$计算出来,这样前向传播的时候,就只需要计算矩阵和相邻的乘法。复杂度为$O(Kn^2)$。如果使用稀疏矩阵($L$比较稀疏)算法,复杂度为$O(k|E|)$.
那么上式是如何体现localization呢?我们知道,矩阵的$k$次方可以用于求连通性,即1个节点经过$k$步能否到达另一个顶点,矩阵$k$次方结果中对应元素非0的话可达,为0不可达。因此$L$矩阵的$k$次方的含义就是代表$\text{k-hop}$之内的节点。进一步,根据拉普拉斯算子的性质。可以证明,如果两个节点的最短路径大于$K$的话,那么$L^{K}$在相应位置的元素值为0。因此,实际上只利用到了节点的K-Localized信息。
另外,作者提到,可以引入切比雪夫展开式来近似$\boldsymbol{L}^k$,因为任何k次多项式都可以使用切比雪夫展开式来近似。(类比泰勒展开式对函数进行近似)。
引入切比雪夫多项式(Chebyshev polynomial) $T_k(x)$的$K$阶截断获得对$\boldsymbol{L}^k$的近似,进而获得对$\boldsymbol{g}_{\theta}(\boldsymbol{\Lambda})$的近似,来降低时间复杂度。
$$
\boldsymbol{g}_{\boldsymbol{\theta^{\prime}}}(\boldsymbol{\Lambda}) \approx \sum_{k=0}^K \theta_k^{\prime} T_k(\tilde{\boldsymbol{\Lambda}})
$$
其中,$\tilde{\boldsymbol{\Lambda}}=\frac{2}{\lambda_{max}}\boldsymbol{\Lambda}-\boldsymbol{I}_n$为经图拉普拉斯矩阵$L$的最大特征值(即谱半径)缩放后的特征向量矩阵(防止连乘爆炸)。$\boldsymbol{\theta}^{\prime} \in \mathbb{R}^{K}$表示一个切比雪夫向量,$\theta_k^{\prime}$是第$k$维分量。切比雪夫多项式$T_k(x)$使用递归的方式进行定义:$T_k(x)=2xT_{k-1}(x)-T_{k-2}(x)$,其中$T_0(x)=1,T_1(x)=x$。
此时,可以使用近似的$\boldsymbol{g}_{\boldsymbol{\theta^{\prime}}}$替换原来的$\boldsymbol{g}_{\theta}$,可以得到:
$$
\begin{aligned}
\boldsymbol{g}_{\boldsymbol{\theta^{\prime}}} * \boldsymbol{x} &\approx \boldsymbol{\Phi} \sum_{k=0}^K \theta_k^{\prime} T_k(\tilde{\boldsymbol{\Lambda}}) \boldsymbol{\Phi}^T \boldsymbol{x} \
&\approx \sum_{k=0}^K \theta_k^{\prime} (\boldsymbol{\Phi} T_k(\tilde{\boldsymbol{\Lambda}}) \boldsymbol{\Phi}^T) \boldsymbol{x} \\
&=\sum_{k=0}^K \theta_k^{\prime} T_k(\tilde{\boldsymbol{L}}) \boldsymbol{x}
\end{aligned}
$$
其中,$\tilde{\boldsymbol{L}}=\frac{2}{\lambda_{max}} \boldsymbol{L}- \boldsymbol{I}_n$。
因此有,
$$
\boldsymbol{y}_{output} = \sigma(\sum_{k=0}^K \theta_k^{\prime} T_k(\tilde{\boldsymbol{L}}) \boldsymbol{x})
$$
参数向量$\boldsymbol{\theta}^{\prime} \in \mathbb{R}^{k}$,需要通过反向传播学习。时间复杂度也是$O(K|E|)$。
第三代的GCN对上式进一步简化,Semi-Supervised Classification with Graph Convolutional Networks
取$K=1$,此时模型是1阶的first-order proximity。即每层卷积层只考虑了直接邻域,类似CNN中3*3的卷积核。
深度加深,宽度减小。即,若要建立多阶 proximity,只需要使用多个卷积层。
并加了参数的一些约束,如: $\lambda_{max}\approx2$,引入renormalization trick,大大简化了模型。
具体推导,首先$K=1,\lambda_{max}=2$代入,
$$
\begin{aligned}
\boldsymbol{g}_{\boldsymbol{\theta^{\prime}}} * \boldsymbol{x} &\approx \theta_0^{\prime} \boldsymbol{x} + \theta_1^{\prime}(\boldsymbol{L}- \boldsymbol{I}_n) \boldsymbol{x} \\
&= \theta_0^{\prime} \boldsymbol{x} - \theta_1^{\prime}(\boldsymbol{D}^{-1/2} \boldsymbol{W} \boldsymbol{D}^{-1/2}) \boldsymbol{x}
\end{aligned}
$$
上述推导利用了归一化拉普拉斯矩阵$\boldsymbol{L}=\boldsymbol{D}^{-1/2}(\boldsymbol{D}-\boldsymbol{W})\boldsymbol{D}^{-1/2}=\boldsymbol{I_n}-\boldsymbol{D}^{-1/2} \boldsymbol{W} \boldsymbol{D}^{-1/2}$。此时只有两个参数,即每个卷积核只有2个参数,$\boldsymbol{W}$是邻接矩阵。
进一步简化,假设$\theta_0^{\prime}=-\theta_1^{\prime}$,则此时单个通道的单个卷积核参数只有1个$\theta$:
$$
\boldsymbol{g}_{\boldsymbol{\theta^{\prime}}} * \boldsymbol{x} = \theta(\boldsymbol{I_n} + \boldsymbol{D}^{-1/2} \boldsymbol{W} \boldsymbol{D}^{-1/2}) \boldsymbol{x}
$$
$\boldsymbol{I_n} + \boldsymbol{D}^{-1/2} \boldsymbol{W} \boldsymbol{D}^{-1/2}$谱半径$[0,2]$太大,使用renormalization trick(关于这个trick,参考从 Graph Convolution Networks (GCN) 谈起,讲的非常好!),
$$
\boldsymbol{I_n} + \boldsymbol{D}^{-1/2} \boldsymbol{W} \boldsymbol{D}^{-1/2} \rightarrow \tilde{\boldsymbol{D}}^{-1/2}\tilde{\boldsymbol{W}} \tilde{\boldsymbol{D}}^{-1/2}
$$
其中,$\tilde{\boldsymbol{W}}=\boldsymbol{W}+\boldsymbol{I}_n$(相当于加了self-connection,本来$\boldsymbol{W}$对角元素为0) , $\tilde{\boldsymbol{D}}_{i,i}=\sum_{j} \boldsymbol{\tilde{W}}_{ij}$。
则:
$$
\underbrace{\boldsymbol{g}_{\boldsymbol{\theta^{\prime}}} * \boldsymbol{x}}_{\mathbb{R}^{n \times 1}} = \theta(\underbrace{\tilde{\boldsymbol{D}}^{-1/2}\tilde{\boldsymbol{W}} \tilde{\boldsymbol{D}}^{-1/2}}_{\mathbb{R}^{n \times n}}) \underbrace{\boldsymbol{x}}_{\mathbb{R}^{n \times 1}}
$$
推广到多通道(单个节点的信息是向量,对比图像上3个通道RGB的值构成3维向量)和多卷积核(每个卷积核只有1个参数),即,
$$
\boldsymbol{x} \in \mathbb{R}^{N \times 1} \rightarrow \boldsymbol{X} \in \mathbb{R}^{N \times C}
$$
其中,$N$是节点的数量,$C$是通道数,或者称作表示节点的信息维度数。 $\boldsymbol{X}$是节点的feature矩阵。
相应的卷积核参数变化:
$$
\theta \in \mathbb{R} \rightarrow \boldsymbol{\Theta} \in \mathbb{R}^{C \times F}
$$
其中,$F$为卷积核数量。
则卷积结果写作矩阵形式如下:
$$
\underbrace{\boldsymbol{Z}}_{\mathbb{R}^{N \times F}} = \underbrace{\tilde{\boldsymbol{D}}^{-1/2}\tilde{\boldsymbol{W}} \tilde{\boldsymbol{D}}^{-1/2}}_{\mathbb{R}^{N \times N}} \underbrace{\boldsymbol{X}}_{\mathbb{R}^{N \times C}} \ \ \underbrace{\boldsymbol{\Theta}}_{\mathbb{R}^{C \times F}}
$$
最终得到的卷积结果$\boldsymbol{Z} \in \mathbb{R}^{N \times F}$。即,每个节点的卷积结果的维数等于卷积核数量。
上述操作可以叠加多层,对$\boldsymbol{Z}$激活一下,然后将激活后的$Z$作为下一层的节点的feature矩阵。
第三代GCN特点总结:
如何理解 Graph Convolutional Network(GCN)? - Becca的回答 - 知乎
The Emerging Field of Signal Processing on Graphs
Spectral Networks and Locally Connected Networks on Graphs
Convolutional Neural Networks on Graphs with Fast Localized Spectral Filtering
Semi-Supervised Classification with Graph Convolutional Networks
如何理解 Graph Convolutional Network(GCN)? - superbrother的回答 - 知乎
Semi-Supervised Classification with Graph Convolutional Networks阅读笔记
]]>Attention主要应用于Seq2Seq模型,故首先简介一下Seq2Seq模型。Seq2Seq模型目标是学习一个输入序列到输出序列的映射函数。应用场景包括:机器翻译(Machine translation)、自动语音识别(Automatic speech recognition)、语音合成(Speech synthesis)和手写体生成(Handwriting generation)。
Seq2Seq模型奠基性的两个工作如下:
NIPS2014:Sequence to Sequence Learning with Neural Networks
该论文介绍了一种基于RNN(LSTM)的Seq2Seq模型,基于一个Encoder和一个Decoder来构建基于神经网络的End-to-End的机器翻译模型,其中,Encoder把输入编码成一个固定长度的上下文向量,Decoder基于上下文向量和目前已解码的输出,逐步得到完整的目标输出。这是一个经典的Seq2Seq的模型,但是却存在两个明显的问题:
注意上图中Encoder得到的上下文向量仅用于作为Decoder的第一个时间步的输入。
Decoder的另一个输入是前一时刻的单词$\boldsymbol{y}_{t-1}$,需要注意的是,在训练阶段$\boldsymbol{y}_{t-1}$是真实label(需要embedding一下),而不是上一时刻的预测值。而在测试阶段,则是上一时刻的预测值(具体使用时需要借助beam-search来得到最优翻译序列)。
但是实际训练过程中,label是否使用真实数据2种方式,可以交替进行,即一种是把标准答案作为Decoder的输入,还有一种是把Decoder上一次的输出的结果作为输入,因为如果完全使用标准答案,会导致收敛的过快,导致测试的时候不稳定。
另外,上述输入输出中的每个单词,都要借助embedding技术。
EMNLP2014:Learning Phrase Representations using RNN Encoder–Decoder for Statistical Machine Translation
和NIPS2014几乎同时发表,思想也是一样的。只不过在这篇文章中,作者提出了一种新的RNN Cell,即GRU代替LSTM来构建Seq2Seq模型。
还有一点不同的是,Encoder得到的上下文向量会作用于Decoder每一个时间步的预测。
总结起来:RNN-based Encoder-Decoder Framework,目标是预测$P(\boldsymbol{y}_1,…,\boldsymbol{y}_{T_y}|\boldsymbol {x}_1,…,\boldsymbol{x}_{T_x})$,其中$\boldsymbol{y}_t, \boldsymbol{x}_s$都是one-hot向量。
给定输入,$x=(\boldsymbol{x}_1,…,\boldsymbol{x}_{T_x})$,将其编码为上下文向量$\boldsymbol {c}$.
$$
\boldsymbol{h}_t = f(\boldsymbol{W}\boldsymbol{x}_t, \boldsymbol{h}_{t-1})
$$
$f$是LSTM或GRU,$\boldsymbol{x}_t$是时间步$t$的单词的one-hot表示,先经过embedding矩阵$\boldsymbol{W}$嵌入后作为RNN在$t$时刻的输入,$\boldsymbol{h}_{t-1}$是$t-1$时间步的encode;$\boldsymbol{h}_t$是时间步$t$的encode。
$$
\boldsymbol{c} = q(\{\boldsymbol{h}_1, …, \boldsymbol{h}_{T_x}\})
$$
$c$是上下文向量,是关于$\{\boldsymbol{h}_1, …, \boldsymbol{h}_{T_x}\}$的函数。$T_x$是输入的最大长度。最简单的,$q(\{\boldsymbol{h}_1, …, \boldsymbol{h}_{T_x}\})=\boldsymbol{h}_T$,即最后一个时间步得到的encode作为上下文向量。
Decoder在给定上下文向量$\boldsymbol{c}$以及已经预测的输出$\{\boldsymbol{y}_1,…,\boldsymbol{y}_{t^{\prime}-1}\}$条件下,预测下一个输出$\boldsymbol{y}_{t^{\prime}}$。换句话说,Decoder将输出$\boldsymbol{y}$上的联合分布分解为有序条件分布 (ordered conditionals):
$$
p(\boldsymbol{y})=\prod_{t=1}^{T_{y}} p(\boldsymbol{y}_t|\{\boldsymbol{y}_1,…,\boldsymbol{y}_{t-1}\}, \boldsymbol{c})
$$
其中,$\boldsymbol{y}=\{\boldsymbol{y}_1,…,\boldsymbol{y}_{T_y}\}$,$T_y$是输出的最大长度。
使用RNN,每个条件分布可以写成下式:
$$
p(\boldsymbol{y}_t|\{\boldsymbol{y}_1,…,\boldsymbol{y}_{t-1}\}, \boldsymbol{c})=g(\boldsymbol{E}\boldsymbol{y}_{t-1},\boldsymbol{s}_t,\boldsymbol{c})
$$
$\boldsymbol{y}_t$是输出词的one-hot向量(全连接+softmax激活后得到),$\boldsymbol{y}_{t-1}$是前一时刻已经预测的输出词的one-hot向量,先经过$\boldsymbol{E}y_{t-1}$embedding后再作为$g$的输入。$g$是一个非线性函数(e.g., 全连接+softmax),输出关于$\boldsymbol{y}_t$的概率分布。$\boldsymbol{s}_t$($\boldsymbol{s}_t=f(\boldsymbol{E} \boldsymbol{y}_{t-1}, \boldsymbol{s}_{t-1},\boldsymbol{c})$,$f$是LSTM/GRU)是RNN的隐藏层状态。(注意,$g$不是RNN提取隐藏层状态的LSTM或GRU,而是隐藏层后面接的全连接层或其他非线性函数,LSTM或GRU提取的Decoder隐状态和上下文向量以及已经预测的输出都将作为$g$的输入,用于预测概率分布)。
如上文所述,传统的Seq2Seq模型对输入序列缺乏区分度,存在明显的两大问题。因此,有大牛提出使用Attention机制来解决问题。下面将按照Attention的不同类型重点介绍一些Attention上的研究工作。
本小节介绍最传统和基础的Attention模型的应用。首先直观感受下Attention机制的一个示意动图。
ICLR2015: Neural Machine Translation by Jointly Learning to Align and Translate
这是ICLR2015提出的文章,机器翻译的典型方法。作者在RNN Encoder-Decoder框架上,引入了Attention机制来同时进行翻译和对齐。使用bidirectional RNN作为Encoder,Decoder会在翻译的过程中通过模拟搜索源句子focus到不同部位上来进行更准确的解码。模型示意图如下:
首先将Decoder中的条件概率写成下式:
$$
p(\boldsymbol{y}_t|\{\boldsymbol{y}_1,…,\boldsymbol{y}_{t-1}\}, \boldsymbol{x})=g(\boldsymbol{E}\boldsymbol{y}_{t-1},\boldsymbol{s}_t,\boldsymbol{c}_t)
$$
其中,$g$一般使用softmax全连接层(或多加几层,输入的3个向量concat到一起后进行Feed Forward),$\boldsymbol{s}_i$是Decoder中RNN在时间步$t$的隐状态,根据如下LSTM或GRU函数计算得到:
$$
\boldsymbol{s}_t=f(\boldsymbol{s}_{t-1},\boldsymbol{E} \boldsymbol{y}_{t-1}, \boldsymbol{c}_t)
$$
$\boldsymbol{s}_{t}$是关于前一时刻Decoder端隐状态$\boldsymbol{s}_{t-1}$,前一时刻已经预测的输出$\boldsymbol{y}_{t-1}$的embedding表示$\boldsymbol{E} \boldsymbol{y}_{t-1}$以及该时刻$t$的上下文向量$\boldsymbol{c}_t$的函数。$f$是LSTM或GRU。
注意,和已有的encoder-decoder不同,这里的条件概率对每一个目标单词$t$都需要有一个不同的上下文向量$\boldsymbol{c}_t$。
而上下文向量$\boldsymbol{c}_t$取决于Encoder端输入序列encode后的RNN隐状态$\boldsymbol{h}_s$(bidirectional RNN,因此$\boldsymbol{h}_s$包含了输入句子$s$位置周围的信息,有,$\boldsymbol{h}_s=[\overleftarrow{\boldsymbol{h}}_s^T; \overrightarrow{\boldsymbol{h}}_s^T]$)
$$
\boldsymbol{c}_t = \sum_{s=1}^{T_x} \alpha_{ts} \boldsymbol{h}_s
$$
而每一个权重$\alpha_{ts}$使用softmax转换为概率分布:
$$
\alpha_{ts} = \frac{\exp(e_{ts})}{\sum_{k=1}^{T_x} (e_{tk})}
$$
而$e_{ts}$是输出$t$和输入$s$的对齐模型(alignment model),衡量了输入位置$s$周围的信息和输出位置$t$的匹配程度。
$$
e_{ts}=a(\boldsymbol{s}_{t-1}, \boldsymbol{h}_s)
$$
$e_{ts}$得分依赖于Decoder端$t$时刻的前一时刻的隐状态$s_{t-1}$和Encoder端$s$时刻的隐状态。文中使用前馈神经网络学习对齐模型,并且和其他组件联合学习,$a$实际上学到的是soft alignment,因此可以很容易应用梯度反向传播。
总之,$\alpha_{ts}$可以理解为衡量了输出单词$t$和输入单词$s$的对齐程度,而$\boldsymbol{c}_t$是$t$时刻,所有encode隐状态根据该对齐程度得到的期望上下文向量,是所有对齐情况下的期望。$\alpha_{ts}$衡量了在计算下一个decoder隐状态$s_t$和预测$y_t$过程中,相对于前一个decoder隐状态$\boldsymbol{s}_{t-1}$,不同$\boldsymbol{h}_s$的重要性程度。这一Decoder中的注意力机制使得只需要关注源句子部分的信息,而不是像此前工作中非要将源句子所有的信息都编码成固定长度的上下文向量来用。
ICML2015: Show, Attend and Tell- Neural Image Caption Generation with Visual Attention
Kelvin Xu等人在该论文中将Attention引入到Image Caption中。Image Caption是一种场景理解的问题,这是视觉领域重要的一个研究方向。场景理解的难点在于既要进行物体识别,又要理解物体之间的关系。这相当于要让机器拥有模仿人类将大量显著的视觉信息压缩为描述性语言的能力。
模型包括两个部分:Encoder和Decoder。其中,Encoder会使用CNN提取图片低层特征;Decoder会在RNN中引入注意力机制,将图片特征解码为自然语言语句。模型总的示意图如下:
如上图,模型把图片经过CNN网络,变成特征图。 LSTM的RNN结构在此上运行Attention模型,最后得到描述。
目标:输入一个图像,输出该图像的描述$y=\{\boldsymbol{y}_1,…,\boldsymbol{y}_C \}, y_i \in \mathbb{R}^K$,其中$K$是词典词汇的数量,$\boldsymbol{y}_i$是词的one-hot表示向量,$C$是描述的长度。
Encoder:
在encoder端,模型使用CNN来提取L个D维vector,每一个都对应图像的一个区域(这里粗体表示向量):
$$
a = \{ \boldsymbol{a}_1, \dots, \boldsymbol{a}_L \}, a_i \in \mathbb{R}^D
$$
在原论文中,原始图像先经过center cropped变为$224\times224$的图像,然后经过卷积和pooling操作,共4次max pooling,最后得到$14 \times 14$的feature map,feature map个数共512个,即512个通道。这里$L=14 \times 14=196$对应的就是196个区域数量,每个区域都是原始图像经过下采样得到的,因此可以通过4次上采样能够恢复原始图像中对应区域。而$D=512$,即每个区域的向量化表示是由所有的feature map相应位置数值构造而成。
与此前的工作使用Softmax层之前的那一层vector作为图像特征不同,本文所提取的这些vector来自于 low-level 的卷积层,这使得Decoder可以通过从所有提取到的特征集中,选择一个子集来聚焦于图像的某些部分。这样子就有点像NLP里的seq2seq任务了,这里的输入从词序列转变成了图像区域vector的序列。作为类比,图像上的$L$个区域($14 \times 14$平展开为196)就相当于句子的长度(单词的数量$T_x$);每个区域的D维向量化表示是由D个Filter提取的该区域的特征concat在一起形成的向量,类比于句子每个单词的embedding经过RNN提取的隐状态向量。
上下文向量$\hat{\boldsymbol{z}}_t$计算如下:
$$
\hat{\boldsymbol{z}}_t = \phi(\{\boldsymbol{a}_i\},\{\alpha_i\})
$$
即,在给定一组提取到的图像不同区域的向量表示$\{\boldsymbol {a_i}\}$,以及不同区域相应的权重$\{\alpha_i\}$条件下,计算上下文向量,最简单的方式是使用上文所述的加权和来处理。本文使用了两种Attention Mechanisms,即Soft Attention和Hard Attention。我们之前所描述的传统的Attention Mechanism就是Soft Attention。Soft Attention是参数化的(Parameterization),因此可导,可以被嵌入到模型中去,直接训练,梯度可以经过Attention Mechanism模块,反向传播到模型其他部分。相反,Hard Attention是一个随机的过程,根据$\{\alpha_i\}$随机采样。Hard Attention不会选择整个encoder的输出做为其输入,Hard Attention会依概率来采样输入端的隐状态一部分来进行计算,而不是整个encoder的隐状态。为了实现梯度的反向传播,需要采用蒙特卡洛采样的方法来估计模块的梯度。
而权重$\alpha_i$的计算,作者引入了一个Attention模型,实际上就是上篇文章MT任务中的对齐模型。
$$
e_{ti}=f_{att}(\boldsymbol{a}_i, \boldsymbol{h}_{t-1})
$$
$t$是当前要预测的输出词的位置,$i$是输入词的位置。
$$
\alpha_{ti}=\frac{exp(e_{ti})}{\sum_{k=1}^{L} (e_{tk})}
$$
Decoder:
使用LSTM来解码并生成描述词序列,LSTM结构单元如下:
具体LSTM的计算:(可以发现如何将$\hat{z}_t$融入到LSTM中的,实际上就是多一个线性变换,再全部加起来)
$$
\begin{pmatrix}
\mathbf{i}_t \\
\mathbf{f}_t \\
\mathbf{o}_t \\
\mathbf{g}_t \\
\end{pmatrix}
=
\begin{pmatrix}
\sigma \\
\sigma \\
\sigma \\
\tanh \\
\end{pmatrix}
\mathbf{T}_{D+m+n, n}
\begin{pmatrix}
\mathbf{E} \mathbf{y}_{t-1} \\
\mathbf{h}_{t-1} \\
\hat{\mathbf{z}}_t \\
\end{pmatrix}
$$
$$
\mathbf{c}_t = \mathbf{f}_t \odot \mathbf{c}_{t-1} + \mathbf{i}_t \odot \mathbf{g}_t
$$
$$
\mathbf{h}_t = \mathbf{o}_t \odot \tanh(\mathbf{c}_t)
$$
第一个式子实际上是四个式子,分别得到输入门、遗忘门、输出门和被输入门控制的候选向量。其中,三个门控由sigmoid激活,得到的是元素值皆在 0 到 1 之间的向量,可以将门控的值视作保留概率;候选向量由tanh激活,得到的是元素值皆在-1到1之间的向量。$\boldsymbol{T}_{s,t}: \mathbb{R}^s \rightarrow \mathbb{R}^t$是仿射变换,在上式也就是要对最右边的三项进行加权求和,可以将T理解为分块矩阵。最右边的三个式子,其中$\boldsymbol{E} \in \mathbb{R}^{m\times K}$是输出词的embedding matrix,$\boldsymbol{y}_{t-1}$是one-hot词表示,$\boldsymbol{E}\boldsymbol{y}_{t-1}$用来lookup,得到dense词向量表示。$\boldsymbol{h}_{t-1} \in \mathbb{R}^n$是前一时刻的decoder状态,$\boldsymbol{\hat{z}}_t \in \mathbb{R}^D$是LSTM真正意义上的“输入”,代表的是捕捉了特定区域视觉信息的上下文向量,既然它和时刻$t$有关,就说明它是一个动态变化的量,在不同的时刻将会捕捉到与本时刻相对应的相关图像区域。这个量将由attention机制计算。
第二个式子是更新旧的记忆单元,element-wise 的运算表示三个门控将对各自控制的向量的每个元素做“取舍”:0 到 1 分别代表完全抛弃到完全保留。第三个式子是得到隐状态。
有了隐状态,就可以计算词表中各个词的概率值,那么取概率最大的那个作为当前时刻生成的词,并将作为下一时刻的输入。其实就是softmax全连接层(两层MLPs+softmax)。$K$是单词的数量。
$$
p(\mathbf{y}_t \mid \mathbf{a}, \mathbf{y}_{t-1}) \propto \exp (\mathbf{L}_o (\mathbf{E} \mathbf{y}_{t-1} + \mathbf{L}_h \mathbf{h}_t + \mathbf{L}_z \hat{\mathbf{z}}_t)) \\
\mathbf{L}_o \in \mathbb{R}^{K \times m} \\
\mathbf{L}_h \in \mathbb{R}^{m \times n} \\
\mathbf{L}_z \in \mathbb{R}^{m \times D}
$$
原论文中还有一些比较有意思的Trick。
解码的输出:
模型生成的一句caption被表示为各个词的one-hot编码所构成的集合,输出的caption y表示为:
$$
y = \{ \mathbf{y}_1, \dots, \mathbf{y}_C \}, y_i \in \mathbb{R}^K
$$
$K$是字典的单词个数,$C$是句子长度。 $\boldsymbol{y}_i$的形式为$(0,0,…,0,1,0,…,0,0)$,即只有第$i$处位置为1,其它位置为0。
RNN建模时,$\boldsymbol{y}_i$会用在embedding,将稀疏one-hot向量转成dense的embedding向量。模型的输出概率$p(\mathbf{y}_t \mid \mathbf{a}, \mathbf{y}_{t-1})$会用于拟合真实的$\boldsymbol{y}_t$。
LSTM初始输入:
LSTM中的记忆单元与隐藏单元的初始值,是两个不同的多层感知机,采用所有特征区域的平均值来进行预测的:
$$
\mathbf{c}_0 = f_{\mathbf{init,c}}({1 \over L} \sum_i^L \mathbf{a}_i) \\
\mathbf{h}_0 = f_{\mathbf{init,h}}({1 \over L} \sum_i^L \mathbf{a}_i)
$$
图像的encode:
文中使用VGGnet作为encoder进行编码,且不进行finetuning。encoder得到$14 \times 14 \times 512$的feature maps。因此decoder处理的是flattened$196 \times 512$ ($i.e. L \times D$)。
Caption的Decode:
在decode时,由于模型每次更新所需要的时间正比于最长的句子,如果随机采样句子进行解码,训练时间会很长。为了解决这个问题,文中会在预处理环节,将句子按照长度分组。每次更新时,随机采样一个长度,然后使用相应的分组内的句子进行训练,这样就能显著提高运行效率。
个人觉得输出词的embedding matrix也可以使用word2vec预训练好的词向量代替,文中没提到。
NIPS2015: Attention-Based Models for Speech Recognition
给定一个英文的语音片段作为输入,输出对应的音素序列。Attention机制被用于对输出序列的每个音素和输入语音序列中一些特定帧进行关联。
ICLR2016: Reasoning about Entailment with Neural Attention
语义蕴含,句子关系推断方面的早期工作,也是采用了基本的Attention模型。给定一个用英文描述的前提和假设作为输入,输出假设与前提是否矛盾、是否相关或者是否成立。举个例子:前提:在一个婚礼派对上拍照;假设:有人结婚了。该例子中的假设是成立的。Attention机制被用于关联假设和前提描述文本之间词与词的关系。
EMNLP2015: A Neural Attention Model for Sentence Summarization
给定一篇英文文章作为输入序列,输出一个对应的摘要序列。Attention机制被用于关联输出摘要中的每个词和输入中的一些特定词。
本部分介绍Attention机制的各种变体。包括但不限于:
NIPS2014: Recurrent Models of Visual Attention
ICLR2015: Multiple Object Recognition with Visual Attention
NIPS2014论文应该是最早的Attention雏形,虽然和我们通常所说的、广泛应用于Seq2Seq的Attention机制不太一样,但是还是值得提一下。这是Google DeepMind2014年提出的一篇计算机视觉领域的文章,适用于处理图像序列或帧序列来进行场景感知或处理(例如Video Caption)。其动机在于随着分辨率提高,计算量不断增长,神经网络难以在实时应用场景中,快速处理这么大的计算量。借鉴人类视觉系统的特点,即,为了理解某个场景,并不是一下子处理整个场景,而是Focus到某些关键的位置上,然后联合起来构建出整个场景信息。故本篇论文利用RNN处理图像序列,并使用强化学习来训练模型,使得模型能够学习attention决策。即,针对实时的场景,基于过去的信息和任务的需要选择下一个要focus的感知区域。这个和人类的感知方式比较相似,也是我们最早理解的Attention机制。
但是,上文所述的广泛应用于Seq2Seq中的Attention不大一样。人类的注意力机制实际上是可以节省计算资源的,注意只需要集中到某些区域,可以忽略大部分区域。Recurrent Models of Visual Attention中的做法和这个是一样的。然而,下文即将要介绍的应用于Seq2Seq模型模型的Attention就不是这样的了。实际上,下文所述Attention模型,需要把每一个部分都观察的仔仔细细(每部分权重都要算一下),才能进一步决策到底需要focus到哪些部分,这和人类的视觉系统不相符,更像是memory,而不是attention(实际上attention可以理解为一种短期记忆,即根据短期记忆在输入特征上分配attention;memory也是另外一种非常重要的机制),然而,这并不妨碍注意力机制的有效性。
EMNLP2015: Effective Approaches to Attention-based Neural Machine Translation
以往的文章,主要将attention应用于不同场景中,而这篇文章提出了新的attention架构,引入了Global Attention和Local Attention的概念。Global Attention和上文的Soft Attention几乎一样,即计算上下文向量时,和所有的encoder隐状态向量求alignment;而Local Attention是Soft Attention和Hard Attention的权衡,既拥有Soft Attention可微分,容易使用反向传播来优化的优点,又拥有Hard Attention复杂度低的优点,除此之外,还不需要强化学习方法进行训练。
首先定义,Encoder得到的源语句单词$s$的隐状态为:$\boldsymbol{\bar{h}}_s$;Decoder中目标语句单词$t$的隐状态为:$\boldsymbol{h}_t$;对每一个目标单词$t$,使用Attention机制计算的上下文向量为$\boldsymbol{c}_t$;Attention机制中的对齐模型为$\boldsymbol{a}_t=f(\{\boldsymbol{\bar{h}_s}\}, \boldsymbol{h_t})$(前面文章中都是使用$\boldsymbol{h}_{t-1}$, 即前一个时间步的Decoder隐状态和Encoder隐状态来计算对齐权重)。
首先是Global Attention,如下图所示:
Global Attention中上下文向量$\boldsymbol{c}_t$的计算路径为:$\boldsymbol{h}_t \rightarrow \boldsymbol{a_t} \rightarrow \boldsymbol{c}_t$。
对齐模型计算:
$$
\boldsymbol{a}_t(s)=\text{align}(\boldsymbol{h}_t, \boldsymbol{\bar{h}_s})=\frac{\exp(\text{score}(\boldsymbol{h}_t, \boldsymbol{\bar{h}}_s))}{\sum_{s^{\prime}}\exp(\text{score}(\boldsymbol{h}_t, \boldsymbol{\bar{h}}_{s^{\prime}}))}
$$
$s$是源语句单词的位置。
$\text{score}$具体可以采用:
$$
\begin{equation}
\text{score}(\boldsymbol{h}_t, \boldsymbol{\bar{h}}_s) = \left\{
\begin{aligned}
\boldsymbol{h}_t^T \boldsymbol{\bar{h}}_s &, & \text{dot} \\
\boldsymbol{h_t}^T \boldsymbol{W}_{\alpha}\boldsymbol{\boldsymbol{\bar{h}}}_s &, & \text{general} \\
\boldsymbol{v_a}^T \tanh(\boldsymbol{W}_{\alpha}[\boldsymbol{h_t}; \boldsymbol{\bar{h}}_s]) &, & \text{concat}
\end{aligned}
\right.
\end{equation}
$$
上下文向量计算:
$$
\boldsymbol{c}_t = \sum_{s=1}^{S} a_{ts} \boldsymbol{\bar{h}}_s
$$
注意图中,框起来的部分作者称为Attention Layer。
接着是Local Attention,如下图所示:
Local Attention的引入是为了解决Global Attention中Attend到源语句中所有的词,一方面复杂度高,另一方面很难翻译长序列语句。Local Attention首先根据目标词的隐状态$\boldsymbol{h}_t$计算源语句中的对齐位置(中心)$p_t$,然后使用以该位置为中心的窗口$[p_t-D, p_t+D]$内的源语句单词$\boldsymbol{\bar{h}_s}$,来计算Attention的权重,计算时使用以$p_t$为中心的高斯核函数进行衰减。具体如下:
计算上下文向量时,同上文,即对窗口内的encoder隐向量进行加权,即$\boldsymbol{c}_t = \sum_{s=1}^{S} a_{ts} \boldsymbol{\bar{h}}_s$。
计算得到上下文向量后,本文直接将$\boldsymbol{c}_t$和$\boldsymbol{h}_t$ concat在一起,并计算经过attention后的隐状态$\boldsymbol{\tilde{h}}_t$:
$$
\boldsymbol{\tilde{h}}_t = \tanh(\boldsymbol{W}_c[\boldsymbol{c}_t, \boldsymbol{h}_t])
$$
再将上述attention后的隐状态输入到一个softmax全连接层,得到预测目标值:
$$
p(y_t |y_{<t}, x) = \text{softmax}(\boldsymbol{W}_s \boldsymbol{\tilde{h}}_t)
$$
按照上述方式来看,每个目标输出单词的预测值,没有利用已经预测的输出单词(embedding)作为输入,也没有利用目标词位置前一时刻的decoder隐状态$\boldsymbol{h}_{t-1}$;只利用了当前时刻Decoder隐状态$\boldsymbol{h}_t$(上下文向量计算中的权重也主要依据这个计算的)。也就是说,每个目标词位置的attention决策是独立的(只和$h_t$本身相关)。
然而在机器翻译当中,通常要维护一个覆盖集,即源语句中哪些单词被翻译过了;同理,在神经机器翻译中,我们在翻译一个目标词时,同样需要关注哪些源语句单词已经被翻译了。因此,作者提出了一个Input-feeding approach,把Decoder端前一时刻attention后的隐状态和前一时刻预测的输出单词的embedding连接起来,作为下一时刻的输入。(这个和传统Attention的几乎没差别)
本文的贡献主要是Local Attention以及提出的各种各样的Alignment函数,其余都和前面的工作大同小异。现总结下Alignment函数如下图所示:
AAAI2018:DiSAN: Directional Self-Attention Network for RNN/CNN-Free Language Understanding
在Baisc Attention中,对于每个查询,每个key对应的value都有一个权重值,即每个查询会对应一个1-D的Attention weight向量。而Multi-dimensional Attention会产生更高维度的Attention矩阵,旨在捕获不同特征空间中的Attention特征。
实际上主要区别在于,之前每个value向量对应一个权重Alignment Score,加权的时候实际上是利用了广播机制,value每个元素feature都乘上该权重;现在修改为在feature-level,每个元素特征都乘上不同的权重系数,因此Alignment Score是和Value同维度数的向量,即右图中的$\boldsymbol{z}_i$。做法很简单,使用MLP对齐的时候,MLP输出层神经元数量等于Value维度数即可,例如这篇文章中使用$f(x_i, q) = \boldsymbol{W}^T \sigma(\boldsymbol{W}^{(1)}\boldsymbol{x}_i + \boldsymbol{W}^{(2)} \boldsymbol{q} + \boldsymbol{b}^{(1)})+\boldsymbol{b}$
其他方式如下:($f(\boldsymbol{u}, \boldsymbol{v})$)
NAACL-HLT2016:Multi-Source Neural Translation
这是2016发表在NAACL-HLT的一篇文章。文章使用英语,德语,法语三种语言建立了一种多源(三语言)机器翻译模型。Intuition在于,如果一篇文章被翻译成了另一种语言,那么就更加倾向于被翻译成其他语言。这样的观点对机器翻译任务有一定的启发,将原本的单一源语言替换为多种源语言,应该可以取得更好的效果。如英语中的“bank”一词原本可以翻译为河岸或是银行,如果源语言中有德语词汇“Flussufer”(河岸)作为帮助,则自然可以精确得到法语中“Berge”(河岸)这样的翻译结果。基于这样的思想,作者在原有的seq2seq+attention模型的基础上做了修改,引入更多源语句,建立一种多源的翻译模型。模型结构如下:
左侧是两种不同语言的源语句,每种语言的源语句都有一个自己的encoder,且结构一样。问题的关键在于如何将两种语言encoder的东西combine在一起,并和decoder的表示进行对齐求attention。由于作者采用了LSTM,因此同时考虑了hidden state和cell state的combination。核心工作就是图中黑色部分的combiners。combiners的输入是两个源语句最后时刻encoder得到的hidden state $\boldsymbol{h}_1, \boldsymbol{h}_2$和cell state $\boldsymbol{c}_1, \boldsymbol{c}_2$,输出是单个hidden state $\boldsymbol{h}$和单个cell state $\boldsymbol{c}$。 (以往的工作似乎没有把encoder的cell state给decoder,从图中还可以看出,两个encoder中,每一层得到的两个源语句的hidden state和cell state都需要经过combiners)
最基本的combiner:对于hideen state,就是把两个encoder的隐状态concat起来,再做一个线性变换+tanh激活:$\boldsymbol{h} = tanh(\boldsymbol{W}_c [\boldsymbol{h}_1 ; \boldsymbol{h}_2 ])$。对于cell state,直接相加: $\boldsymbol{c}=\boldsymbol{c}_1+\boldsymbol{c}_2$。
LSTM variant combiner:
$$
\begin{aligned}
\boldsymbol{i} &= \text{sigmoid}(\boldsymbol{W}_1^{i} \boldsymbol{h}_1 + \boldsymbol{W}^{i}_2 \boldsymbol{h}_2) \\
\boldsymbol{f}_j &= \text{sigmoid}(\boldsymbol{W}_j^f \boldsymbol{h}_j), j=1,2 \\
\boldsymbol{o} &= \text{sigmoid}(\boldsymbol{W}_1^{o} \boldsymbol{h}_1 + \boldsymbol{W}^{o}_2 \boldsymbol{h}_2)\\
\boldsymbol{u} &= \text{tanh}(\boldsymbol{W}_1^{u}\boldsymbol{h}_1 + \boldsymbol{W}_2^{u}\boldsymbol{h}_2) \\
\boldsymbol{c} &= \boldsymbol{i} \odot \boldsymbol{u} + \boldsymbol{f}_1 \odot \boldsymbol{c}_1 + \boldsymbol{f}_2 \odot \boldsymbol{c}_2 \\
\boldsymbol{h} &= \boldsymbol{o} \odot \tanh(\boldsymbol{c})
\end{aligned}
$$
唯一要提的就是,$\boldsymbol{h}_1,\boldsymbol{h}_2$作为输入,每个encoder得到的cell state各自对应一个自己的遗忘门。
到目前为止,都不涉及到attention。上文得到的$\boldsymbol{c}$和$\boldsymbol{h}$只是作为decoder的初始输入(前一时刻的输入,以前的Seq2Seq模型,似乎cell state没有传给decoder)。
至于attention,作者做了很小的改动。采用的是EMNLP2015: Effective Approaches to Attention-based Neural Machine Translation中的Local Attention。在这个基础上,让decoder的隐状态同时和两个encoder得到的隐状态进行对齐,并各自计算得到一个上下文向量,$\boldsymbol{c}_t^1, \boldsymbol{c}_t^2$,注意这个c是上下文向量,跟上文所述cell state无关。最后计算Decoder的Attentional Hidden State时,使用$\boldsymbol{\tilde{h}}_t = \tanh(\boldsymbol{W}_c[\boldsymbol{h}_t,\boldsymbol{c}_t^1,\boldsymbol{c}_t^2])$。也就是之前只使用1个上下文向量,这里面使用两个上下文向量。
下面是实验的一个case:
NAACL-HLT2016:Hierarchical Attention Networks for Document Classification
文本分类是一项基础的NLP任务,在主题分类,情感分析,垃圾邮件检测等应用上有广泛地应用。其目标是给每篇文本分配一个类别标签。本文中模型的直觉是,不同的词和句子对文本信息的表达有不同的影响,词和句子的重要性是严重依赖于上下文的,即使是相同的词和句子,在不同的上下文中重要性也不一样。就像人在阅读一篇文本时,对文本不同的内容是有着不同的注意度的。而本文在attention机制的基础上,联想到文本是一个层次化的结构,提出用词向量来表示句子向量,再由句子向量表示文档向量,并且在词层次和句子层次分别引入attention操作的模型。
模型结构如上图所示,词先经过Bidirectional RNN(GRU)提取到word annotation,然后经过1个MLP得到word annotation对应的隐表示(这一步在Basic Attention中没有),然后使用该隐表示和全局的word-level上下文隐向量$\boldsymbol{u}_w$进行对齐,计算相似性,得到softmax后的attention权重,最后对句子内的词的word annotation根据attention权重加权,得到每个句子的向量表示。接着,将得到的句子表示同样经过Bidirectional RNN(GRU)提取sentence annotation,再经过MLP得到对应的隐表示,接着将其和全局的sentence-level上下文隐向量$\boldsymbol{u}_s$进行对齐计算,得到句子的attention权重,最后加权sentence annotation得到文档级别的向量表示。得到文档表示后再接一个softmax全连接层用于分类。
这里最有趣的一点是,全局的word-level上下文隐向量$\boldsymbol{u}_w$和全局的的sentence-level上下文隐向量$\boldsymbol{u}_s$,是随机初始化的,且也是通过模型进行学习的。这二者就像专家一样,是高级咨询顾问。为了得到句子的向量表示,我们询问$\boldsymbol{u}_w $哪些词含有比较重要的信息?为了得到文档的向量表示,我们询问$\boldsymbol{u}_s$哪些句子含有比较重要的信息?
ACL2017:Attention-over-Attention Neural Networks for Reading Comprehension
比较巧妙,但很容易理解,直接上图:
两个输入,一个Document和一个Query,分别用一个双向的RNN进行特征抽取,得到各自的隐状态$\boldsymbol{h}_{doc}$和$\boldsymbol{h}_{query}$。(Embedding Layer+Bi-GRU Layer)。接着要计算document和query之间每个词的相似性得分,
然后基于query和doc的隐状态进行dot product,得到doc和query的attention关联矩阵$M \in \mathbb{R}^{|D| \times |Q|}$(Document所有词和Query所有词和之间的关联矩阵,行是Document,列是Query)。然后按列(column)方向进行softmax操作,得到query-to-document的attention值$\alpha(t)$,表示t时刻的query word的document-level attention。按照行(row)方向进行softmax操作,得到document-to-query的attention值$\beta(t)$,表示t时刻的document word的query-level attention,再对$\beta(t)$按照列方向进行累加求平均得到averaged query-level attention值$\beta(t)$,(可以证明,按列对$\beta(t)$平均后仍然是概率分布),这个求平均的操作可以理解为求query-level每个词和document所有词的平均关联性。
最后再基于上一步attention操作得到$\boldsymbol{\alpha}$和$\boldsymbol{\beta}$,再进行attention操作,即attention over attention得到最终的attended attention $\boldsymbol{s}=\boldsymbol{\alpha}^T \boldsymbol{\beta} \in \mathbb{R}^{|D|}$,即Document每个词都有一个attended attention score。
预测的时候,预测词典中每个词的概率,将词w在document中出现的位置上对应的attention值进行求和。例如图中Mary出现在Document首尾,故把这两个attention score相加,作为预测的概率。
文章的亮点在于,引入document和query所有词pair-wise的关联矩阵,分别计算query每个词document-level attention(传统的方法都只利用了这个attention),和document每个词的query-level attention,对后者按列取平均得到的averaged query-level attention。进一步,二者点乘得到attended document-level attention,也即attention-over-attention。
这个和上文层次化Attention有点像。
NIPS2017:Convolutional Sequence to Sequence Learning
2017年,FaceBook Research在论文《Convolutional Sequence to Sequence Learning》提出了完全基于CNN来构建Seq2Seq模型。Motivation在于,以往的自然语言处理领域,包括 seq2seq 任务中,大多数都是通过RNN来实现。这是因为RNN的链式结构,能够很好地应用于处理序列信息。但是,RNN也存在着劣势:一个是由于RNN运行时是将序列的信息逐个处理,不能实现并行操作,导致运行速度慢;另一个是传统的RNN并不能很好地处理句子中的结构化信息,或者说更复杂的关系信息,同时对于长语句中词依赖关系的捕捉不够好。相比之下,CNN的优势就凸显出来。最重要的一点就是,CNN能够并行处理数据,计算更加高效。此外,CNN是层级结构,与循环网络建模的链结构相比,层次结构提供了一种较短的路径来捕获词之间远程的依赖关系,因此也可以更好地捕捉更复杂的关系,具体而言低层的卷积网络可以捕获邻近的词之间的关系;高层的卷积网络以低层的卷积网络的输出作为输入,可以捕获远程的词之间的关系。另外,作者在Decoder中,使用了multi-step attention,即,在 decoder 的每一个卷积层都会进行 attention 操作,并将结果输入到下一层。有点类似于人做阅读理解时,会反复去原文中寻找是否有合适的答案(且每次寻找时,理解会加深,找的更准)。当然,这种多跳机制在下文所述的End-to-End Memory Networks中实际上已经有所体现了。
直接上模型图:(英文翻译成德文,从上到下看)
Embedding Layer:word embedding+position embedding。
Convolutional Block Structure:层级的卷积块结构,通过层级叠加能够得到远距离的两个词之间的关系信息,encoder和decoder都由多层的Convolutional Block叠加而成。每层由1个Block构成,且“卷积计算+非线性计算+残差连接”看作一个Convolutional Block。卷积计算时,以单词$i$为中心的窗口$[i-k/2, i+k/2]$内$k$个$d$维的embedding词全部concat在一起,得到输入$\boldsymbol{X} \in \mathbb{R}^{kd}$;卷积核矩阵为$\boldsymbol{W} \in \mathbb{R}^{kd \times 2d}$,可以理解为每个卷积核大小为$kd$,一共有2d个卷积核,卷积完的输出$\boldsymbol{Y}=[\boldsymbol{A}, \boldsymbol{B}] \in \mathbb{R}^{2d}$;非线性运算时,采用了门控结构(GLU),计算公式为: $v([\boldsymbol{A},\boldsymbol{B}])=\boldsymbol{A} \otimes \delta(\boldsymbol{B})$, 其中$v$是非线性运算,$\delta$是门控函数。也就是说上述2d个卷积核,卷积得到的前d个元素构成的向量为A,后d个元素构成的向量为B,且B作为门控函数的输入。$v$的输出也是d维的。残差连接时(GLU的右侧),直接加上单词$i$的embedding得到一个Block的输出。作者为了保证卷积的输出长度和输入长度一致,添加了padding策略。这样多个Blocks可以叠加在一起。Decoder最后一层Block的输出经过softmax全连接层得到下一个词的概率。
Multi-step Attention:上面描述还未使用到Attention,只不过用多层卷积块分别提取了Encoder表示和Decoder表示,Decoder还未用到Encoder的信息。Multi-step意味着Decoder每一个卷积层都会进行Attention。首先将Decoder经过卷积层提取到的特征表示和前一个已经预测的输出词的embedding结合在一起,$\boldsymbol{d}_i^l = \boldsymbol{W}_d^l \boldsymbol{h}_i^l + \boldsymbol{b}_d^l + \boldsymbol{g}_i$,再和Encoder最后一个Block提取的特征表示$\boldsymbol{z}_j^u$($u$是Encoder最后一个Block)求Attention(点乘+softmax),记做$a_{ij}^{l}$。接着计算上下文向量,除了利用$\boldsymbol{z}_j^u$,还利用了对应单词的embedding,则$\boldsymbol{c}_i^l =\sum_{j=1}^m a_{ij}^l(\boldsymbol{z}_j^u+ \boldsymbol{e}_j)$。最后将$\boldsymbol{c_i}^l$加到Decoder的特征表示上$\boldsymbol{h}_i^l$上($\boldsymbol{c_i}^l+\boldsymbol{h}_i^l$),作为Block的输出,且是Decoder下一个Block的输入。如此,在Decoder每一个卷积层都会进行 attention 的操作,得到的结果输入到下一层卷积层,这就是多跳注意机制multi-hop attention。这样做的好处是使得模型在得到下一个注意力时,能够考虑到之前的已经注意过的词。
ACL2016:Incorporating Copying Mechanism in Sequence-to-Sequence Learning
ACL2017:Get To The Point: Summarization with Pointer-Generator Networks
首先是“NIPS2015:Pointer Network“。作者想解决的是输出序列语句中每个元素是离散的单词,且该元素和输入序列语句中每个位置相对应的应用场景(an output sequence with elements that are discrete tokens corresponding to positions in an input sequence,说白了就是拷贝),如寻找凸包(比如训练的时候最多4个顶点,后来遇到10个顶点的几何图形就解决不了了)等。这种场景的特点是,输出序列的词汇表会随着输入序列长度的改变而改变,也就是说对很多样例而言,out-of-vocabulary现象是经常存在的。传统的seq2seq模型无法解决该问题,因为对于这类问题,输出往往是输入集合的子集,且输出的类别词汇表是可变的。基于这种特点,作者考虑能不能找到一种结构类似编程语言中的指针,每个指针对应输入序列的一个元素,从而我们可以直接操作输入序列而不需要特意设定输出词汇表。作者给出的答案是指针网络(Pointer Networks)。Pointer Networks的核心思想在于,直接将输入序列对应的Attention Score向量作为Pointer指针来选择输入序列的一部分作为输出,因为Attention可以衡量不同输入序列token的重要性程度(而先前的Attention Score用于加权encoder的隐状态并得到一个上下文向量用于Decoder阶段)。
总结一下,传统的带有注意力机制的seq2seq模型的运行过程是这样的,先使用encoder部分对输入序列进行编码,然后对编码后的向量做attention,最后使用decoder部分对attention后的向量进行解码从而得到预测结果。但是作为Pointer Networks,得到预测结果的方式便是输出一个概率分布,也即所谓的指针。换句话说,传统带有注意力机制的seq2seq模型输出的是针对输出词汇表的一个概率分布,而Pointer Networks输出的则是针对输入文本序列的概率分布。直接优化该概率分布的交叉熵损失即可。
接着我们先介绍下ACL2017应用Pointer Network的文章“Get To The Point: Summarization with Pointer-Generator Networks“,这篇文章略好懂一些。作者提出了Pointer-Generator模型,在传统的Attention Encoder-Decoder基础上加入了Pointer Network+Coverage技术来解决文本摘要的seq2seq模型存在的两大缺陷:1、模型容易不准确地再现事实细节,也就是说模型生成的摘要不准确;2、往往会重复,也就是会重复生成一些词或者句子。模型结构如下:
这里主要介绍Pointer Networks部分。作者对Pointer Networks应用的思想非常直观,就是用它来复制源文本中的单词。简单来说,在每一次预测的时候,通过传统seq2seq模型的预测(即softmax层的结果)可以得到针对词汇表的概率分布(图中绿色柱形图),然后通过Pointer Networks可以得到针对输入序列的概率分布(图中蓝色柱形图),对二者做并集就可以得到结合了输入文本中词汇和预测词汇表的一个概率分布(最终结果的柱形图中的“2-0”这个词不在预测词汇表中,它来自输入文本),这样一来模型就有可能直接从输入文本中复制一些词到输出结果中。当然,直接这样操作未必会有好的结果,因此作者又加入了一个$P_{gen}$来作为soft概率。Pgen的作用可以这样理解:决定当前预测是直接从源文本中复制一个词过来还是从词汇表中生成一个词出来,二者通过插值combine起来。
$$
p(w)=p_{gen}P_{\text{vocab}}(w)+(1-p_{gen})\sum_{i:w_i=w} a_{i}^t
$$
其中,$p_{gen}$根据上下文向量,decoder层隐状态,decoder输入,经过1层MLP+sigmoid得到。$P_{\text{vocab}}(w)$是Decoder输出层得到的词汇表中$w$的概率,$\sum_{i:w_i=w} a_{i}^t$则是对输入序列中,$w$词对应的attention值加起来(可能多次出现)。
最后是ACL2016的文章“Incorporating Copying Mechanism in Sequence-to-Sequence Learning”,几乎和ACL2017文章思想一样。文章创新点包括3个部分:
预测:基于两种模式的混合概率模型预测下一个词的概率分布。包括:Generation-Mode,用来根据词汇表生成词汇,计算词汇表词的生成概率;Copy-Mode,用来直接复制输入序列中的一些词,计算源语句序列词被拷贝的概率。最后预测时,二者概率相加(上一篇文章根据$p_{gen}$插值,这里直接相加)。因此,该模型具备解决OOV问题的能力。
Decoder隐状态的更新:传统的Seq2Seq模型在Decoder层计算下一个时刻的隐状态时,使用的信息包括前一时刻隐状态,attention后的上下文状态,前一时刻已经预测的输出词的embedding。而该模型中,还使用了前一时刻已经预测的输出词在源语句Encoder中对应的特定位置的隐状态(因为前一时刻的输出词可能是来自于源语句序列的拷贝,故在Encoder中有对应的隐状态)。
Encoder隐状态的使用方式:传统的Seq2Seq模型对于Encoder隐状态的使用只包括Attention Read,即转成attentional上下文向量在Decoder中使用,这可以看做是Content-based Addressing。而本文还加了一种使用方式Selective Read,也就是上述”Decoder隐状态更新”中所述,会使用前一时刻已经预测的输出词在源语句Encoder中对应的特定位置的隐状态,这种方式可以看做Location-based Addressing(伴随着信息的流动,下一个位置的信息在预测下一个Decoder隐状态时会被关注,因此Location-based Addressing使得模型具备拷贝源语句某个连续子序列的能力)。
模型结构如下:
上图解读分成3部分,首先令Encoder得到的所有hidden state为矩阵$\boldsymbol{M}$。目前要预测当前时刻的输出词 Jebara。
左侧和常规的Attention模型一致,在预测此刻输出词”Jebara”时,使用前一时刻的Decoder隐状态$\boldsymbol{s}_3$和$\boldsymbol{M}$求Attention,该Attention得分向量作为源语句每个词的概率分布(文中好像用的是$\boldsymbol{s}_4$,那这个应该是未更新前的)。
右侧下半部分,根据$\boldsymbol{s}_{t-1}$,$\boldsymbol{y}_{t-1}$, $\boldsymbol{c}$,$\boldsymbol{M}$更新此刻的Decoder状态$\boldsymbol{s}_t$。重点是前一时刻输出词$\boldsymbol{y}_{t-1}$(Tony)除了它的embedding之外,作者还考虑了如果前一时刻的输出词是输入序列某个位置的词,例如Tony就是输入序列的词,那么利用Attention向量对这些输入词的Encoder hidden state进行加权作为对输入序列的Selective Read(此处是Tony,但是Tony可能出现多次;如果没有出现,那么这部分为空,退化为传统的方法)。然后将Tony的Embedding和Selective Read连接在一起作为$\boldsymbol{y}_{t-1}$。最后一起经过LSTM/GRU得到此刻的$\boldsymbol{s_t}$。
最后右侧上半部分,Decoder根据生成模式和拷贝模式计算下一个词的概率分布。词语分成3大部分,源序列输入词,词汇表词,未知词(统一设置成UNK)。下一个词概率分布:
$$
p(\boldsymbol{y}_t |\boldsymbol{s}_t , \boldsymbol{y}_{t−1}, \boldsymbol{c}_t, \boldsymbol{M}) = p(\boldsymbol{y}_t , \text{g} |\boldsymbol{s}_t , \boldsymbol{y}_{t−1}, \boldsymbol{c}_t ,\boldsymbol{M}) + p(\boldsymbol{y}_t ,\text{c}|\boldsymbol{s}_t , \boldsymbol{y}_{t−1}, \boldsymbol{c}_t, \boldsymbol{M})
$$
其中,第一个式子是生成模式(g),对应右上图左侧;第二个词时拷贝模式(c),对应右上图右侧。具体不同模式词汇的概率分布都是先根据得分模型(MLP)计算不同词的得分,再进行softmax得到分布;生成模式得分模型依赖于上一步计算的$\boldsymbol{s}_t$和输出词的embedding表示;拷贝模式得分模型依赖于$\boldsymbol{s}_t$和输入词的hidden state(M中某列)。$p(\boldsymbol{y}_t|\cdot)$所有计算情况如下图所示,图中$\varphi$就是得分模型。
图中,$X$是源序列输入词;$V$是词汇表的词;unk是未知词。某个输出词可能属于上述4种情况中的一种。
NIPS2015:End-To-End Memory Networks
ACL2016:Key-Value Memory Networks for Directly Reading Documents
ICML2016:Ask Me Anything:Dynamic Memory Networks for Natural Language Processing
基于记忆的Attention机制将注意力分数的计算过程重新解释为根据查询/问题$q$进行soft memory addressing的过程,将编码视为从基于attention分值的memory中查询注意力分支的过程。从重用性的角度上,这种注意力机制能够通过迭代memory更新(也称为多跳)来模拟时间推理过程,逐步将注意力引导到正确的答案位置,对于答案和问题没有直接关系的复杂问答效果较好(需要多步推理)。从灵活性角度看,可以人工设计key的嵌入以更好的匹配问题,人工设计value的嵌入来更好的匹配答案。这种解耦的模块化设计,能够在不同组件中注入领域知识,使模块之间的通信更有效,并将模型推广到传统问答之外的更广泛的任务。
形式化来说,memory中存储的是key-value pairs,$\{(\boldsymbol{k}_i, \boldsymbol{v}_i)\}$,给定一个查询$\boldsymbol{q}$。定义上下文向量获取3步骤:
实际上memory存储的就是输入序列(更准确的说是外部记忆,输入序列是一种外部记忆,也可以引入其他领域先验知识,如知识库来构造外部记忆库),只不过可以设计key和value;如果key和value相等,那么上述就退化成了Basic Attention的操作了。
首先是ICLR2015文章”Memory Network”。该模型的出发点在于,传统的深度学习模型(RNN、LSTM、GRU等)使用hidden states或者Attention机制作为他们的记忆功能(实际上是短期的内部记忆),但是这种方法产生的记忆太小了,无法精确记录一段话中所表达的全部内容,也就是在将输入编码成dense vectors的时候丢失了很多信息。所以本文就提出了一种可读写的外部记忆模块(external memory),并将其和inference组件联合训练,最终得到一个可以被灵活操作的记忆模块。
这篇文章的贡献在于提出了一种普适性的模型架构memory networks。其核心组件包括4部分:
简单来说,就是输入的文本经过Input模块编码成向量,然后将其作为Generalization模块的输入,该模块根据输入的向量对memory进行读写操作,即对记忆进行更新(最基本的更新就是将memory划分为slots,以slot为单位进行读写,更新的时候,最简单的方法就是$\boldsymbol{m}_{H(x)}= I(x)$,即新根据输入x进行Hash索引,然后替换掉某个Slot为最新的input的内部特征表示)。然后Output模块会根据Question(也会进过Input模块进行编码)对memory的内容进行权重处理(Question会触发对memory的Attention),将记忆按照与Question的相关程度进行组合得到输出向量,最终Response模块根据输出向量编码生成一个自然语言的答案出来。
接着是NIPS2015的文章“End-To-End Memory Networks”。作者的应用场景是问答系统(比较复杂的问答推理),包括3要素,input-question-answer。
首先介绍下语句表示组件(对应上篇论文的I组件)。语句表示组件的作用是将语句 表示成一个向量。作者在bag-of-words(BoW)基础上添加位置序列信息。令某个语句为为$\boldsymbol{x}_{i} = \{\boldsymbol{x}_{i1}, \boldsymbol{x}_{i2},…, \boldsymbol{x}_{in}\}$。则语句向量化表示为:
$$
\boldsymbol{m}_i = \sum_j \boldsymbol{l}_j \cdot \boldsymbol{A} \boldsymbol{x}_{ij}
$$
其中,$\boldsymbol{A} \boldsymbol{x}_{ij}$看做是每个单词的embedding表示,$l_j$是根据位置计算的权重向量,称作position encoding。
$$
l_{kj} = (1 − j/J) − (k/d)(1 − 2j/J)
$$
$J$是语句长度,$j$是单词序号,$k$代表$\boldsymbol{l}_j$的第$k$个元素,$d$是Embedding的维度数($\boldsymbol{A} \boldsymbol{x}_{ij}$维度数)。
此外,语句之间也存在时序关系,作者对语句之间的时序也进行了encoding,但是一笔带过。坐在在计算$\boldsymbol{m}_i$ 和 $\boldsymbol{c}_i$ 时加了一个额外的叫做 temporal encoding的模型,$m_{i}=\sum_{j} \boldsymbol{A} \boldsymbol{x}_{ij} + T_{\boldsymbol{A}}(i)$。$T_{A}$是个矩阵,编码了时序信息,也是需要学习。当然,Position encoding和Temporal Encoding可以同时考虑。
下面要介绍的模型的memory input/output, question都需要利用该组件进行向量化表示,只不过Embedding矩阵不同。
首先给出模型架构图:
上图左侧(a)是单层的网络结构。最左边的就是memory,里面存储着输入集合$\{\boldsymbol{x}_i\}$,每个$\boldsymbol{x}_i=\{\boldsymbol{x}_{i1}, \boldsymbol{x}_{i2},…, \boldsymbol{x}_{in}\}$代表一个句子。memory的输入和输出不同,按照我的理解memory的输入是key,输出是value。输入key用于计算和查询的相似性,输出value用于计算上下文向量。
对于输入记忆(可以理解为Key memory,记忆的一种表现形式),即图中下半部分蓝色线条,使用上述语句表示组件(Embedding A)将每个语句$\boldsymbol{x}_i$转成向量表示$\boldsymbol{m}_i$作为memory的输入(可以理解为$\boldsymbol{m}_i$存储在memory中,不断写入memory直到fixed buffer size),即key,memory input用于得到memory不同语句的attention得分向量。首先将问题语句$\boldsymbol{q}$也使用语句表示组件(Embedding B)转成向量化表示$\boldsymbol{u}$,即query,然后根据key和query和计算$p_i= Softmax(\boldsymbol{u}^T \boldsymbol{m}_i )$,这是address memory+normalize操作。
对于输出记忆(可以理解为Value memory,记忆的另一种表现形式),即图中上半部分黄色线条,首先根据语句表示组件(Embedding C)将语句转成$\boldsymbol{c}_i$作为memory的输出,即value,然后利用该输出以及$p_i$,加权得到attentional上下文向量,即:$\boldsymbol{o} = \sum_i p_i \boldsymbol{c}_i$, 这是read contents操作。
最后预测的时候,将问题表示$\boldsymbol{u}$和上下文向量$\boldsymbol{o}$相加,经过Softmax全连接层预测答案的概率分布(文中似乎只针对单个单词的答案。对于多个单词的答案,会把答案句子看成一个整体,从多个候选的答案句子中选择其中一个),$\hat{\boldsymbol{a}} = Softmax(\boldsymbol{W}(\boldsymbol{o} + \boldsymbol{u}))$,其中,$\boldsymbol{W} \in \mathbb{R}^{V \times d}$。$\hat{\boldsymbol{a}}$是词汇表所有词的概率,使用交叉熵损失进行训练。
上述是单层网络,作者将多个单层网络stack在一块,来解决多跳(Multi-Hop)操作(我的理解是每一跳都要和memory交互,形成更有用的记忆上下文向量$\boldsymbol{o}$,并不断更新查询语句表示$\boldsymbol{u}$,将注意力引导向正确的答案(查询表示向量基础上加上记忆上下文向量进行Transition,来引导到最佳答案位置),如上图(b)所示。从图中可以看出,每经过一层都要和memory交互,且后一层的问题语句表示为,$\boldsymbol{u}^{k+1}= \boldsymbol{u}^k + \boldsymbol{o}^k$。为了减少参数量,作者对$\boldsymbol{A}$,$\boldsymbol{C}$,$\boldsymbol{W}$矩阵做了限制,比如后一层的$\boldsymbol{A}$为前一层的$\boldsymbol{C}$;最后的$\boldsymbol{W}$是最后一层的$\boldsymbol{C}^{k}$。
对于这里面memory的理解,我个人认为memory会使用所有的问答系统的输入语句经过语句表示模块后提取的特征表示来初始化。后面训练的时候,如果遇到的输入语句已经在memory中了,那么就直接替换其旧值来更新memory(embedding A矩阵训练过程中在更新,因此$\boldsymbol{m_i}$也会相应的更新,同理memoy的输出$\boldsymbol{c}_i$也可以更新)。如果memory的容量有限,那么先随机初始化满,后面训练的时候遇到不在memory的语句,再根据一定策略替换掉某个值(例如使用Hash策略或FIFO策略,文章没细说)。
接着是ACL2016文章,”Key-Value Memory Networks for Directly Reading Documents”。这篇文章在key和value上进一步解耦,并引入先验知识分别来设计key embedding和value embedding,也就是人工设计key的嵌入以更好的匹配问题,人工设计value的嵌入来更好的匹配答案。模型结构如下:
几乎一样,这里的Key Addressing就是Input Memory Addressing,Value Reading就是Output Memory Reading。核心的创新之处在于,
还有一个有趣的地方,之前的模型会限制记忆的大小,主要是因为不能保留所有的语句。这里为了解决大型记忆库的计算效率,提出了Key Hashing的概念。对于每个Question,Key Addressing过程中作者引入了Key Hashing,即可以从大型的记忆库中使用Hash索引检索出部分记忆,例如对应key里头至少有1个单词和Question相同的记忆,再根据部分记忆Address+Read。
最后是ICML2016的文章,“Ask Me Anything:Dynamic Memory Networks for Natural Language Processing“,采取了更复杂的动态记忆网络。前面两篇文章,都是使用Bag-of-Words提取语句向量化表示,这篇文章使用RNN来提取语句向量化表示。并且前面文章预测的答案一般只有1个单词,这里可以多个单词。
模型细分为Input Module,Question Module, Episodic Memory Module和Answer Module。模型结构如下:
Input Module:对输入(语句,故事,文章,Wiki百科)使用GRU提取隐状态表示$\boldsymbol{c}_t$。如果输入是一句话,那么提取到的隐状态个数等于单词个数(每个单词对应一个);如果输入是多个语句,那么提取的隐状态等于语句数(每个语句对应一个,训练时将所有语句concat在一起,语句之间添加特殊分割token,经过GRU后,保留每个token处提取到的隐状态表示,如图$\boldsymbol{c}_t=\boldsymbol{s}_t$, $t=1,2…,8$)。
Question Module:对问题使用GRU提取隐状态,不同的是只保留问题最后一个时刻得到的隐状态$\boldsymbol{q}$。
Episodic Memory Module:本模块和Input Module是对齐的,对齐的目的是要计算Input不同Token的Attention Score值。该模块主要包含Attention机制、Memory更新机制两部分组成,每次迭代都会通过Attention机制对输入向量进行权重计算,然后生成新的记忆。第$i$次迭代过程中,
$$
\boldsymbol{h}_t^i={g}_t^i \text{GRU}(\boldsymbol{c}_t , \boldsymbol{h}_{t−1}^i) + (1 − {g}_t^i)\boldsymbol{h}_{t−1}^i \\
\boldsymbol{e}^i = \boldsymbol{h}^i_{T_c} \\
\boldsymbol{m}^i = \text{GRU}(\boldsymbol{e}^i , \boldsymbol{m}^{i−1} )
$$
Episodic Memory Module场景向量$\boldsymbol{e}^{i}$用于压缩和抽象输入序列,相当于将输入序列状态集合压缩并抽象成一个场景描述向量$\boldsymbol{e}^{i}$,这个场景描述向量是和具体问题以及具体输入都是相关的。为了计算场景向量,该模块维护了自己的隐状态$\boldsymbol{h}_t^i$,根据融合了Attention机制的第一个公式来计算;第二个公式表明,最后一个时刻得到的隐状态作为提取到的新场景$\boldsymbol{e}^i$;第三个公式再根据提取到的新场景和前一次迭代得到的记忆更新记忆。
上述过程,一般会经过多次迭代(可以理解为多跳),将最后一次迭代得到的强化的记忆作为下一个Answer Module的输入。
Answer Module:采用GRU。将上述提取到的最后一次迭代的记忆$\boldsymbol{a}_0=\boldsymbol{m}^{T_M}$作为初始隐状态,问题$\boldsymbol{q}$和前一时刻预测的输出$\boldsymbol{y}_{t-1}$作为输入,得到当前时刻的隐状态$\boldsymbol{a_t}$,接一个softmax全连接层得到该时刻输出词的概率分布。
$$
\boldsymbol{y_t} = softmax(W^{(a)} \boldsymbol{a}_t) \\
\boldsymbol{a}_t = \text{GRU}(([\boldsymbol{y}_{t−1}, \boldsymbol{q}], \boldsymbol{a}_{t−1})
$$
这篇文章的动态性我个人理解为,每输入一句话,记忆就会产生和更新,且这种记忆是Input-Level的,有点像短期的记忆(和Attention比较像,Attention也是Input-Level的短期内部记忆)。而之前3篇文章的工作,记忆库是初始的一次性读取所有输入并产生memory库,这个记忆库是Task-Level的,跟这个任务相关的数据都能用于构造该记忆库,只不过受限于容量,记忆库也需要辞旧迎新。不管如何,二者的记忆表示都需要在训练过程中不断更新。
另外,这篇文章的优点就是将Memory机制更好的应用到了Seq2Seq模型。前面的3篇工作都不是标准的Seq2Seq模型,都只是利用简单的Bag-of-Words来处理序列,预测的时候,答案要么是单个单词;要么是看成一个整体的句子。而本文则用GRU在Answer Module建模答案序列。
NIPS2017: Attention Is All You Need
Google Brain团队在2017年提出了一种新的神经网络架构,称作Transformer。该架构只使用了attention机制(+MLPs),不需要RNN、CNN等复杂的神经网络架构,并行度高。
文章创新点包括:
1. Encoder:
输入的序列长度是$n$,embedding维度是$d_{model}$,所以输入是$n \times d_{model}$的矩阵$\boldsymbol{X}$。
Attention层:N=6,6个重复一样的结构(可以看出这里也是使用了多跳),每种结构由两个子层组成:
子层1:Multi-Head self-attention
源语句的self attention。Multi-Head Attention如下图右边所示,每个Multi-Head Attention包含了$h$个Scaled Dot-Product Attention组件,也就是每个Head就是一个Scaled Dot-Product Attention组件,如下图左边所示。
每个Head获取一种子空间的语义,多个Head可以看做是ensemble,且可以并行计算。对于一个Head,
a)首先,原始的$\boldsymbol{Q} \in \mathbb{R}^{n \times d_{model}}$、$\boldsymbol{K} \in \mathbb{R}^{n \times d_{model}}$、$\boldsymbol{V} \in \mathbb{R}^{n \times d_{model}}$先经过全连接进行线性变换映射成$\bar{\boldsymbol{Q}}=\boldsymbol{Q} \boldsymbol{W}_i^Q \in \mathbb{R}^{n \times d_k} , \bar{\boldsymbol{K}}=\boldsymbol{K} \boldsymbol{W}_i^{K} \in \mathbb{R}^{n \times d_k}, \bar{\boldsymbol{V}}=\boldsymbol{V} \boldsymbol{W}_i^{V} \in \mathbb{R}^{n \times d_v}$。
b) 接着,将映射后的$\bar{\boldsymbol{Q}}, \bar{\boldsymbol{K}}, \bar{\boldsymbol{V}}$输入到Scaled Dot-Product Attention,得到中间Attention值,记做,$\text{head}_i = \text{Attention}(\bar{\boldsymbol{Q}}, \bar{\boldsymbol{K}}, \bar{\boldsymbol{V}}) \in \mathbb{R}^{n \times d_v}$。对于$\text{Attention}$函数,先计算$\bar{\boldsymbol{Q}}$和$\bar{\boldsymbol{K}}$点乘相似性,并使用$1/\sqrt{d_k}$缩放,然后经过softmax激活后得到权重分布,最后再对$\bar{\boldsymbol{V}}$加权,即:$\text{Attention}(\bar{\boldsymbol{Q}}, \bar{\boldsymbol{K}}, \bar{\boldsymbol{V}})=\text{softmax}(\frac{\bar{\boldsymbol{Q}} \bar{\boldsymbol{K}}^T}{\sqrt{d_k}}) \bar{\boldsymbol{V}}$
c) 然后,将所有的中间Attention值concat在一起$\boldsymbol{C}=\text{Concat}(\text{head}_1, \text{head}_2,…, \text{head}_h) \in \mathbb{R}^{n \times hd_v}$,
d) 最后,再经过一个线性映射$\boldsymbol{W}^O \in \mathbb{R}^{hd_v \times d_{model}} $,得到最终输出的Multi-Head Attention值,$\text{Multi-Head}(\boldsymbol{Q},\boldsymbol{K},\boldsymbol{V})=\boldsymbol{C} \boldsymbol{W}^{O} \in \mathbb{R}^{n \times d_{model}}$,其捕获了不同表示子空间的语义。
综合起来,即:
$$
\text{Multi-Head}(\boldsymbol{Q},\boldsymbol{K},\boldsymbol{V})=\text{Concat}(\text{head}_1, \text{head}_2, …, \text{head}_h) \boldsymbol{W}^{O} \\
\text{where} \ \text{head}_i = \text{Attention}(\boldsymbol{Q} \boldsymbol{W}_i^Q , \boldsymbol{K} \boldsymbol{W}_i^K , \boldsymbol{V} \boldsymbol{W}_i^V) \\
\text{where} \ \text{Attention}(\boldsymbol{Q}, \boldsymbol{K}, \boldsymbol{V})=\text{softmax}(\frac{\boldsymbol{Q} \boldsymbol{K}^T}{\sqrt{d_k}}) \boldsymbol{V}
$$
子层1的输出:$\text{O}^{\text{Encoder},1}=\text{LayerNorm}(X + \text{Multi-Head}(X))$,此时$\boldsymbol{Q}=\boldsymbol{K}=\boldsymbol{V}=\boldsymbol{X} \in \mathbb{R}^{n \times d_{model}}$。
子层2:
position-wise 前馈神经网络。即上述输出的矩阵每一行代表相应位置的单词经过attention后的表示,每个位置的向量$\in \mathbb{R}^{d_{model}}$经过两层的前馈神经网络(中间接RELU激活)得到一个输出FFN。
$$
\text{FFN}(x) = max(0, xW_1+b_1)W_2+b_2, \forall x \in \{\text{O}^1_{1,*}, …,\text{O}^1_{n,*}\}
$$
上述参数所有位置共享,$F=\{\text{FFN}(x)\} \in \mathbb{R}^{n \times d_{model}}$。
子层2的输出:$O^{\text{Encoder},2}=\text{LayerNorm}(O^{\text{Encoder},1}+F)$
Decoder:
输入层:
已经翻译出的目标词word embedding+position embedding。结构同encoder中的输入层,每个单词embedding维度为$d_{model}$,假设已经翻译了$m$个词,则输入为矩阵$\boldsymbol{Y}\in \mathbb{R}^{m \times d_{model}}$。
Attention层:共6个。
子层1:Masked Multi-Head Self-Attention
目标语句的self-attention,加了掩码的multi-head attention,防止目标语句中前面的单词attend到后面的单词,来维护自回归的性质。这和Encoder中不同,Encoder中没有加该限制。具体实现时,只需要在scaled dot-product Attention中,将softmax的输入中不合法的attend连接设置成无穷小即可(这样经过softmax后这些权重为0)。
该层的输出同样采取Add和LayerNorm。
子层2:Multi-Head Attention
前面两次用到的Multi-Head Attention都是源语句或目标语句各自内部的Attention。而该子层2是目标语句和源语句之间的Attention。此时,$\boldsymbol{Q}$是Decoder端的单词表示,即上述Masked Multi-Head Self-Attention得到的输出,$\boldsymbol{K}$, $\boldsymbol{V}$是Encoder端的输出,即前文所述的$O^{\text{Encoder},2}=\boldsymbol{K}=\boldsymbol{V}$。
该子层允许目标语句每个词都能attend到源语句不同的单词上,且每个目标单词都能计算一个对应的上下文向量。该子层的输出$\in \mathbb{R}^{m \times d_{model}}$。
子层3:Position wise 前馈神经网络
和Encoder中的一致。输出$\in \mathbb{R}^{m \times d_{model}}$。
输出层:
将上述依次经过6个Attention层的输出经过一个全连接层并softmax激活后得到下一个预测的单词的概率分布。
另外,Transformer比较好的文章可以参考以下两篇文章:一个是Jay Alammar可视化地介绍Transformer的博客文章The Illustrated Transformer ,非常容易理解整个机制;然后可以参考哈佛大学NLP研究组写的“The Annotated Transformer ”,代码原理双管齐下,很细致。
总之,这篇文章中提出的Transformer本质上是个叠加的自注意力机制够成的深度网络,是非常强大的特征提取器,尤其是在NLP领域。Transformer近几年也一跃成为踢开RNN和CNN传统特征提取器,荣升头牌,大红大紫。很多后续的NLP先进的研究工作都会基于Transformer展开。例如,词预训练工作上,18年OpenAI工作:Improving Language Understanding by Generative Pre-Training(GPT)和 18年Google AI Language工作:BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding (BERT),这两个重要工作都是基于Transformer特征提取器做的,其提出的两阶段训练方式(pre-training+fine-tuning)做迁移学习几乎刷爆了所有的NLP任务。
本文主要对基本的Attention机制以及Attention的变体方面的工作进行了梳理。我们不难发现Attention机制简单,优雅,效果好,沟通了输入和输出之间的联系,易于推广和应用到多种多样的任务和场景中,如计算机视觉,NLP,推荐系统,搜索引擎等等。除此之外,我们可以回顾下早期的一些奠基性的工作,注意力机制的好处在于很容易融入到其他早期的一些工作当中,来进一步提升早期成果,例如,将注意力机制引入到早期词预训练过程中,作为特征提取器,来提升预训练的效果,这在今年NLP工作中尤为突出(e.g.,BERT)。还比如,可以将注意力机制用于模型融合;或者将注意力机制引入到门限函数的设计中(e.g.,GRU中代替遗忘门等)。总之,Attention机制的易用性和有效性,使得很容易引入到现有的很多工作中,也很容易的应用到各种各样的实际业务或场景当中。另外Attention的改进工作包括了,覆盖率(解决重复或丢失信息的问题),引入马尔科夫性质(前一时刻Attention会影响下一时刻的Attention,实际上多跳注意力能够解决该问题),引入监督学习(例如手动对齐或引入预训练好的强有力的对齐模型来解决Attention未对齐问题)等等。
2018:An Introductory Survey on Attention Mechanisms in NLP Problems
NIPS2014:Sequence to Sequence Learning with Neural Networks
ICLR2015: Neural Machine Translation by Jointly Learning to Align and Translate
ICML2015: Show, Attend and Tell- Neural Image Caption Generation with Visual Attention
NIPS2015: Attention-Based Models for Speech Recognition
ICLR2016: Reasoning about Entailment with Neural Attention
EMNLP2015: A Neural Attention Model for Sentence Summarization
NIPS2014: Recurrent Models of Visual Attention
ICLR2015: Multiple Object Recognition with Visual Attention
EMNLP2015: Effective Approaches to Attention-based Neural Machine Translation
NAACL-HLT2016:Hierarchical Attention Networks for Document Classification
NAACL-HLT2016:Multi-Source Neural Translation
ACL2017:Get To The Point: Summarization with Pointer-Generator Networks
NIPS2015:End-To-End Memory Networks
ACL2016:Key-Value Memory Networks for Directly Reading Documents
ICML2016:Ask Me Anything:Dynamic Memory Networks for Natural Language Processing
NIPS2017:Convolutional Sequence to Sequence Learning
ACL2017:Attention-over-Attention Neural Networks for Reading Comprehension
NIPS2017: Attention Is All You Need
Improving Language Understanding by Generative Pre-Training
BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding
AAAI2018:DiSAN: Directional Self-Attention Network for RNN/CNN-Free Language Understanding
Attention and Memory in Deep Learning and NLP
A Beginner’s Guide to Attention Mechanisms and Memory Networks
]]>欢迎关注我的公众号”蘑菇先生学习记“,更快更及时地获取推荐系统前沿进展!
排序学习(Learning to Rank, LTR)最早兴起于信息检索领域。经典的信息检索模型包括布尔模型、向量空间模型 、 概率模型、语言模型以及链接分析等。这些在不同时期提出的模型都是无监督排序方法,其共同特点是利用一些简单的特征进行排序,例如词频、逆文档频率等。这些传统排序方法的优点在于容易进行经验参数的调整,得到最优的参数,用以对检索文档按照一定标准(往往是查询与文档之间的相关性)进行排序。
随着搜索引擎需要处理的数据量呈指数增长,人为凭经验优化参数的过程变得越来越复杂。另外,影响文档排序的信息多种多样(文本相关性中的VSM、LM、BM25分值;临近度;PageRank值;是否是垃圾网页;URL深度;域名重要性等),然后这些经典的模型往往偏重某一方面的因素而忽略了其他可以用于排序的重要因素,例如概率模型和语言模型都没有考虑网页链接、网页 pagerank 值等互联网结构对排序的影响。在这种情况下,排序学习应运而生。排序学习的定义为:基于机器学习中用于解决分类与回归问题的思想,提出利用机器学习方法解决排序的问题。排序学习的目标在于自动地从训练数据中学习得到一个排序函数,使其在文本检索中能够针对文本的相关性、重要性等衡量标准对文本进行排序。机器学习的优势是:整合大量复杂特征并自动进行参数调整,自动学习最优参数,降低了单一考虑排序因素的风险;同时,能够通过众多有效手段规避过拟合问题。
而在推荐系统领域,传统的推荐算法主要可以分为3 大类:基于内容的推荐算法、协同过滤推荐算法以及混合推荐算法。这些传统推荐算法重点考虑用户和物品之间的二元关系,大都可以转化为评分预测问题,根据用户对物品的评分进行排序后产生推荐列表。但仅仅依据用户对物品的评分产生推荐结果并不能准确地体现用户的偏好。随着数据的增长,关于用户、物品、上下文、搜索等信息的获取成为了可能,而这些因素对用户的偏好有很大的影响。单一的推荐模型仅能从某一个方面的因素考虑用户的偏好,此时就需要排序模型来综合考虑各种影响用户偏好的因素,推荐系统领域的排序学习也因此应运而生。
基于排序学习的推荐算法通用模型如下所示,
排序学习广义上可以算作是一种监督性学习,将推荐系统中已经处理好的交互数据或人为标注好的数据作为训练集进行学习。这里可以采用点级、对级、列表级等不同的排序技术,根据训练数据构建输入样本,并训练得到一个排序模型$ f(u,i)$,其中,$u\in U$ 表示某一特定用户,$U$表示所有用户的集合, 而$i \in I$ 表示某一具体物品, $I$表示所有物品的集合。在测试阶段,系统根据训练得到的排序模型$f(u,i)$ 对目标用户$\gamma$ 产生一个物品排序列表$\{ i_{\gamma,1} , i_{\gamma,2} ,…,i_{\gamma,n} \}$, 并将该列表推荐给用户$\gamma$, 其中 $i_{\gamma,1}$ 表示在目标用户 $\gamma$ 的物品排序列表中排在第1位的物品,以此类推。
不难发现:排序学习融合进推荐算法之中,其目的在于对具有潜在购买力的目标用户,根据训练得到的排序模型对物品列表进行排序,最终得到一个排序列表,作为该目标用户的推荐列表进行推荐。不得不说IR领域的LTR方法和推荐领域的LTR方法非常像。只不过,推荐领域的LTR更强调利用原始交互数据(interaction data)进行排序学习,原始交互数据更像是一种无监督数据,因此从狭义上来说,推荐系统很大程度上应当归到无监督学习,而IR领域更强调人为专家标注的监督数据进行排序学习,因此更应该归到监督学习。另外,IR领域的OLTR(Online Learning to Rank, SIGIR2016: Slides: Online Learning to Rank for Information Retrieval )利用的是交互数据,更接近于推荐系统领域的LTR。
特别要强调的是,工业界的推荐系统通常会分为两个阶段,召回阶段和排序阶段。召回阶段根据用户的兴趣和历史行为,从千万级的物品库中挑选出一个小的候选集(e.g., 几百到几千个物品)。这些候选都是用户很大概率会感兴趣的内容,排序阶段在此基础上进行更精准的计算,能够给每一个物品进行精确打分,进而从成千上万的候选中选出用户最感兴趣的少量物品(e.g., 十几个)。一般召回阶段包含了多个通道的召回模型,比如协同过滤,主题模型,基于内容的推荐等通道(不同通道召回时,可以使用近似近邻搜索、最大点积搜索等搜索算法提高召回速度),每种召回模型分别考虑了某个或某些影响用户偏好的因素,因此不同召回模型能够从物品库中选出多样性的物品。然而多个通道的召回的物品是不具有可比性的(e.g.,不同模型预测方式不同),且因为数据量太大也难以一一进行更加精确的偏好和质量评估,因此需要在排序阶段对召回结果进行统一的准确的打分排序。
个人认为召回模型和排序模型不是正交的关系,召回模型的输出结果可以进一步根据一定策略排序并进行推荐,大部分召回模型可以看做是pointwise的排序模型;排序模型也可以不需要进行召回,直接根据预测值排序并进行推荐。只不过在实际应用过程中,用户对物品的满意度是有很多维度因子来决定的,用户的偏好是复杂而多样的,为了保证多样化、且精准的推荐,通常需要先使用多种多样的模型,从多种多样的数据源里头挖掘用户偏好,每种模型只考察小部分的因素,多种模型能保证多样性,这是由召回阶段负责的;而不同模型产生的结果通常不具有可比性,无法通过人为制定的规则来融合各种结果并展示给用户,因此通常需要一个排序模型对召回的结果进行排序,且需要进一步综合考虑各种影响用户偏好的因素(特征工程)以及用户真实的反馈行为(数据标注),使用排序模型进行排序学习。至于由哪个模型充当最终排序的角色,这就主要根据最佳实践来选择的。通常,机器学习模型能够充当这样的角色(LR、GBDT、DNN等)。因此下文主要就是调研实践中表现较好的排序模型,另外在结尾部分,本文还讨论了关于排序学习的一些高级话题。
排序学习方法按照输入样例的不同,一般可分为3类:点级(pointwise)、对级(pairwise)、列表级(listwise)。点级方法输入包括用户、物品等特征,根据其对待排序的不同方式划分为回归和分类两种方法,它们分别将排序问题退化为回归与分类问题求解;对级方法考虑物品对之间的偏序关系,将问题转换为有序分类问题,更接近排序问题的实质。列表级方法输入所有相关联的物品集合,更加全面地考虑了不同物品的序列关系,因而成为近年被研究较多的方法。
因此,排序学习主要依赖于用户行为的数据标注,用户、物品、搜索、上下文的特征工程以及排序模型。
其中,用户行为的数据标注主要从用户搜索、系统展示以及用户实际的反馈操作中收集得到。标注数据包括Pointwise方式、Pairwise方式、Listwise方式。
Pointwise方式中,单个物品对于某个用户而言,要么是正样本、要么是负样本。对于正样本,用户实际的反馈操作包括点击、浏览、收藏、下单、支付等,不同操作反映了该物品对用户需求的不同匹配程度,对应的样本可以看做正样本,且赋予不同的权重。对于负样本,为了模拟用户的真实浏览行为(从上往下),可以采取Skip Above策略,即用户点过的物品之上,采样没有点过的物品作为负样本。
Pairwise方式中,主要构造物品pair对,对单个用户而言,没有绝对的偏好,只有对某个物品的相对偏好(e.g., 比起B,用户更喜欢A)。同样存在多种策略,可以收集Pairwise数据标注。例如,
$$
\begin{aligned}
&\text{Click} > \text{Skip Above}; \\
&\text{Last Click} > \text{Skip Above}; \\
&\text{Click} > \text{Earlier Click};\\
&\text{Click} > \text{No-Click Next}。
\end{aligned}
$$
其中,Click >Skip Above代表某个点击的物品比排在该物品之前、但用户略过的物品更好。
Listwise方式中,会考察列表级别的排序。例如,列表的NDCG指标融入到目标函数中,目标函数能够优化列表级别的排序指标。
特征工程涵盖面较广,包括用户特征、物品特征、搜索特征、上下文特征(时间、地点、天气等)等,以及不同特征之间的交叉关联,还包括从其他高阶特征,如使用主题模型提取的用户兴趣分布,使用神经网络提取的高阶特征等等,这些特征都可以作为排序模型的输入。
Pointwise模型的关键要素如下:
优势:
劣势:
Pairwise模型的关键要素如下:
优势:
劣势:
Listwise模型的关键要素如下:
优势:
排序模型利用样本的标注、样本的特征工程,并借助排序模型进行训练和学习。排序模型对候选物品按照得分进行排序,并最终按顺序展示有限个物品给用户。得分一般使用$P(y|\boldsymbol{x})$来衡量,即在给定特征$\boldsymbol{x}$条件下,用户行为是$y$的概率($y$一般取0或者1)。$\boldsymbol{x}$是上述所述特征工程得到的各种各样特征;$y$是上述所述数据标注中,收集到的各种各样的用户操作。大部分用于CTR点击率预估($y$代表点击行为)的模型,都可以用在推荐系统的排序阶段。
另外,实际应用时,不管哪种模型,都要支持离线学习和在线学习。离线学习根据标注的历史数据进行离线训练。在线学习根据用户实时的搜索,实时的反馈,实时的特征变化等,对模型进行增量更新和迭代,并实时的进行在线排序。同时,在线学习还要兼顾探索-利用问题(exploration-exploitation dilemma),如果只展示用户一定满意的物品,那其余潜在满意或不满意的物品就很难获取反馈。在线学习的算法设计核心要素如下图所示(SIGIR2016: Slides: Online Learning to Rank for Information Retrieval):
可以看出,包含了各种各样的排序模型ranker(解决exploitation)、各种各样的探索策略(解决exploration)、收集用户实时的反馈(如点击、停留时间等)、反馈数据处理(将反馈数据处理并转换成输入空间格式)、不同ranker不同损失函数的在线更新。
下文主要对应用较广的一些排序模型ranker进行调研。
首先介绍Pointwise排序模型,这种模型直接对标注好的pointwise数据,学习$P(y|\boldsymbol{x})$或直接回归预测$y$。
LR(LogisticRegression)逻辑回归模型,用于建模Pointwise方式的数据。解释性强,方便debug,并且通过特征权重可以解释推荐的内容,找到模型的不足之处。实际优化过程中,会给样本添加不同权重,例如根据反馈的类型点击、浏览、收藏、下单、支付等,依次提高权重,优化如下带权重的损失:
$$
J(\theta)=-\frac{1}{m}\sum_{i=1}^m w_i \cdot \Big( y_i log(\sigma_\theta(\boldsymbol{x}_i))+(1-y_i)log(1-\sigma_\theta(\boldsymbol{x}_i))\Big)
$$
其中,$w_i$是样本的权重,$y_i$是样本的标签。$\sigma_{\theta}(\boldsymbol{x}_i)=\frac{1}{1+e^{-(\boldsymbol{\theta}\cdot \boldsymbol{x}+ \boldsymbol{b})}}$。
另外,LR是个线性分类模型,要求输入是线性独立特征。我们使用的稠密的特征(维度在几十到几百之间)往往都是非线性的,并且具有依赖性,因此需要对特征进行转换。特征转换需要对特征的分布,特征与label的关系进行分析,然后采用合适的转换方法。通常使用以下几种:Polynomial Transformation(多项式变换),Logarithmic or Exponential Transformation(对数变换或指数变换,例如特征符合幂率分布),Interaction Transformation(组合特征变换)和Cumulative Distribution Function(累计分布函数)等。这些特征变换相当于人工将特征转换为线性特征,以提高特征的表达能力。
虽然LR模型简单,解释性强,不过在特征逐渐增多的情况下,劣势显而易见的;
另外值得注意的是,目前工业界普遍使用FTRL(Follow-the-Regularized-Leader)优化算法来在线更新LR等模型。
分解机FM(Factorization Machine)是由Konstanz大学Steffen Rendle于2010年最早提出的,旨在解决稀疏数据下的特征组合问题。FM设计灵感来源于广义线性模型和矩阵分解。
在线性模型中,我们会单独考察每个特征对Label的影响,一种策略是使用One-hot编码每个特征,然后使用线性模型LR来进行回归,但是one-hot编码后,一者,数据会变得稀疏,二者,很多时候,单个特征和Label相关性不够高。最终导致模型性能不好。为了引入关联特征,可以引入二阶项到线性模型中进行建模:
$$
y(\boldsymbol{x}) = w_0+ \sum_{i=1}^n w_i x_i + \sum_{i=1}^n \sum_{j=i+1}^n w_{ij} x_i x_j
$$
$y(\boldsymbol{x})$是未激活前的回归值,$x_i,x_j$是经过One-hot编码后的特征,取0或1。只有当二者都为1时,$w_{ij}$权重才能得以学习。然而由于稀疏性的存在,满足$x_i,x_j$都非零的样本很少,导致组合特征权重参数缺乏足够多的样本进行学习。
矩阵分解思想此时发挥作用。借鉴协同过滤中,评分矩阵的分解思想,我们也可以对$w_{ij}$组成的二阶项参数矩阵进行分解,所有二次项参数 $w_{ij}$可以组成一个对称阵$W$,那么这个矩阵就可以分解为 $W=V^TV$,$V$的第 $j$ 列便是第 $j$维特征的隐向量。换句话说,每个参数 $w_{ij}=⟨v_i,v_j⟩$,这就是FM模型的核心思想。因此,FM的模型方程为:
$$
y(\boldsymbol{x}) = w_0+ \sum_{i=1}^n w_i x_i + \sum_{i=1}^n \sum_{j=i+1}^n \langle \boldsymbol{v}_i, \boldsymbol{v}_j \rangle x_i x_j
$$
这里的关键是每个特征都能学习到一个隐向量。这样$w_{ij}=⟨v_i,v_j⟩$不仅仅可以通过$x_i,x_j$进行学习,凡是和$x_i$相关联的特征$h$, 都对学习$x_i$的隐向量$v_i$有所帮助,同理和$x_j$关联的其他特征对学习$x_j$的隐向量$v_j$有所帮助。这样$w_{ij}=⟨v_i,v_j⟩$就有足够多的样本进行学习。
乍看上述式子的时间复杂度为$O(n^2)$,$n$是特征的数量,但是重写上述方程,可以得到:
$$
\begin{aligned}
\sum_{i=1}^{n-1}\sum_{j=i+1}^n(\boldsymbol{v}_i^T \boldsymbol{v}_j)x_ix_j
&= \frac{1}{2}\left(\sum_{i=1}^n\sum_{j=1}^n(\boldsymbol{v}_i^T \boldsymbol{v}_j)x_ix_j-\sum_{i=1}^n(\boldsymbol{v}_i^T \boldsymbol{v}_i)x_ix_i\right)\\
&=\frac{1}{2}\left(\sum_{i=1}^n\sum_{j=1}^n\sum_{l=1}^kv_{il}v_{jl}x_ix_j-\sum_{i=1}^n\sum_{l=1}^k v_{il}^2x_i^2\right)\\\
&=\frac{1}{2}\sum_{l=1}^k\left(\sum_{i=1}^n(v_{il}x_i)\sum_{j=1}^n(v_{jl}x_j)-\sum_{i=1}^nv_{il}^2x_i^2\right)\\
&=\frac{1}{2}\sum_{l=1}^k\left(\left(\sum_{i=1}^n(v_{il}x_i)\right)^2-\sum_{i=1}^n (v_{il}x_i)^2\right)\\
\end{aligned}
$$
可以看出上述的时间复杂度为$O(kn)$。因此,FM能够解决LR进行特征组合学习时,遇到的稀疏特征学习问题以及学习的复杂度高问题。
GBDT(Gradient Boosting Decision Tree) 又叫 MART(Multiple Additive Regression Tree)。是一种迭代的决策树算法,该算法由多棵决策树组成,所有树的结果累加起来做预测。近些年因为广泛引用于搜索排序,而引起大家关注。GBDT本身也可以做排序学习,但更多的和其他排序模型结合起来一起做排序。下面要介绍的是两种和线性模型结合起来做排序的典型方法。
GBDT+LR方法是Facebook2014年提出在论文Practical Lessons from Predicting Clicks on Ads at Facebook提出的点击率预估方案。其动机主要是因为LR模型中的特征组合很关键, 但又无法直接通过特征笛卡尔积解决,只能依靠人工经验,耗时耗力同时并不一定会带来效果提升。如何自动发现有效的特征、特征组合,弥补人工经验不足,缩短LR特征实验周期,是亟需解决的问题。Facebook 2014年的文章介绍了通过GBDT(Gradient Boost Decision Tree)解决LR的特征组合问题。核心思想是利用GBDT训练好的多棵树,某个样本从根节点开始遍历,可以落入到不同树的不同叶子节点中,将叶子节点的编号作为GBDT提取到的高阶特征,该特征将作为LR模型的输入。首先简要介绍下GBDT。
GBDT是基于Boosting 思想的ensemble模型,由多棵决策树组成,具有以下优点:
原论文中的模型结构如下:
图中$\boldsymbol{x}$是一个样本,$\boldsymbol{x}$两个子节点对应两棵子树Tree1、Tree2为通过GBDT模型学出来的两颗树。遍历两棵树后,$\boldsymbol{x}$样本分别落到两棵树的不同叶子节点上,每个叶子节点对应提取到的一个特征,那么通过遍历树,就得到了该样本对应的所有特征。由于树的每条路径,是通过最小化均方差等方法最终分割出来的有区分性路径,根据该路径得到的特征、特征组合都相对有区分性,效果理论上不会亚于人工经验的处理方式。 最后,将提取到的叶子节点特征作为LR的输入。
GBDT模型的特点,非常适合用来挖掘有效的特征、特征组合。业界不仅GBDT+LR融合有实践,GBDT+FM也有实践,2014 Kaggle CTR竞赛冠军就是使用GBDT+FM,可见,使用GBDT融合其它模型是非常值得尝试的思路。另外,GBDT树模型可以使用目前主流的XGBoost或者LightGBM替换,这两个模型性能更好,速度更快。
GBDT+LR排序模型中输入特征维度为几百维,都是稠密的通用特征。这种特征的泛化能力良好,但是记忆能力比较差,所以需要增加高维的(百万维以上)内容特征来增强推荐的记忆能力,包括物品ID,标签,主题等特征。GBDT不支持高维稀疏特征,如果将高维特征加到LR中,一方面需要人工组合高维特征,另一方面模型维度和计算复杂度会是$O(n^2)$级别的增长。所以设计了GBDT+FM的模型如图所示,采用Factorization Machines模型替换LR。
该模型既支持稠密特征,又支持稀疏特征。其中,稠密特征通过GBDT转换为高阶特征(叶子节点编号),并和原始低阶稀疏特征作为FM模型的输入进行训练和预测,并支持特征组合。且根据上述,FM模型的复杂度降低到$O(n)$(忽略隐向量维度常数)。
GBDT+FM模型,对embedding等具有结构信息的深度特征利用不充分,而深度学习(Deep Neural Network)能够同时对原始稀疏特征(通过嵌入式embedding方式)和稠密特征进行学习,抽取出深层信息,提高模型的准确性,并已经成功应用到众多机器学习领域。因此可以将DNN引入到排序模型中,提高排序整体质量。
YouTube 2016发表了一篇基于神经网络的推荐算法Deep Neural Networks for YouTube Recommendations。文中使用神经网络分别构建召回模型和排序模型。简要介绍下召回模型。召回模型使用基于DNN的超大规模多分类思想,即在时刻$t$,为用户$U$(上下文信息$C$)在视频库$V$中精准的预测出用户想要观看的视频为$i$的概率,用数学公式表达如下:
$$
p(w_t=i|U,C)=\frac{e^{v_i^T u}}{\sum_{j \in V} e^{v_j^Tu}}
$$
向量$u$是
分为离线计算和在线服务两个部分。离线计算的时候,通过embedding提取用户的不同特征(历史观影序列、搜索词),同类型特征先average,然后再将不同类型特征concat起来,作为MLP的输入,最后一层隐藏层的输出作为用户的embedding向量,再和视频的embedding向量点乘,并用于预测该视频概率。(输出层神经元由所有视频构成,最后一层隐藏层和该视频对应的输出层某个神经元相连接的权重向量就是该视频的embedding)。在线服务的时候,利用学习到的用户embedding和视频embedding,并借助近似近邻搜索,求出TopN候选结果(这里的问题是最后使用的video vectors如何构建的问题,是直接使用最后全连接层的权重还是使用最底下embedded video watches中的各视频的embedding。这个问题已有大神讨论过,见关于’Deep Neural Networks for YouTube Recommendations’的一些思考和实现)
排序模型和上述几乎一样,只不过最后一层输出不是softmax多分类问题,而是logistic regression二分类问题,并且输入层使用了更多的稀疏特征和稠密特征。之所以在候选阶段使用softmax,是因为候选阶段要保证多样性等,因此面向的是全量片库,使用softmax更合理。而在排序阶段,需要利用实际展示数据(impression data)、用户反馈行为数据来对候选阶段的结果进行校准,由于召回阶段已经过滤了大量的无关物品,因此排序阶段可以进一步提取描述视频的特征、用户和物品关系的特征等。
如下图:
同样分为训练部分和服务部分。训练时,提取了更多关于视频、用户、上下文的特征,其中,稀疏特征通过embedding方式传入,稠密特征通过归一化、幂率变换等传入,最后使用加权的logistic regression来训练,权重使用观看时长表示,最大化$P(y|\boldsymbol{x})$的概率。
训练好后,使用$e^{Wx+b}$来计算得分并排序即可(不需要进行sigmoid操作,排序时二者等价)。
该模型是Google 2016论文 Wide & Deep Learning for Recommender Systems 提出的,用于Google Play应用中app的推荐。该模型将线性模型组件和深度神经网络进行融合,形成了在一个模型中实现记忆和泛化的宽深度学习框架。其中,宽度学习组件使用广义的线性模型(也可以看做是单层的感知器);而深度学习组件使用多层感知器。结合这两种学习技术,能够使得推荐系统同时捕捉到记忆性和泛化性。宽度学习组件的输入主要是稀疏特征以及稀疏特征间转换后的交叉特征,能够实现记忆性,记忆性体现在从历史数据中直接提取特征的能力;深度学习组件的输入包括了稠密特征以及稀疏特征,其中稀疏特征通过embedding方式转换成稠密特征,能够实现泛化性,泛化性体现在产生更一般、抽象的特征表示的能力。我们希望在宽深度模型中的宽线性部分可以利用交叉特征去有效地记忆稀疏特征之间的相互作用,而在深层神经网络部分通过挖掘特征之间的相互作用,提升模型之间的泛化能力。下图是宽深度学习模型框架:
如上图,左侧为宽度组件,使用单层感知器,直接和输出相连接。右侧为深度组件,使用多层感知器。
wide learning 形式化为:$y=W_{\text{wide}}^T \{\boldsymbol{x}, \phi(\boldsymbol{x}\} + b$, $\{\boldsymbol{x}, \phi(\boldsymbol{x})\}$是concatenated起来的特征,其中$\boldsymbol{x}$是原始稀疏特征,$\phi(\boldsymbol{x})$是手动精心设计的、变换后的稀疏特征,例如使用叉乘来提取特征间的关联(特征组合)。这个特征需要精心设计,取决于你希望模型记住哪些重要信息。deep learning形式化为:$a^{l+1} = W^T_{deep} a^{l} + b^{l}$,deep组件的输入包括连续值特征以及稀疏特征。其中稀疏特征通过embedding方式转换成稠密特征。sigmoid激活后:
$$
P(\hat{r}_{ui}=1|x) = \sigma(W^T_{\text{wide}}\{\boldsymbol{x},\phi(\boldsymbol{x})\} + W^T_{\text{deep}}a^{(l_f)}+ bias)
$$
$\hat{r}_{ui}=1$表示正反馈行为,$P(\hat{r}_{ui}=1|x)$是正反馈行为的概率。上述手工设计的特征在很大程度上影响模型的性能。
在Google Play App推荐应用上,针对该场景设计的神经网络架构如下:
从上图可以看出,宽度组件主要从稀疏特征(类别特征)中进行特征组合操作;深度组件从原始稠密特征(连续值特征),以及将稀疏特征通过embedding方式,输入到MLP提取高阶特征。宽度和深度组件输出结果相加,并通过sigmoid函数激活,最后一起联合优化Logistic Loss进行学习。
DeepFM是2017年提出的一种端到端模型,解决了上述Wide & Deep Learning中手工设计特征的问题。DeepFM整合了Factorization Machine(FM)和MLP。其中FM能够建模特征间的低阶关联,MLP能够建模特征间的高阶关联。
DeepFM不需要特征工程,它将Wide-Deep Learning中的Wide组件使用FM替换。DeepFM的输入是一个M-fields的数据,每条数据由$(u,i)$数据对组成,$u、i$分别指的是用户和商品特征。最终预测的结果是:
$$
P(\hat{r}_{ui}=1|\boldsymbol{x}) = \sigma(y_{\text{FM}}(\boldsymbol{x}) + y_{\text{MLP}}(\boldsymbol{x}))
$$
要注意,指向FM层中inner product的橙色的线的dense embedding代表的是FM模型中二阶项的$w_{ij}=⟨v_i,v_j⟩$中的$v_i$和$v_j$。另外,还可以看到原始稀疏特征有一条直接指向FM层中的Addition黑色的线,这代表的是FM中的一阶项的$⟨w, x_j⟩$中的$x$,$x$是原始稀疏特征(取值0/1)。而指向MLP中的黑色的线dense embedding是稀疏特征嵌入后的稠密特征。因此每个特征值实际上要学习两种embedding(FM二阶项、MLP输入)。
上述输入侧中的稀疏特征既可以包括类别型特征,又可以包括连续值特征,其中类别型特征使用one_hot方式来表示,连续值特征使用连续值本身来表示(可能需要归一化处理),也可以先根据其分布离散化后,再使用one_hot方式表示(图上画出来的架构应该更倾向于后者)。稀疏特征再通过embedding层转换为稠密特征输入到MLP中。另外,之所以说不需要人工特征工程,是因为交叉特征工作是模型自动进行的,在输入侧不需要手动进行交叉特征处理。
DCN是论文Deep & Cross Network for Ad Click Predictions中提到的架构,该论文是2017年四位在谷歌的中国人发表的一篇文章。用复杂网络结构做CTR预估。相比于DeepFM,主要优势在于能够学习更高阶的特征组合。在DeepFM中,宽度组件中FM的特征组合阶数为2,而在DCN中可以任意阶。模型结构如下:
在输入侧,稀疏特征通过embedding层转化为稠密特征后,和连续特征concat起来,一起作为模型的输入。因此,输入层面只有embedding column+continuous column, 特征组合在网络结构中自动实现。上图右侧是常见的MLP深度网络,左侧是本文提出的交叉网络。
对于cross network, 首先将输入embedding column + continous column定义为$x_0 \in \mathbb{R}^d$,则第$l+1$层的cross layer:
$$
x_{l+1} = x_0 x_l^Tw_l + b_l + x_l = f(x_l,w_l,b_l) + x_l
$$
其中$w_l$($w_l \in \mathbb{R}^{d}$)和$b_l$($b_l\in \mathbb{R}^{d}$)为第$l$层的参数。Cross Network这部分网络的总参数量非常少,仅仅为$L_c \times d \times 2$,每一层的维度也都保持一致,最后的output依然与input维度相等。另一方面,特征交叉的概念体现在每一层,当前层的输出的高阶特征都要与第一层输入的原始特征做一次两两交叉(外积)。至于为什么要再最后又把$x_l$给加上,可能是为了借鉴ResNet的思想,最终交叉层网络$f:\mathbb{R}^d \rightarrow \mathbb{R}^{d}$,要去拟合的是$x_{l+1} - x_{l}$这一项残差。外积操作示意图如下:
可以看出,上述的交叉特征操作面向的是stack后的稠密特征$x_0$(embedding+continuous)以及cross layer输出的稠密特征$x_l$之间的。这和FM以及DeepFM中基于原始稀疏特征进行交叉特征不大一样。
Deep Network侧就不多说了,和传统DNN一样,input进来,简单的N层full-connected layer的叠加,所以参数量主要还是在deep侧。
最后Cross Network输出和Deep Network输出concat在一起,使用一个Logistic层预测$P(y=1|\boldsymbol{x})$即可。
点级排序学习技术完全从单个物品的分类得分角度计算,没有考虑物品之间的顺序关系。而对级排序学习技术则偏重于对物品顺序关系是否合理进行判断,判断任意两个物品组成的物品对$<\text{item 1} , \text{item 2}>$,是否满足顺序关系,即,item 1是否应该排在 item 2 前面(相比于item 2, 用户更偏好于item 1)。具体构造偏序对的方法见Basic一节。支持偏序对的模型也有很多,例如支持向量机、BPR、神经网络等。然而,无论使用哪一种机器学习方法,最终目标都是判断对于目标用户,输入的物品对之间的顺序关系是否成立,从而最终完成物品的排序任务来得到推荐列表。
RankSVM来自于2002年发表的一篇论文Optimizing Search Engines using Clickthrough Data,截止到2018.12.12,引用量4208。它是在SVM基础上优化物品偏序对的pairwise损失。在SVM中,为实现软间隔最大化, 需要满足约束$y_i(w^Tx_i +b) > 1- \xi_i$,$y_i$代表样本$x_i$是正样本(1)还是负样本(-1)。而RankSVM是典型的pairwise方法,考虑两个有偏序关系的物品对,训练样本为$x_{u,i}-x_{u,j}$,则优化目标为:
$$
\begin{split}
& min_{w,b} \frac{1}{2}||w||^2 + C\sum_{i=1}^n \xi_{uij} \\
s.t., & y_{uij}(w^T(x_{u,i}-x_{u,j})) \geq 1-\xi_{uij}, \xi_{uij}\geq 0
\end{split}
$$
此时,$y_{uij}$代表用户$u$对$i$的喜爱程度比对$j$的喜爱程度高时,为1,否则为-1。上述优化等价于优化如下Hinge Loss:
$$
L_{w}=\sum_{(u,i,j)\in \mathcal{S} \cup \mathcal{D}}[1- y_{uij}\cdot w^T x_{u,i}+ y_{uij} \cdot w^Tx_{u,j}]_{+}
$$
其中,$S$集合中,$y_{uij}=1$,$D$集合中,$y_{uij}=-1$。$[z]_{+}=max(0,z)$。
上述的改进工作一般是围绕不同pair有序对权重不同展开,即$\xi_{uij}$前会加个权重。
Hinge Ranking Loss是排序学习中非常重要的损失函数之一,大部分做ranking任务的模型都会采用。
BPR(Bayesian Personalized Ranking)来自于2009年发表的一篇论文BPR: Bayesian Personalized Ranking from Implicit Feedback,截止到2018.12.12,引用量达到1550。它基于这样的假设,用户对交互过物品比起其他没有被交互过的物品而言更喜爱(而对于用户交互过的物品对之间不假设偏序关系,同样,对于用户没有交互过的物品对之间也不假设偏序关系)。从而将 “用户-物品 ”交互矩阵可以转换为物品对偏序关系矩阵。如下图所示:
上述是交互矩阵转换为物品偏序对矩阵的过程。所有用户的物品偏序对矩阵可以表示成3元组,$⟨u,i,j⟩$,该三元组的含义为:相对于物品$j$,用$u$更喜欢物品$i$,使用符号$i >_u j$表示。令$D_s=\{(u,i,j)|i \in I_u^{+} ∧ j \in I \backslash I_u^{+}\}$。$I_u^{+}$表示用户$u$交互过的物品集合。
在此基础上 ,作者提出了基于贝叶斯的个性化排序算法,其目标最大化物品排序的后验概率。
$$
\prod_{(u,i,j) \in D_s} P(\Theta|i>_uj) \propto \prod_{(u,i,j) \in D_s} P(i>_uj|\Theta) P(\Theta)
$$
似然部分,
$$
P(i >_u j|\Theta) = \sigma(\hat{x}_{uij}(\Theta))=\sigma(\hat{x}_{ui}(\Theta)-\hat{x}_{uj}(\Theta))
$$
先验部分$P(\Theta)$可以根据参数的假设分布选择,如高斯分布。
对后验概率取log,并取反后得到Logistic Ranking Loss,也是BPR的优化目标(BPR-OPT):
$$
\begin{align}
L(\Theta) &= -\left(\sum_{(u,i,j) \in D_S}ln P(\Theta|i>_uj)+ln P(\Theta) \right) \\
&= \sum_{(u,i,j)\in D_s} -ln(\sigma(\hat{x}_{ui}(\Theta)-\hat{x}_{uj}(\Theta))) + \lambda_{\Theta} ||\Theta||^2
\end{align}
$$
$\Theta$是使用的模型的参数,可以使用不同的模型,例如:使用矩阵分解,则$\Theta=\{P,Q\}$, $P$是用户隐因子矩阵,$Q$是物品隐因子矩阵,则预测值$\hat{x}_{ui}(\Theta) = p_u^T q_i$,此时损失为:
$$
\sum_{(u,i,j)\in D_s} -ln \sigma(p_u^Tq_i-p_u^Tq_j)+\lambda(||p_u||^2+||q_i||^2)
$$
这篇文章的主要贡献就是提出了上述BPR优化目标。BPR优化目标中的模型$\Theta$可以使用多种多样的模型,包括协同过滤、神经网络等等。很多神经网络方法会采用该损失。
Logistic Ranking Loss和Hinge Ranking Loss是排序学习中非常重要的两种损失函数。大部分模型,包括神经网络都会采用,不同模型间的差异在于得分函数$\hat{x}_{ui}$的不同,例如设计不同神经网络架构来预测该得分。
还有个模型是RankNet,和BPR损失非常像,会在下面介绍LambdaMART的时候提到。
WARP(Weighted Approximate-Rank Pairwise)是2011年论文WSABIE: Scaling Up To Large Vocabulary Image Annotation提出的一种Pairwise排序损失,截止2018.12.12,引用量为455。WARP主要用于优化Top K推荐。WARP在Hinge Loss基础上考虑了正样本的排序。通常的Top K推荐只关注前K个结果,忽略了对某些排名很低的正样本的惩罚。WARP引入加权排序指标,对那些排名很低的正样本进行惩罚,加大权重,使得模型更关注这些正样本的学习。样本的权重:
$$
w_{ui} = log(rank(u,i)+1)
$$
$rank(u,i)$代表用户$u$推荐结果中物品$i$的排名。越大说明排名越低,则权重越高。在Hinge Loss改进:
$$
L_{WARP}=\sum_{u \in \mathcal{U}} \sum_{(i,j)\in \mathcal{D}_u} w_{ui}[1+f_{u,j}-f_{u,i}]_{+}
$$
其中,$f_{u,i}$代表用户$u$对$i$的预测值,$f_{u,j}$同理。可以使用矩阵分解中点乘形式来预测。$[z]_{+}=max(0,z)$是hinge loss损失。推导即,对正样本$i$的预测值要比$j$大一个margin值,即,$f_{u,i}-f_{u,j}>1$, 则:$f_{u,j}-f_{u,i} < -1$, 则:$f_{u,j}-f_{u,i} + 1< 0$, 对于满足该式的损失为0,否则损失为$f_{u,j}-f_{u,i}+1$,即为$[1+f_{u,j}-f_{u,i}]_{+}$。
优化的时候,作者提出了一种采样的方法来估计$rank(u,i)$。即对每对$(u,i)$, 一直采样,直到有一个样本$j$不满足$f_{u,i}-f_{u,j}>1$, 记采样次数为$N$, $J$为所有物品的个数。则$rank(u,i) \approx \lfloor {\frac{J}{N}} \rfloor$。这个可以直观理解,采样次数$N$越小,说明很容易采到$j$, 即$i$的排名不是很高($rank(u,i)$值大),因此对其进行惩罚,让模型关注该正样本$i$, 使得优化后该样本排名能高一些。
大部分用于做排序的深度神经网络模型都会采用RankSVM中提出的pairwise Hinge Loss或BPR中的pairwise Logistic Loss,主要差别仅在于打分模型不同。下面列举部分:
LambdaMART是LambdaRank的提升树版本,而LambdaRank又是基于pairwise的RankNet。因此LambdaMART本质上也是属于pairwise排序算法,只不过引入Lambda梯度后,还显示的考察了列表级的排序指标,如NDCG等,因此,也可以算作是listwise的排序算法。LambdaMART由微软于2010年的论文Adapting Boosting for Information Retrieval Measures提出,截止到2018.12.12,引用量达到308。本小节主要介绍LambdaMART,参考文章 From RankNet to LambdaRank toLambdaMART: An Overview。
LambdaMART是基于 LambdaRank 算法和 MART (Multiple Additive Regression Tree) 算法,将排序问题转化为回归决策树问题。MART 实际就是梯度提升决策树(GBDT, Gradient Boosting Decision Tree)算法。GBDT 的核心思想是在不断的迭代中,新一轮迭代产生的回归决策树模型拟合损失函数的梯度,最终将所有的回归决策树叠加得到最终的模型。LambdaMART 使用一个特殊的 Lambda 值来代替上述梯度,也就是将 LambdaRank 算法与 MART 算法结合起来,是一种能够支持非平滑损失函数的学习排序算法。
首先是RankNet,RankNet和BPR非常像。创新之处都在于,原本Ranking常见的评价指标都无法求梯度,因此没法直接对评价指标做梯度下降,而它们将不适宜用梯度下降求解的 Ranking 问题,转化为对偏序概率的交叉熵损失函数的优化问题,从而适用梯度下降方法。
RankNet 的终极目标是得到一个带参的算分函数:
$$
s = f(x; w)
$$
于是,根据这个算分函数,我们可以计算物品 $x_i$ 和 $x_j$ 的得分 $s_i$ 和 $s_j$。
$$
s_i = f(x_i; w)\quad s_j = f(x_j; w)
$$
然后根据得分计算二者的偏序概率:
$$
P_{ij} = P(x_i \rhd x_j) = \frac{1}{1 + \exp\bigl(-\sigma \cdot (s_i - s_j)\bigr)}
$$
其中,$\sigma$是Sigmoid函数的参数,决定了Sigmoid曲线的形状。(不得不说,作者定义的这个Sigmoid函数的参数太坑爹了,正常大家会用$\sigma$来表示Sigmoid函数,此处却拿来表示Sigmoid函数的参数,原论文写成了$\sigma (s_i - s_j)$,一开始以为是最外面的Sigmoid函数里头又嵌套了个Sigmoid函数,结果看了大半天,才发现此处的$\sigma$只是个参数,故本文还是加上$\cdot$点乘符号来区分 )
再定义交叉熵为损失函数:
$$
\begin{aligned}
L_{ij} &=
-\bar{P}_{ij}\log P_{ij} - (1 - \bar{P}_{ij})\log (1 - P_{ij}) \\
&= -\frac{1}{2}(1+S_{ij})log P_{ij} -\frac{1}{2}(1-S_{ij}) log(1-P_{ij}) \\
&= -\frac{1}{2}S_{ij}(\log P_{ij} - \log(1-P_{ij})) -\frac{1}{2}(log P_{ij} + \log(1-P_{ij}))\\
&= -\frac{1}{2}S_{ij}\log(\frac{P_{ij}}{1-P_{ij}}) - \frac{1}{2} \log (P_{ij}(1-P_{ij})) \\
&= -\frac{1}{2}S_{ij} \cdot \sigma \cdot (s_i-s_j) - \frac{1}{2}\log ( \frac{\partial P_{ij}}{\partial (\sigma \cdot (s_i - s_j))})\\
&= -\frac{1}{2}S_{ij} \cdot \sigma \cdot (s_i-s_j) - \frac{1}{2} \Bigl(-\sigma \cdot (s_i-s_j)-2\log (1+exp(-\sigma \cdot (s_i-s_j) ))\Bigr) \\
&=\frac12 (1 - S_{ij})\cdot \sigma \cdot (s_i - s_j) + \log\Bigl\{1 + \exp\bigl(-\sigma \cdot (s_i - s_j)\bigr)\Bigr\}
\end{aligned}
$$
上式利用了性质,$P=\frac{1}{1+e^{-x}} \rightarrow x=log (\frac{P}{1-P}), P(1-P)=\frac{\partial P}{\partial x}$。
上式是单个样本的损失,$S_{ij}=\{1,-1,0\}$是标签,$\bar{P}_{ij}$是物品$i$比$j$排序靠前的真实概率,即,$i \rhd j$($S_{ij}=1$)则为1,$j \rhd i$($S_{ij}=-1$) 为0,否则为1/2($S_{ij}=0$)(这个概率定义也是不同于BPR的一个地方)。则:$\bar{P}_{ij}=\frac{1}{2}(S_{ij}+1)$.
最后可以进行梯度下降:
$$
w_k \to w_k - \eta\frac{\partial L}{\partial w_k}.
$$
注意,和BPR一样,算法函数$f(x_i; w)$可以取任何模型,如GBDT、DNN、LR等。
在介绍LambdaRank的动机之前,我们从一张图从Intuition的角度来考察RankNet学习过程中,列表的排序变化。
这里每条横线代表一个物品,其中蓝色的表示相关的物品,灰色的则表示不相关的物品。在某次迭代中,RankNet 将物品的顺序从左边变成了右边。于是我们可以看到:
这启发我们,能不能直接定义关于排序指标的梯度呢?
此时LambdaRank登场。LambdaRank是一个经验算法,它不是通过显示定义损失函数再求梯度的方式对排序问题进行求解,而是分析排序问题需要的分数$s$的梯度的物理含义,直接定义梯度,即Lambda梯度。只希望$L$对$s$的梯度可以按照理想NDCG指标的方向走。
首先看下RankNet的梯度:
$$
\frac{\partial L}{\partial w_k} =
\sum_{(i, j) \in P}\frac{\partial L_{ij}}{\partial w_k} =
\sum_{(i, j) \in P}
\frac{\partial L_{ij}}{\partial s_i}\frac{\partial s_i}{\partial w_k}
+
\frac{\partial L_{ij}}{\partial s_j}\frac{\partial s_j}{\partial w_k}
$$
不难证明:
$$
\frac{\partial L_{ij}}{\partial s_i} = \sigma \cdot \Biggl[\frac12(1 - S_{ij}) -\frac{1}{1 + \exp\bigl(\sigma \cdot (s_i - s_j)\bigr)}\Biggr] = -\frac{\partial L_{ij}}{\partial s_j}
$$
令,$\lambda_{ij}\mathrel{\stackrel{\mbox{def}}{=}} \frac{\partial L_{ij}}{\partial s_i} = -\frac{\partial L_{ij}}{\partial s_j}$.
则RankNet梯度写作:
考虑对于有序对 $(i,j)$,有 $S_{ij}=1$,于是有简化,
$$
\lambda_{ij}= \frac{-\sigma}{1 + \exp\bigl(\sigma \cdot (s_i - s_j)\bigr)}
$$
在此基础上,考虑评价指标$Z$(比如 NDCG,$\Delta |NDCG|$)的变化:
$$
\lambda_{ij}= \frac{-\sigma}{1 + \exp\bigl(\sigma \cdot (s_i - s_j)\bigr)}\cdot \lvert\Delta Z \rvert
$$
其中$\Delta Z$表示将物品$i$和$j$位置相互调换之后重新计算得到的评估指标的差值(此时其他的物品顺序是不变的)。
稍微有点变化的是,我们希望对于$S_{ij}=1$,$\lambda_{ij}$越大越好。因此,此时的目标是最大化某个效用函数$C$,有:$\lambda_{ij}= \frac{\partial C(s_i-s_j)}{\partial s_i}$。则,此时需要使用梯度上升!
$$
w_k \to w_k + \eta\frac{\partial C}{\partial w_k}
$$
至于$C$长什么样没有显示定义,但是可以证明$C=-L \cdot |\Delta Z|$。
即$C$反了一下(相对于$L$),正好梯度更新也反一下(变成加法)。(个人认为这里也是非常啰嗦的)
考虑偏序对的对称性,对于单个物品$i$,
$$
\lambda_{i} = \sum_{(i, j) \in P}\lambda_{ij} - \sum_{(j, i) \in P}\lambda_{ij}
$$
每个物品移动的方向和趋势取决于其他所有与之 label 不同的物品(比它靠前或比它靠后都考虑)。$i$比越多的物品$j$真实排名更优,则$\lambda_i$越大;反之,则越小。
由于引入了排序指标,Lambda梯度更关注位置靠前的物品的排序位置的提升。有效的避免了下调位置靠前的物品的情况发生。LambdaRank相比RankNet的优势在于分解因式后训练速度更快,同时考虑了排序指标,直接对问题求解,效果更明显。上述优化背后真正的损失函数的探索工作也有些文章在研究,参考CIKM18: The LambdaLoss Framework for Ranking Metric Optimization,也可参见下文Advanced Topics中Ranking Metric Optimization一节。
最后轮到LambdaMART登场。其中,MART又称作GBDT,是是一种 Boosting 思想下的算法框架。它通过加法模型,将每次迭代得到的子模型叠加起来;而每次迭代拟合的对象都是学习率与损失函数梯度的乘积。这两点保证了 MART 是一个正确而有效的算法。MART 中最重要的思想,就是每次拟合的对象是损失函数的梯度。值得注意的是,在这里,MART 并不对损失函数的形式做具体规定。实际上,损失函数几乎只需要满足可导这一条件就可以了。这一点非常重要,意味着我们可以把任何合理的可导函数安插在 MART 模型中。LambdaMART 就是用LambdaRank中提出的Lambda梯度代替了损失函数的梯度,将 Lambda和MART结合起来罢了。
LambdaMART有很多有点:
AdaRank是Jun Xu(研一教我们网络数据挖掘的老师) etc.于2007年在SIGIR文章中SIGIR2007: AdaRank: A Boosting Algorithm for Information Retrieval提出的方法,目前引用量718。AdaRank利用Boosting来解决Listwise排序学习问题。思路来源于Adaboost算法,通过组合多个“弱”排序函数,得到“强”的排序函数,并且可以在“查询级别”考虑弱排序函数的构造和组合。
其损失函数推导如下:
$E$是排序评价指标函数,根据真实的排序标注$\boldsymbol{y}_i$(作为物品的相关性分数的参考),希望最大化模型$f$得到的排序结果$\pi(q_i,\boldsymbol{d_i},f)$。然后借助$e^{-x} \geq 1-x$不等式关系,转成指数损失函数。然后使用Adaboost中的加性模型$f$进行优化和学习,具体的优化过程和Adaboost几乎一样:根据误差不断调整样本的权重分布,不断更新加性模型。
更多排序学习模型参考维基百科列出的方法:Approach: Learning to Rank。
本节主要讨论排序学习的一些高级话题。
由于排序学习主要应用于大数据的场景,因此急需一个扩展性强的工具支持排序学习。到2018年12月之前,都不存在一个开源的工作能够大规模的进行排序学习,工业界一般都会自己搭建分布式系统来进行排序学习。幸运的是,Google于2018年12月初新开源了既支持开箱即用、又可扩展的TensorFlow库TF-Ranking,可用于排序学习。
TF-Ranking提供了一个统一的框架,包含了一系列state-of-arts排序学习算法,并提供了灵活的API,支持了多种特性,如:自定义pairwise 或 listwise 损失函数,评分函数,指标等;多物品联合评分;非平滑排序度量指标的直接优化;无偏的排序学习方法(下面会介绍到)。同时,TF-Ranking还能够利用Tensorflow提供的深度学习特性,如稀疏特征的embedding,大规模数据扩展性、泛化性等。
代码见:Github: TF-Ranking,论文见:TF-Ranking: Scalable TensorFlow Library for Learning-to-Rank,博客见:Blog: TF-Ranking。
多物品联合打分是最近刚刚提出的一种排序学习模型,见论文DAPA2019:Learning Groupwise Scoring Functions Using Deep Neural Networks。传统的排序学习模型单个物品独立的被打分(pairwise当中,物品也是单独被打分,再进行比较的),但实际应用过程中,也会关注跨物品之间的比较,每一个物品的相关性会取决于整个物品列表的分布。
在这篇文章中,作者提出了一个groupwise scoring functions(GSFs),该函数接收一组物品作为输入,通过考察该组物品的feature级别之间的联系,来同时进行打分,该函数输出每个物品相对于组内其他物品的相对得分,最后采用投票机制将该物品所在的不同组中其得分累加作为该物品的最终得分。
令输入物品的数量为n。思想很简单,就是把所有物品的特征concat在一起,通过MLPs输出不同物品的得分值,这个是全局的对比模型。但是作者做了一些改进,让模型输出和输入物品的顺序无关;捕捉物品之间的局部对比模式。对于第二个改进,只需要限制一次同时进行对比的物品的数量为m。对于第一个改进,作者从n个文档列表中取出所有m个物品之间的排列组合Permutations,将所有的排列组合得到的组中,物品出现过的组的得分加起来作为该物品的最终评得分,这样就和输入顺序无关。得到不同物品的最终得分后,最后定义真实标签和预测得分之间的损失时,作者还是使用了pairwise loss,不过该模型确实能同时输出n个不同输入物品的得分。由于排列组合的复杂度较高,作者在训练过程中做了一些技巧来降低复杂度,比如对n个物品先做shuffle,然后取shuffle后的子序列作为组,即,每个位置$i \sim i+m$之间的物品构成一组。同时,pairwise模型是该模型的特例,当n=2且m=1时就退化为pairwise模型。模型架构如下图所示:
前面我们提到,不管是pointwise还是pairwise都不能直接优化排序度量指标。在listwise中,我们通过定义Lambda梯度来优化排序度量指标,如LambdaRank和LambdaMART,然后Lambda梯度是一种经验性方法,缺乏理论指导。最近,有研究者提出了优化排序度量指标的概率模型框架,叫做LambdaLoss(CIKM18: The LambdaLoss Framework for Ranking Metric Optimization),提供了一种EM算法来优化Metric驱动的损失函数。文中提到LambdaRank中的Lambda梯度在LambdaLoss框架下,能够通过定义一种良好、特殊设定的损失函数求解,提供了一定的理论指导。
传统的pointwise或pairwise损失函数是平滑的凸函数,很容易进行优化。有些工作已经证明优化这些损失的结果是真正排序指标的界,即实际回归或分类误差是排序指标误差(取反)的上界(bound)。但是这个上界粒度比较粗,因为优化不是metric驱动的。
然而,直接优化排序指标的挑战在于,排序指标依赖于列表的排序结果,而列表的排序结果又依赖于每个物品的得分,导致排序指标曲线要么不是平坦的,要么不是连续的,即非平滑,也非凸。因此,梯度优化方法不实用,尽管有些非梯度优化方法可以用,但是时间复杂度高,难以规模化。为了规模化,目前有3种途径,1是近似法,缺点是非凸,容易陷入局部最优;2是将排序问题转成结构化预测问题,在该方法中排序列表当做最小单元来整体对待,损失定义为实际排序列表和最理想排序列表之间的距离,缺点是排序列表排列组合数量太大,复杂度高;3是使用排序指标在迭代过程中不断调整样本的权重分布(回顾下WRAP就是这种,LambdaRank也属于这种,$|\Delta NDCG|$就可以看做是权重。),这个方法优点是既考虑了排序指标,同时也是凸优化问题。
本文的动机之一就是探索LambdaRank中提出的Lambda梯度真正优化的损失函数是什么。文章通过提出LambdaLoss概率框架,来解释LambdaRank可以通过EM算法优化LambdaLoss得到。进一步,可以在LambdaLoss框架下,定义基于排序和得分条件下,metric-driven的损失函数。
假定给定文档集合下,不同文档的模型预测得分$\boldsymbol{s}=\Phi(\boldsymbol{x})$确定了一个关于所有可能排序排列组合的分布,即$p(\pi|\boldsymbol{s})$,其中$\pi$是其中一种排序列表结果。也就是说,模型$\Phi$可以得到多种排序结果,而每种排序结果下,文档真实标签$\boldsymbol{y}$的似然$p(\boldsymbol{y}|\boldsymbol{s},\pi)$是不同的(pairwise loss只和$\boldsymbol{s}$有关,而Lambda梯度不仅和$s$有关,还和位置(即排序)有关)。我们将$\pi$看做隐变量,则真实标签$\boldsymbol{y}$的似然关于该隐变量分布的期望如下:
$$
p(\boldsymbol{y}|\boldsymbol{s})=\sum_{\pi \in \Pi} p(\boldsymbol{y}|\boldsymbol{s},\pi)p(\pi|\boldsymbol{s})
$$
我们的目标是学习排序模型$\boldsymbol{s}=\Phi(\boldsymbol{x})$来最大化该期望$p(\boldsymbol{y}|\boldsymbol{s})$(可以类比EM算法中的$P(X|\Theta)$,我们这里的$\boldsymbol{y}$是EM中的$X$,因为我们要最大化的是文档的标签的似然值)。
则负对数似然为(考察了List-Level的损失):
$$
l(\boldsymbol{y},\boldsymbol{s})= -\log_2 P(\boldsymbol{y}|\boldsymbol{s})=-\log_2 \sum_{\pi \in \Pi} p(\boldsymbol{y}|\boldsymbol{s},\pi)p(\pi|\boldsymbol{s})
$$
这个式子有两个核心要素,1是排序分布$p(\pi|\boldsymbol{s})$,2是似然$P(\boldsymbol{y}|\boldsymbol{s},\pi)$。这两个核心要素取不同形式,会得到不同的损失函数。
1) 似然$P(\boldsymbol{y}|\boldsymbol{s},\pi)$不同形式:
Logistic: $p(y_i >y_j|s_i,s_j)=\frac{1}{1+e^{-\sigma \cdot (s_i-s_j)}}$,此时$\boldsymbol{y}$和$\pi$没关系,只和得分之间的相对关系有关。则$\forall \pi$,$P(\boldsymbol{y}|\boldsymbol{s},\pi)=P(\boldsymbol{y}|\boldsymbol{s})$,故负对数似然求和公式中可以把该似然提取出来,排序列表分布求和为1,则损失等价于Logistic Loss,$l(\boldsymbol{y},\boldsymbol{s})=-\log_2 p(\boldsymbol{y}|\boldsymbol{s})=\sum_{y_i>y_j} \log_2(1+e^{-\sigma \cdot (s_i-s_j)})$,注意$\sigma$是参数。
generalized logistic: $p(y_i >y_j|s_i,s_j, \pi_i, \pi_j)=\frac{1}{1+e^{-\sigma \cdot (s_i-s_j)}}^{|\Delta \text{NDCG}_{ij}|}$。这是带指数的广义Logistic分布。此处使用了$|\Delta \text{NDCG}_{ij}|$代表排序列表$\pi_i$和$\pi_j$(交换i和j)的NDCG值的差。下面会证明通过EM算法可以根据该式得到LambdaRank的损失函数。
借鉴上述的思想,可以得到如下1个文档级别的训练样本的损失函数:(我将其称为 ranking-sensitive pairwise loss),
$$
l(\boldsymbol{y},\boldsymbol{s})=-\sum_{y_i>y_j}\log_2 \sum_{\pi}p(y_i>y_j|s_i,s_j,\pi_i,\pi_j)p(\pi|\boldsymbol{s})
$$
2) 至于排序分布$p(\pi|\boldsymbol{s})$,作者举了上述LambdaLoss框架中,使用高斯分布作为排序分布时,等价于我们熟知的SoftRank方法,而使用Plackett-Luce作为排序分布时,等价于我们熟知的ListNet算法。
使用EM算法优化上述损失:
C是抽样得到的所有的训练样本(每个训练样本都是文档列表级别的,由$(\boldsymbol{y},\boldsymbol{x},\pi)$构成,也可以理解为E步会对每个原始文档集合$\boldsymbol{x}$排序($\pi$),得到的所有文档集合排序结果构成M步的训练样本),M步在C上求期望损失。
其中,
$$
l_C(\boldsymbol{y},\boldsymbol{s})=-\sum_{\pi}p^{(t)}(\pi|\boldsymbol{s}) \log_2 p(\boldsymbol{y}|\boldsymbol{s},\pi) \approx -\frac{1}{K} \sum_{k=1}^K \log_2 P(\boldsymbol{y}|\boldsymbol{s},\pi^{k})
$$
其中,$\pi^{k}$是根据分布$p^{(t)}(\pi|\boldsymbol{s})$采样得到的。
更特殊的,直接使用hard assignment distribution来表示$p^{(t)}(\pi|\boldsymbol{s})$。
$$
H(\hat{\pi}|\boldsymbol{s})=1 \text{and} H(\pi|\boldsymbol{s})=1 \forall \pi \neq\hat{\pi}
$$
其中,$\hat{\pi}$是按照得分$\boldsymbol{s}$降序排序得到的列表。(此时EM算法和K-means中的优化方法一样,可以将K-means中E步将样本归入到某个类别簇 类比为 此处对文档列表排一个序,每种序对应一个类别,类别是隐向量;将文档按照得分降序得到唯一的序类别于K-means中将某个样本硬性(hard)的归入到一个具体的类。)
此时,可以通过推导下述负对数似然损失函数得到LambdaRank的损失函数:
$$
l(\boldsymbol{y},\boldsymbol{s})=-\sum_{y_i>y_j}\log_2 \sum_{\pi}p(y_i>y_j|s_i,s_j,\pi_i,\pi_j)H(\pi|\boldsymbol{s})
$$
E步:根据当前模型计算所有文档的得分,然后按照得分降序排序,得到排序结果$\hat{\pi}$。
M步:所有Complete的文档列表的损失简化为:
$$
\begin{aligned}
l_C(\boldsymbol{y},\boldsymbol{s})&=
-\sum_{\pi}p^{(t)}(\pi|\boldsymbol{s}) \log_2 p(\boldsymbol{y}|\boldsymbol{s},\pi) \\
&= -\sum_{\pi} H(\pi|\boldsymbol{s})\log_2 p(\boldsymbol{y}|\boldsymbol{s},\pi) \\
&= -\log_2 p(\boldsymbol{y}|\boldsymbol{s}, \hat{\pi})
\end{aligned}
$$
进一步,代入generalized logistic可得到:
$$
\begin{aligned}
l_C(\boldsymbol{y},\boldsymbol{s}) &= -\log_2 p(\boldsymbol{y}|\boldsymbol{s}, \hat{\pi}) \\
&= -\sum_{y_i>y_j} \log_2 p(y_i>y_j|s_i,s_j,\hat{\pi}_i,\hat{\pi}_j) \\
&=\sum_{y_i>y_j}|\Delta \text{NDCG}_{ij}| \log_2(1+e^{-\sigma \cdot (s_i-s_j)})
\end{aligned}
$$
因此,上式是LambdaRank潜在的损失函数。
作者进一步给出了定义Metric-driven Loss的方法:
LamdaLoss中一个最具吸引力的特性是,似然部分$p(\boldsymbol{y}|\boldsymbol{s}, \pi)$既考虑了得分,又考虑了排序。这提供了一个沟通依赖于得分的传统损失函数(e.g., pairwise loss)和依赖于排序的排序度量指标(e.g., NDCG)的桥梁。
作者给出一些常用的排序度量指标的metric-driven Loss。主要利用0-1Loss的上界为Logistic Loss这一性质。即:
$$
\mathcal I_{s_i<s_j} \leq \log_2(1+e^{-\sigma \cdot(s_i-s_j)})
$$
作者推导了Average Relevance Position($ARP=\sum_{i=1}^n y_i \cdot i$),ARP是cost-based function,越小越好。
$$
\begin{aligned}
\text{ARP}&=\sum_{i=1}^n y_i (\sum_{j=1}^n \mathcal{I}_{s_i < s_j} +1) \\
&=\sum_{i=1}^n\sum_{j=1}^n y_i \mathcal{I}_{s_i < s_j} + C_1\\
&\leq \sum_{i=1}^n\sum_j^n y_i \log_2(1+e^{-\sigma \cdot(s_i-s_j)}) + C_1
\end{aligned}
$$
此时在LambdaLoss框架下的,相应的损失函数为,$\text{APR-LOSS1}$:
$$
l(\boldsymbol{y},\boldsymbol{s})=-\sum_{i=1}^n\sum_{j=1}^n \log_2 \sum_{\pi}(\frac{1}{1+e^{-\sigma \cdot (s_i-s_j)}})^{y_i} H(\pi|\boldsymbol{s})
$$
上述推导有2个技巧:1) 把ranking中的position $i$写成关于$\mathcal I_{s_i<s_j}$的形式,这样可以利用0-1损失上界为Logistic损失这一性质。2) 把Metric转成Metric-driven loss过程中,先整理成generalized logistic形式,这个就是排序分布$p(\pi|\boldsymbol{s})$,再利用EM算法中概率排序分布取hard assignment distribution,将generalized logistic进一步改写成$\sum_{\pi} p(\pi|\boldsymbol{s}) H(\pi|\boldsymbol{s})$;再取负对数得到损失。另外文中还给出了ARP的另一种损失。
作者还推导了NDCG的LambdaLoss,由于NDCG是gain-based function,故先转成Loss:
$$
\text{NDCG}_{\text{cost}}=\sum_{i=1}^n G_i - \sum_{i=1}^n \frac{G_i}{D_i} =\sum_{i=1}^n \frac{G_i}{D_i}(D_i-1)=\sum_{i=1}^n G_i(1-\frac{1}{D_i})
$$
其中,$G_i=\frac{2^{y_i}-1}{max_\text{DCG}}$,对于给定的文档列表,$G_i$是个常数 (和排序无关,$G_i$公式中分子只和标签$y_i$有关, 分母是最优的DCG值,是个常数。所以可以直接加到损失函数中);第二项其实就是NDCG($D_i=log_2(1+i)$, $\text{NDCG}=\sum_{i=1}^n \frac{G_i}{D_i}$),这么定义是因为下文推导方便。
因为:$D_i − 1 = \log_2 (1 + i) − 1 ≤ i − 1$,有:
$$
\begin{aligned}
\text{NDCG}_{\text{cost}} &=\sum_{i=1}^n \frac{G_i}{D_i}(D_i-1)\\
& \leq \sum_{i=1}^n \frac{G_i}{D_i}(i-1) \\
& \leq \sum_{i=1}^n \frac{G_i}{D_i}\sum_{j=1}^n\mathcal{I}_{s_i < s_j} \\
& \leq \sum_{i=1}^n \frac{G_i}{D_i} \log_2(1+e^{-\sigma \cdot (s_i-s_j)})
\end{aligned}
$$
同理可得,LmabdaLoss损失为:
$$
l(\boldsymbol{y},\boldsymbol{s})=-\sum_{i=1}^n\sum_{j=1}^n \log_2 \sum_{\pi}(\frac{1}{1+e^{-\sigma \cdot (s_i-s_j)}})^{\frac{G_i}{D_i}} H(\pi|\boldsymbol{s})
$$
上述问题是$i$太大时,上界太松了。因此,作者又提出了另一种损失,利用了性质(这个性质有待证明)$1-\frac{1}{D_i}=\sum_{j=1}^{i-1}|\frac{1}{D_{|i-j|}}-\frac{1}{D_{|i-j|}+1}|=\sum_{j=1}^{i-1} \delta_{ij}$。最后可以推导出NDCG第二种形式的损失(关键):
$$
l(\boldsymbol{y},\boldsymbol{s})=-\sum_{y_i>y_j} \log_2 \sum_{\pi}(\frac{1}{1+e^{-\sigma \cdot (s_i-s_j)}})^{\delta_{ij}|G_i-G_j|} H(\pi|\boldsymbol{s})
$$
上式的好处在于,可以通过重新定义$G_i$和$D_i$来扩展出很多NDCG-like metrics的LambdaLoss。也可以用来优化binary情况下的,MRR-like metrics。
作者还推导出上述得到的LambdaRank Loss优化结果实际上是优化如下metric的上界,
$$
\text{Metric}_{\text{LambdaRank}}=\sum_{i=1}^n G_i \sum_{j=1}^{i-1}|\frac{1}{D_i}-\frac{1}{D_j}|
$$
可以证明,使用LambdaLoss优化该metric得到的$\text{NDCG}_{\text{cost}} \leq \text{Metric}_{\text{LambdaRank}}$,因此LambaLoss结果更好。
另外,上述讨论都基于hard assignment $\hat{\pi}$。作者也考虑了soft assignment,并作为下一步工作。
先前的研究表明,受到排版的影响,给定排序的项目列表,无论其相关性如何,用户更有可能与前几个结果进行交互,这实际上是一种位置偏差(Position Bias),即,被交互和用户真正喜欢存在差距,因为靠前,人们更倾向于交互,而很多靠后未点击的物品,用户可能更感兴趣,倘若将这些靠后的物品挪到前面去,那用户交互的概率可能会更高。 这一观察激发了研究人员对无偏见的排序学习(Unbiased Learning-to-Rank)的兴趣。常见的解决途径包括,对训练实例重新赋权来缓解偏差;构造无偏差损失函数进行无偏排序学习;评估时使用无偏度量指标等。
这里介绍两篇近期研究无偏排序学习的论文:
在WSDM17的文章中,作者提到目前解决位置偏差的方法主要包括,考察相对偏差(点击和未点击之间的偏好差异),但是问题是也只能针对已经展示的物品列表构建偏序对,仍然存在偏差;显示建模概率点击模型(把位置和上下文偏差考虑了,例如使用latent变量),但问题是为了估计模型参数,同样的查询需要进行很多次(数据充足)才行准确估计,和实际情况不相符,不够使用;在实际展示过程中,引入随机探索机制(exploration),例如使用bandit feedback,这样可以解决偏差问题,但是这可能降低模型的推荐质量。
在本文中,作者提出了一个有理论指导,又有经验保障的方法,从观测的隐式反馈中进行排序学习,可以克服上述限制。本文借鉴了因果推理中反事实估计技术(可参考这个回答IPS:inverse propensity scoring),开发了一种可被证实的、无偏的估计器,可以从有偏差的反馈数据中进行学习并评估排序性能。基于该估计器,作者提出了一种针对LTR的倾向加权经验风险最小化(Propensity-Weighted Empirical Risk Minimization,ERM)方法,作者将该方法应用到一种新的排序学习算法中,称为Propensity SVM-Rank。
作者首先在文章中提出了基于Inverse Propensity Scoring(IPS)的Partial-Info Learning-to-Rank。这部分内容其实并没有太多的新意,不过是把从Multi-armed Bandit领域用IPS来做Unbiased Offline Evaluation的思路借鉴过来。不过文章指出了一个核心问题,那就是如何来估计这些Propensity Probability,也就是当前系统(推荐系统、搜索引擎)选择各个文档的概率。传统上,特别是以前的Unbiased Offline Evaluation基于随机产生文档顺序,因此这些Propensity Probability都是Uniform分布的。但这样的设计在现实中是不可能的,因为Uniform分布的文档,用户体验会变得很差。这篇文章采取了这样一个思路,文章假设现在系统的“偏差”可以通过一个Position-based Click Model with Click Noise(PCMCN)来解释。简单说来PCMCN就是来对用户查看一个排序文档进行建模,从而达到Propensity Probability能够被方便预测,这么一个目的。为了能够PCMCN,作者们还提出了一个基于交换两个位置文档的实验方法,用于收集数据。值得肯定的是,仅仅交换两个位置文档的方法,相比于以前的Uniform的方法,要更加注重用户体验。文章的实验部分展示了在人工数据以及真实系统中的表现。总体说来,能够对“有偏差”的用户数据建模,比直接利用这些数据,训练的模型效果要来的好得多。
WSDM2018这篇文章指出传统解决位置偏差的方法都是在查询结果上添加随机扰动因素,然后展示给用户,根据收集到的用户反馈估计学习点击偏差模型,这样的问题是用户体验较差。作者在文中提出了一种不需要依赖这种随机化,只从常规的反馈数据中学习点击偏差模型的方法,该方法是基于回归的EM算法(regression-based Expectation-Maximization (EM) algorithm)。
简单来说,先使用伯努利变量$O$来表示一个相关的文档是否被观测到(通俗点就是,能不能判断一个文档和查询是不是相关的;能确定相关或者不相关,那么就代表被观测到了;不能确定就代表没观测到),$O$受到很多因素影响,如位置,整个文档列表等,使用$P(O_i=1)$表示被观测的倾向性(Propensity)。然后作者利用我们在上文提到的IPS或IPW(Inverse Propensity Weighting)对不同文档赋权重$w_i=\frac{1}{P(O_i=1)}$,即越不容易被展示,其权重越大(这是因果推理中的思想,即一个事件发生概率很低,结果却发生了,那这个事件的信息量是很大的)。这样可以对ARP(上一小节提到的)损失进行加权:
$$
\begin{aligned}
\sum_{i \in \pi:o_i=1,r_i=1} w_i \cdot i &= \sum_{i \in \pi:o_i=1,r_i=1} w_i \cdot (\sum_{j \in \pi} \mathcal{I}_{s_j>s_i}+1) \\
&=\sum_{i \in \pi:o_i=1,r_i=1} \sum_{j\in \pi} w_i \cdot \mathcal{I}_{s_j>s_i} + const
\end{aligned}
$$
其中,$w_i$就是IPW。Logistic Loss或Hinge Loss是上述损失的上界,因此可以采用通常的pairwise损失来学习。这里的关键转成了估计倾向性(Propensity)$P(O_i=1)$。
作者在常规的隐式反馈数据集上($(c,q,d,k)$,$c$代表点击与否,$q$是查询,$d$是文档,$k$是位置),构建一个概率点击模型,
$$
P(C = 1|q,d,k) = P(E = 1|k) · P(R = 1|q,d)
$$
即给定查询、文档、位置条件下(某查询$q$返回的结果中排在某位置$k$的文档$d$),点击的概率受到两方面影响,对于某个位置$k$用户examine的概率$\theta_k=P(E=1|k)$以及该文档和查询相关的概率$\gamma_{q,d}=P(R=1|q,d)$。
并且可以证明,Propensity中的观测变量$O$和点击模型中Examine变量$E$是等价的(当用户examine了某个文档($E=1$),那么文档相关性与否完全可以根据用户是否点击来推测,点了说明相关,没点说明不相关,则$O=1$;$E=0$时,这个文档可能相关也可能不相关,则$O=0$)。
因此,思路就是可以利用实际的点击数据,最大化点击数据的似然,并且把相关性变量$R$、Examine变量$E$都看做是隐变量,使用EM算法求解,E步固定模型,估计隐变量后验分布$P(E,R|C,q,d,k)$;M步固定隐变量后验分布,最大化对数似然($\log P(\mathcal{L}) = c \log \theta_k \gamma_{q,d} + (1 − c) \log(1 − \theta_{k} \gamma_{q,d}), \mathcal{L}=\{(c,q,d,k)\}$)。
另外,作者提出了对标准的EM算法的改进,把文档和查询的特征融入到模型中,使用一个回归模型来估计文档和查询之间的相关性$\gamma_{q,d}=f(\boldsymbol{x}_{q,d})$。$f$可以使用任意回归模型(当相关性是多值时),也可以使用GBDT。如果是二值的,也可以使用任意的判别式模型,如逻辑回归。
通过上述方法,既可以学习$\theta_k=P(E=1|k)=P(O=1)$,还可以学习出相关性函数$f(\boldsymbol{x})$。这个过程是单独进行的。
接着,再使用估计到的Propensity$P(O_i=1)$代入到ARP损失(或其他NDCG-like、MRR-like),使用hinge pairwise loss或logistic pairwise loss进行学习。
上述两个过程是分离开的。个人认为第二个过程可以使用LambdaLoss中的方法进行改进,将LambdaLoss改进成Unbias Ranking Metric Optimization。
本文对实践中表现较好的排序学习模型进行了调研,包括Pointwise Ranker,Pairwise Ranker以及Listwise Ranker。最后,还讨论了关于排序学习的一些高级话题,例如排序学习的规模化工具、多物品联合打分、排序度量指标优化方法、无偏排序学习等。
未来的工作可以考虑实现其中的一些模型,并应用于实际项目中。针对项目的实际场景,可以进一步考虑对已有模型进行改进,例如可以对排序学习中的一些高级话题进行探索,并期望将解决方案融入到已有模型中,使得最终的排序学习模型产生的结果在实践中表现更好,能够既注重用户体验、又能够关注到不同物品之间的公平性、结果更加多样性等等。
WWW2008: Slides: Learning to Rank for Information Retrieval
SIGIR2016: Slides: Online Learning to Rank for Information Retrieval
ADKDD14: Practical Lessons from Predicting Clicks on Ads at Facebook
ICDM2010: Factorization Machine
RecSys2016: Deep Neural Networks for YouTube Recommendations
关于’Deep Neural Networks for YouTube Recommendations’的一些思考和实现
RecSys2016: Wide & Deep Learning for Recommender Systems
IJCAI2017: DeepFM: A Factorization-Machine based Neural Network for CTR Prediction
ADKDD2017:Deep & Cross Network for Ad Click Predictions
SIGKDD2012: Optimizing Search Engines using Clickthrough Data
UAI2009: BPR: Bayesian Personalized Ranking from Implicit Feedback
IJCAI2011: WSABIE: Scaling Up To Large Vocabulary Image Annotation
ICLR2016: Session-based Recommendations with Recurrent Neural Networks
WWW2017: Collaborative Metric Learning
WWW2018: Latent Relational Metric Learning via Memory-based Attention for Collaborative Ranking
SIGIR2018: Adversarial Personalized Ranking for Recommendation
WSDM2018: Neural Personalized Ranking for Image Recommendation
ICML2005: RankNet: Learning to Rank using Gradient Descent
NIPS2006: LambdaRank: Learning to Rank with Non-Smooth Cost Functions
Inf Retrieval2010: LambdaMART: Adapting Boosting for Information Retrieval Measures
MSR-TR2010: From RankNet to LambdaRank toLambdaMART: An Overview
SIGIR2007: AdaRank: A Boosting Algorithm for Information Retrieval
TF-Ranking: Scalable TensorFlow Library for Learning-to-Rank
DAPA2019:Learning Groupwise Scoring Functions Using Deep Neural Networks
CIKM2018: The LambdaLoss Framework for Ranking Metric Optimization
WSDM2008:SoftRank: Optimizing Non-Smooth Rank Metrics
ICML2007:ListNet:Learning to Rank: From Pairwise Approach to Listwise Approach
WSDM2017: Unbiased Learning-to-Rank with Biased Feedback
WSDM2018: Position Bias Estimation for Unbiased Learning to Rank in Personal Search
最后,欢迎大家关注我的微信公众号,蘑菇先生学习记。会定期推送关于算法的前沿进展和学习实践感悟。
]]>