task05

作者: kingron | 来源:发表于2020-02-19 21:26 被阅读0次

    卷积神经网络基础

    二维卷积层

    二维互相关运算

    二维互相关(cross-correlation)运算的输入是一个二维输入数组和一个二维核(kernel)数组,输出也是一个二维数组,其中核数组通常称为卷积核或过滤器(filter)。卷积核的尺寸通常小于输入数组,卷积核在输入数组上滑动,在每个位置上,卷积核与该位置处的输入子数组按元素相乘并求和,得到输出数组中相应位置的元素。图1展示了一个互相关运算的例子,阴影部分分别是输入的第一个计算区域、核数组以及对应的输出。

    Image Name

    图1 二维互相关运算

    # 用`corr2d`函数实现二维互相关运算,它接受输入数组`X`与核数组`K`,并输出数组`Y`
    
    import torch 
    import torch.nn as nn
    
    def corr2d(X, K):
        H, W = X.shape
        h, w = K.shape
        Y = torch.zeros(H - h + 1, W - w + 1)
        for i in range(Y.shape[0]):
            for j in range(Y.shape[1]):
                Y[i, j] = (X[i: i + h, j: j + w] * K).sum()
        return Y
    
    X = torch.tensor([[0, 1, 2], [3, 4, 5], [6, 7, 8]])
    K = torch.tensor([[0, 1], [2, 3]])
    Y = corr2d(X, K)
    print(Y)
    
    # output:
    # tensor([[19., 25.],
    #         [37., 43.]])
    

    二维卷积层

    二维卷积层将输入和卷积核做互相关运算,并加上一个标量偏置来得到输出。卷积层的模型参数包括卷积核和标量偏置。

    class Conv2D(nn.Module):
    
        def __init__(self, kernel_size):
            super(Conv2D, self).__init__()
            self.weight = nn.Parameter(torch.randn(kernel_size))
            self.bias = nn.Parameter(torch.randn(1))
    
        def forward(self, x):
            return corr2d(x, self.weight) + self.bias
    

    互相关运算与卷积运算

    卷积层得名于卷积运算,但卷积层中用到的并非卷积运算而是互相关运算。我们将核数组上下翻转、左右翻转,再与输入数组做互相关运算,这一过程就是卷积运算。由于卷积层的核数组是可学习的,所以使用互相关运算与使用卷积运算并无本质区别。

    特征图与感受野

    二维卷积层输出的二维数组可以看作是输入在空间维度(宽和高)上某一级的表征,也叫特征图(feature map)。影响元素x的前向计算的所有可能输入区域(可能大于输入的实际尺寸)叫做x的感受野(receptive field)。

    以图1为例,输入中阴影部分的四个元素是输出中阴影部分元素的感受野。我们将图中形状为2 \times 2的输出记为Y,将Y与另一个形状为2 \times 2的核数组做互相关运算,输出单个元素z。那么,zY上的感受野包括Y的全部四个元素,在输入上的感受野包括其中全部9个元素。可见,我们可以通过更深的卷积神经网络使特征图中单个元素的感受野变得更加广阔,从而捕捉输入上更大尺寸的特征。

    超参:填充和步幅

    填充

    填充(padding)是指在输入高和宽的两侧填充元素(通常是0元素),图2里我们在原输入高和宽的两侧分别添加了值为0的元素。

    Image Name

    图2 在输入的高和宽两侧分别填充了0元素的二维互相关计算

    如果原输入的高和宽是n_hn_w,卷积核的高和宽是k_hk_w,在高的两侧一共填充p_h行,在宽的两侧一共填充p_w列,则输出形状为:

    $$

    (n_h+p_h-k_h+1)\times(n_w+p_w-k_w+1)

    $$

    我们在卷积神经网络中使用奇数高宽的核,比如3 \times 35 \times 5的卷积核,对于高度(或宽度)为大小为2 k + 1的核,令步幅为1,在高(或宽)两侧选择大小为k的填充,便可保持输入与输出尺寸相同。

    步幅

    在互相关运算中,卷积核在输入数组上滑动,每次滑动的行数与列数即是步幅(stride)。此前我们使用的步幅都是1,图3展示了在高上步幅为3、在宽上步幅为2的二维互相关运算。

    Image Name

    图3 高和宽上步幅分别为3和2的二维互相关运算

    一般来说,当高上步幅为s_h,宽上步幅为s_w时,输出形状为:

    $$

    \lfloor(n_h+p_h-k_h+s_h)/s_h\rfloor \times \lfloor(n_w+p_w-k_w+s_w)/s_w\rfloor

    $$

    如果p_h=k_h-1p_w=k_w-1,那么输出形状将简化为\lfloor(n_h+s_h-1)/s_h\rfloor \times \lfloor(n_w+s_w-1)/s_w\rfloor。更进一步,如果输入的高和宽能分别被高和宽上的步幅整除,那么输出形状将是(n_h / s_h) \times (n_w/s_w)

    p_h = p_w = p时,我们称填充为p;当s_h = s_w = s时,我们称步幅为s

    leNet

    #import
    import sys
    sys.path.append("/home/kesci/input")
    import d2lzh1981 as d2l
    import torch
    import torch.nn as nn
    import torch.optim as optim
    import time
    
    
    #net
    class Flatten(torch.nn.Module):  #展平操作
    
        def forward(self, x):
            return x.view(x.shape[0], -1)
    
    class Reshape(torch.nn.Module): #将图像大小重定型
    
        def forward(self, x):
            return x.view(-1,1,28,28)      #(B x C x H x W)
        
    net = torch.nn.Sequential(     #Lelet                                                  
        Reshape(),
        nn.Conv2d(in_channels=1, out_channels=6, kernel_size=5, padding=2), #b*1*28*28  =>b*6*28*28
        nn.Sigmoid(),                                                       
        nn.AvgPool2d(kernel_size=2, stride=2),                              #b*6*28*28  =>b*6*14*14
        nn.Conv2d(in_channels=6, out_channels=16, kernel_size=5),           #b*6*14*14  =>b*16*10*10
        nn.Sigmoid(),
        nn.AvgPool2d(kernel_size=2, stride=2),                              #b*16*10*10  => b*16*5*5
        Flatten(),                                                          #b*16*5*5   => b*400
        nn.Linear(in_features=16*5*5, out_features=120),
        nn.Sigmoid(),
        nn.Linear(120, 84),
        nn.Sigmoid(),
        nn.Linear(84, 10)
    )
    

    卷积神经网络进阶

    LeNet: 在大的真实数据集上的表现并不尽如⼈意。

    1. 神经网络计算复杂。
    2. 还没有⼤量深⼊研究参数初始化和⾮凸优化算法等诸多领域。

    机器学习的特征提取:手工定义的特征提取函数
    神经网络的特征提取:通过学习得到数据的多级表征,并逐级表⽰越来越抽象的概念或模式。

    神经网络发展的限制:数据、硬件

    AlexNet

    首次证明了学习到的特征可以超越⼿⼯设计的特征,从而⼀举打破计算机视觉研究的前状。
    特征:

    1. 8层变换,其中有5层卷积和2层全连接隐藏层,以及1个全连接输出层。
    2. 将sigmoid激活函数改成了更加简单的ReLU激活函数。
    3. 用Dropout来控制全连接层的模型复杂度。
    4. 引入数据增强,如翻转、裁剪和颜色变化,从而进一步扩大数据集来缓解过拟合。
    Image Name
    import time
    import torch
    from torch import nn, optim
    import torchvision
    import numpy as np
    import sys
    sys.path.append("/home/kesci/input/") 
    import d2lzh1981 as d2l
    import os
    import torch.nn.functional as F
    
    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    
    class AlexNet(nn.Module):
    
        def __init__(self):
            super(AlexNet, self).__init__()
            self.conv = nn.Sequential(
                nn.Conv2d(1, 96, 11, 4), # in_channels, out_channels, kernel_size, stride, padding
                nn.ReLU(),
                nn.MaxPool2d(3, 2), # kernel_size, stride
                # 减小卷积窗口,使用填充为2来使得输入与输出的高和宽一致,且增大输出通道数
                nn.Conv2d(96, 256, 5, 1, 2),
                nn.ReLU(),
                nn.MaxPool2d(3, 2),
                # 连续3个卷积层,且使用更小的卷积窗口。除了最后的卷积层外,进一步增大了输出通道数。
                # 前两个卷积层后不使用池化层来减小输入的高和宽
                nn.Conv2d(256, 384, 3, 1, 1),
                nn.ReLU(),
                nn.Conv2d(384, 384, 3, 1, 1),
                nn.ReLU(),
                nn.Conv2d(384, 256, 3, 1, 1),
                nn.ReLU(),
                nn.MaxPool2d(3, 2)
            )
             # 这里全连接层的输出个数比LeNet中的大数倍。使用丢弃层来缓解过拟合
            self.fc = nn.Sequential(
                nn.Linear(256*5*5, 4096),
                nn.ReLU(),
                nn.Dropout(0.5),
                #由于使用CPU镜像,精简网络,若为GPU镜像可添加该层
                #nn.Linear(4096, 4096),
                #nn.ReLU(),
                #nn.Dropout(0.5),
    
                # 输出层。由于这里使用Fashion-MNIST,所以用类别数为10,而非论文中的1000
                nn.Linear(4096, 10),
            )
    
        def forward(self, img):
    
            feature = self.conv(img)
            output = self.fc(feature.view(img.shape[0], -1))
            return output
    

    相关文章

      网友评论

          本文标题:task05

          本文链接:https://www.haomeiwen.com/subject/xauzfhtx.html