FCN大总结:
- FCN虽然是一篇现在来看比较简单的一个网络结构,但是却能够连年在应用量上霸榜。现在我们就来一窥究竟。在深入了解FCN之前,还是需要对转置卷积进行一个比较充分的总结,这样在理解网络结构的时候会好受得多。
转置卷积:
-
转置卷积其实用一句话来概括就是普通卷积重新排列的矩阵和要卷积的拉平之后的feature map进行矩阵相乘得到的。这句话很绕,可以慢慢解释。
-
例如上面的卷积,可以对卷积核进行矩阵重排,变成下面的矩阵:
-
把要拉平的feature map拉平之后矩阵相乘
-
转置卷积就是把原来重新排列之后的矩阵进行转置,和2 * 2 的feature map(也就是原来普通卷积的输出feature map)拉平之后进行矩阵相乘。如下图所示
-
转置卷积只恢复原来的形状,不恢复数值,使得网络在上采样的时候能够进行参数的学习。
转置卷积的stride:
- stride其实就是相当于卷积的时候卷积块数值之间的离散情况,或者说,就是卷积核数据两两之间插入了几个0.
- 这张图片大致把整个转置卷积的过程体现出来了。
- 当卷积核的kernel_size = k,stride = s,padding = p,输入图片size = n x n,输出feature map的size为m。stride也可以这样理解,就是每一个卷积核的数据被padding数据围绕的圈数+1.
- m=ns−(s−1)+2(k−1)−(k−1)−2p=(n−1)s−2p+k\begin{aligned} m &=n s-(s-1)+2(k-1)-(k-1)-2 p =(n-1) s-2 p+k \end{aligned}m=ns−(s−1)+2(k−1)−(k−1)−2p=(n−1)s−2p+k
转置卷积的backward:
- 初等的转置卷积相当于如下的计算:
-
最重要的是求导的时候进行矩阵的转换:
-
从以下计算式对所有的参数(xi,jx_{i,j}xi,j)进行求导
y00=k00x00+k01x01+k10x10+k11x11y_{00}=k_{00} x_{00}+k_{01} x_{01}+k_{10} x_{10}+k_{11} x_{11}y00=k00x00+k01x01+k10x10+k11x11
y01=k00x01+k01x02+k10x11+k11x12y_{01}=k_{00} x_{01}+k_{01} x_{02}+k_{10} x_{11}+k_{11} x_{12}y01=k00x01+k01x02+k10x11+k11x12
y10=k00x10+k01x11+k10x20+k11x21y_{10}=k_{00} x_{10}+k_{01} x_{11}+k_{10} x_{20}+k_{11} x_{21}y10=k00x10+k01x11+k10x20+k11x21
y11=k00x11+k01x12+k10x21+k11x22y_{11}=k_{00} x_{11}+k_{01} x_{12}+k_{10} x_{21}+k_{11} x_{22}y11=k00x11+k01x12+k10x21+k11x22 -
求导的时候把求导的结果扩展成一个矩阵:
-
这样在backward就可以通过矩阵运算进行加速了。
-
如果想看kernel size = 3 的详细推导可以参考这篇文章:https://www.cnblogs.com/qizhou/p/13895967.html
-
其实转置卷积的实现就是conv的backward,这是pytorch的原版实现方式!
- 接下来终于可以进入FCN的论文解读了:
FCN:
- 在abstract,作者提到,FCN的backbone来自于同时期的网络,这里选择了VGG,GoogleNet,和AlexNet。他们把原来分类的模型进行一定的finetune应用到分割任务上。通过skip architecture(就是网络的短路线,把卷积层的feature map引出来contact用的),把低层和深层的feature map合并起来进行像素级分割,最终收获了state of art的成绩。不光检测精度好,而且一张图片前向推理的速度不到0.2s。网络结构如下:
- 这是第一个端到端的分割卷积网络,能够用有监督训练对每一个像素的类别进行预测。而且输入图片的size可以随意,它把VGG最后的fc层改成了conv层。其中上采样的层使得网络能够进行像素级别的分类。
论文提出:
- 论文作者看到了全连接层的缺点。比如AlexNet或者是VGG等,他们最后接的全连接层把空间坐标和维度全部都丢掉了,而且输入的图片因为全连接层的存在只能是同一个size的,这极大地限制了网络的实用性。然而,全连接和卷积其实本质都是一样的,就是矩阵乘法,为什么一定要用全连接层呢?用FC层代替它不香吗?而且,运算速度还比FC层快了5倍,所以作者开始了对Convnet的探索之旅。
- 他又在其他的分割网络中看到了,其实现在还没有一个端到端能够直接训练的分割网络,一般来说,送到网络中的还是一个一个Patch,就像RCNN那样,这样会多了一堆重复计算,还不如直接像Faster RCNN学习,直接把整个图片送到网络,再对feature map进行切分。所以作者也为了实现这个目标进行了一系列实验,最终有了这个论文。而且作者认为,用patch进行训练,在进行SGD的时候梯度是不稳定的,你切的patch不同,loss就不同,到时候随机性太大网络就很难训练了。
- 作者也考虑到了,如果减少网络中下采样的次数会怎么样?作者做实验认为,这种方法是有代价的,因为它意味着更多的计算量,而且网络很有可能过拟合,比他们原来设计的网络还烂。作者把feature map的size减小的原因是这样能够使得网络变得更深一些,这样才能更好的分类,而且降低参数。之后feature map很小了再用转置卷积上采样回来。
- 最后在进行像素级分类的时候,作者使用了上采样的方法,而且关于上采样这一个小结的标题就是:上采样其实就是卷积的反向传播,pytorch在实现转置卷积的时候应该就是受到了这一篇文章的启发。
网络结构:
- 话不多说,先把图片丢上去。其实现在来看网络结构并不是非常复杂,只不过最后的时候把各个卷积核进行上采样再拼接起来。
- FCN-32s,直接把conv7层进行32倍上采样进行预测。
- FCN-16s,把Pool4层的卷积层和进行两倍上采样的conv7进行elewise相加,最后进行16倍上采样之后,再进行预测。
- FCN-8s,Pool3层 + 2倍上采样的Pool4层 + 4倍上采样的 conv7层elewise相加,进行8倍上采样再进行预测。
- 作者认为,底层的卷积核包含的信息更多是位置信息和纹理信息,高层的卷积核包含的信息更多是语义信息和抽象的信息。如果把这些卷积核的信息contact起来,提取的特征会比较完全,比较有代表性。然而,低层的feature map的大小显然比高层的大,如何结合起来呢?这就要用到我们之前讲的上采样的知识了。作者选择了转置卷积,因为这个卷积的参数是可以学习的,能够通过神经网络的反向传播训练得到更多的信息,比双线性插值等复杂度更高。
- 在进行预测的时候,作者是对每一个像素进行softmax prediction处理。
评价指标:
- pixel accuracy: ∑inii/∑iti\sum_{i} n_{i i} / \sum_{i} t_{i}∑inii/∑iti
- mean accuraccy: (1/ncl)∑inii/ti\left(1 / n_{\mathrm{cl}}\right) \sum_{i} n_{i i} / t_{i}(1/ncl)∑inii/ti
- mean IU: (1/ncl)∑inii/(ti+∑jnji−nii)\left(1 / n_{\mathrm{cl}}\right) \sum_{i} n_{i i} /\left(t_{i}+\sum_{j} n_{j i}-n_{i i}\right)(1/ncl)∑inii/(ti+∑jnji−nii)
- frequency weighted IU:(∑ktk)−1∑itinii/(ti+∑jnji−nii)\left(\sum_{k} t_{k}\right)^{-1} \sum_{i} t_{i} n_{i i} /\left(t_{i}+\sum_{j} n_{j i}-n_{i i}\right)(∑ktk)−1∑itinii/(ti+∑jnji−nii)
- nijn_{i j}nij 表示类别为 i 预测为 j 的像素个数,niin_{i i}nii就是表示预测对的像素。ti=∑jnijt_{i}=\sum_{j} n_{i j}ti=∑jnij 相当于类别为 i 的所有像素
- mean IU表示像素之间的交并比,其实和IOU有异曲同工之处。其实可以说是预测对的像素比上类别为 i 的像素加上所有预测为 i 的像素减去预测为类别 i 的并且正确的像素。
- frequency weighted IU就是给每一个种类的像素加上一个权重。如果类别出现的频率大,那么IU的比重就越大。
论文意义:
-
首先在语义分割问题上实现了端到端的训练,而且超越了当时sota。
-
把FC层用1 x 1卷积代替,加快了推理速度,实现了图片的多尺度输入。
-
采用了转置卷积进行上采样成原图大小进行预测,这是比较新的想法。
-
以下是一些比赛的结果,看看就好。不过作者基本没有用FCN-8s模型,估计是计算太慢了,所以很多没有用吧。FCN-8s模型在比赛中的实用度还是需要讨论的。