CNN学习记录

基本结构

1. 卷积层

参考:卷积神经网络(CNN)综述
在这里插入图片描述

卷积操作,N——输出大小,k——卷积核,P——Padding像素值,s——步长
k通常是奇数,一方面可以保证使用 Same 填充时填充像素数P是整数,对原图片的填充是对称的;另一方面奇数宽度的卷积核具有一个中心像素点,可以表示卷积核的位置。
在这里插入图片描述

x = torch.randn(size = (1,1,100,100))

conv1 = nn.Conv2d(1, 20, kernel_size=3,stride=1, padding=1)
print(conv1(x).size()) #torch.Size([1, 20, 100, 100])

conv1 = nn.Conv2d(1, 20, kernel_size=7,stride=2, padding=3)
print(conv1(x).size()) #torch.Size([1, 20, 50, 50])

2. 池化层

池化即为降采样操作,常出现在卷积层后。常用的池化函数有Mean-Pooling(均值池化)、Max-Pooling(最大值池化)、Min-Pooling(最小值池化)、Stochastic-Pooling(随机池化)等。
下面示例为4*4平均池化降采样为1进行的操作:

conv1 = nn.Conv2d(1, 20, kernel_size=3,stride=1, padding=1)
AvgDownsample = nn.AvgPool2d(kernel_size=4, stride=4)

x = torch.randn(size = (1,1,100,100))
c1 = conv1(x)
p1 = AvgDownsample(c1)
print(c1.size() , p1.size()) #torch.Size([1, 20, 100, 100]) torch.Size([1, 20, 25, 25])

3. 全连接层

卷积取的是感受野不同的局部特征,全连接就是把前面的局部特征重新通过权值矩阵进行连接,使每一个特征都对结果有影响。
只用一层全连接层(部分激活线性组合)有时候没法解决非线性问题,两层或以上(激活+组合+激活+组合)就可以很好地解决非线性问题。

来源
另外,全连接层可由卷积实现:
如果前层是全连接层的全连接层,将其转化为1x1的卷积;
如果前层是卷积层的全连接层,将其转化为hxw的全局卷积。

如下:输入为 (1,20,25,25)
直接用连接层时,指定输入输出节点数,输入展平, fc(in_channel,out_channel)
现在为输入 (1,20,25,25),线性层1输出1024,线性层2输出10
则卷积代替第一层:
·filter=25, in_channel = 20,out_channel=1024,padding=0,s=1
代替第二层:
·filter=1, in_channel = 1024,out_channel=10,padding=0,s=1

##in: print(p1.size())=  1,20,25,25
conv2liner1 = nn.Conv2d(20, 1024, kernel_size=(p1.size()[-1]),stride=1, padding=0)
conv2liner2 = nn.Conv2d(1024, 10, kernel_size=1,stride=1, padding=0)

c2l1 = conv2liner1(p1)
c2l2 = conv2liner2(c2l1)
print(c2l1.size() , c2l2.size()) #torch.Size([1, 1024, 1, 1]) torch.Size([1, 10, 1, 1])

p1 = torch.flatten(p1, 1)#展平
l1 = liner1(p1)
l2 = liner2(l1)
print(l1.size() , l2.size()) #torch.Size([1, 1024]) torch.Size([1, 10])

4. 激活函数(层)

  • Sigmoid函数
    在这里插入图片描述

饱和时梯度值非常小。由于BP算法反向传播的时候后层的梯度是以乘性方式传递到前层,因此当层数比较多的时候,传到前层的梯度就会非常小,网络权值得不到有效的更新,即梯度耗散。如果该层的权值初始化使得f(x) 处于饱和状态时,网络基本上权值无法更新。

  • Tanh函数 (Sigmoid下移0.5)
    在这里插入图片描述

与sigmoid相比,它的输出均值是0,使得其收敛速度要比sigmoid快,减少迭代次数。然而,从途中可以看出,tanh一样具有软饱和性,从而造成梯度消失

  • ReLU函数
    在这里插入图片描述

可以看到,当x<0时,ReLU硬饱和,而当x>0时,则不存在饱和问题。所以,ReLU 能够在x>0时保持梯度不衰减,从而缓解梯度消失问题。这让我们能够直接以监督的方式训练深度神经网络,而无需依赖无监督的逐层预训练。   
然而,随着训练的推进,部分输入会落入硬饱和区,导致对应权重无法更新。这种现象被称为“神经元死亡”。与sigmoid类似,ReLU的输出均值也大于0,偏移现象和 神经元死亡会共同影响网络的收敛性。

  • Leaky ReLU 、参数化ReLU 、随机化ReLU
  • ELU

5. bn层(批规范化)

参考
加快了收敛速度,缓解了深层网络的“深度弥散”与梯度爆炸。
在这里插入图片描述

输入:输入数据x1…xm(这些数据是准备进入激活函数的数据)
计算过程中可以看到,
1.求数据均值;
2.求数据方差;
3.数据进行标准化(个人认为称作正态化也可以)
4.训练参数γ,β
5.输出y通过γ与β的线性变换得到新的值
第4步为了让训练而增加的BN能够有可能还原最初的输入,即 γ = V a r ( x i ) = σ β \gamma=\sqrt{ Var(x_i)}=\sigma_\beta γ=Var(xi) =σβ β = E ( x i ) = u β \beta=E(x_i)=u_\beta β=E(xi)=uβ从而保证整个网络的容量。

在正向传播的时候,通过可学习的γ与β参数求出新的分布值;
在反向传播的时候,通过链式求导方式,求出γ与β以及相关权值:
在这里插入图片描述
学习文章

对某一层的输入数据做归一化,然后送入网络的下一层,这样是会影响到本层网络所学习的特征的,比如网络中学习到的数据本来大部分分布在0的右边,经过RELU激活函数以后大部分会被激活,如果直接强制归一化,那么就会有大多数的数据无法激活了,这样学习到的特征不就被破坏掉了么?论文中对上面的方法做了一些改进:变换重构,引入了可以学习的参数,这就是算法的关键之处:这两个希腊字母就是要学习的。

训练相关

经典网络

参考

  • AlexNet
    在这里插入图片描述特点:

    • 卷积层的卷积核不断减小(11、5、3)
    • 应用了Overlapping(重叠池化),重叠池化就是池化操作在部分像素上有重合。池化核大小是n×n,步长是k,如果k=n,则是正常池化,如果 k<n, 则是重叠池化。重叠池化有避免过拟合的作用。
    • 在fc6、fc7全连接层引入了drop out的功能。
    • 采用了Relu激活函数:ReLU(x) = max(x,0) 。
    • LRN(Local Response Normalization) 局部响应归一化,LRN模拟神经生物学上一个叫做 侧抑制(lateral inhibitio)的功能,侧抑制指的是被激活的神经元会抑制相邻的神经元。LRN局部响应归一化借鉴侧抑制的思想实现局部抑制,使得响应比较大的值相对更大,提高了模型的泛化能力。LRN只对数据相邻区域做归一化处理,不改变数据的大小和维度。
    • 数据增强:在数据处理这部分作者提到过将每张图片处理为256××256的大小,但网络结构图中的输入却为224××224,这是因为作者在256××256大小的图片上使用了一个224××224的滑动窗口,将每个滑动窗口中的内容作为输入,这样就能将整个数据集扩大到原来的(256−224)×(256−224)=1024(256−224)×(256−224)=1024倍。
  1. VGG

vgg-16使用小卷积(kernel=3,padding=1)实现增加网络深度同时不改变输出大小,而由2x2的pooling进行输出大小减半,随着深度增加其卷积层通道数也从3、64、128、256、512逐渐增加。

VGG与Alexnet相比,具有如下改进几点:
1、去掉了LRN层,作者发现深度网络中LRN的作用并不明显,干脆取消了
2、采用更小的卷积核-3x3,Alexnet中使用了更大的卷积核,比如有7x7的,因此VGG相对于Alexnet而言,参数量更少
3、池化核变小,VGG中的池化核是2x2,stride为2,Alexnet池化核是3x3,步长为2

在这里插入图片描述

  1. NIN (Network-in-Network)

1、利用多层感知机(多层全连接层与非线性函数的组合)代替传统(线性)卷积层
2、全局平均池化的出现替代了全连接层

在这里插入图片描述

  1. GoogleNet
    参考
    Inception-v1
    一般来说,提升网络性能最直接的办法就是增加网络深度和宽度,这也就意味着巨量的参数。但是,巨量参数容易产生过拟合也会大大增加计算量。
    文章认为解决上述两个缺点的根本方法是将全连接甚至一般的卷积都转化为稀疏连接。一方面现实生物神经系统的连接也是稀疏的,另一方面对于大规模稀疏的神经网络,可以通过分析激活值的统计特性和对高度相关的输出进行聚类来逐层构建出一个最优网络。

在这里插入图片描述
1 . 采用不同大小的卷积核意味着不同大小的感受野,最后拼接意味着不同尺度特征的融合;
2 . 之所以卷积核大小采用1、3和5,主要是为了方便对齐。设定卷积步长stride=1之后,只要分别设定pad=0、1、2,那么卷积之后便可以得到相同维度的特征,然后这些特征就可以直接拼接在一起了;
3 . 文章说很多地方都表明pooling挺有效,所以Inception里面也嵌入了。
4 . 网络越到后面,特征越抽象,而且每个特征所涉及的感受野也更大了,因此随着层数的增加,3x3和5x5卷积的比例也要增加。

但是,使用5x5的卷积核仍然会带来巨大的计算量。 为此,文章借鉴NIN2,采用1x1卷积核来进行降维。
例如:上一层的输出为100x100x128,经过具有256个输出的5x5卷积层之后(stride=1,pad=2),输出数据为100x100x256。其中,卷积层的参数为128x5x5x256。假如上一层输出先经过具有32个输出的1x1卷积层,再经过具有256个输出的5x5卷积层,那么最终的输出数据仍为为100x100x256,但卷积参数量已经减少为128x1x1x32 + 32x5x5x256,大约减少了4倍。
在这里插入图片描述

Inception-v2

通过一些实验:
1 . 避免表达瓶颈,特别是在网络靠前的地方。 信息流前向传播过程中显然不能经过高度压缩的层,即表达瓶颈。从input到output,feature map的宽和高基本都会逐渐变小,但是不能一下子就变得很小。比如你上来就来个kernel = 7, stride = 5 ,这样显然不合适。
另外输出的维度channel,一般来说会逐渐增多(每层的num_output),否则网络会很难训练。(特征维度并不代表信息的多少,只是作为一种估计的手段)
2 . 高维特征更易处理。 高维特征更易区分,会加快训练。
3. 可以在低维嵌入上进行空间汇聚而无需担心丢失很多信息。 比如在进行3x3卷积之前,可以对输入先进行降维而不会产生严重的后果。假设信息可以被简单压缩,那么训练就会加快。
4 . 平衡网络的宽度与深度。
在这里插入图片描述
大尺寸的卷积核可以带来更大的感受野,但也意味着更多的参数,比如5x5卷积核参数是3x3卷积核的25/9=2.78倍。为此,作者提出可以用2个连续的3x3卷积层(stride=1)组成的小网络来代替单个的5x5卷积层,(保持感受野范围的同时又减少了参数量)
且实验表示,添加3x3后再增加非线性层会提高性能。

  1. ResNet
    参考
    实验发现深度网络出现了退化问题(Degradation problem):网络深度增加时,网络准确度出现饱和,甚至出现下降。深层网络存在着梯度消失或者爆炸的问题,这使得深度学习模型很难训练。(即使有权重初始化策略和BN能改善,但实际情形不容乐观)

残差学习:对于一个堆积层结构(几层堆积而成)当输入为 x x x时其学习到的特征记为 H ( x ) H(x) H(x) ,现在我们希望其可以学习到残差 F ( x ) = H ( x ) − x F(x)=H(x)-x F(x)=H(x)x ,这样其实原始的学习特征是 F ( x ) + x F(x)+x F(x)+x 。之所以这样是因为残差学习相比原始特征直接学习更容易。当残差为0时,此时堆积层仅仅做了恒等映射,至少网络性能不会下降,实际上残差不会为0,这也会使得堆积层在输入特征基础上学习到新的特征,从而拥有更好的性能。
在这里插入图片描述
为什么残差学习相对更容易,从直观上看残差学习需要学习的内容少,因为残差一般会比较小,学习难度小点。不过我们可以从数学的角度来分析这个问题,首先残差单元可以表示为:
在这里插入图片描述
其中 x l x_l xl x l + 1 x_{l+1} xl+1 分别表示的是第 l l l 个残差单元的输入和输出,注意每个残差单元一般包含多层结构。 F F F 是残差函数,表示学习到的残差,而 h ( x l ) = x l h(x_l)=x_l h(xl)=xl 表示恒等映射, f f f 是ReLU激活函数。基于上式,我们求得从浅层 l l l 到深层 L L L 的学习特征为:
在这里插入图片描述
利用链式规则,可以求得反向过程的梯度:
在这里插入图片描述式子的第一个因子 α l o s s / α x L \alpha loss/\alpha x_L αloss/αxL表示的损失函数到达 L L L 的梯度,小括号中的1表明短路机制可以无损地传播梯度,而另外一项残差梯度则需要经过带有weights的层,梯度不是直接传递过来的。残差梯度不会那么巧全为-1,而且就算其比较小,有1的存在也不会导致梯度消失。所以残差学习会更容易。

在这里插入图片描述为了实际计算的考虑,作者提出了一种bottleneck的结构块来代替常规的Resedual block,它像Inception网络那样通过使用1x1 conv来巧妙地缩减或扩张feature map维度从而使得我们的3x3 conv的filters数目不受外界即上一层输入的影响,自然它的输出也不会影响到下一层module。

因为前向过程中有恒等映射的支路存在,因此在反向传播过程中梯度的传导也多了更简便的路径,仅仅经过一个relu就可以把梯度传达给上一个模块。
所谓反向传播就是网络输出一个值,然后与真实值做比较的到一个误差损失,同时将这个损失做差改变参数,返回的损失大小取决于原来的损失和梯度,既然目的是为了改变参数,而问题是改变参数的力度过小,则可以减小参数的值,使损失对参数改变的力度相对更大。
因此残差模块最重要的作用就是改变了前向和后向信息传递的方式从而很大程度上促进了网络的优化。即shortcut模块会在前向过程中帮助网络中的特征进行恒等映射,在反向过程中帮助传导梯度,让更深的模型能够成功训练。

  1. DenseNet
    相比ResNet,DenseNet提出了一个更激进的密集连接机制:即互相连接所有的层,具体来说就是每个层都会接受其前面所有层作为其额外的输入。且DenseNet是直接concat来自不同层的特征图,这可以实现特征重用,提升效率。
    文章写的比较全。
    但由于每个Feature map都要使用,所以很耗显存。
  2. ResNext
    参考文章
    ResNeXt提出了一种介于普通卷积核深度可分离卷积的这种策略:分组卷积,通过控制分组的数量(基数)来达到两种策略的平衡。分组卷积的思想是源自Inception,不同于Inception的需要人工设计每个分支,ResNeXt的每个分支的拓扑结构是相同的。最后再结合残差网络,得到的便是最终的ResNeXt。
    在这里插入图片描述

在这里插入图片描述
a是ResNeXt基本单元,如果把输出那里的1x1合并到一起,得到等价网络b拥有和Inception-ResNet相似的结构,而进一步把输入的1x1也合并到一起,得到等价网络c则和通道分组卷积的网络有相似的结构。


记录一些错误:

  • ValueError: Expected more than 1 value per channel when training, got input size torch.Size([1, 32, 1, 1])
    bn层报错,因为输入为batch_size=1,此时在使用model前增加 model.eval()
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值