CNN 学习总结 (Pytorch)

  这篇博客总结一下我在学习卷积神经网络(CNN)中遇到的疑惑

  • 卷积神经网络出现的原因?

  如果模型很大,可能会过拟合,所以我们必须要对模型进行一些限制。因此首先要思考我们如何针对影像问题来做limitation。对一个影响辨识系统而言,最重要的是侦测在这张图片中有没有很重要的patten,例如我们人类看一张鸟类的图片,怎么知道这是一只鸟呢?肯定是先看鸟嘴、鸟爪等部分,这些在影像系统中就是很重要的。
  基于此,CNN提出了卷积的概念,CNN会设定一个区域叫做 Receptive Field(感受野),每一个 Neuron 都只关心自己的 Receptive Field 所发生的事情就好了,这个 Receptive Field 我们称之为kernal。一般 kernal size 取 3x3 或者5x5。当然,有人会说能不能把一整张图当做一个kernal ,是可以的,但是这样计算量太大了。

  • 3x3 或者5x5 的 kernal 会不会太小了,能侦查到patten吗?

  是可以的。只要卷积的层数足够多。
  因为我们用3x3做kernal的时候,计算出来的第一层卷积是原图中3x3的patten,但是如果我们对第一层的卷积再做一次kernal,那就不止是3x3了(就是原图的5x5的patten了)。因此只要network够深,就没有侦查不到的patten。

  • CNN中常见的名词

  padding:padding(填充)参数的作用是决定在进行卷积或池化操作时,是否对输入的图像矩阵边缘补0
  stride:滑动卷积核时的步长stride(例如每次滑动一个或两个)
  kernal:卷积核,通常为3x3或者5x5
  filter:卷积核的数量(神经元的数量)。这个地方怎么理解呢,一个3x3的卷积核有9个参数,这些参数是通过learning出来的,一个卷积核扫过一幅图后,会生成一幅新的图,因为卷积核的参数是不同的,因此生成的图片也是不同的。但是卷积核的作用是侦查patten的对吧,一个图片中不可能只有一个patten吧,比如说一幅图片有100个patten,鸟嘴、鸟爪、牛蹄、猪头等特征都是patten,当将一头猪的图片输入到网络中,猪头这个patten的权重就会非常大,相反鸟嘴、鸟爪、牛蹄的patten权重就很低。所以filter的个数也就代表了神经元的数目。
  pooling:池化

  • Pytorch的程序讲解

    整体流程是:
  卷积(Conv2d) -> BN(batch normalization) -> 激励函数(ReLU) -> 池化(MaxPooling) ->
  全连接层(Linear) -> 输出

# 定义网络结构
class CNNnet(torch.nn.Module):
    def __init__(self):
        super(CNNnet,self).__init__()
        self.conv1 = torch.nn.Sequential(
            torch.nn.Conv2d(in_channels=1,
                            out_channels=16,
                            kernel_size=3,
                            stride=2,
                            padding=1),
            torch.nn.BatchNorm2d(16),
            torch.nn.ReLU()
        )
        self.conv2 = torch.nn.Sequential(
            torch.nn.Conv2d(16,32,3,2,1),
            torch.nn.BatchNorm2d(32),
            torch.nn.ReLU()
        )
        self.conv3 = torch.nn.Sequential(
            torch.nn.Conv2d(32,64,3,2,1),
            torch.nn.BatchNorm2d(64),
            torch.nn.ReLU()
        )
        self.conv4 = torch.nn.Sequential(
            torch.nn.Conv2d(64,64,2,2,0),
            torch.nn.BatchNorm2d(64),
            torch.nn.ReLU()
        )
        self.linear = torch.nn.Linear(2*2*64,100)
        self.linear = torch.nn.Linear(100,10)
    def forward(self, x):
        x = self.conv1(x)
        x = self.conv2(x)
        x = self.conv3(x)
        x = self.conv4(x)
        x = self.linear(x.view(x.size(0),-1))
        x = self.linear(x)
        return x
model = CNNnet()
print(model)

  首先图片经过卷积层。卷积层第一个参数是input channel ,如果是RGB图像,就是3维,如果是灰度图就是1维第二个参数是output channel,也就是filter,设置多少个卷积核,每个卷积核做运算后输出新的“图片”,后续的参数再是卷积核的大小、步长、填充等等。重点要理解这个output channel

  继续来看全连接层,全连接层的输入是什么呢,是卷积层的输出。例如最后一个卷积层定义了64个filter,那我们之前说了,每一个filter做运算后会生成新的图片是吧,所以这个64只是代表了有64个新图片,每个图片是多少尺寸呢?上述程序是2x2的尺寸,因此全连接层是输入就是64x2x2。

  那么问题来了,怎么判断做完卷积后新图片的大小?假设输入的tensor size为C H W,若in_channels=C,out_channels=Cout,kernel_size=k,stride=s,padding=p,那么输出的tensor size是:
  Cout*((H + 2*p - k)/s+1) * ((W + 2*p - k)/s+1)

  这种方法需要手动计算,有时候还可能计算错误,这里再提供一种方法,执行完下述程序后,加上一句 print(x.size()) 将数据打印出来,然后再填到torch.nn.Linear(input,100)里

    def forward(self, x):
        x = self.conv1(x)
        x = self.conv2(x)
        x = self.conv3(x)
        x = self.conv4(x)
        print(x.size())

  最后要注意程序中的这句话,x = self.linear(x.view(x.size(0),-1)) 几乎可以看到每一个CNN有关的代码中,都有维度转换这一句,因为全连接层是输入一个向量,不是输入一个矩阵,所以要把这个卷积后的结果拉直再输入到Linear中。

  推荐三篇博客参考:
https://blog.csdn.net/liming89/article/details/113006867
https://blog.csdn.net/jining11/article/details/89114502?
https://blog.csdn.net/qq_34714751/article/details/85610966?

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值