第二次作业:卷积神经网络 part 2

耗尽温柔 提交于 2020-08-10 09:26:23

【第二部分】 代码练习

MobileNetV1 网络

MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications, 2017https://arxiv.org/abs/1704.04861

VGG,GoogleNet,ResNet进一步提高CNN的性能。但是到ResNet,网络已经达到152层,模型大小动辄几百300MB+。这种巨大的存储和计算开销,严重限制了CNN在某些低功耗领域的应用。在实际应用中受限于硬件运算能力与存储(比如几乎不可能在手机芯片上跑ResNet-152),所以必须有一种能在算法层面有效的压缩存储和计算量的方法。而MobileNet/ShuffleNet正为我们打开这扇窗。
Mobilenet v1是Google于2017年发布的网络架构,旨在充分利用移动设备和嵌入式应用的有限的资源,有效地最大化模型的准确性,以满足有限资源下的各种应用案例。Mobilenet v1核心是把卷积拆分为Depthwise+Pointwise两部分。
Depthwise 处理一个三通道的图像,使用3×3的卷积核,完全在二维平面上进行,卷积核的数量与输入的通道数相同,所以经过运算会生成3个feature map。卷积的参数为: 3 × 3 × 3 = 27,如下所示:

Depthwise卷积
Pointwise 不同之处在于卷积核的尺寸为1×1×k,k为输入通道的数量。所以,这里的卷积运算会将上一层的feature map加权融合,有几个filter就有几个feature map,参数数量为:1 × 1 × 3 × 4 = 12,如下图所示:

替代文字
因此,可以看出,同样得到4个feature map,使用Depthwise+Pointwise处理,参数数量可以大大降低。







class Block(nn.Module):
    '''Depthwise conv + Pointwise conv'''
    def __init__(self, in_planes, out_planes, stride=1):
        super(Block, self).__init__()
        # Depthwise 卷积,3*3 的卷积核,分为 in_planes,即各层单独进行卷积
        self.conv1 = nn.Conv2d(in_planes, in_planes, kernel_size=3, stride=stride, padding=1, groups=in_planes, bias=False)
        self.bn1 = nn.BatchNorm2d(in_planes)
        # Pointwise 卷积,1*1 的卷积核
        self.conv2 = nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=1, padding=0, bias=False)
        self.bn2 = nn.BatchNorm2d(out_planes)
    def forward(self, x):
        out = F.relu(self.bn1(self.conv1(x)))
        out = F.relu(self.bn2(self.conv2(out)))
        return out

比如,把上图的代号化为实际的数字,输入图片维度是11 × 11 × 3,标准卷积为3 × 3 × 3 ×16(假设stride为2,padding为1),那么可以得到输出为6 × 6 × 16的输出结果。现在输入图片不变,先通过一个维度是3 × 3 × 1 × 3的深度卷积(输入是3通道,这里有3个卷积核,对应着进行计算,理解成for循环),得到6 × 6 × 3的中间输出,然后再通过一个维度是1 × 1 × 3 ×16的1 ×1卷积,同样得到输出为6 × 6 × 16。还可以借助一幅经典的GIF图来理解.

MobileNetV2 网络

MobileNetV2: Inverted Residuals and Linear Bottlenecks, CVPR 2018https://arxiv.org/abs/1704.04861
MobileNet V1 的主要问题: 结构非常简单,但是没有使用RestNet里的residual learning;另一方面,Depthwise Conv确实是大大降低了计算量,但实际中,发现不少训练出来的kernel是空的。
MobileNet V2 的主要改动一:设计了Inverted residual block

ResNet中的bottleneck,先用1x1卷积把通道数由256降到64,然后进行3x3卷积,不然中间3x3卷积计算量太大。所以bottleneck是两边宽中间窄(也是名字的由来)。
现在我们中间的3x3卷积可以变成Depthwise,计算量很少了,所以通道可以多一些。所以MobileNet V2 先用1x1卷积提升通道数,然后用Depthwise 3x3的卷积,再使用1x1的卷积降维。作者称之为Inverted residual block,中间宽两边窄。




MobileNet V2 的主要改动二:去掉输出部分的ReLU6

在 MobileNet V1 里面使用 ReLU6,ReLU6 就是普通的ReLU但是限制最大输出值为 6,这是为了在移动端设备 float16/int8 的低精度的时候,也能有很好的数值分辨率。Depthwise输出比较浅,应用ReLU会带来信息损失,所以在最后把ReLU去掉了(注意下图中标红的部分没有ReLU)。

下面就是 Inverted residual block 部分的代码,主要思路就是:
expand + Depthwise + Pointwise 其中,expand就是增大feature map数量的意思。需要指出的是,当步长为1的时候,要加一个 shortcut;步长为2的时候,目的是降低feature map尺寸,就不需要加 shortcut 了。


  1. MobileNet v1 与 v2 微结构的区别
    v1 的微结构

    v2 的微结构

    可以看到有两个区别。




  2. v2在原有的dw之前加了一个pw专门用来升维。这么做是因为dw给多少通道就输出多少通道,本身没法改变通道数,先加pw升维后,dw就能在高维提特征了。
  3. v2把原本dw之后用来降维的pw后的激活函数给去掉了。这么做据作者说是因为他认为非线性在高维有益处,但在低维(例如pw降维后的空间)不如线性好。
  4. MobileNet v2 与 ResNet 微结构的区别
    ResNet 的微结构(Residual Module)

    MobileNet v2 的微结构(Inverted Residual Module)

    可以看到基本结构很相似。不过ResNet是先降维(0.25倍)、提特征、再升维。而v2则是先升维(6倍)、提特征、再降维。另外v2也用DW代替了标准卷积来做特征提取。
    注:上面的示意表达式省略了Shortcut。





HybridSN 高光谱分类网络

这篇论文构建了一个 混合网络 解决高光谱图像分类问题,首先用 3D卷积,然后使用 2D卷积.

  1. 定义 HybridSN 类
    模型的网络结构为如下图所示:
    HybridSN
    三维卷积部分:


  • conv1:(1, 30, 25, 25), 8个 7x3x3 的卷积核 ==>(8, 24, 23, 23)
  • conv2:(8, 24, 23, 23), 16个 5x3x3 的卷积核 ==>(16, 20, 21, 21)
  • conv3:(16, 20, 21, 21),32个 3x3x3 的卷积核 ==>(32, 18, 19, 19)
    接下来要进行二维卷积,因此把前面的 32*18 reshape 一下,得到 (576, 19, 19)
    二维卷积:(576, 19, 19) 64个 3x3 的卷积核,得到 (64, 17, 17)
    接下来是一个 flatten 操作,变为 18496 维的向量,
    接下来依次为256,128节点的全连接层,都使用比例为0.4的 Dropout,
    最后输出为 16 个节点,是最终的分类类别数。





class HybridSN(nn.Module):
  def __init__(self):
    super(HybridSN,self).__init__()
    self.conv3d1 = nn.Conv3d(1,8,kernel_size=(7,3,3))

    self.conv3d2 = nn.Conv3d(8,16,kernel_size=(5,3,3))
 
    self.conv3d3 = nn.Conv3d(16,32,kernel_size=(3,3,3))

    self.conv2d4 = nn.Conv2d(576,64,kernel_size=(3,3))
  
    self.fc1 = nn.Linear(18496,256)
    self.fc2 = nn.Linear(256,128)
    self.fc3 = nn.Linear(128,16)
    self.dropout = nn.Dropout(0.4)
#?
  

【第三部分】 论文阅读心得

Beyond a Gaussian Denoiser: Residual Learning of Deep CNN for Image Denoising

参考:https://www.jianshu.com/p/3687ffed4aa8
图像去噪的目的是从一个遵循图像劣化模型y=x+v的噪声观察y中恢复数据x。一个常见的假设是v是加性白噪声(AWGN),具有标准偏差。
文章重点:
强调了residual learning(残差学习)和batch normalization(批量标准化)在图像复原中相辅相成的作用,可以在较深的网络的条件下,依然能带来快的收敛和好的性能。
文章提出DnCNN,在高斯去噪问题下,用单模型应对不同程度的高斯噪音;甚至可以用单模型应对高斯去噪、超分辨率、JPEG去锁三个领域的问题。

网络结构:
第一部分:Conv(3 * 3 * c * 64)+ReLu (c代表图片通道数)
第二部分:Conv(3 * 3 * 64 * 64)+BN(batch normalization)+ReLu
第三部分:Conv(3 * 3 * 64)
每一层都zero padding,使得每一层的输入、输出尺寸保持一致。以此防止产生人工边界(boundary artifacts)。第二部分每一层在卷积与reLU之间都加了批量标准化(batch normalization、BN)。









不同的是DnCNN并非每隔两层就加一个shortcut connection,而是将网络的输出直接改成residual image(残差图片),设纯净图片为x,带噪音图片为y,假设y=x+v,则v是残差图片。即DnCNN的优化目标不是真实图片与网络输出之间的MSE(均方误差),而是真实残差图片与网络输出之间的MSE。
2.1.残差学习
根据ResNet中的理论,当残差为0时,堆积层之间等价于恒等映射,而恒等映射是非常容易训练优化的。作者注意到在图像复原领域(尤其是在噪音程度较小的情况下),噪音图片与纯净图片的残差非常小,所以理论上残差学习非常适合运用到图像复原上。

通俗讲,这样的网络设计就是在隐层中将真实的图片x从原噪音图y中消去。作者注意到:在超分领域,低分辨率图片就是高分辨率图片的双三次上采样操作形成的,故超分领域的残差图片和去高斯噪声领域的残差图片是等价的,同理还有JPEG解锁领域的残差图片。(?)这样,用一个模型应对三种问题便有了可能性,最终实验证明确实有效。

2.2.批量标准化batch normalization
SGD(随机梯度下降法)广泛应用于CNN的训练方法中,但是训练的性能却很大程度受内部协变量移位这一问题所影响。BN就是在每一层的非线性处理之前加入标准化、缩放、移位操作来减轻内部协变量的移位。可以给训练带来更快的速度,更好的表现,使网络对初始化变量的影响没有那么大。

内部协变量移位(internal covariate shift):深层神经网络在做非线性变换前的激活输入值,随着网络深度加深或者在训练过程中,其分布逐渐发生偏移或者变动,之所以训练收敛慢,一般是整体分布逐渐往非线性函数的取值区间的上下限两端靠近(对于Sigmoid函数来说,意味着激活输入值WU+B是大的负值或正值),所以这导致反向传播时低层神经网络的梯度消失,这是训练深层神经网络收敛越来越慢的本质原因。

批量标准化(batch normalization):就是通过一定的规范化手段,把每层神经网络任意神经元这个输入值的分布强行拉回到均值为0方差为1的标准正态分布,即把越来越偏的分布强制拉回比较标准的分布,这样使得激活输入值落在非线性函数对输入比较敏感的区域,所以输入的小变化才就会导致损失函数有较大的变化,意思就是让梯度变大,避免梯度消失问题产生,而且梯度变大意味着学习收敛速度快,能大大加快训练速度。

2.3.网络深度network depth
作者参考《Very deep convolutional networks for large-scale image recognition》的标准,将DnCNN的卷积核大小设置为3 * 3,并且去掉了所有的池化层。

感受野:是卷积神经网络中某一层输出的特征图对到网络输入图像中映射的区域的大小。

感受野计算时有下面的几个情况需要说明:

第一层卷积层的输出特征图像素的感受野的大小等于滤波器的大小;
深层卷积层的感受野大小和它之前所有层的滤波器大小和步长有关系;
计算感受野大小时,忽略了图像边缘的影响,即不考虑padding的大小。
此外,关于每一层的strides的说明,这个strides是之前所有层stride的乘积,即


strides(i)= stride(1) * stride(2) * ...* stride(i-1)

对于单层卷积网络,其feature map上每个特征点对应原图上的感受野大小等于卷积层滤波器的大小;对于多层卷积网络,可由此逐层往回反馈,通过反复迭代获得原始输入图像中感受野大小,即后面深层的卷积层感受野大小就和之前所有网络层的滤波器大小和步长有关系了,在计算的时候,忽略图像Padding的大小。使用的公式可以表示如下:

r(i) = (r(i+1) - 1) * stride(i) + c(i)

其中,r(i)表示第i层感受野大小,stride(i)表示第i层步长,c(i)表示第i层卷积核大小。
此外,对于卷积网络中的激活函数层(ReLU/Sigmoid/...)等,感受野迭代公式为:

r(i)=r(i+1)

对于DnCNN网络,网络层数是d的时候,网络的感受野就是(2d+1) * (2d+1)。DnCNN的感受野与网络深度d相关,而卷积神经网络中的感受野可以类比到传统去噪算法中的effective patch size。故作者参考最主流的几个去噪算法,根据2d+1=effective patch size,反向推出DnCNN一个合适的网络深度。

最终,在噪声水平为25的情况下,作者选择EPLL的36*36作为参考标准,因为EPLL的effective patch size横向比较最小(如果DnCNN选择最小的感受野都能胜过这些主流算法,就说明DnCNN很牛逼)。处理高斯去噪的DnCNN的深度为17,通用去噪任务的DnCNN的深度为20。

作者做了三种实验:

对比有无residual learning与batch normalization对复原效果、收敛快慢的影响,最终证明这两是相辅相成的,都利用上时网络各方面性能达到最好。

根据特定程度的高斯噪声训练DnCNN-S、根据不定程度的高斯噪声训练DnCNN-B、根据不同程度的噪音(包括不同程度的高斯噪声、不同程度的低分辨率、不同程度的JPEG编码)训练的DnCNN-3来与最前沿的其他算法做对比实验。结论:DnCNN-S有最好的性能,但是DnCNN-B也有优于其他算法的性能,证明了DnCNN-B具有很好的盲去高斯噪声的能力;DnCNN-3则证明了DnCNN-3具有不俗的复原图像的泛化能力。

对比了DnCNN与其他前沿去噪算法的运行速度的实验,结论:速度还是不错的,CPU\GPU环境下均属于中上水平。

CVPR2018的论文《Squeeze-and-Excitation Networks》

论文链接:https://arxiv.org/abs/1709.01507
参考:https://blog.csdn.net/u014380165/article/details/78006626
SENet的核心思想在于通过网络根据loss去学习特征权重,使得有效的feature map权重大,无效或效果小的feature map权重小的方式训练模型达到更好的结果。

Figure1表示一个SE block。主要包含Squeeze和Excitation两部分,接下来结合公式来讲解Figure1。

首先Ftr这一步是转换操作(严格讲并不属于SENet,而是属于原网络,可以看后面SENet和Inception及ResNet网络的结合),在文中就是一个标准的卷积操作而已,输入输出的定义如下表示。

这里写图片描述

那么这个Ftr的公式就是下面的公式1(卷积操作,vc表示第c个卷积核,xs表示第s个输入)。

Ftr得到的U就是Figure1中的左边第二个三维矩阵,也叫tensor,或者叫C个大小为H*W的feature map。而uc表示U中第c个二维矩阵,下标c表示channel。

接下来就是Squeeze操作,公式非常简单,就是一个global average pooling:

因此公式2就将HWC的输入转换成11C的输出,对应Figure1中的Fsq操作。为什么会有这一步呢?这一步的结果相当于表明该层C个feature map的数值分布情况,或者叫全局信息。

再接下来就是Excitation操作,如公式3。直接看最后一个等号,前面squeeze得到的结果是z,这里先用W1乘以z,就是一个全连接层操作,W1的维度是C/r * C,这个r是一个缩放参数,在文中取的是16,这个参数的目的是为了减少channel个数从而降低计算量。又因为z的维度是11C,所以W1z的结果就是11C/r;然后再经过一个ReLU层,输出的维度不变;然后再和W2相乘,和W2相乘也是一个全连接层的过程,W2的维度是C*C/r,因此输出的维度就是11C;最后再经过sigmoid函数,得到s。

也就是说最后得到的这个s的维度是11C,C表示channel数目。这个s其实是本文的核心,它是用来刻画tensor U中C个feature map的权重。而且这个权重是通过前面这些全连接层和非线性层学习得到的,因此可以end-to-end训练。这两个全连接层的作用就是融合各通道的feature map信息,因为前面的squeeze都是在某个channel的feature map里面操作。

在得到s之后,就可以对原来的tensor U操作了,就是下面的公式4。也很简单,就是channel-wise multiplication,什么意思呢?uc是一个二维矩阵,sc是一个数,也就是权重,因此相当于把uc矩阵中的每个值都乘以sc。对应Figure1中的Fscale。

了解完上面的公式,就可以看看在实际网络中怎么添加SE block。Figure2是在Inception中加入SE block的情况,这里的Inception部分就对应Figure1中的Ftr操作。

Figure3是在ResNet中添加SE block的情况。

看完结构,再来看添加了SE block后,模型的参数到底增加了多少。其实从前面的介绍可以看出增加的参数主要来自两个全连接层,两个全连接层的维度都是C/r * C,那么这两个全连接层的参数量就是2*C^2/r。以ResNet为例,假设ResNet一共包含S个stage,每个Stage包含N个重复的residual block,那么整个添加了SE block的ResNet增加的参数量就是下面的公式:

CVPR2019的论文《Deep Supervised Cross-modal Retrieval》

跨模式检索的核心是如何衡量不同类型数据之间的内容相似性。在本文中提出了一种新颖的跨模式检索方法,称为深度监督跨模式检索(Deep Supervised Cross-modal Retrieval, DSCMR)。它旨在找到一个通用的表示空间,在其中可以直接比较来自不同模态的样本。

框架

包括两个子网络——一个是图像模态,另一个是文本模态,端到端训练
对于图像:利用预训练在 ImageNet 的网络提取出图像的 4096 维的特征作为原始的图像高级语义表达。然后后续是几个全连接层,来得到图像在公共空间中的表达。
对于文本:利用预训练在 Google News 上的 Word2Vec 模型,来得到 k 维的特征向量。一个句子可以表示为一个矩阵,然后使用一个 Text CNN 来得到原始的句子高级语义表达。之后也是同样的形式,后面是几个全连接层来得到句子在公共空间中的表达。
为了确保两个子网络能够为图像和文本学到公共的表达,我们使这两个子网络的最后几层共享权重。直觉上这样可以使得同一类的图片和文本生成尽可能相似的表达
最后面是一层全连接层来进行分类
这样以后,跨模态的联系可以很好的学到,并且有区分性的特征也可以同时学到




易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!