浅析文本摘要算法(Document Summarization)

概述

文本摘要算法,指的是在一篇文章中,摘要出核心观点的算法。主流的文本摘要算法生成一篇文章的摘要,摘要长度在3~4句话左右。

历史

在深度学习算法出现之前,人们使用了贪心算法、图算法来研究文本摘要。同时,为了衡量一段生成的摘要是否和标准摘要(gold summary)相似,学术界提出了一系列标准,这些标准现在广泛用于文本摘要算法的模型评价,其中最为常用的就是ROUGE – A Package for Automatic Evaluation of Summarieszz中提到的ROUGE-x系列算法。

深度学习提出后,LSTM/GRU作为摘要生成的强有力工具,一举打破传统算法的效果。最为主流的摘要生成模型是基于抽取式和生成式的,这两种模型将在后面详述。

随着深度学习的发展,很多其他算法也被引入。如一些文章使用强化学习,直接尝试训练一个能够获得最高ROUGE得分的模型。一些文章借助机器视觉方向的研究,优化模型结构。也有文章训练模型,判断句子相对于文章的重要性,进而间接实现摘要提取。

抽取式和生成式文本摘要

既然是摘要,那么显然,摘要中很大一部分都应该是原文中出现过的词语。同时,基于语法的考虑,也需要引入一些没有在原文中出现的词。

这时,就引出了文本摘要算法的两大学派—— 抽取式(extractive)和生成式(abstractive)。

  • extractive算法希望直接从文本中,抽出若干词语,连成一句话。词汇的抽取通常使用循环神经网络,配合注意力机制。得到“下一个词”可能是谁的概率分布。
  • abstractive算法希望从词汇表中,直接选出“下一个词”。

不论是abstractive的文本摘要,还是extractive的文本摘要,模型都由两个部分构成的,即一个编码器(encoder)和一个解码器(decoder)。

  • 对于编码器来说,通常都是将输入文本导入一个循环神经网络,生成出一个上下文特征向量c
  • 对于解码器来说,通常也是使用一个循环神经网络。以编码器生成的表征原文的上下文特征向量c,和之前生成的词汇{y_1, y_2, \dots, y_t},生成出摘要的下一个词y_t

数据集

当前研究人员多使用CNN/DailyMail作为数据集,在该数据集中,每一组数据是一个新闻稿,平均每篇文章39句话。同时还有一个“多句”的摘要。

著名论文

Get To The Point: Summarization with Pointer-Generator Networks

这篇文章提出了一个Pointer-Generator模型,既可以通过Pointer拷贝原文的文字,也可以通过Generator生成不存在原文中的文本。这两个模型通过一个开关p_{gen}进行选择——

P(w) = p_{gen} P_{vocab}(w) + (1-p_{gen})\sum_{i:w_i=w} a_i^t

其中P_{vocab}表示从词汇表中选择一个单词的概率分布,而a_i则是从原文选择第i个词汇的概率分布。

在此基础上,本文还提出了一种称之为覆盖率机制(coverage mechanism)的方式,用以解决抽取式摘要中最容易出现的内容重复的问题。

SummaRuNNer: A Recurrent Neural Network based Sequence Model for Extractive Summarization of Documents

这篇文章核心目标是仅仅是在“句子级别”进行摘要,即从原文中选择若干适合作为摘要的句子。该文章使用两层GRU,依次在“词语”级别和“句子”级别总结信息,最终获得一个可以表征全局性质的向量d。接着,再参考句子级别的特征向量s_i、全局特征向量d、以及RNN的隐状态h_i,生成对于句子的评分。

Ranking Sentences for Extractive Summarization with Reinforcement Learning

这篇文章的核心目标是给一篇文章的句子按照与主题的相关度进行排序,文章指出,在之前的方法中,通常是训练模型,使得对于每一个句子的估价尽量靠近一个指定的ground-true。但提升对于ground-true的近似并不一定能够提高模型的ROUGE评分。因此,文章提出使用强化学习的方式,直接学习句子的label,进一步最大化ROUGE评分(注意,这里ROUGE评价指标是不可导的,因此才需要用到强化学习)。

Neural Document Summarization by Jointly Learning to Score and Select Sentences

这篇文章仍然是句子级别摘要的算法,其思想借鉴了MMR算法,在MMR算法中,借助一个建立在语句集合中的评分函数r(S),迭代选择能够最大化加入后r(S')值的句子。即

g(S_i) = r(S_{t-1} \cap {S_i}) - r(S_{t-1})

g(S_i)可以看做在选择了S_{t-1}后,第i篇文章S_i的评分。使用神经网络结构去学习g(S_i)即可实现——能够参考之前选取句子集合信息的语句选择算法。

BanditSum: Extractive Summarization as a Contextual Bandit

这篇文章也是借助强化学习尝试拟合文本的ROUGE得分,并且提出了新的结构用于防止摘要倾向于前面的句子。

Bottom-Up Abstractive Summarization

这篇文章与Pointer-Generator相似,不过为了解决前文中文本拷贝倾向于拷贝整句话的bug。在输入给Pointer-Generator模型之前,先给输入的文本加了一个mask,过滤掉其中一部分,这样就导致文本不再倾向于拷贝连续的内容。

DeepChannel: Salience Estimation by Contrastive Learning for Extractive Document Summarization

这篇文章训练模型,拟合P(D|S),即给定摘要S,能够恢复原文D的概率。而函数P(D|S)的训练,可以借助文章D,摘要S,一句不重要的话S_2这三部分进行训练。生成P(D|S)后,再使用贪心算法构造摘要集合。

一句话解析最大边缘相关性算法(MMR, Maximal Marginal Relevance)

随着网络资源的丰富,找到和询问(query)最相关的一系列文本成为了学者们研究的问题。

之前的做法通常是直接计算逐个候选文本与询问的相关度。将前K大值对应的文档作为“最相关文档”输出出来。但是这种做法适用于那些候选文本集合较小,且只有少量文本与询问存在关联的情况。

但实际上,我们还有另一种场景,以搜索引擎为首的这类环境中,潜在的相关文档非常多,我们需要非常高的召回率(recall),并且尽量降低结果的冗余性(redundance)。在这种情况下,MMR就有用武之地了。

实际上MMR的算法核心思想可以用一句话解释——

A document has high mariginal relevance if it is both relevant to the query and contains minimal similarity to previously selected documents.

一个文章拥有高边缘相关性(MMR)当且仅当它与询问相关性高,而且与之前已经选出来的文章集合相关性低。

而使用公式化的表达如下——

MMR \overset{def}{=}  \underset{D_i \in R \backslash S}{Arg max} \left[ \lambda (Sim_1(D_i, Q) - (1-\lambda) \underset{D_j \in S}{max} Sim(D_i, D_j) \right]

其中,Q表示询问,D_i表示文档,S表示选择出来的相关文档集合,Sim表示任意一种文档相关性计算函数。

以上就是MMR的解释,MMR在文档摘要方面有很多应用。想要更细了解,可以参考文献 The Use of MMR, Diversity-Based Reranking for Reordering Documents and Producing Summaries

Learning Convolutional Neural Networks for Graphs

图卷积网络(Graph Convolutional Network),顾名思义,就是把图像处理中的卷积层运用到图上,图卷积网络能够处理如下两类问题[1]——

  • 给定一系列图作为训练集,可以训练出一个函数,该函数能够对未知的图进行分类或回归。
  • 给一张很大的图,学习图的表示函数(representation),并对于未知的图,推导出一些性质,诸如判断一个节点的类型,或是消失的边权等等。

回顾卷积神经网络,一个像素的特征值,来自于该层输入中,这个像素空间上临近点的像素特征。卷积神经网络的成功,从某种意义上来说,正式借助了这种隐含的空间特征。对于NLP也是同理

但是,对于大部分图而言,并没有这么好的特征可以利用,要将CNN迁移到图上面,需要解决这两个问题——

  • 找到一部分中间点,这些中间点将各自总结其邻域节点的特征。
  • 计算每个中间点临近图的正则化表示,即向量空间中的一个可以编码这个图的表示

定义术语

首先,需要定义图的节点的标号(labeling)和排名(ranking)。标号是一个给图上每个节点赋予一个权值的映射l(u)。而排序是将图上每一个节点权值从小到大排名后的排名映射r(u)。即满足对于任意u, v \in Vr(u)<r(v)当且仅当l(u)>l(v)

倘若r(u)函数和l(u)函数都是单射的,那么使用r(u)对于图中的节点编号进行置换,可以得到A^l(G)

上述定义其实是有道理的,假设l(u)是一个能够描述节点位置的函数,那么使用r(u)映射后的图G'可以用来当做一个图的标准化(Canonicalization)结构,这个结构能够用来比较两个图是否同构(Isomorphism)。

l(u)的最优化是NP的,但是可以构造出相对有效的l(u)——用距离“中心节点”的距离函数作为l(u),这里的“中心节点”是Node Sequence Selection函数的结果。

算法流程

Node Sequence Selection

为了对图进行卷积操作,我们需要定义卷积的stride和width。实际的算法非常简单,既然我们假设了r(u)函数能够有效刻画节点空间位置,那么在按照r(u)排序后的节点序列中,使用一个width大小stride步长的滑动窗口就可以完成节点的选择了。

Neighborhood Assembly

这一个步骤,试图对于上一步得到的若干个节点,分别找到一个大小为k的领域,这里用了简单的广度优先搜索算法。

Graph Normalization

图的规范化操作使用上一步得到的中心节点及其领域,重新对于领域中的节点进行标号,进而通过标号的排名进行置换,此时的图就相对规范了。由于距离不是单射函数,所以文中引用了NAUTY的方法,对于同样距离的节点进行区分。

Convolutional Architecture

文中的模型能够同时处理点权和边权,仅需要改变CNN的stride参数即可,具体实现略

评价

  • 没有公开代码,可复现性存疑
  • 适合作为GCN的入门论文,但和现在主流的GCN不一样。

引用

  1. Niepert M, Ahmed M, Kutzkov K. Learning convolutional neural networks for graphs[C]//International conference on machine learning. 2016: 2014-2023.

FaceNet: A Unified Embedding for Face Recognition and Clustering 阅读笔记

简介

该论文试图去解决人脸识别的课题,人脸识别有三个研究方向,分别为

  1. 验证(verification),用于判断两个图像是否为同一个人
  2. 识别(recognition),用于识别一个图像是哪个人
  3. 聚类(clustering),在一系列图片中,找到一个经常出现的人

通常的人脸识别算法流程是这样的——

与之相反,论文提出的模型,以直接生产特征向量为目标,也就是说,特征向量不再作为一个中间信息,而是一个模型实实在在优化的目标。论文中的这种损失函数称为Triplet Loss。

模型

我们希望构造函数f(x),将图片x映射到特征空间\mathbb{R}^d,使得所有相同身份的人脸拥有较小的欧几里得距离,反之不同人脸的距离较大。在Triplet Loss的构造中,为了满足尺度的恒定,还额外规定f(x)位于单位球体上,即|f(x)| = 1

模型希望相同人脸特征距离近,不同人脸特征距离远,量化到数学公式上就是

|f(x_i^a)-f(x_i^p)|^2 + \alpha < |f(x_i^a)-f(x_i^n)|^2

其中x_i^a为基准图片(anchor),x_i^p为同一身份的不同图片(positive),x_i^n为不同身份的不同图片(negative). 而\alpha被称为TripletLoss的边缘距离(margin)

由于算力的原因,不能计算出所有可能的x_i^ax_i^px_i^n组合,即所有Triplet。因此,选择有代表性的Triplet是非常有必要的。一种非常暴力的做法是,找到上述不等式中前半部分的最大值以及后半部分的最小值,即argmax|f(x_i^a)-f(x_i^p)|^2argmin|f(x_i^a)-f(x_i^n)|^2,他们的组合一定是优化的瓶颈部分。我们将他们作为Hard Triplet,单纯优化他们就可以较快收敛。

由于图片画质以及误标记等原因,全局的argmax和argmin表现并不好,不过将其改成mini-batch内部的argmax与argmin就好了。

Identity-Aware Convolutional Neural Network for Facial Expression Recognition 阅读笔记

这篇论文核心目标是提高人脸表情识别的精度。经典的表情识别算法,会将表情图片映射到特征空间(feature space)中的特征向量,而两个特征向量的欧几里得距离来衡量两个表情的相似度。

作者发现常规模型容易将“同一个人(indentity)”的特征向量放在一起而非“同一个表情(expression)”。这个问题表现在模型训练的时候,模型容易“偷偷”记录下训练数据中人物的面貌,并基于此进行判断。倘若随便换一个测试集,模型的准确度就有非常大的下降。(比如模型会记录下某黑人胖子A的吃惊的表情特征,但是之后测试集中,倘若是一个黑人瘦子B吃惊的表情,那么模型就不怎么容易判别出来了)

如下图,现有的模型的特征向量如图(a)所示依赖于人物,而作者的模型能挖掘和人物无关的表情特征,反映到特征空间中如图(b)所示。

文章提出的模型称为identity-aware convolutional neural network (IACNN) ,其核心思想是学习与表情有关(expression-related)的特征,并在同时,故意学习一个和人物有关(identity-related)的特征,后者虽然不利于网络的实际识别,但是却有利于让前者变得与身份无关(identity-invariant).

同时,该文章提出了一种距离的计算法则,能够让相似的表情的特征向量相距较近,而不相似的表情的特征向量相距较远。(不过这个计算法则感觉并不算亮点或是创新)

首先定义欧几里得距离作为接下来的距离公式——

D(f^E(I_1), f^E(I_2)) = |f^E(I_1), f^E(I_2)|^2

下面是一个自定义的损失函数公式——

L^{exp}_{Contrastive} = \frac{z_i^E}{2} * D(f^E(I_{i, 1}), f^E(I_{i,2})) + \frac{1-z_i^E}{2} * max(0, \alpha^E - D(f^E(I_{i, 1}), f^E(I_{i,2})))

这个公式看着很长,实际上非常简单,当两个图片属于同一个表情(exp),那么z_i=1 ,优化损失函数倾向于让他们的特征向量靠近;而倘若不属于同一个表情,z_i=0,优化损失函数倾向于让他们至少有\alpha^E的距离。这个损失函数可以用于训练提取表情特征的网络f^E(x)。顺便一提f^E是一个基于CNN的网络。

与上面相似,我们也可以创造一个L^{ID}_{Contrastive}专门用来训练提取身份特征的网络F^{ID}

L^{ID}_{Contrastive} = \frac{z_i^E}{2} * D(f^{ID}(I_{i, 1}), f^{ID}(I_{i,2})) + \frac{1-z_i^{ID}}{2} * max(0, \alpha^{ID} - D(f^{ID}(I_{i, 1}), f^{ID}(I_{i,2})))

通过上述的网络f^{ID}f^E,我们对于一个图片能够生成表情相关的特征FC_{exp}和身份相关特征FC_{ID},令他们的组合特征为FC_{feat}.

使用FC_{feat}进行预测,得到损失函数L^1_{softmax}L^2_{softmax}(1和2分别是两张图片),使用FC_{exp}进行预测,得到L^{exp1}_{softmax}L^{exp2}_{softmax}

最终损失函数如下

L = \lambda_1 L^{ID}_{Contrastive} + \lambda_2 L^{Exp}_{Contrastive} + \lambda_3 L^1_{softmax}+ \lambda_4 L^2_{softmax}+ \lambda_5 L^{exp1}_{softmax}+ \lambda_6 L^{exp2}_{softmax}

可以发现,优化损失函数L,身份特征相关的信息倾向于聚集在FC_{ID}中,从而使FC_{Exp}的信息是纯粹的面部无关信息。那么最后测试集上,单纯使用FC_{Exp}进行预测,就不会存在模型对于训练集人物过于依赖的问题了。

An Introduction To Compressive Sampling 阅读笔记

通常我们讲的采样都要求采样率至少两倍于带宽,这是香农在1948年就提出了的。而本文讲的则恰恰相反,本文试图介绍如何使用压缩感知(Compressive Sampling/Sencing)的方式,使用尽量少的样本,刻画出信号本身。

从实用性角度来看,尽管本文的所有算法都可以拓展至连续信号,但是本文将单纯讲述离散信号在欠采样时的CS,毕竟这才是对工业界最有意义的。因为在离散前采样的信号中,有一个很重要的问题——

压缩感知的原理

假设有一个离散信号f \in R^n,是否有可能构造出m \ll n个波形,能够“几乎”完整刻画原来f所携带的信息?

首先向讲一讲关于稀疏性(Sparsity)的问题,令f =  \Psi x,其中\Psi是一个n\times n的矩阵。我们可以理解为将f使用特征x进行表征,而倘若我们提取x中前S大的值,而将其他位置强行置0(这样便于压缩,且不会显著对于结果产生影响),则称呼得到的向量x_S为S稀疏向量(S-sparse). 此时,我们可以通过x_S计算出f_S  = \Psi x_S

那么,接下来,m的取指大概为多少可以保证信号能够被“几乎”完整恢复呢?论文通过一系列推导,给出了一个式子

m \geq C \cdot \mu^2(\Phi, \Psi) \cdot S \cdot log n

其中\mu函数表征了感知基\Phi和表征基\Psi的相关程度,S是指x是S-sparse向量,C是某个常数。

而上述公式带入实际的图像压缩中,每一个缺失项倘若对应至少四个不连续的采样点,就能准确恢复原来的图像。

若干难题

文中提出并解决了基于上述算法的两个问题——

  1. 对于极其欠采样的样本,是否可以恢复如此高的分辨率?
  2. 实际的检测设备都存在噪音,噪音将如何影响该算法?

为了解决上述两个问题,作者提出了一个叫做restricted isometry property(RIP)的限制条件,倘若条件满足,不仅欠采样样本可以被完整恢复,而且还可以将误差限制在一个较小的区间中。而RIP的细节这里不叙述。

感知基的选择

感知基选择非常随便,只要满足RIP准则就可以。而文中提到了在单位球体上面随机取点,或者使用标准正交基与一个随机矩阵的乘积生成。

应用

  1. 数据压缩
  2. 信道编码
  3. 数据获取

等等

参考文献

  • E. J. Candès and M. B. Wakin, An introduction to compressive sampling, IEEE Signal Processing Magazine, 21-30, March 2008.

Structural Deep Embedding for Hyper-Networks 阅读笔记

所谓的Network Embedding就是指,对于一个网络(或者简单地说,图),给每个节点一个特征向量X_i,而该特征向量能够表征网络中节点的结构信息。这篇文章是Network-Embedding中的一篇较为重要的文章。


Abstract

网络嵌入(Network Embedding)近年来吸引了很多人的注意,传统的方法多局限于由点与点二元组关系形成的图,但是,在实际生活中,图本身很难是标准的二元组关系,在有些情况下,一条关系(relationship)会涉及到三个甚至更多的主体,我们可以称之为超边(hyperedge)。当超边成为一个不可分割的独立整体,则传统算法会遇到不少困难。本文将介绍一种算法,用于对于超网络(hyper-network)的嵌入。并且证明,传统算法不可能成功Embedding存在不可分割超边的网络。

Introduction

对于hyper-network的embedding,一个非常简单的方式是将其转化为普通图,这里有两种常用做法,一种是直接将图中的超边转化为一个“团(clique)”,另一种是为超边本身分配一个虚拟节点,并向其包含的所有元素连边。他们分别被称作clique expansion和star expansion。在这些算法中,我们都假设了超边是可分的,即,一个超边包含的点集的子集仍然是有意义的,这在实际生活中是不存在的。上述的算法的诸多问题便是这篇文章需要解决的——

  • 节点的不可分解性:如电影的推荐中的<user, moive, tag>三元组的子集 <user,tag>是不合法的。
  • 结构保留特性:实现局部细节的embed是相对简单的,但是网络整体结构的embed却相对复杂。而我们还需要解决同时embed局部、全局的特征。

对于第一个问题,文章设计了不可分解的多元组相似性函数,这种函数本身的结构保证了超边的子集不会存在。我们从理论上证明该函数是非线性性的,如果使用带非线性层的神经网络实现,则可以实现强力的非线性性。

对于第二个问题,我们使用自编码器来保证相似的节点拥有相似的embedding。

Related Work

早期的图Embedding使用了线性代数的方式,使用图的主特征向量来作为图的编码。由于线性代数中的特征向量分解是一个相对昂贵的方式,因此实际上这种做法并不常用

近年来,一个叫做RamdomWalk的算法提出新的思路,通过刻画一系列随机游走的路径来Embed一个图。在此之后,很多学者都在其基础上进行了创新,诸如使用更好的刻画函数,或者引入深度学习来优化。

然而,上述所有的算法,假设了图是标准的由边的二元组构成的。在存在超边的途中,现有的算法不是无法保证超边的不可分解性,就是过于低效。

Notations and Definitions

术语

如右图所示,相比于图论中的“无向图”,我们的超图更类似于

一个“有向图”。也可类比于之前提到的<user,movie,tag>三元组,节点本身是有类别的。我们定义点集

V = \{V_t\}_{t=1}^{T}

表示所有节点可以按照类别分为T类。

超边边集则可以表示为

E=\{(v_1,v_2,\dots,v_{n_i})\} (n_i \geq 2)

最终第j类的第i个节点的Embedding可以计算为

X_i^j

对于N个节点,我们可以定义相似性函数

\mathcal{S}(X_1,X_2,\dots,X_n)

相似性

节点的一阶相似性(First-order Proximity)刻画了N个节点的直接相似性,其定义非常简单,只要这N个节点组成一个超边,则这N个节点的一阶相似性是1。当然,这里就隐含定义了这N个节点的任意子集都不存在一阶相似性。

显然,单纯的一阶相似性定义是不完善的,这时,我们可以进一步定义二阶相似性。

二阶相似性定义在任意两个节点上,当两个节点x_ix_j共有邻居时,他们应该是二阶相似的。这也应该反映到节点的Embedding上面。举一个例子,在上面那张图上,A_1的邻居应该是\{(L_2,U_1),(L_1,U_2)\},而由于A_1A_2拥有共同的邻居(L_1,U_2)则他们应该是二阶相似的。

Deep Hyper-Network Embedding

模型设计

我们计算的网络Embedding需要保证一阶相似性,即对于模型生成的Embedding值X_i,倘若一个点集组成了超边,则他们的X_i的一阶相似性函数应该尽可能大,反之尽可能小——

特征1:我们令X_i为模型生成的Embedding值,则

  • (v_1, v_2, \dots , v_n) \in E, \mathcal(S)(X_1, X_2, \dots, X_n)应该尽可能大(或者说至少得大于某个比较大的阈值)
  • (v_1, v_2, \dots , v_n) \notin E, \mathcal(S)(X_1, X_2, \dots, X_n)应该尽可能小(或者说至少得小于某个比较小的阈值)

有了上述定义,文章进一步通过列举反例,证明了倘若\mathcal(S)仅仅是依赖于X_1,X_2,\dots, X_n的一个线性函数\mathcal(S) = \sum_i W_i X_i,是无法正确刻画特征1的。当然,了解过深度学习的读者应该就能发现,这恰好是深度学习中的非线性层引入的动机。

后续讨论我们默认N=3,更大的N对应算法很容易在N=3的情况修改得到。下图是网络的结构图——

在输入节点Embeding (X_i, X_j, X_k),我们可以通过非线性函数将他们映射到一个非线性空间L中。

L_{ijk} = \sigma(W_a^{(2)} X_i^a + W_b^{(2)} X_j^b + W_c^{(2)} X_k^c + b^{(2)})

而我们进一步将L映射到一个概率空间S

S_{ijk} = \mathcal{S} (X_i^a, X_j^b, X_k^c) =  \sigma(W^{(3)} * L_{ijk} + b^{(3)})

上面两层共同构成了我们的非线性相似性函数\mathcal{S},最终的目标函数定义如下

\mathcal{L}_1 = -(R_{ijk} \log S_{ijk} + (1-R_{ijk}) \log (1-S_{ijk}))

上式中的R_{ijk}被定义为“节点i,j,k是否组成一个超边”的0\1值函数。

接下来,我们考虑如何生成二阶相似性。之前我们介绍了模型中的第二层和第三层,而模型的第一层就是用来保证二阶相似性的。从图中,我们可以发现,模型使用了一个AutoEncoder,那么任何AutoEncoder都需要一个可供编码的东西,我们这里使用AutoEncoder编码什么呢?作者设计了一个编码矩阵A_i.

H表示在图G(V,E)的关联矩阵,h(v,e)=1当且仅当v \in e,而D表示图的度数矩阵。令A = H H^T -D。在离散数学中,可以证明,A矩阵的第i行A_i刻画了节点i的邻居的信息。而AutoEncoder就可以如下构造——

X_i = \sigma(W^{(1)} * A_i + b_i)

\hat{A}_i = \sigma(\hat{W}^{(1)} * X_i + b_i)

对于AutoEncoder的损失函数,我们有一个小优化,即只计算A_i不等于0的项。

\mathcal{L}_2 = \sum_t ||sign(A_i^t) \cdot (A_i^t-\hat{A}_i) ||_F^2

最终模型的损失为

\mathcal{L} = \mathcal{L}_1 + \alpha \mathcal{L}_2

模型训练

使用SGD算法训练。

Experiment

Conclusion

 

Efficient Large-scale Approximate Nearest Neighbor Search on the GPU 阅读笔记 – 实现与分析

由于篇幅太长,这篇文章的Introduction和Related Work在另一篇文章里。


PQT的简介

乘积量化树(Product Quantization Tree)是基于多层倒排表(Inverted Multi-Index)和分层PQ算法形成的。其核心思想将之前的一个码书(Codebook)修改为基于层次化的树形结构。树形结构可以加速实时的查询,以及离线的排序。相比于之前的多层倒排表,PQT拥有更多地簇(Bins)。最后PQT还巧妙地运用一些技巧在重排序中服用之前计算过的距离值。

右图阐述了一个PQT查询的例子。查询向量[x]_1[x]_2的各个部分一次经过4个Cluster的粗排序和5个Cluster的精排序。对于第一层而言,只有w个最佳的Cluster可以到下一层继续搜索,如图中阴影部分所示(w=2)。

PQT的结构

将样本集合中所有的向量x \in \mathcal{X}归类为簇B_l从而形成若干个互不相交的子集,\mathcal{X} = \bigcup_{k=1}^{K} B_k。接下来,我们将详述如何将一个向量映射到簇中,即如何构造映射m : \mathcal{X} \rightarrow \mathcal{I}_1 \times \mathcal{I}_2 \times \dots \times \mathcal{I}_P

索引树包含两层量化器,第一层是传统的P部分(P part)的PQ量化器,在这个量化器中,每一部分的码表含有k_1个码字。在第一层量化器之后,选出的簇进一步使用第二层k_2个码字的量化器量化。这种方法中,总共存在的簇有K = (k_1 \cdot k_2)^P个。

对于码书的训练,每一部分独立生成码书,首先量化器使用Lloyd Iteration中的Linde-Buzo-Gray算法生成,所有第一层量化器分出的簇进一步使用第二层量化。

对比在多层倒排表中,使用了两级的乘积量化,其中第二级用于排序,我们也用两级索引,至于为什么是两级,只是从经验上来看,两级能够最好得平衡簇的总个数。

PQT的询问操作

一个实际的询问操作包含四个步骤——

  • tree traversal
  • bin proposal
  • vector proposal
  • re-ranking

在tree-traversal步骤中,正如之前对PQT结构的叙述,每一个向量都能归类为一个level-2的簇中。通过剪枝的策略,tree-traversal步骤使用的向量比较次数实际上是相对较少的。在比较了所有k_1个level-1簇后,询问向量距离每一个簇的距离被排序,并且只有最近的w个簇被进一步计算。在提取出了最近的w个level-1簇,接下来这些level-1簇所对应的level-2簇的中心再和询问向量进行比较。在标准参数下,在四百万簇的数据集下,只需要80次向量比较。具体细节可参见论文。

在bin-proposal步骤中,从我们获取的“最好的”簇i=(i_{1,1},i_{2,1},\dots,i_{P,1})开始,我们仍然需要一系列临近的簇,以保证在后续的处理中,有足够多的向量可供选择。正如右图所示,我们需要找到一个顺序,合理组织“次好”的向量,使得遍历完所有较近向量的这组合。着这种便利,通常来说,可以看做是一个斜线从左下向右上方移动维护的下方区域。具体的实现方式,绿线是Dijkstra-based traverse,但是无法再GPU上面实现,而红色、绿色线则是可行的。对于每一个簇,我们都可以在离线阶段预处理出最近的簇。

使用Line Quantization进行重排序

通过上述的索引,每一个询问向量都被归类于最近的簇,并获得了一个量化损失(quantization loss)。在传统方法中,我们就需要依次对于簇所包含的所有向量进行比较,但是显然这样会有巨大的花销。而在我们的算法中,我们重用了一些信息以达到更优的效率。

离线预处理

在传统方法中,一个簇所包含的所有向量是不可分的,这就导致了我们必须花巨大的计算力去依次比较所有的向量。 文中提出的Line Quantization巧妙地解决了向量不可分的问题。即,虽然每一个向量【黑点】相对于level-2簇中心【红点】是不可区分。但是他却可以被投影到两个最近level-1簇中心的连线上【紫点】。巧妙的是,对于所有level-1中心,询问的x_1点与他们的距离都是已经算过的!

右图描述了如何计算对于任意询问向量y距离某一个数据库样本x的距离。其中,c_i,c_j为两个距离x很近的level-1簇中心。

 

(1)   \begin{align*} d(y,x) &= \sum_{p=1}^{P} d([y]_p, [x]_p)^2 \\ & \apporx \sum_{p=1}^{P} h_p(y,x)^2 \\ & \apporx \sum_{p=1}^{P} (b_p^2 + \lambda_p^2 \cdot c_p^2 + \lambda_p \cdot (a_p^2-b_p^2-c_p^2)) \end{align*}

通过这个式子,我们可以用我们之前计算过的,询问向量距离level-1簇中心的距离信息,为x找到一个更加精确的距离估计值。

在GPU上实现

这个模型非常适合在GPU上面实现,不过由于我并不太了解GPU的实现,顾就不在这里赘述,读者可以对照论文自行理解。

The Design Philosophy of the DARPA Internet Protocols 论文阅读报告

本文介绍了Internet中最基本的协议——TCP/IP协议的设计思想。由David.D Clack所著,他作为整个TCP/IP协议设计的参与者,见证了协议从1973年最初的版本,逐渐被改进,到最终成型的一系列尝试。在文章中,作者总结了设计中的一系列目标,以及存在的问题。让我们得以窥见这一段艰辛的摸索之路。

各种协议的设计,其基本目标无非两个: 1) 能够尽可能的兼容协议发布之前已存在的硬件设施; 2)能够尽可能的有利于协议发布之后的因特网发展。这些基本目标不仅为我们理解TCP/IP的后续发展有帮助,也能够让我们知道,为什么在计算机科学领域,很多的实现都是建立在“协议”上的。

在基本目标之上,人们基于对于因特网的畅想,设计出了一系列有严格层次关系的次级目标,如稳定性,经济性,可解释性等。由于Internet协议的设计流程过于复杂,常常会遇到两种不同实现方式的权衡取舍,由于实现确立了稳定性、经济性这一类不同目标的重要性排序,故可以基于此进行取舍。这种目标导向的协议构建,一方面确实省去了非常多的试错的时间,另一方面,却会缺少一些长远的考虑(例如由于对性能的要求并没有卸载目标中,导致性能在早期完全没有被重视等等,又例如一对多的信息传递没有在早期协议中支持,导致在长时间无法实现)。

互联网协议的稳定性作为最重要的目标,毫无疑问来自于互联网历史上的军方背景。也在之后的普及中发现其局限性,报文协议(UDP)的诞生或多或少的解决了这个尴尬的境地。不过UDP能够成功诞生还是算非常幸运的了,通常来说协议的修改总是耗时耗力,有时还会和原来的协议冲突,诸如一对多的广播就一直没有能够成功的引入。总之,协议设计者的远见与用心真的是非常的重要。而TCP/IP协议的设计流程,从文中提到的寥寥几句可以推测出,确实不是设计者拍脑袋的结果,而是无数次试验,并用一篇篇论文推动而来的。反观现在良莠不齐的学术论文,我觉得在协议设计中的这种,基于某个具体目标驱动的研究,才是能让学术界向前推进的正确方法。

由于网络的协议的更改需要兼容之前的功能,而论文写作至今又过去了接近30年,TCP/IP协议在30年前存在的缺陷,随着互联网体量的增大,在现在解决更需要花费巨大的人力财力。IPV6协议的创立可能会解决少量表层问题,但是很多结构上的缺陷仍然无从修复。可能这是计算机网络领域的一大难题。期待在未来,能有技术上的爆炸性突破,其力量,能够足以颠覆计算机领域坚守了三十余年的TCP/IP协议。也许量子通信就是这样的潜力吧。

Efficient Large-scale Approximate Nearest Neighbor Search on the GPU 阅读笔记 – 背景介绍

由于篇幅太长,这篇文章的讲述了文章的Introduction和Related Work部分。而文章的主体部分在Efficient Large-scale Approximate Nearest Neighbor Search on the GPU 阅读笔记 – 实现与分析 这篇文章里面。


摘要

这篇论文讲的是在高维空间的最近点搜索问题(ANN)的一个实现算法,该算法继承自 乘积量化(Product Quantization) 算法。在该算法中,提出了如下几点:

  • 将原来的乘积量化算法进行分层,使用树形结构减少向量的比较次数
  • 提出了一个重排序算法,该算法有更好的并行度

简介

最近点搜索问题(NN)就是在D维空间中,对于一个向量y,找寻样本集合\mathcal{X}中,最近点的问题,形式化表达——

(1)   \begin{equation*} N(y) =\mathop{\arg\min}_{x \in \mathcal{X}} d(y,x) \end{equation*}

在视觉识别的领域的很多课题中,该问题的维数D变得非常大,引入了一种称之为 “维数灾难” 的现象。形象的解释这个问题,对于一个体积a^128的128维高维立方体,一个体积0.1 \times a^128的立方体,边长也是0.1^{\frac{1}{128}} = 0.982\times a。从这个例子可以看到,由于高维立方体体积增长速度过于迅速,我们基本不可能通过遍历区域的方式进行搜索。例如,在128维空间中,即使我们只要访问10%的体积,这些体积分配到单维度上也超过了98%。

给予上述瓶颈,大多数应用中,我们都是用了临近点搜索的方式(ANN),搜索一个相对较近的邻居。对于该问题,人们已经研究出了很多基于CPU的实现,从KD树(KD-tree),到随机KD森林(Randomized KD forest),和KD-mean Trees。这一系列算法都试图将搜索空间缩减到一个包含询问点的尽量小的邻域。

另一个截然不同的实现方式是局部敏感哈希算法(Local Sensitive Hashing),这个方法将整个数据库的向量的一系列随机投影使用哈希表储存,在询问中,对于和询问向量落在了同一个哈希项中的样本向量进行额外的距离检查。

上述基于CPU的ANN算法在像GPU迁移的时候都会遇到或多或少的问题,而基于GPU的算法则很多都是纯粹暴力算法。而在这篇文章中提出的算法,不仅高效利用了GPU,甚至其CPU版本都和上述算法匹敌。

在效率评估上,由于在实际生产中,存在一个“离线预处理”阶段计算所有询问无关的数据,以及一个“在线计算”阶段,实时处理询问相关的计算。因此,最科学的方式应该是将两个阶段的用时分别测量。

向量量化(Vector Quantization)是一个简单的ANN算法,它将样本集\mathcal{X}中所有的向量进行聚类。对于某个询问向量,距离其最近的聚类中心所对应的样本集子集\mathcal{X}_k \subset \mathcal{X}是最有可能存在最近点的。然而倘若询问点恰好位于两个聚类的边界上,则算法就不那么容易找到最近点了。另一方面,一个聚类簇在V图上的相邻聚类簇的个数随着维数的增加指数级增长。

乘积量化(Product Quantization)算法是当下很多最前沿ANN算法的核心,一般来说,基于PQ的算法都有如下几步

  1. 通过一个高效但是低精度的算法,选出一系列候选点集。
  2. 在重排序过程(re-ranking step)中,使用近似距离将候选点集进一步排序。
  3. 排序后的前面K个候选点重新计算实际距离并取最近者。

在PQ类算法的基础上,我们平行提出了一个称之为Product Quantization Tree的算法(PQT),这个算法的贡献点有

  1. 二级乘积和树形结构,减少计算量
  2. 引入Dijkstra算法的松弛操作
  3. 一个O(P)复杂度的近似排序算法,其中P为询问向量的分段数

背景

向量量化与乘积量化

由于我们的算法是基于PQ算法的,因此下面将介绍PQ算法。

首先,乘积算法(Product Quantization)的鼻祖是向量量化(Vector Quantization)算法。已知最初的样本集合\mathcal{X} = \{x_1,x_2,x_3,\dots,x_n\},以及一个码表(codebook)\mathcal{C} = \{c_1,c_2,\dots,c_k\},我们可以定义映射c(x) = \arg \min _{c \in \mathcal{C}} d(x,c),将每个样本点映射到最近的码字。同时,对于每个码字也控制了一系列样本点,令这些点集为C_kC_k =\ {x \in \mathbb{R}^D | c(x) = c_k\},这个点集也成为簇(cluster)或盒子(bin)。直接使用码字代表样本点,虽然引入了一些距离上的不精确,但是在后续寻找相似向量中很有用。在上述算法中,关键点集合可以通过一个叫Lloyd Iteration的算法得到。

在PQ算法中,高维的向量空间可以等价于若干低维向量空间的乘积,假设D = P \cdot m,那么对于所有的样本向量都可以进行分解,x \in ([x]_1,[x]_2,\dots,[x]_p)^T, [x]_i \in \mathbb{R}^m. 对于x \in \mathbb{R}^D,我们可以将该高维空间中的码表定义为C = C_1 \times C_2 \times \dots \times C_P,这个集合里面实际上包含了k^P个D维码字,但是却只需要k \cdot P个m维码字。由于码字变得非常非常多,我们可以对于高维向量进行更加精细的匹配。最终,一个向量的编码(Canonical Projection)定义为其P个独立组成部分的码字组合而成——

    \[c_p : \mathcal{X} \rightarrow \mathcal{C}_p, x\mapsto c_p(x) := \mathop{\arg \min}_{c \in C_p}  d([x]_p,c)\]

    \[c(x) = (c_1(x),c_2(x), c_3(x), \dots, c_p(x))^T\]

从上式可以发现,对于P个部分的量化操作使用了不同的码书,这些码书和VQ一样,都可以使用Lloyd Iteration生成。

诚然,查询任意一个向量处于哪一个簇是非常简单的。但是任意向量所归属的簇在大部分情况下都是空的,这是因为数据分布的稀疏性。不过,在实际使用中,查询向量通常和样本有相同分布,在这个条件下,我们确实可以成功的依照簇找到最近的向量。即使如此,我们还是需要考虑最坏的情况。

一些研究者为了实现更加精确的乘积量化方式,找到了一些解决方式,比如对于所有询问x,统一使用一个线性变换R修饰。及每次查询Rx。不过这个方法在GPU上并不怎么方便。

右图的四部分就分别介绍了“向量量化(Vector Quantization)”和“乘积量化(Product Quantization)”对应的中心点分布图。下层的两幅图则尝试按照不同的“粒度”实现树状查询,在之后会详细讨论。

 

倒排文件系统

对于一个询问y \in \mathbb{R}^D,有的文章使用了含“非对称距离计算”的倒排系统实现。在这个实现中,首先一次VQ,在规模k的码书中提取一系列候选码字(原文中是在8192个向量中,提取0.05%,即64个候选)。不过,即使是64个候选码字也廊括了524288个样本向量。

在这个实现中,选择一组合理的码字消耗了k个D维向量距离运算,在计算了k次距离之后,其中最近的w个码字对应的样本集合的并集\mathcal{L}_c \in \mathcal{X}就是“极有可能包含答案的向量集合”。这一系列向量进一步在基于PQ算法的重排序(re-ranking)。按照中心向量c_wy的距离r_w = y-c_w,从小到大排序,在之前文章中,由于询问向量y事先知道,所以这个距离被放在了查找表(lookup-table)中。

询问向量y和其最近的候选向量可以在集合\mathcal{L}_c中使用相似的方式查找到。只不过这一次,候选集合\mathcal{L}_c小了很多,而码书包含了更多(k_2个词).通过新的码书对应的距离函数,重排序得到更加靠谱的候选集合\mathcal{L}_s,最终,在\mathcal{L}_s中,选择前几个进行最精确的距离计算。

上述步骤意味着共有k_1 + w \cdot k_2次距离计算,在论文默认的规模中,意味着24576次高维向量距离计算每询问。

一个层次化的实现会将总共的距离计算次数将至200,不过,在NVIDIA Titan X架构下,16k的向量距离计算比256次计算慢62倍,因此,在这个问题上,就近多少次距离计算是运行效率的瓶颈。

多索引倒排

相比于之前,在整个数据及上使用VQ,多层次倒排索算法使用了PQ算法,减少了询问向量与中心向量的距离计算次数,而增加了Cluster的总数。

对于y的每一部分,都给定了其到k个中心向量的距离。这些距离经过排序生成如下表格——

(2)   \begin{align*} [y]_1 \rightarrow \{i_{10}, i_{11}, i_{12}, \dots, i_{1k-1}\} \\ [y]_2 \rightarrow \{i_{20}, i_{21}, i_{22}, \dots, i_{2k-1}\} \\ \vdots \\ [y]_P \rightarrow \{i_{P0}, i_{P1}, i_{P}, \dots, i_{Pk-1}\} \\ \end{align*}

上面式子中i_{23}指的是询问向量第二部分的第三近的向量。在此基础上的NN搜索,使用启发式算法,从i=(i_{10},i_{20},\dots,i_{P0})开始。可以使用优先队列,一次访问最近的一个簇中的向量,直到足够多的向量被访问。

讨论

上述的基于VQ和基于PQ的查询算法都能达到很好的精准度。基于VQ的算法需要很大的内含D维向量的码书,即使基于PQ算法的码书会小一些,但是从总量上也非常大。另一方面,两个算法都需要与询问相关的离线初始化操作。这在实时的查询中是不可行的。

对于之前提到的诸多问题,在接下来一章中,我们将使用乘积量化树(Product Quantization Tree)来解决上述的问题,并提出不同的Cluster选择算法,和基于投影的重排序算法。最后,我们将讨论该算法如何在GPU上面运算。

参考文章

理解 product quantization 算法

K-means聚类算法的三种改进(K-means++,ISODATA,Kernel K-means)介绍与对比