深度学习领域的god father,Hilton大神终于发表了他关于capsule研究的最新成果《Dynamic Routing Between Capsules》。之前就曾经听过许多关于capsule的相关消息,我已经是被吊足了胃口,这几天今天终于有机会可以一睹capsule到底是何方神圣。
其实,在读这篇论文的过程中,可能是缺少一些前置知识,虽然能把握论文在讲什么,但我一直觉得自己没透彻,所以比一般论文花了更久的时间(头悬梁锥刺股),直到现在我依然觉得自己的理解有问题,所以这是一篇带着很多问题的论文笔记。
什么是capsule
capsule到底是是什么呢?我们知道在一般的深度网络中的某一个layer的输入和输出,都是通过某种数值(标量)来表示。譬如在人脸这个概念,对于深度网络来说,可能人脸对应某个featuremap上的一个数值a表示其存在性,但是人脸还有一些别的属性(方脸还是圆脸),但由于独立性,这些特征往往没有办法通过一个数值表示。
那么我们可不可以加入一个值(假想的filter)来专门表示方圆脸,我们把这个值叫做b,然后我们又加入了一些值来表示眼睛的大小、皮肤的好坏等等,于是我们得到了一组有序数值(a,b,c,d,...)来表示人脸这个实体,这组有序数值其实就是一个向量(vector),所以我们干脆就用一个向量来表示人脸好了,而这些vector就是capsule的输入和输出。在capsule中特征不再是一个个数值,而是一个个向量。
这篇论文中,使用vector的长度来表示实体的存在,vector的方向表示实体的特性。
怎么处理capsule
我们现在已经得到了capsule的概念了,我们使用向量来替代了标量。但是向量在处理上不能使用标量的方法,譬如,一般的激活函数没有办法处理向量,由输入向量到输出向量也不能使用简单的加权。本篇文章提出了使用动态路由(dynamic routing)的方式处理向量。
首先,针对激活函数,本文提出了一种非线性squashing函数:
其中,vj为输出,sj为输入,j为capsule的编号。
这个公式很类似于传统的具有挤压性质的激活函数:
- 其输出的向量的长度被限制在了[0,1)。
- 对于输出向量长度挤压,即长度较小时递增较快,长度较长时递增较慢。
在有了激活函数之后,我们需要解决vector to vector的方法问题,本文使用了变换矩阵加上加权路由的方式。
首先,使用变换矩阵将前层capsule的向量映射到后层capsule的空间上:
其中j为对应后层capsule的编号,i为前层capsule的编号。
在得到映射后,通过路径耦合系数的加权来得到输入到后层的向量:
其中,耦合系数cij就是bij的softmax:
bij通过贡献度(点积)更新,即路径对最终结果所起作用:
(这么看上去,这不就是个attention机制么囧) routing的具体流程如下:
以上就是capsule层实现的细节。
CapsNet的结构
本文介绍了一个使用capsule的网络:CapsNet。
在第一个capsule之前,存在整两个卷积层来抽取特征。对为什么使用传统卷积大概的解释就是,正如前面所说的capsule中的vector是要包含“实体”的属性信息,而如果直接使用像素点作为输入,包含的属性信息过少。况且,卷积也可以说是一种特例的capsule,即一维向量,我们可以认为浅层实体的属性太少,只需要一维就可以表达。
第二个卷积的输出为32组8维vector的capsule,可以认为是传统卷积具有832个filter,然后将这些filter分为8组。这个capsule层被称为PrimaryCaps,其中包含了36乘32个8维的vector,对于每一个66的平面上的vector,它们是共享权值的。
在PrimaryCaps之后,就是表示数字实体的capsule层,每一个capsule为一个16维的vector,其长度表示了该数字实体是否存在。
由于长度没有归一化,所以对多个实体的判断是可以共存的。
以上就是这篇论文是怎样去应用capsule这个想法的,目前笔记的施工还有一些没完成,但是基本的原理已经讲完了。总的来说,这篇论文的基本主旨是实现capsule的尝试,还是存在很多问题,看的时候我也是一脸懵逼,譬如说为什么要用CNN,为什么要用类似全连接的方式,属性为什么是完全分离的,为什么低级实体的属性可以在不考虑其它低级实体的情况下直接向高级实体的属性映射...虽然存在着种种问题,但是这篇文章还是做出了初步的成果(重叠数字等),说明capsule是可用的,为我们挖了一个新的大坑。期待后续更深入的研究。