神经网络骨架搭建及卷积

 本部分主要是对卷积神经网络的骨架搭建流程以及卷积相关操作进行说明。

目录

基本骨架——nn.Module

卷积

理论知识

实践


基本骨架——nn.Module

 关于神经网络的一些工具主要位于 torch.nn 里面,其中 nn 是神经网络(Neural Network)的缩写。torch.nn 里的 Containers 类给神经网络定义了一些骨架结构,我们只需在骨架中添加相应的操作部分即可构成神经网络。具体情况请通过官方文档查看:PyTorch官方文档

Containers 一共有6个模块结构,其中最重要也是最常用的是 Module 模块,该模块给所有的神经网络都提供了一个骨架,我们搭建的所有神经网络都需要从 Module 这个类中继承,示例如下:

import torch.nn as nn
import torch.nn.functional as F

class Model(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(1, 20, 5)
        self.conv2 = nn.Conv2d(20, 20, 5)

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

首先创建了一个Model 的类继承 Module ,在 Model 这个子类中需要重写初始化和操作函数,一定要使用   super().__init__() 方法对父类的属性也进行初始化。示例代码中的 forward 函数代表前向传播,在该函数中对参数 x 进行了两次卷积和两次非线性激活,卷积用于特征提取,非线性激活用于引入非线性变换,增加模型的表达能力。

实例化相关代码如下:

import torch
from torch import nn

class Model(nn.Module):
    def __init__(self):
        super().__init__()

    def forward(self, x):
        output = x + 1
        return output

model = Model()
x = torch.tensor(1.0)
output = model(x)
print(output)

卷积

理论知识

在神经网络中,卷积(Convolution)主要用于从输入数据中提取特征,并在模型的不同层级中共享权重,以减少参数数量。卷积操作基于滤波器(也称为卷积核或特征检测器)和输入数据之间的运算。滤波器是一个小的矩阵,它通过在输入数据上滑动并与其进行逐元素相乘,然后将结果求和来计算输出值。这个过程可以看作是对输入数据的局部区域进行加权求和。

这里我们对于卷积的相关操作进行简单说明:

假设输入一个灰度图像是 5\times5 的二维数组,其中每一个数字表示在这个像素中的颜色显示,通过随机生成或模型训练得到一个3\times3 卷积核,让该卷积核在这个二维数组中以 3\times3 的形式进行匹配,并逐个对应相乘求和得到一个数值,将该数值称为原图像的一个特征值,如下图示:

神经网络骨架搭建及卷积_第1张图片

我们这里设置的步长为1,意味着每次匹配完后,卷积核会以1个单位进行移动,直至边缘,全部匹配一遍后,我们会得到一个 3\times3 的二维数组,如果设置的步长为2,则最终会得到一个 2\times 2 的数组,该数组即为卷积后的输出,实际上,卷积就是将图像的特征提取并融合,将图像进行缩小的过程。最终结果如下图示:

神经网络骨架搭建及卷积_第2张图片

注:这里不对卷积做详细介绍,后期会出系统性的卷积神经网络结构和原理的讲解,十分抱歉。

conv2d

Applies a 2D convolution over an input image composed of several input planes.

这里 nn.conv2d 表示输入的是二维数组,我们这里进行重点讲解。

通过官网我们可以看到有 torch.nn torch.nn.functional ,其中 nn 表示一个封装的类,而functional 则是具体的函数源代码,两个处于互相对应的关系。我们通过 functional 查看 conv2d 的具体使用方法,如下图:

神经网络骨架搭建及卷积_第3张图片

  • input:输入的特征图(N图像数量,C通道数,H高度,W宽度),其中通道数可以理解为输入几个卷积核,就有几个通道
  • weight:卷积核的权重
  • bias:可选偏置,大小为(out_channels)的一维张量。默认为None,表示不使用偏置,表示是否对卷积后的结果加/减一个常数
  • stride:卷积核每次移动的步长,默认为1
  • padding:在特征图四周填充的大小,默认为0,表示不进行填充,填充可以更好的保留边缘特征
  • dilation:卷积核中的空洞大小,默认为1,表示不进行空洞卷积
  • groups:分组卷积的分组数,默认为1,表示不进行分组卷积
  • return:返回进行卷积操作后得到的特征图

实践

我们这里的代码部分是以上述输入的二维数组为例,阐述了 stride 和 padding 参数设置的区别。

output = F.conv2d(input, kernel, stride=1)
output2 = F.conv2d(input, kernel, stride=2)

显示结果如下:

神经网络骨架搭建及卷积_第4张图片

可以看出,当 stride=1 和 2 时,输出的结果与上述推导的理论相符,分别为 3\times3 和 2\times 2 的数组。

output3 = F.conv2d(input, kernel, stride=1, padding=1)  # padding 设置的值,是往外扩充的行列数,值都是0,至于想要修改这个值,还有另外一个参数,一般不改
output4 = F.conv2d(input, kernel, stride=1, padding=0)  # padding 默认值是 0

显示结果如下:

神经网络骨架搭建及卷积_第5张图片

从padding = 1 和 0 可以看出,当 padding = n 时,会在输入数组四周向外扩充 n 行/列,填充的数值默认为0。而这种方式的好处就是能够更好的保留边缘信息,因为不进行填充时,中间部分的特征值会经过多次计算,而边缘只有一次计算,意味着对于边缘特征提取的信息比较匮乏,而扩充一定的行列数就可以让边缘值也经过多次计算,从而保留边缘特征,增加感受野,更易于模型训练。

相关代码如下:

import torch
import torch.nn.functional as F 

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]])

kernel = torch.tensor([[1, 2, 1],
                       [0, 1, 0],
                       [2, 1, 0]])
print("input:", input)
print("kernel:", kernel)
print("input.shape:", input.shape)
print("kernel.shape:", kernel.shape)

input = torch.reshape(input, (1, 1, 5, 5))  
kernel = torch.reshape(kernel, (1, 1, 3, 3))  

print("input.shape:", input.shape)
print("kernel.shape:", kernel.shape)
output = F.conv2d(input, kernel, stride=1)
print(output)
output2 = F.conv2d(input, kernel, stride=2)
print(output2)
output3 = F.conv2d(input, kernel, stride=1, padding=1) 
print(output3)
output4 = F.conv2d(input, kernel, stride=1, padding=0)
print(output4)

你可能感兴趣的:(PyTorch深度学习快速入门,神经网络,深度学习,pytorch)