胶囊网络

前言

在使用CNN处理图像时,如果我们使用人脸数据训练这么一个CNN,训练出来的CNN可以很好地识别人脸,但是如果我们改变人脸某些元素的位置,比如将一个眼睛和嘴巴调换位置,CNN依然会认为这是一张人脸。这是因为CNN是通过使用卷积核去识别关键特征,而在人脸中眼睛和嘴巴都是关键元素,所以即使它们互换位置,CNN也依然会认为这是一张人脸。如果我们想要让CNN可以识别这些位置错误的脸不是人脸,那就需要给CNN喂一些位置错误的脸,并告诉CNN这不是一张人脸,这样训练出来的CNN才能识别出位置错误的脸不是人脸。我们可以发现,CNN不能从一张正常人脸中学习到眼睛和嘴巴的相对位置关系,除了相对位置关系,其实还有很多很重要的信息是CNN不能捕获的,CNN只能捕获到关键元素是否存在的信息而不能捕获到关键元素之间更多的联系信息。CNN利用池化层扩大了感受野,也减弱了因旋转和平移等因素对图像识别造成的影响,但也因此丢失了关键元素之间的相对位置信息。胶囊网络的提出就是为了让模型可以既捕获关键元素的信息,也可以捕获关键元素之间的联系信息。

胶囊网络

胶囊

在常用的神经网络中,使用神经元来接收信号并产生信号,神经元的输入是上一层神经元的输出,神经元的输出是一个常数,可以表示为下面的式子:

其中$h^l$表示第$l$层的神经元的输出,$W_l$表示模型从第$l$层到$l+1$层的参数矩阵,可以看到每一层的输出都是一个向量,向量的每一个元素表示神经元的输出,即神经元产生的信号是常数。

胶囊和神经元最大的不同是胶囊产生的信号是向量而不是常数,向量的模表示产生的信号强弱而向量的方向表示信号的属性。原来的神经元输出信号强度,值越大说明关键元素存在概率越高;而胶囊输出信号强度和属性,不仅能够说明关键元素的存在概率,还能说明关键元素的一个具体方位等信息。那么一层胶囊的信号输出如何传递给下一层胶囊,得到下一层胶囊的信号输出呢,这时候就需要使用到动态路由。

激活函数

常用神经网络的激活函数都是针对处理常量设计的,现在胶囊的输入输出信号都是向量,所以需要一个处理向量的激活函数,这个激活函数如下:

利用向量的模,将输出信号的模压缩到$[0,1)$范围之间。

动态路由

动态路由其实就是胶囊之间的信号传递,我们知道在常用的神经网络中,神经元与神经元之间的联系是使用一个参数控制的,比如上一层第$i$个神经元和下一层第$j$个神经元之间的联系是$W_{i,j}$。同样地,上一层第$i$个胶囊和下一层第$j$个胶囊之间的联系也可以使用$W_{i,j}$表示,只是$W_{i,j}$不再是一个数,而是一个矩阵,通过矩阵变换将上一层的胶囊的向量变换到下一层的胶囊的向量形式,即完成空间转换,我们可以用下式表示:

其中$u_{j|i}$是第$l$层第$i$个胶囊要传递给$l+1$层第$j$个胶囊的信号,是一个向量。然后对于下一层每个胶囊的输出信号,通过对上一层各个胶囊针对这个胶囊的输出进行加权求和,即:

可以看到上一层各个胶囊关于当前层当前胶囊的权重之和等于1,而且权重$c_{i,j}$和$b_{i,j}$相关。那么$b_{i,j}$又是什么呢,$b_{i,j}$初始时全部等于0,即相当于对于当前层各个胶囊,是对上一层的所有胶囊针对这个胶囊的输出取平均。取平均后会得到一个输出信号,这个输出的方向会和上一层某个胶囊针对这个胶囊的输出相似,增大相似胶囊的权重,减小不相似胶囊的权重。度量两个向量是否相似,可以使用内积,所以$b_{i,j}$的更新式子如下:

迭代上式达到一定次数(一般是三次),就可以得到$b_{i,j}$,从而得到下一层胶囊的输出$v_j^{l+1}$。在求$b_{i,j}$的过程,初始时是设置上一层各个胶囊的输出的权重相同,然后通过不断修正,一些胶囊的输出得到较大激励,从而使得上一层某些胶囊在下一层的某些胶囊中发挥主要作用,从而完成胶囊之间的信号传递,完成动态路由过程。