Pytorch深度学习实践学习笔记(十一)CNN(高级篇)

简单的神经网络是串行的结构;非串行的网络结构具有一定的应用场景。

复杂网络会出现严重的代码冗余:GoogLeNet

C语言等:函数/类的方式。

Pytorch:通过将不同的神经层封装成一个块。

Inception Model:可以实现对多种超参数的选择,例如Kernel的大小,随着训练的进行,效果好的卷积核所在的层权重会越来越高。

 不同的路径,Batch一定相同,要求输出的时候W与H必须相同,通道数可以不同,通过Concatenate操作,将不同的输出的张量拼接起来。

1*1的卷积核的作用:对不同的通道取权重,将不同通道的信息融合起来。在一次卷积的过程中,多个通道会合成一个通道,这个工作重复n次,即可输出n个通道。而这n个通道中的每个通道都是原来输入的通道的信息融合。

 运算复杂度=卷积核的大小*图像大小*输入通道数*输出通道数

通过1*1的卷积可以使得通道数远远降低,使得运算复杂度降低。

因此这样的卷积核又称为Network in Network

Inception的类构造:

class InceptionA(nn.Module):
    def __init__(self, in_channels):                #输入通道可以变化
        super(InceptionA, self).__init__()
        self.branch1x1 = nn.Conv2d(in_channels, 16, kernel_size=1)      #将这个函数声明为1*1
                                                                      #的卷积,在forward调用

        self.branch5x5_1 = nn.Conv2d(in_channels,16, kernel_size=1)    #这里的通道分了两块
        self.branch5x5_2 = nn.Conv2d(16, 24, kernel_size=5, padding=2) #第一块输出是16通道
        #因此第二块的输入就是16,同时输出是24,利用padding扩展图像,使得图像输出大小不变

        self.branch3x3_1 = nn.Conv2d(in_channels, 16, kernel_size=1)    #这一条分支有三个步骤
        self.branch3x3_2 = nn.Conv2d(16, 24, kernel_size=3, padding=1)
        self.branch3x3_3 = nn.Conv2d(24, 24, kernel_size=3, padding=1)

        self.branch_pool = nn.Conv2d(in_channels, 24, kernel_size=1)    #池化分支的定义,给出                
        #输入输出的大小和一些参数,先声明,再forward里面调用。
    
    def forward(self, x):
        branch1x1 = self.branch1x1(x)                                    #只需要一个函数,直
                                                                        #接调用就好

        branch5x5 = self.branch5x5_1(x)
        branch5x5 = self.branch5x5_2(branch5x5)

        branch3x3 = self.branch3x3_1(x)

        branch3x3 = self.branch3x3_2(branch3x3)                    #forward都是在调用init中
        branch3x3 = self.branch3x3_3(branch3x3)                #已经声明的函数进行计算
        
        branch_pool = F.avg_pool2d(x, kernel_size=3, stride=1, padding=1) #池化层的函数
        branch_pool = self.branch_pool(branch_pool)               #先做一个平均池化
                                                            #再调用自己的函数,做1*1的卷积 

        outputs = [branch1x1, branch5x5, branch3x3, branch_pool]    
        return torch.cat(outputs, dim=1)    #将输出按照1拼到一起,这个维度是由通道决定的
        #张量的维度是[Batch Channel W H]按照Channel拼起来 就应该是第一个维度

网络的类的构造:

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(1, 10, kernel_size=5)        #先声明了两个卷积层
        self.conv2 = nn.Conv2d(88, 20, kernel_size=5)

        self.incep1 = InceptionA(in_channels=10)            #声明了两个调用  输入分别是10
        self.incep2 = InceptionA(in_channels=20)            #和20

        self.mp = nn.MaxPool2d(2)                        #声明最大池化层和全连接
        self.fc = nn.Linear(1408, 10)

    def forward(self, x):
        in_size = x.size(0)                         #对函数的调用,先选出了输入的维度
        x = F.relu(self.mp(self.conv1(x)))        #对输入的x先做了一个卷积、池化和relu
        x = self.incep1(x)                        #cov1的卷积层输出一定是10个通道
        #卷积层的输出作为incep1的输入,无论输入通道是多少,输出通道总是88,这是由incep各个分支的
        #通道数加起来决定的

        x = F.relu(self.mp(self.conv2(x)))        #同样的这个卷积层输入应当是88通道输出是20
        x = self.incep2(x)                        #这里输入通道数是20,输出又变成了88
        x = x.view(in_size, -1)                   #池化层减小了图片的大小,用view把张量展开成
                                                  #向量
        x = self.fc(x)                            #再进入全连接做一个分类
        return x

用这个替换上一讲的卷积神经网络,就能输出结果。

Residual Network:

梯度消失:当网络层数过多的时候,反向传播过程中,梯度若乘以一个小于1的数字,其值会越来越小,导致反向传播的梯度消失,无法到达最优点。可以利用逐层训练的方法进行训练,训练好一层后锁定,继续训练下一层,但是层数过多,十分复杂。

跳连接:在经过全连接层等后,先加上输入,再进行激活,这样就可以在原来的梯度上加上1,防止梯度消失。

这样的层,要求输入和输出的维度完全一致,才可以加起来。

class ResidualBlock(nn.Module):
    def _init_ (self,channels):
        super(ResidualBlock, self)._init_()
        self.channels = channels
        self.conv1 = nn.Conv2d(channels, channels,
                               kernel_size=3, padding=1)#卷积层输入和输出的通道保持一致,            
                                                        #padding保证图像大小不变
        self.conv2 = nn.Conv2d(channels, channels,
                                kernel size=3,padding-1)

    def forward(self, x):
        y = F.relu(self.conv1(x))#卷积后激活
        y = self.conv2(y)        #再卷积 完成正常的结构
        return F.relu(x + y)     #此处本身应当直接激活完成两层的结构,但是先加上输入在激活,防止
                                 #梯度消失

 新的网络结构:

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(1, 16, kernel_size=5)
        self.conv2 = nn.Conv2d(16, 32, kernel_size=5)
        self.mp = nn.MaxPool2d(2)
        self.rblock1 = ResidualBlock(16)
        self.rblock2 = ResidualBlock(32)
        self.fc = nn.Linear(512, 10)

    def forward(self, x):
        in_size = x.size(0)
        x = self.mp(F.relu(self.conv1(x)))
        x = self.rblock1(x)
        x = self.mp(F.relu(self.conv2(x)))
        x = self.rblock2(x)
        x = x.view(in_size, -1)
        x = self.fc(x)

更多的RNN网络

He K, Zhang X, Ren S, et al. Identity Mappings in Deep Residual Lecture 11 Networks[C]

Huang G, Liu Z, Laurens V D M, et al. Densely Connected Convolutional Networks[J].2016: 2261-2269.

深度学习“花书”

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值