摘要: 本文将对 Capsule 进行分析。 整体上来看,Capsule 算法的细节不是很复杂,对照着它的流程把 Capsule 用框架实现它基本是没问题的。所以,困难的问题是理解 Capsule 究竟做了什么,以及为什么要这样做,尤其是 Dynamic Routing 那几步。
论文原网址:请戳
根据论文完成的部分代码
整体上来看,Capsule 算法的细节不是很复杂,对照着它的流程把 Capsule 用框架实现它基本是没问题的。所以,困难的问题是理解 Capsule 究竟做了什么,以及为什么要这样做,尤其是 Dynamic Routing 那几步。
众所周知,Capsule 给人的感觉就是“似乎有太多人为约定的内容”,没有一种“虽然我不懂,但我相信应该就是这样”的直观感受。所以尽可能将 Capsule 的来龙去脉思考清楚,使我们能觉得 Capsule 是一个自然、流畅的模型,甚至对它举一反三。
虽然都是先分析了动态路由的结果,然后指出输出是输入的某种聚类,这个“从结果到原因”的过程多多少少有些望文生义的猜测成分。但这次则反过来,直接确认输出是输入的聚类,然后反推动态路由应该是怎样的,其中含糊的成分大大减少。
与其说 Capsule 是一个具体的模型,倒不如说 Capsule 是一个建模的框架,而框架内每个步骤的内容,是可以自己灵活替换的,而 Hinton 所发表的论文,只是一个使用案例。
这是一个怎样的框架呢?
当然,对于关注新闻的读者来说,这已经不是什么新消息。可能读者会有疑问:用向量来表示特征有什么稀奇的,本来神经网络的特征输入不就是一个向量吗?
原来神经网络(MLP)的每一层输入是一个向量,然后输出是,我们就将 x 的每一个分量都看成一个特征,那么每个特征都是标量了。
而所谓的特征向量化后,那么每一层的输入变成了,然后输出是 ,这时候的输入 x 也看成是 n 个特征,但每个特征都是一个 dx 维向量;输出 y 则看成是 k 个特征,每个特征是一个 dy 维向量。
换一个角度看,其实就是说 MLP 每一层的输入输出由单个的向量变成了向量的集合(矩阵)。
或者我们可以将它换一个名称,叫做“特征的分布式表示”。也许有读者看到了“分布式表示”,会想起 NLP 中的词向量。
没错,词向量一开始确实叫做“分布式表示”(Distributed Representation),当看到 Capsule 的这一特点,第一反应也就是词向量。
同时也可以用词向量代替 one hot 来表示一个词,这样表达的信息就更为丰富了,而且所有的词都位于同一向量空间,方便后续处理。
此外,事实上图像中早也有这样的例子,众所周知彩色图像一般有 RGB 三个通道,每个通道 256 个选择,所以一共可以表达 256 的三次方,即 16777216 种颜色(约 1700 万)。
为什么不直接用 1700 万个数字来分别表示这 1700 种颜色,而要分开 3 组,每组 256 个数字呢?
这其实也是一种分布式表示,这样可以更好地表达色彩的多样性。比如红色的相近颜色是什么色?也许有人说橙色,也有人说紫色,也有可能是粉红,单一一个数字难以表达多种的相似性,而分组后则可以。
更进一步说,我们在对图像不断进行卷积操作时,所得结果的通道维度,其实就是图像特征的一种分布式表示了。
Capsule 的第二个特点,是通过聚类来组合特征。
通过将底层特征组合为上层的特征,是跟我们的认知规律是相符的。在NLP中,我们有“字–>词–>句–>段”的层层组合;在图像中,我们也有“点–>线–>面–>体”的层层组合。
面对新事物(上层特征),我们总会将它分解为我们熟悉的一些事物(底层特征),然后脑海里将这些事物映射到这个新事物(特征组合)。
对于我们来说,这个分解和组合的过程,不一定有什么目的,而只是为了用我们自己的方式去理解这个新事物(在大脑中形成良好的特征表达)。
这也就能理解 Hinton 诟病深度学习、发展 Capsule 的原因之一了,因为他觉得现在深度学习的模型针对性太强,比如 MNIST 分类模型就只能做单个数字的识别,多个数字的识别就要重新构建数据集、重新设计并训练模型。
而事实上,我们的根本目的并不是单纯地做任务,而是通过任务形成良好的、普适的特征表达,这样才有可能形成真正的人工智能。
那么,怎么完成这个组合的过程呢?试想一下,两个字为什么能成为一个词,是因为这两个字经常“扎堆”出现,而且这个“堆”只有它们俩。这就告诉我们,特征的聚合是因为它们有聚类倾向,所以 Capsule 把聚类算法融入到模型中。
要注意,我们以前所说的聚类,都是指样本间的聚类,比如将 MNIST 的图片自动聚类成 10 个类别,或者将 Word2Vec 训练而来的词向量聚类成若干类,聚类的对象就是一个样本(输入)。
而 Capsule 则设想将输入本身表示为若干个特征向量,然后对这些向量进行聚类(特征间的聚类),得到若干中心向量,接着再对这些中心向量聚类,层层递进,从而完成层层抽象的过程。这是一种特征间的聚类。
现在问题就来了。既然是聚类,是按照什么方法来聚类的呢?然后又是怎么根据这个聚类方法来导出那个神奇的 Dynamic Routing 的呢?后面我们会从K-Means出发来寻根问底,现在让我们先把主要思路讲完。
通过特征的组合可以得到上层特征,那如何对比特征的强弱程度呢?
Capsule 的答案是:模长。这就好比在茫茫向量如何找出“突出”的那个?只需要看看谁更高就行了。因此通过特征向量的模长来衡量它自己的“突出程度”,显然也是比较自然的选择。
此外,一个有界的度量也是我们希望的,因此我们对特征向量做一个压缩:
既然本文不断强调 Capsule 是通过聚类来抽象特征的,那么就有必要来细谈一下聚类算法了。Capsule 所使用的聚类算法,其实是 K-Means 的变种。
聚类算法有很多,理论上每种聚类算法都是可能的,然而要将聚类算法嵌入到 Capsule 中,还需要费上一点周折。
K-Means 聚类本质上是一种“中心聚类方法”——聚类就是找类别中心。为了定义中心,我们就需要一个相近程度的度量,常用的是欧氏距离,但这并不是唯一的选择。
所以这里我们干脆在一个更加一般的框架下介绍 K-Means:K-Means 希望把已有的数据 u1,u2,…,un 无监督地划分为 k 类,聚类的方法是找出 k 个聚类中心 v1,v2,…,vk,使得类内间隔最小:
怎么去最小化 L 来求出各个中心呢?如果读者不希望细细了解推导过程,可以跳过这一节,直接看下一节。
因为 L 中有 min 这个操作,所以直接求它的梯度会有困难(不是不能求,而是在临界点附近不好处理),事实上有很多类似的问题没能得到很好的解决,都是因为它们的 loss 中有 min。
然而,这里我们可以“软化”这个 L,使得它可以求导。因为我们有一个很漂亮的公式:
现在就可以把我们选择的度量代入(8)式进行计算了。我们可以看一个最基本的例子,这时候就有:
欧氏距离并不适合用在 Capsule 中,这是因为欧氏距离得到的中心向量是类内的向量的平均,这样类内向量越多,也不会导致中心向量的模越长,这不满足我们前面说的“小弟越多,势力越大”的设计。
什么距离比较适合呢?在论文 Dynamic Routing Between Capsules 中有一段话:
The initial coupling coefficients are then iteratively refined by measuring the agreement between the current output vjvj of each capsule, jj, in the layer above and the prediction û j|i made by capsule ii. The agreement is simply the scalar product aij=vj⋅u^j|i…
对应到本文,大概的意思是用内积⟨ui,vj⟩作为相似度的度量,也就是说,d(ui,vj)=−⟨ui,vj⟩。但仔细思考就会发现问题,因为这样的 d 是无下界的。
无下界的函数我们不能用来做 loss,所以我一直被这里困惑着。直到有一天,我觉得可以将 vj 先归一化,然后再算内积,这样一来实际上是:
经过漫长的准备,Dynamic Routing 算法已经呼之欲出了。
按照第一部分,我们说 Capsule 中每一层是通过特征间聚类来完成特征的组合与抽象,聚类需要反复迭代,是一个隐式的过程。我们需要为每一层找到光滑的、显式的表达式:
假设 Capsule 的输入特征分别为 u1,u2,…,un,然后下一层的特征向量就是 v1,v2,…,vk,它就是前一层 n 个向量聚为 k 类的聚类中心,聚类的度量是前面的归一化内积,于是我们就可以写出迭代过程:
这样就完了?远远还没有。我们还要解决好几个问题。
如何做好类别初始化? 因为聚类结果跟初始化有关,而且好的初始化往往是聚类成功的一大半。现在我们要将聚类这个过程嵌入到模型中,作为模型的一部分,那么各个应该怎么选取呢?
如果同一初始化,那么无法完成聚类过程;如果随机初始化,那又不能得到确定的聚类结果,就算类中心向量不变,但是类的顺序也可能变化。
如何识别特征顺序?我们知道,聚类的结果跟样本的顺序是无关的,也就是说,如果将输入向量的顺序打乱,聚类的结果还是一样的。
对于样本间的聚类,这是一个优点;然而如果是特征间的聚类,那么就有可能不妥了,因为不同顺序的特征组合可能代表不同的含义(就好比词序不同,句子含义也会不同),如果都给出一样的结果,那么就丧失了特征的序信息了;
如何保证特征表达能力?动态路由将上层 Capsule 作为底层 Capsule 的聚类结果,每个类可能包含多个特征向量,但如果仅仅用类中心向量整个类的整体特征(上层特征),会不会降低了上层 Capsule 的特征表达能力?
有意思的是,以上三个问题都可以由同一个方法解决:加变换矩阵。
首先,为了模型的简洁性,我们将所有 ui 的和平均分配到每个类中作为。那怎么分辨出各个不同的类呢?我们在输出到每个类之前,给每个类都配一个变换矩阵 Wj,用来分辨不同的类,这时候动态路由变成了:
个人认为,Capsule 的确是新颖的、有前景的的研究内容。也许它不一定(但也是有可能的)是未来的发展方向。Geoffrey Hinton 大胆地将聚类的迭代过程融入到神经网络中,因此诞生了 Capsule,那是不是说,可以考虑将其他比较直观的算法也融入到里边,从而造就其他有意思的玩意?让我们拭目以待。