神经网络中的基本结构--卷积层和最大池化

神经网络中的基本结构

卷积层

torch.nn卷积层 Convolution Layers

torch.nn提供的包针对场景
nn.Conv1d对由多个输入平面组成的输入信号应用一维卷积。
nn.Conv2d在由多个输入平面组成的输入信号上应用 2D 卷积。
nn.Conv3d对由多个输入平面组成的输入信号应用 3D 卷积。

nn.Conv2d 常用于对图像的卷积层

torch.nn.Conv2d( in_channels , out_channels , kernel_size , stride = 1 , padding = 0 , dilation = 1 , groups = 1 , bias = True , padding_mode = ‘zeros’ , device = None , dtype = None )

该模块支持TensorFloat32

  • 参数:

    • in_channels :int, 输入图像中的通道数

    • out_channels : int, 卷积产生的通道数

    • kernel_size : (int / tuple),卷积核的大小

    • stride控制互相关、单个数字或元组的步幅。

    • padding控制应用于输入的填充量。它可以是一个字符串 {‘valid’, ‘same’} 或一个整数元组,给出在两边应用的隐式填充量。

    • dilation控制内核点之间的间距;也称为 à trous 算法。很难描述,但是这个链接 很好地可视化了dilation它的作用。

    • groups控制输入和输出之间的连接。 in_channels并且out_channels都必须能被 整除 groups。例如,

      • 在 groups=1 时,所有输入都卷积到所有输出。
      • 在 groups=2 时,该操作等效于并排有两个卷积层,每个卷积层看到一半的输入通道并产生一半的输出通道,并且随后将两者连接起来。
      • 在 groups=in_channels处,每个输入通道都与自己的一组过滤器

对于stride和padding的理解:

  • stride: 控制卷积核进行卷积计算下一次跳跃的步幅
  • padding: 原3*3大小的数据,padding后在其周围阔充0,=1就是将周围添加一圈0变为5*5大小

in_channels :int, 输入图像中的通道数

out_channels : int, 卷积产生的通道数

对于in、out channels的理解:

in_channels=1,out_channels =1,则卷积层生成一个卷积核进行卷积计算,将卷积计算后的结果作为输出;

in_channels=1,out_channels =2,卷积层会生成两个卷积核,得到两个卷积后的计算结果,将这两个计算后的结果当作一个输出结果进行输出。两个卷积核不一定相等。

简单的示例:


import torch
import torchvision
from torch import nn
from torch.nn import Conv2d
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter

dataset = torchvision.datasets.CIFAR10("../DataSet", train=False, transform=torchvision.transforms.ToTensor(),
                                       download=True)
dataloader = DataLoader(dataset, batch_size=64)


# 搭建简单的神经网络
class Tudui(nn.Module):
    def __init__(self):
        super(Tudui, self).__init__()
        # 设置conv1,因为输入图像为彩色图像in_ch=3, 想输出6层out_ch=6,使用卷积核3*3,步幅1,不扩充
        self.conv1 = Conv2d(in_channels=3, out_channels=6, kernel_size=3, stride=1, padding=0)

    def forward(self, x):
        x = self.conv1(x)
        return x

writer = SummaryWriter()
tudui = Tudui()
# print(tudui)

for da in dataloader:
    imgs, targets = da
    output = tudui(imgs)
    print(imgs.shape)       # torch.Size([64, 3, 32, 32])
    print(output.shape)     # torch.Size([64, 6, 30, 30])
    writer.add_images("input", imgs, step)
    # torch.Size([64, 6, 30, 30])  -> [xxx, 3, 30, 30]

    output = torch.reshape(output, (-1, 3, 30, 30))
    writer.add_images("output", output, step)

    step = step + 1

writer.close()

示例讲解

  • print(imgs.shape) # torch.Size([64, 3, 32, 32])

    • 64 为DataLoader(dataset, batch_size=64)batch_size=64
    • 3 是数据集中数据本来的三色通道, 即彩色图像的三通道色
    • 32, 32是图片大小32*32
  • print(output.shape) # torch.Size([64, 6, 30, 30])

    卷积计算之后的形状输出,

    • 64 为DataLoader(dataset, batch_size=64)batch_size=64
    • 6是out_channels=6,
    • 30,30 是经过卷积计算后的图像大小,30*30.

池化层

pytorch池化层相关内容的

nn.MaxPool1dApplies a 1D max pooling over an input signal composed of several input planes.
nn.MaxPool2dApplies a 2D max pooling over an input signal composed of several input planes.
nn.MaxPool3dApplies a 3D max pooling over an input signal composed of several input planes.
nn.MaxUnpool1dComputes a partial inverse of MaxPool1d.
nn.MaxUnpool2dComputes a partial inverse of MaxPool2d.

MaxPool 最大池化,也被成为下采样

MaxUnPool ,上采样

AvgPool,平均池化

最常用的是MaxPool2d。

MaxPool2d

torch.nn.MaxPool2d( kernel_size , stride = None , padding = 0 , dilation = 1 , return_indices = False , ceil_mode = False )

参数
  • kernel_size – 最大的窗口大小,
  • stride——,步幅,窗口的步幅。默认值为kernel_size
    • 这一点要和卷积层中的参数进行区分,卷积层中默认为1.
  • padding – 要在两边添加隐式零填充
  • dilation – 控制窗口中元素步幅的参数,一般不进行设置
  • return_indices - 如果True,将返回最大索引以及输出。torch.nn.MaxUnpool2d以后有用
  • ceil_mode – 如果为 True,将使用ceil而不是floor来计算输出形状,默认是False
    • ceil:向上取整
    • floor:向下取整

参数kernel_size, stride, padding,dilation可以是:

  • 单个int- 在这种情况下,高度和宽度尺寸使用相同的值
  • a tupleof two int – 在这种情况下,第一个int用于高度维度,第二个int用于宽度维度,及(2,3)为 高2,宽3的矩阵

dilation – 控制窗口中元素步幅的参数,相关的空洞卷积

额外引入——空洞卷积
  • 标准卷积:以3*3为例,以下分辨率不变与分辨率降低的两个实例;

标准卷积

  • 空洞卷积:在3*3卷积核中间填充0,有两种实现方式,第一,卷积核填充0,第二,输入等间隔采样。

空洞卷积

标准卷积与空洞卷积在实现上基本相同,标准卷积可以看做空洞卷积的特殊形式。

空洞卷积的作用

空洞卷积有什么作用呢?

  • 扩大感受野:在deep net中为了增加感受野且降低计算量,总要进行降采样(pooling或s2/conv),这样虽然可以增加感受野,但空间分辨率降低了。为了能不丢失分辨率,且仍然扩大感受野,可以使用空洞卷积。这在检测,分割任务中十分有用。一方面感受野大了可以检测分割大目标,另一方面分辨率高了可以精确定位目标。
  • **捕获多尺度上下文信息:**空洞卷积有一个参数可以设置dilation rate,具体含义就是在卷积核中填充dilation rate-1个0,因此,当设置不同dilation rate时,感受野就会不一样,也即获取了多尺度信息。多尺度信息在视觉任务中相当重要啊。

从这里可以看出,空洞卷积可以任意扩大感受野,且不需要引入额外参数,但如果把分辨率增加了,算法整体计算量肯定会增加。

池化操作

比如,一个5*5大小的输入图像,池化核大小为3(3*3),stride默认同池化核大小一致。

具体的池化操作,

  1. 3*3大小的池化,映射到5*5的输入上,从中筛选出3*3范围内最大的值输出

在这里插入图片描述

  1. stride默认与池化核大小一致,则向后移动,出现如图所示,仅有6个元素被池化核覆盖。
    在这里插入图片描述

    • 当类似情况发生时,参数ceil_mode就发挥作用了,及从这6个数中选取最大值还是将这6个数放弃。
      • ceil_mode = True:保留,并将其中最大值输出
      • ceil_mode = False:不保留,不从这6个数中选择,并舍弃这6个数
  2. 最后,逐步完成池化

在这里插入图片描述

  1. 具体的代码实现:

    import torch
    from torch import nn
    from torch.nn import MaxPool2d
    
    input = torch.tensor([[1, 2, 0, 3, 1],
                          [0, 1, 2, 3, 1],
                          [1, 2, 1, 0, 0],
                          [5, 2, 3, 1, 1],
                          [2, 1, 0, 1, 1]], dtype=torch.float32)
    input = torch.reshape(input, (-1, 1, 5, 5))
    print(input.shape)
    
    
    class Tudui(nn.Module):
        def __init__(self):
            super(Tudui, self).__init__()
            self.maxpool1 = MaxPool2d(kernel_size=3, ceil_mode=False)
    
        def forward(self, input):
            output = self.maxpool1(input)
            return output
    
    
    tudui = Tudui()
    
    output = tudui(input)
    print(output)
    # 当ceil_mode=False时,输出tensor([[[[2.]]]])
    tensor([[[[2., 3.],
              [5., 1.]]]])
    

使用数据集进行池化操作并记录

import torch
import torchvision
from torch import nn
from torch.nn import MaxPool2d
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter

dataset = torchvision.datasets.CIFAR10("../data", train=False, download=True,
                                       transform=torchvision.transforms.ToTensor())

dataloader = DataLoader(dataset, batch_size=64)

class Tudui(nn.Module):
    def __init__(self):
        super(Tudui, self).__init__()
        self.maxpool1 = MaxPool2d(kernel_size=3, ceil_mode=False)

    def forward(self, input):
        output = self.maxpool1(input)
        return output

tudui = Tudui()

writer = SummaryWriter("../logs_maxpool")
step = 0

for data in dataloader:
    imgs, targets = data
    writer.add_images("input", imgs, step)
    output = tudui(imgs)
    writer.add_images("output", output, step)
    step = step + 1

writer.close()

池化的作用

(1)保留主要特征的同时减少参数和计算量,防止过拟合。

(2)invariance(不变性),这种不变性包括translation(平移),rotation(旋转),scale(尺度)。

Pooling 层说到底还是一个特征选择,信息过滤的过程。也就是说我们损失了一部分信息,这是一个和计算性能的一个妥协,随着运算速度的不断提高,妥协会越来越小。

现在有些网络都开始少用或者不用pooling层了。

各类池化

  • 平均池化(avgpooling)可以保留背景信息。在feature map上以窗口的形式进行滑动(类似卷积的窗口滑动),操作为取窗口内的平均值作为结果,经过操作后,feature map降采样,减少了过拟合现象。前向传播就是把一个patch中的值求取平均来做pooling,那么反向传播的过程也就是把某个元素的梯度等分为n份分配给前一层,这样就保证池化前后的梯度(残差)之和保持不变。
  • 最大池化(maxpooling)可以提取特征纹理。减少无用信息的影响。maxpooling也要满足梯度之和不变的原则,max pooling的前向传播是把patch中最大的值传递给后一层,而其他像素的值直接被舍弃掉。那么反向传播也就是把梯度直接传给前一层某一个像素,而其他像素不接受梯度,也就是为0。所以max pooling操作和mean pooling操作不同点在于需要记录下池化操作时到底哪个像素的值是最大,也就是max id,这个变量就是记录最大值所在位置的,因为在反向传播中要用到。
  • 全局池化(global pooling)来获取全局上下文关系。不以窗口的形式取均值,而是以feature map为单位进行均值化。即一个feature map输出一个值。
  • 6
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值