视觉处理基础

本文深入介绍了卷积神经网络(CNN)的基础知识,包括卷积层、池化层及其参数,如卷积核、步幅、填充等。还探讨了激活函数和卷积函数的作用,并通过实例展示了卷积运算。接着,讨论了局部池化和全局池化的区别。最后,介绍了两个经典CNN模型——LeNet-5和AlexNet的架构和特点。
摘要由CSDN通过智能技术生成

视觉处理基础

1、卷积神经网络简介

  • 卷积神经网路由一个或多个卷积层和顶端的全连通层(对应经典的神经网路)组成,同时也包括关联权重和池化层(pooling layer)等

    下面是一个卷积神经网络的例子:

    在这里插入图片描述

    上图为卷积神经网络的一般结构,其中包括卷积神经网络的常用层,如卷积层、池化层、全连接层和输出层;有些还包括其他层,如正则化层、高级层等。接下来我们就各层的结构、原理等进行详细说明。

    import torch.nn as nn
    import torch.nn.functional as F
    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
     
    class CNNNet(nn.Module):
        def __init__(self):
            super(CNNNet,self).__init__()
            self.conv1 = nn.Conv2d(in_channels=3,out_channels=16,kernel_size=5,stride=1)
            self.pool1 = nn.MaxPool2d(kernel_size=2,stride=2)
            self.conv2 = nn.Conv2d(in_channels=16,out_channels=36,kernel_size=3,stride=1)
            self.pool2 = nn.MaxPool2d(kernel_size=2, stride=2)
            self.fc1 = nn.Linear(1296,128)
            self.fc2 = nn.Linear(128,10)      
     
        def forward(self,x):
            x=self.pool1(F.relu(self.conv1(x)))
            x=self.pool2(F.relu(self.conv2(x)))
            #print(x.shape)
            x=x.view(-1,36*6*6)
            x=F.relu(self.fc2(F.relu(self.fc1(x))))
            return x
     
    net = CNNNet()
    net=net.to(device)
    

2、卷积层

  • 卷积层是卷积神经网络的核心层,而卷积(Convolution)又是卷积层的核心。卷积我们直观的理解,就是两个函数的一种运算,这种运算称为卷积运算。

    在这里插入图片描述

  • 输入和卷积核都是张量,卷积运算就是用卷积分别乘以输入张量中的每个元素,然后输出一个代表每个输入信息的张量其中卷积核(kernel)又称为权重过滤器或简称过滤器(filter)

2.1、卷积核

  • 卷积核,从这个名字可以看出它的重要性,它是整个卷积过程的核心

    比较简单的卷积核或过滤器有 Horizontalfilter、Verticalfilter、Sobel filter 等。这些过滤器能够检测图像的水平边缘、垂直边缘、增强图片中心区域权重等。

    1. 垂直边缘检测

      这个过滤器是 3x3 矩阵(注,过滤器一般是奇数阶矩阵),其特点是有值的是第 1 列和第 3 列,第 2 列为 0。经过这个过滤器作用后,就把原数据垂直边缘检测出来了。

      在这里插入图片描述

    2. 水平边缘检测

      这个过滤器也是 3x3 矩阵,其特点是有值的是第 1 行和第 3 行,第 2 行为 0。经过这个过滤器作用后,就把原数据水平边缘检测出来了。

      在这里插入图片描述

    过滤器对图像水平边缘检测、垂直边缘检测的效果图:

    在这里插入图片描述

  • 在深度学习中,过滤器的作用不仅在于检测垂直边缘、水平边缘等,还需要检测其他边缘特征

    过滤器如何确定呢?过滤器类似于标准神经网络中的权重矩阵 W W W W W W 需要通过梯度下降算法反复迭代求得。同样,在深度学习学习中,过滤器也是需要通过模型训练来得到

    卷积神经网络主要目的就是计算出这些 filter 的数值。确定得到了这些 filter 后,卷积神经网络的浅层网络也就实现了对图片所有边缘特征的检测

2.2、步幅

  • 小窗口(实际上就是卷积核或过滤器)在左边窗口中每次移动的格数(无论是自左向右移动,或自上向下移动)称为步幅(strides),在图像中就是跳过的像素个数
  • 参数 strides 是卷积神经网络中的一个重要参数,在用 PyTorch 具体实现时,strides 参数格式为单个整数或两个整数的元组(分别表示在 height 和 width 维度上的值)

2.3、填充

  • 当输入图片与卷积核不匹配时或卷积核超过图片边界时,可以采用边界填充(padding)的方法。即把图片尺寸进行扩展,扩展区域补零

  • 根据是否扩展 padding 又分为 Same、Valid

    采用 Same 方式时,对图片扩展并补 0;采用 Valid 方式时,对图片不扩展。

    如何选择呢?在实际训练过程中,一般选择 Same,使用 Same 不会丢失信息。

    设补 0 的圈数为 p,输入数据大小为 n,过滤器大小为 f,步幅大小为 s,则有:
    p = f − 1 2 p=\frac{f-1}{2} p=2f1
    卷积后的大小为:
    n + 2 p − f s + 1 \frac{n+2p-f}{s}+1 sn+2pf+1

2.4、多通道上的卷积

  • 3 通道图片的卷积运算与单通道图片的卷积运算基本一致,对于 3 通道的 RGB 图片,其对应的滤波器算子同样也是 3通道的

    例如一个图片是 6 x 6 x 3,分别表示图片的高度(height)、宽度(weight)和通道(channel)过程是将每个单通道(R,G,B)与对应的 filter 进行卷积运算求和,然后再将 3 通道的和相加,得到输出图片的一个像素值

    在这里插入图片描述

  • 为了实现更多边缘检测,可以增加更多的滤波器组

    下图就是两组过滤器 Filter W0 和 Filter W1。 7 ∗ 7 ∗ 3 7*7*3 773 输入,经过两个 3 ∗ 3 ∗ 3 3*3*3 333 的卷积(步幅为 2),得到了 3 ∗ 3 ∗ 2 3*3*2 332 的输出。Zero padding 对于图像边缘部分的特征提取是很有帮助的,可以防止信息丢失。最后,不同滤波器组卷积得到不同的输出,个数由滤波器组决定。

    在这里插入图片描述

2.5、激活函数

  • 卷积神经网络与标准的神经网络类似,为保证其非线性,也需要使用激活函数,即在卷积运算后,把输出值另加偏移量,输入到激活函数,然后作为下一层的输入

    在这里插入图片描述

  • 常用的激活函数有:tf.sigmoid、tf.nn.relu 、tf.tanh、 tf.nn.dropout 等。

2.6、卷积函数

  • 卷积函数是构建神经网络的重要支架,通常 Pytorch 的卷积运算是通过 nn.Conv2d 来完成

    下面先介绍 nn.Conv2d 的参数,及如何计算输出的形状(shape)。

    1. nn.Conv2d 函数

      torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True, padding_mode='zeros')
      
      • in_channels(int):输入信号的通道
      • out_channels(int):卷积产生的通道
      • kerner_size(int or tuple):卷积核的尺寸
      • stride(int or tuple, optional):卷积步长
      • padding(int or tuple, optional):输入的每一条边补充 0 的层数
      • dilation(int or tuple, optional):卷积核元素之间的间距
      • groups(int, optional):控制输入和输出之间的连接: group=1,输出是所有的输入的卷积;group=2,此时相当于有并排的两个卷积层,每个卷积层计算输入通道的一半,并且产生的输出是输出通道的一半,随后将这两个输出连接起来
      • bias(bool, optional):如果 bias=True,添加偏置。其中参数 kernel_size,stride,padding,dilation 也可以是一个 int 的数据,此时卷积 height 和 width 值相同;也可以是一个 tuple 数组,tuple 的第一维度表示height 的数值,tuple 的第二维度表示 width 的数值
    2. 输出形状

      在这里插入图片描述


3、池化层

  • 池化(Pooling)又称为下采样通过卷积层获得图像的特征后,理论上可以直接使用这些特征训练分类器(如 Softmax)。但是,这样做将面临巨大的计算量的挑战,而且容易产生过拟合现象

    为了进一步降低网络训练参数及模型的过拟合程度,就要对卷积层进行池化处理。常用的池化方式通常有 3 种:

    1. 最大池化(Max Pooling)选择 Pooling 窗口中的最大值作为采样值
    2. 均值池化(Mean Pooling)将 Pooling 窗口中的所有值相加取平均,以平均值作为采样值
    3. 全局最大(或均值)池化与平常最大或最小池化相对而言,全局池化是对整个特征图的池化而不是在移动窗口范围内的池化
  • 池化层在 CNN 中可以用来减小尺寸,提高运算速度及减小噪声影响,让各特征更具有健壮性。

    池化层比卷积层更简单,它没有卷积运算,只是在滤波器算子滑动区域内取最大值或平均值。

    而池化的作用则体现在降采样:保留显著特征、降低特征维度,增大感受野

3.1、局部池化

  • 通常使用的最大或平均池化,是在特征图(Feature Map)上以窗口的形式进行滑动(类似卷积的窗口滑动),操作为取窗口内的平均值作为结果值。经过操作后,特征图降采样,减少了过拟合现象。

    其中在移动窗口内的池化被称为局部池化

  • 在 PyTorch 中,最大池化常使用 nn.MaxPool2d,平均池化使用 nn.AvgPool2d

    class torch.nn.MaxPool2d(kernel_size, stride=None, padding=0, dilation=1, return_indices=False, ceil_mode=False)
    
    • kernel_size:池化窗口的大小,取一个 4 维向量,一般是 [height, width],如果两者相等,可以是一个数字;
    • stride:窗口在每一个维度上滑动的步长,一般也是 [stride_h, stride_w],如果两者相等,可以是一个数字;
    • padding:和卷积类似;
    • dilation:卷积对输入数据的空间间隔;
    • return_indices:是否返回最大值对应的下标;
    • ceil_mode:使用一些方块代替层结构。

    假设输入 input 的形状为: ( N , C , H i n , W i n ) (N,C,H_{in},W_{in}) (N,C,Hin,Win)

    输出 output 的形状为: ( N , C , H o u t , W o u t ) (N,C,H_{out},W_{out}) (N,C,Hout,Wout),则输出大小与输入大小的计算公式如下:
    H o u t = [ H i n + 2 × p a d d i n g [ 0 ] − d i l a t i o n [ 0 ] × ( k e r n e l _ s i z e [ 0 ] − 1 ) − 1 s t r i d e [ 0 ] + 1 ] H_{out}=[\frac{H_{in}+2 \times padding[0] - dilation[0] \times (kernel\_size[0] - 1)-1}{stride[0]}+1] Hout=[stride[0]Hin+2×padding[0]dilation[0]×(kernel_size[0]1)1+1]

    W o u t = [ W i n + 2 × p a d d i n g [ 1 ] − d i l a t i o n [ 1 ] × ( k e r n e l _ s i z e [ 1 ] − 1 ) − 1 s t r i d e [ 1 ] + 1 ] W_{out}=[\frac{W_{in}+2 \times padding[1] - dilation[1] \times (kernel\_size[1] - 1)-1}{stride[1]}+1] Wout=[stride[1]Win+2×padding[1]dilation[1]×(kernel_size[1]1)1+1]

    如果不能整除,则取整数。

3.2、全局池化

  • 与局部池化相对的就是全局池化,全局池化也分为最大或平均池化。

    所谓的全局池化就是针对常用的平均池化而言,平均池化会有它的 filter_size,而全局平均池化(Global Average Pooling,GAP)就没有 size,它针对的是整张 Feature Map,即一个特征图输出一个值

  • 使用全局平均池化代替 CNN 中传统的全连接层。在使用卷积层的识别任务中,全局平均池化能够为每一个特定的类别生成一个特征图。

    GAP 的优势在于:各个类别与 Feature Map 之间的联系更加直观(相比于全连接层的黑箱来说),Feature Map 被转换为分类概率也更加容易,因为在 GAP 中没有参数需要调,所以避免了过拟合现象。GAP 汇总了空间信息,因此对输入的空间转换鲁棒性更强。

  • Keras 中可以使用:全局最大池化层(GlobalMaxPooling2D);

    Pytorch 中可以使用:自适应池化层(AdaptiveMaxPool2d(1)) 或 nn.AdaptiveAvgPooling2d(1)


4、现代经典网络

4.1、LeNet-5

  1. 模型架构

    LeNet-5 模型结构为**输入层-卷积层-池化层-卷积层-池化层-全连接层-输出**,为串联模型。

  2. 模型特点

    • 每个卷积层包含 3 个部分:卷积、池化和非线性激活函数;
    • 使用卷积提取空间特征;
    • 采用降采样(Subsample)的平均池化层(Average Pooling);
    • 使用双曲正切(Tanh)的激活函数;
    • 最后使用 MLP 作为分类器。

在这里插入图片描述

import torch.nn as nn
class LeNet5(nn.Module):

    def __init__(self):
        super(LeNet5, self).__init__()
        # 1 input image channel, 6 output channels, 5x5 square convolution kernel
        self.conv1 = nn.Conv2d(1, 6, 5)
        self.conv2 = nn.Conv2d(6, 16, 5)
        # an affine operation: y = Wx + b
        self.fc1 = nn.Linear(16 * 5 * 5, 120) # 这里论文上写的是conv,官方教程用了线性层
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)

    def forward(self, x):
        # Max pooling over a (2, 2) window
        x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))
        # If the size is a square you can only specify a single number
        x = F.max_pool2d(F.relu(self.conv2(x)), 2)
        x = x.view(-1, self.num_flat_features(x))
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

    def num_flat_features(self, x):
        size = x.size()[1:]  # all dimensions except the batch dimension
        num_features = 1
        for s in size:
            num_features *= s
        return num_features


net = LeNet5()
print(net)
LeNet5(
  (conv1): Conv2d(1, 6, kernel_size=(5, 5), stride=(1, 1))
  (conv2): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1))
  (fc1): Linear(in_features=400, out_features=120, bias=True)
  (fc2): Linear(in_features=120, out_features=84, bias=True)
  (fc3): Linear(in_features=84, out_features=10, bias=True)
)

4.2、AlexNet

在这里插入图片描述

import torchvision
model = torchvision.models.alexnet(pretrained=False) #我们不下载预训练权重
print(model)
AlexNet(
  (features): Sequential(
    (0): Conv2d(3, 64, kernel_size=(11, 11), stride=(4, 4), padding=(2, 2))
    (1): ReLU(inplace=True)
    (2): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)
    (3): Conv2d(64, 192, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
    (4): ReLU(inplace=True)
    (5): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)
    (6): Conv2d(192, 384, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (7): ReLU(inplace=True)
    (8): Conv2d(384, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (9): ReLU(inplace=True)
    (10): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (11): ReLU(inplace=True)
    (12): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)
  )
  (avgpool): AdaptiveAvgPool2d(output_size=(6, 6))
  (classifier): Sequential(
    (0): Dropout(p=0.5, inplace=False)
    (1): Linear(in_features=9216, out_features=4096, bias=True)
    (2): ReLU(inplace=True)
    (3): Dropout(p=0.5, inplace=False)
    (4): Linear(in_features=4096, out_features=4096, bias=True)
    (5): ReLU(inplace=True)
    (6): Linear(in_features=4096, out_features=1000, bias=True)
  )
)
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值