前生今世-------------------------------------------->
早期的CNN网络,如VGG,利用的是直接堆叠卷积层和池化层的办法,如下图所示(vgg16):
从左(bottom)到右(top),feature map的分辨率逐渐减小,这其中有两个问题如下:
(1)卷积或池化的本质其实是滤波,滤波必然造成信息损失,层层滤波会造成信息层层损失,top层的特征虽然理论上是最discriminative的特征,但其实损失了不少bottom层上的有用信息;
(2)在反向传播(backward)的过程中,top层的梯度(diff)是要传递给bottom层的,计算公式:
diff_bootom = sum(diff_top * W(权重))
W权重的数值都小于1,在diff反向传播的过程中,一层一层的乘以当前层的W,diff会变得越来越小,直至梯度消失,在某一层的梯度消失之后,该层将不会知道自己的W如何改变才能减小top层的loss(前线阵地战况如何啊?损失惨重吗?电话信号传过来根本听不清,我该如何配合前线?)
resnet在这种情况下应运而生(很佩服何凯明大神,想法简单但不平凡,说明大神对deep learning已经炉火纯青,活学活用,融会贯通了),resnet解决了三个问题(针对VGG等直筒式网络的缺点):
(1)通过shot cut connection或者highway& byway,将底层的信息运送给top层,弥补了信息损失,容易提取到更彪悍的特征;
(2)反向传播时,top层的误差,可以通过byway直接传过来(抄小路,抄近道),梯度消失的问题有效减轻(将军,前线东路缺粮,需要支援,多亏总部给我们的这条电话专线啊);
(3)googlenet和resnet的出现,推动了神经网络发生质变,整个网络的信息流动更加繁荣和活跃(网络越来越宽,并行旁路不断进化变种,底层信息不断的越位, 越权上访,更加民主和高效),形如densenet, resneXt, Xception, inception, atten(se-net)等;
CNN网络繁荣的同时,也促进了网络优化的产生,如mxnet等并行框架,卷积核心的设计等,目的都是使得网络运行更快,模型体积更小,mobilenet-v1独树一帜(可分离卷积 depth wise convolution & point wise convolution),在卷积上做出了很巧妙的改进,更适合在移动端进行推理,时间复杂度更低,mobilenet-v1的论文可以参考如下:
https://arxiv.org/pdf/1704.04861.pdf
完善自我------------------------------------------------>
mobilenet-v2由mobilenet-v1改进而来,mobilenet-v1是google早在2016年就研究的产物,只不过2018年发现没人这么做过,所以就发表出来了(占坑很重要).V1采用了类似vgg的直筒结构,所以是有缺点的,正好resnet方兴未艾,所以就搭一下resnet的快车,并做了些分析和改进(inverted residuals & linear bottlenecks).
mobilenet-v2: https://arxiv.org/pdf/1801.04381.pdf
首先,明确并回忆几个概念:
(1)嵌入在高维空间中的低维感兴趣流形(降维)
一个流形好比是一个 d 维的空间,在一个 m 维的空间中 (m > =d) 被扭曲之后的结果
什么时候最能体现出流形的本征信息呢?m==d的时候,你会很清楚的看清流行实质信息,形如下图:
再举一个简单的例子说明流形学习,这个例子就是鱼网捕鱼,当刚把一张很大的网投入水里的时候,假设网住了很多鱼,但由于网子的展开面积很大,这时我们要进入到网子里面用手徒手抓鱼的时候,很难抓到一条,因为单位水体积里面,鱼的密度太小了.如果先收紧网子,再徒手抓鱼的时候,那么会很容易捕捉到一条鱼,因为单位水体积里,鱼太多了.
上面例子中的鱼即是流形信息,收紧鱼网的动作则是流形学习(降维的过程),人则是relu函数(捕捉).mobilenet-v1有一个width multiplier, 作用是减少map channel的数量,在这里我觉得牵扯到流形学习上面来的话,显得很生硬,只是一个减少运算的操作而已嘛,何必流形~~.
mobilenet-v2论文中,关于流形学习的这段论述,只是为了阐述一个观点,relu函数不可靠,需要线性变换,输入到relu的channel个数越多(网子越大),信息(鱼)隐藏的越隐蔽(不好抓),不容易被人抓到(relu开启),linear bottleneck.
(2)relu激活函数
函数图像如下图所示:
relu函数的优点:
(1)相比较sigmoid函数来说,由于在正向区间为线性,导数为常量1,梯度不至于饱和,可减轻梯度消失,快速收敛;
(2)计算简单,分段线性操作
但是,relu是有缺点的:
(1)输入在负数区间内,relu的输出是0,一旦输出为0,则relu节点会永久死亡,梯度不能再通过此节点反向传播;
(2)当反向传播的梯度很大时,relu之前的卷积层权重经过更新后()会变得很负,下次输入relu
的时候,也会导致relu输出为0,从而有可能会永久死亡关闭
relu的反向传播可参考caffe的代码加以理解:
template <typename Dtype>
void ReLULayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
const vector<bool>& propagate_down,
const vector<Blob<Dtype>*>& bottom)
{
if (propagate_down[0])
{
const Dtype* bottom_data = bottom[0]->cpu_data();
const Dtype* top_diff = top[0]->cpu_diff();
Dtype* bottom_diff = bottom[0]->mutable_cpu_diff();
const int count = bottom[0]->count();
for (int i = 0; i < count; ++i)
{
bottom_diff[i] = top_diff[i] * ((bottom_data[i] > 0); // 当输入bottom_data[i] 小于等于0时,梯度无法反向传播,权重无法更新,可能会永久死亡
}
}
}
relu激活函数的缺点,也是mobilenet-v2(inception, Xception等同理)中linear bottleneck设计的主要因素.
(3)inverted residuals:
由于采用了Depth wise conv和point wise conv, 这个两个卷积的核心都很小,而且Depth又采用了一个单channel的卷积,会造成信息的丢失,同时输入给下层的信息不丰富.输入到relu的数值极有可能是负数,也会引起relu的死亡.
这个结构的设计是有两个优势或目的的:
a. 丰富特征信息,适应可分离卷积这种特殊结构;
b. 隐藏信息,将流形信息(鱼)嵌入到更大的空间(网与水体)中,不容易被人(relu)抓到(过滤).
讲完了linear bottleneck与inverted residual,基本就讲完这篇论文了,论文中又说了一些其他的,内存与计算速度方面的优势等,本来想把整篇论文翻译一遍,但觉得意义不大,所以放弃了,有不明白的地方,可以探讨.