如何看待Hinton的论文《Dynamic Routing Between Capsules》?

论文链接:[1710.09829] Dynamic Routing Between Capsules Capsule 是一组神经元,其活动向量(activity vector)表示特定实体类型的实例化参数,如对象或对象部分。我们使用活动向量的长度表征实体存在的概率,向量方向表示实例化参数。同一水平的活跃 capsule 通过变换矩阵对更高级别的 capsule 的实例化参数进行预测。当多个预测一致时,更高级别的 capsule 变得活跃。我们展示了判别式训练的多层 capsule 系统在 MNIST 数据…
关注者
2544
被浏览
80584

2017.11.17更新:

在雷锋网AI研习社的邀请下,2017.11.17做了一场该论文的在线技术分享,ppt和视频已放出(百度网盘pan.baidu.com/s/1qYuTM0 密码: hha7),需要的小伙伴可以去下载。注:该ppt和视频仅作为学术交流使用,不得用于商业用途,若使用到ppt中原创的图表,请声明来源。


先安利我的githubgithub.com/naturomics,已经使用Tensorflow复现了该论文的核心算法,目前test accuracy达到99.57(论文:99.75),我这个repo也已经收获1.3k+的star,谢谢各位的关注。


正文:

这里我将从以下几个方面作答:

  1. 解释论文:通过对比传统神经网络来理清什么是capsule及capsNet模型结构的细节
  2. 评论及其他



首先,一张图告诉你capsule是啥玩意,这个图就可以把论文Sec 2的大部分内容囊括进来:

图中右边是传统神经元的模型,它接受来自上一层多个神经元的输出 x_i (标量值)作为输入,对其进行加权、求和,然后进行sigmoid、ReLU等非线性操作,最后输出一个标量值;左边就是capsule论文Sec 2的几个公式,做一个对比,我们可以发现,capsule的输入是一个向量u_i,输出v_j也是一个向量,中间的公式Eq.1和Eq.2 就是从u_i到v_j的计算过程,这个过程可以一一地跟传统的神经元计算过程对应起来,u_i到u_hat(Eq.2)是一个仿射变换,这是传统神经元所没有的操作,然后u_hat到s_j是在c_ij的加权下然后对 i 维度进行求和的操作,这个可以看作向量版的加权求和过程,再接着就是s_j到v_j,Eq. 1这个squashing函数已经在楼上有同学进行分析,我不再赘述,我们需要知道的是,这个函数是非线性的,而且输出的v_j保持了s_j的维度,所以可以看作是向量版激活函数。

到了这里,我们可以看到,capsule就是一个向量版的神经元,所以可以叫它张量神经元,而不是所谓的“胶囊”(前一版写的是矢量神经元,最近跟小伙伴们反复讨论了capsule名字翻译的问题,网上现在都翻译为“胶囊”,我表示不忍直视,学术名词应该要具有直观的意义,能让大部分人在已有的知识体系下快速认识一个新名词所具有的特征,能够轻易辨别跟已有概念的区别以及共通点,另外,名字的变化也能够充分体现我们对事物认知的变化,就以这里我对capsule的翻译来说,我也经历了从矢量神经元到张量神经元的变化,这是因为我也慢慢意识到,既然神经元的输入输出可以从标量扩展到向量,那么向量也可以进一步扩展到张量这个概念,所以,我认为取名张量神经元更合适。当然,至于神经元的输出是否需要扩展到三维、四维的张量,这也是个值得研究的问题)


接着,就是CapsNet模型的结构。

这个model不算最后的reconstruction部分的话,总共就三层。

其中第一层不值得多说,就是一个常规的conv layer,得到一个20x20x256的输出。按照原文的意思,这层的主要作用就是先在图像pixel上做一次局部特征检测,然后才送给capsule。至于为何不从第一层就开始使用capsule提取特征?当然,MNIST是灰度图,每个pixel是一个标量,每个pixel看作低层capsule的输出u_i的话,就不符合capsule输入输出都是vector的要求(不考虑标量是长度为1的vector这个情况,那将退化成现在的CNN模式),但如果把这点作为第一层使用常规conv层的理由,我认为并不充分,我们完全可以使用3 channel的图像数据集来做experiment,达到capsule输入为vector的要求。既然这样,那又是为什么这么设计这层呢,是capsule不具备常规的convolution局部特征检测的能力还是别的原因呢?这是我的一个小疑问,读了原文后我并未从中得到相关的解答,有待进一步实验解决这个疑问。


而第二层(PrimaryCaps)才是真正开始使用capsule的层,但这层跟它的低一层,也就是上面说的conv layer之间,却并未使用routing算法。按照我的理解,这层才是真正为了做routing而准备的。我们先来看下,如果在第一层的输出上做常规的32 channel, 9x9 kernel size和strides 2的CNN,结果是怎么样的呢?事实上我们将得到一个6x6x32的输出,或者说是6x6x1x32的输出(这个1不是随便加的,下面有作用),如图(1):

图 (1)

将这个图与原文的Figure 2对比可以看出,原本convolution每次的计算输出是一个scalar value,现在到了PrimaryCaps这里成了一个长度为8的vector,也就是从6x6x1x32到了6x6x8x32(这里1就起作用了,从1到8的转变,也就是从标量向矢量的变化)。这是怎么做到的呢?按照我的理解,其实可以看作第二层在第一层的输出上用8个不同的conv2d层做了共8次32 channel, 9x9 kernel size和strides 2的卷积(每个conv2d分别一次),如下图(2)所示,每次都得到一个6x6x1x32的输出,共8个,再把这些输出在6x6x1x32的第三个纬度上concatenate, 就得到了第二层最终的输出:6x6x8x32大小的高维矩阵,也就对应上了论文里的Figure 2。

图 (2)

这么理解下来,我们可以发现,primaryCaps层就是多个常规卷积层的叠堆,换句话,就是把8个conv2d封装在一起,然后形成一种新的neural unit,hinton称之为capsule,在这层这种neural unit可以输出8x1的vector,接着第三层我们就能看到输出的是16x1的vector。就说明了这种neural unit的输出可以根据需要设计verctor的输出维度。


——这里我要提一下,有位同学提出,这里的输出[6, 6] grid相互之间是共享权重的,然后又提到6x6x32=1152,这好像没有共享权重啊,我想这位同学是误读了,请大家要仔细阅读,这里在解释的是conv1 和 primaryCaps层之间的变化,按照我上面这个思路,6x6 grid之间是权重共享的,提到1152是在后面primaryCaps和digitCaps层之间的计算了。请大家注意辨别。


此外,第二层的卷积操作除了可以看作是多个常规的卷积叠堆后的效果外,还有一点是跟传统的卷积过程是不一样的,那就是对每个长度为8的vector做了文中的Eq. 1的向量单位化和缩放操作(存疑的地方:capsule内部每次的卷积只做加权求和,但不做非线性的activation非线性转换,还是加权求和后也做ReLU这类non-linearity activation呢,读了多次论文似乎没提到),公式如下,其他楼层有这个公式的解读:

Eq. 1

到了这里,第二层的计算也就完了。第三层(DigitCaps)在第二层的输出之上就开始使用了 routing 算法。这一层依然可以跟传统的网络做比较,可以看作一个全连接层,这在原文里也有提到:

文中第4节的第一段第二行就说了,这个Net就是两个卷积层加第三层的fully connected layer,说明Hinton大大也是认为这个就相当于capsule版的全连接层。怎么理解呢?上图:

图 (3)

请你先把第二层的6x6x8x32输出看作上图左边的样子,也就是每个长度为8x1的vector就是一个点,一个向量点!这里说的一个点在文中就是指u_i。而第三层的输出也可以看作是由10个神经元输出的10个点,每个点同样是向量点,其中向量的维度为16x1,在文中就是指v_j。所以第二层向第三层共输入32x6x6=1152个点,即 i 取值为0到32x6x6=1152, 而 j 取值为从0到10, 其中第三层的每个神经元代表一类数字(0-9)出现的可能性。那么就好理解了,传统的一个神经元就是对输出做加权求和然后非线性激活,现在就不是这样了,而是每个神经元(capsule)内部使用routing算法。至于这个routing算法起到了什么作用呢?结合他人的观点后,我认为这个routing确实有几分类似于 attention的机制,但它跟attention的差别就是,routing是低层neural unit选择高层neural unit,而attention是高层的选择低层的。


评论及其他:

  1. 有同学评论说u_i能不能表示一维的向量,这是绝对可以的,不仅u_i可以是一维的,v_j也可以是一维,如果这样做,那么论文里的第二层就退化为现在的卷积层,第三层就变为一个全连接层,但是神经元内部不再是常规的加权求和然后active了,而是新版的加权求和并active,Hinton称之为routing。懒癌发作,更多讨论请直接看评论里我的回复,了解更具体的看法。
  2. 读完这个文章后,我们可以发现其实只有第二层和第三层之间做了routing,而且是 fully connect的,那么我们是否还可以用capsule来做自带routing过程的capsule版卷积层呢?只是做这种卷积层的必要性值得探讨,因为routing已经具备了一定的层与层之间的选择性连接的功能,而卷积是先验性地设计结构,做到人为地选择层与层之间的部分连接。到了这里,让我想起了今年初那篇Deformable Convolutional Network的贡献,还没读过的同学可以了解下。
  3. 宣传了那么久的capsule概念,到底能不能革现在的CNN的命呢?我的态度,那还是让时间说话吧。但是这个工作我还是很认可的,因为我认为它的贡献至少有一下两点:(a)把传统的单个神经元从scalar in scalar out的模式扩展到了verctor in vector out(甚至还可以 matrix in matrix out啊[笑]),这是个拓展性的工作,即使曾经有人有过vector in vector out这样的想法,但是我没见过有实现的(知道哪有的话请告知);(b) 就是routing 这样不需要BP算法来更新参数的,routing里面只有b_ij参数——虽然整个capsule内部还是多多少少使用了BP,但我们还是期待Hinton能做到更少使用BP吧
  4. 但是,我们真的必须要丢弃BP吗?我认为这不是必须的,你要看Hinton为啥认为BP不好。据我的了解(没有做很多官方数据考据,请注意),Hinton的其中一个观点,就是认为现在的model参数更新都是由最后的loss fun通过BP来决定,这个太不合理了,loss fun设计得不好,整个model就废了,“一人独大”的感觉。在我了解到Hinton的capsule理念之后,我受到了一定的启发,就是每个neural unit的参数更新不仅应该受到global的loss fun影响,还应该受到这个capsule的周边capsule影响,就是一个model结构局部影响,根据这个思路,我产生了一个我认为值得去尝试的新算法,待我日后实验,欢迎跟进。


注:

  1. github上一个叫Siraj的略有名气的同学copy了我的工作却没有“明显”地声明来源(readme最后加了一行并不显眼的说明),导致最近经常有同学问我是不是Siraj,我不是。我不知道是应该感谢他为我打广告,还是要谴责他,不过我已选择了相应的开源协议,他的行为也还在协议之内,所以谴责之词也无从说起,在此还是非常感谢曾经想为我打抱不平的小伙伴们。
  2. 非常欢迎大家通过PR或Issue帮助改善代码、丰富功能,我将继续做一些拓展性的实验,进一步研究capsule的效果。