神经网络的基本骨架(第六期)

78 阅读6分钟

神经网络的基本骨架

神经网络的基本骨架构成为:input-->卷积层-->池化层-->正则化层-->非线性激活-->线性层。(个别层可以根据模型训练需要进行添加或删除),下面是各个层的依次介绍。

卷积层

卷积原理

  1. 通过卷积核在图片上按指定步长向右向下移动,将卷积核覆盖的像素乘以对应位置卷积核的值再的相加,最终得到一个总和,作为卷积后图片的对应位置的像素,然后卷积核向右或向下移动step步,继续重复上面的操作,直到原图片的所有像素均被卷积,这时卷积操作完成。

    stateDiagram-v2
    图片-->[[1,2,3,4,5]\n[1,2,3,4,5]\n[1,2,3,4,5]\n[1,2,3,4,5]]
    卷积核 --> [1,1,1]\n[1,1,1]\n[1,1,1]
    [1,1,1]\n[1,1,1]\n[1,1,1]-->(进行卷积的结果)
    [[1,2,3,4,5]\n[1,2,3,4,5]\n[1,2,3,4,5]\n[1,2,3,4,5]]-->(进行卷积的结果)
    (进行卷积的结果)-->[18,27,36]\n[18,27,36]
    

如上,卷积核为3x3的一个全1的核,原图为4x5的一个单通道图片,卷积后的图片为2x3的一个单通道图片。

(单通道即只有一个维度)(作为对比彩色图片为3通道图(分别为RGB三个通道)),

2.卷积核首先覆盖在图片的左上角,即覆盖了[[1,2,3][1,2,3],[1,2,3]],将该位置的像素进行卷积,即1x1+2x1+3x1+1x1+2x1+3x1+1x1+2x1+3x1=18

所以卷积后的图片的左上角第一个像素为18,然后将卷积核向右移动step步(这里step设置为1),此时卷积核覆盖了[[2,3,4][2,3,4],[2,3,4]],进行卷积操作,即 2x1+3x1+4x1+2x1+3x1+4x1+2x1+3x1+4x1=27

这就是卷积后的图片的第二个像素,然后继续向右…………… 当右边走到头后就可以将卷积核开始向下移动step步,然后重复上面的操作。

注意:卷积核必须完全在图片上,不能在图片外,也不能一半在外一半在内,如果不满足上述要求,就表示卷积核走到头了

pytorch中的卷积函数

头文件

from torch.nn import Conv2d

函数

Conv2d(in_channels=3, out_channels=32, 
kernel_size=(5, 5), 
stride=(1, 1), padding=0)

#参数:
# in_channels 输入图片的通道数 (输入图片层数)
# out_channels 输出图片的通道数  (输出图片层数)
# kernel_size 卷积核 (卷积核个数=in_channels * out_channels)
# stride 卷积核每次移动的步长(横向移动步长,纵向移动步长)
# padding 围绕着原图填充一圈,填充值为0。该参数作用:让在图片边缘
# 的小于卷积核大小的位置的像素可以借助填充,单独进行一次卷积。

池化层

1.与卷积层类似,但是需要的不是卷积核,而是空洞卷积,进行“卷积”的方式也不同,其余性质与卷积层一致。

stateDiagram-v2
卷积核 --> [[1,1,1]\n[1,1,1]\n[1,1,1]]
空洞卷积 --> 
[[1,0,1,0,1]\n[0,0,0,0,0]\n[1,0,1,0,1]\n[0,0,0,0,0]\n[1,0,1,0,1]]

[[1,1,1]\n[1,1,1]\n[1,1,1]] --> 转化
转化 --> [[1,0,1,0,1]\n[0,0,0,0,0]\n[1,0,1,0,1]\n[0,0,0,0,0]\n[1,0,1,0,1]]
  • 由上图可见,空洞卷积将普通卷积核中的每一个值用0隔开了,从而构成了一种新的卷积核,这就叫做空洞卷积核(简称空洞卷积)
  • 池化层进行"卷积"的方式:卷积核覆盖的位置的所有像素,找出其中像素值最大的像素,作为结果进行输出,这就叫最大池化。

pytorch中的池化函数

头文件

from torch.nn import MaxPool2d

函数

MaxPool2d(kernel_size=(3, 3), ceil_mode=True)
#参数
#kernel_size 池化核(stride一般取默认即与池化核
# 大小一致)(这里会自动将3x3的核转化成空洞卷积核)
#ceil_mode  向上取整--沙鲁模式
#(当图片像素不足池化核大小时,是否依然保留并计算)

#最大池化层作用:保留数据特征同时减小数据量

非线性激活

作用

  1. 在神经网络中加入一些非线性的特征

头文件

from torch.nn import  ReLU

函数

ReLU()
# 非线性激活作用:在网络中引入一些非线性特征
# ReLU()函数作用:图片像素小于或等于0的返回0,大于0的返回原值

正则化层

头文件

from torch.nn import BatchNorm2d

函数

BatchNorm2d(num_features=3)
#参数
#num_features  图片通道数
#正则化作用: 防止过拟合

线性层

头文件

from torch.nn import Linear

函数

self.linear=Linear(196608, 10)
#参数
#in_features :输入图像(必须为线性图
# --->[1,1,1,xxx](可简化为[xxx],如torch.flatten输出[xxx]))
#out_features :输出图像(同样为线性图[xxx])

# 线性层作用:保留数据特征同时减小数据量

介绍一个可以将图片展开的函数(变为线性图)

#torch.flatten(imgs)
# 参数
# input 图片(tensor类型)

# 函数作用:将图片展平(即变为[1,1,1,xxx])

简单神经网络的搭建

from torch import nn
from torch.nn import Conv2d, MaxPool2d, ReLU, BatchNorm2d, Linear
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
import torchvision
import torch


#nn.Module 为神经网络的基本骨架,所有的神经网络都要继承它


data_compose=torchvision.transforms.Compose([torchvision.transforms.ToTensor()])
test_dataset2=torchvision.datasets.CIFAR10(root="./test_dataset2", train=False, transform=data_compose, download=True)

dataload=DataLoader(test_dataset2, batch_size=64, shuffle=True, num_workers=0, drop_last=True)


#神经网络的搭建
class NetWork(nn.Module):

    def __init__(self):
        super(NetWork, self).__init__()

        #卷积层
        self.conv1=Conv2d(in_channels=3, out_channels=6, kernel_size=(3, 3), stride=(1, 1), padding=0)
        #参数:
        # in_channels 输入图片的通道数 (输入图片层数)
        # out_channels 输出图片的通道数  (输出图片层数)
        # kernel_size 卷积核 
        #(卷积核个数=in_channels * out_channels)
        # stride 卷积核每次移动的步长(横向移动步长,纵向移动步长)



        #池化层(与卷积层类似)
        self.maxpool=MaxPool2d(kernel_size=(3, 3), ceil_mode=True)
        #参数
        #kernel_size 池化核(stride一般取默认即与池化核大小一致)
        #ceil_mode  向上取整--沙鲁模式(当图片像素不足池化核大小时,是否依然保留并计算)

        #最大池化层作用:保留数据特征同时减小数据量


        #非线性激活
        self.relu=ReLU()

        #非线性激活作用:在网络中引入一些非线性特征
        # ReLU()函数作用:图片像素小于或等于0的返回0,大于0的返回原值


        #线性层
        self.linear=Linear(196608, 10)
        #参数
        #in_features :输入图像(必须为线性图--->[1,1,1,xxx]
        #(可简化为[xxx],如torch.flatten输出[xxx]))
        #out_features :输出图像(同样为线性图[xxx])

        # 线性层作用:保留数据特征同时减小数据量


        # 正则化层
        self.batchnormal=BatchNorm2d(num_features=3)
        #参数
        #num_features  图片通道数
        #正则化作用: 防止过拟合



        self.model=nn.Sequential(
            nn.Conv2d(in_channels=3, out_channels=6, 
            kernel_size=(3, 3), stride=(1, 1), padding=0),
            nn.ReLU(),
            )     
            #类似transform中的Compose()函数,输入的图片会依次经过
            #各个层的处理


    def forward(self, x, y):      #输出函数(对父类方法的重写)
    #(神经网络传入数据后自动调用)
        return self.conv1(x), self.maxpool(x), self.linear(y)

    #torch.flatten(imgs)
    # 参数
    # input 图片(tensor类型)

    # 函数作用:将图片展平(即变为[1,1,1,xxx])




if __name__ == '__main__':
    net=NetWork()
    writer = SummaryWriter(r"E:\python\pythonProject_pyTorch\
    nn_model")
    # print(net)
    step=0
    for data in dataload:
        imgs, targets =data


        output1, output2, output3=net(imgs, torch.flatten(imgs))
        print("原图大小:"+str(imgs.shape))

        #.shape-->[N,C,W,H](batch_size(图片数  量),channel(图片
        #通道数),图片高,图片宽)

        print("卷积后图的大小:"+str(output1.shape))
        writer.add_images("imgs", imgs, step)

        #tensorBoard最多显示三通道的图片,及彩色图片,
        #高于3通道的图片若想要显示,需要改变图片通道数即维度
        output=torch.reshape(output1, (-1, 3, 30, 30))
        #函数作用:
            #改变图片维度即通道数
        #参数
        #input: 要改变的图片(图片类型必须是Tensor)
        #(shape): 要改变的大小
        #返回值: 改变后的图片(Tensor类型)

        print("最大池化后图的大小:"+str(output2.shape))

        writer.add_images("output", output, step)
        writer.add_images("output2", output2, step)

        step=step+1

        print("线性层输出后大小:"+str(output3.shape))

    writer.close()