0
点赞
收藏
分享

微信扫一扫

卷积神经网络——上篇【深度学习】【PyTorch】

在觉 2023-08-22 阅读 64

文章目录

5、卷积神经网络

5.1、卷积

5.1.1、理论部分

全连接层后,卷积层出现的意义?

一个足够充分的照片数据集,输入,全连接层参数,GPU成本,训练时间是巨大的。

(convolutional neural networks,CNN)是机器学习利用自然图像中一些已知结构的创造性方法,需要更少的参数,在处理图像和其他类型的结构化数据上各类成本,效果,可行性普遍优于全连接层。

卷积层做了什么?

将输入和核矩阵进行互相关运算,加上偏移后得到输出。

图片中找模式的原则

  • 平移不变性
  • 局部性

(详细待补充)

二维卷积层

在这里插入图片描述

Y = X ★ W + b Y = X ★ W + b Y=XW+b

  • W W W k h × k w k_h × k_w kh×kw

  • 偏差 b∈ R

  • 输出 Y Y Y ( n h − k h + 1 ) × ( n w − k w + 1 ) ( n_h - k_h + 1)×(n_w - k_w + 1) nhkh+1×nwkw+1

  • ★:二维交叉操作子 | 外积

  • W 和 b是可学习的参数

  • 卷积效果举例

    在这里插入图片描述

    5.1.2、代码实现

    (1)实现互相关运算


    import torch
    from torch import nn
    from d2l import torch as d2l
    
    def corr2d(X, K):  #@save
        """计算二维互相关运算"""
        h, w = K.shape
        Y = torch.zeros((X.shape[0] - h + 1, X.shape[1] - 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.0, 1.0, 2.0], [3.0, 4.0, 5.0], [6.0, 7.0, 8.0]])
    K = torch.tensor([[0.0, 1.0], [2.0, 3.0]])
    corr2d(X, K)
    

    实现二维卷积层

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

    (2)学习由X生成Y卷积核


    #一个输入通道、一个输出通道,不使用偏置
    conv2d = nn.Conv2d(1,1,kernel_size=(1,2),bias =False)
    
    X = X.reshape((1,1,6,8))
    Y = Y.reshape((1,1,6,7))
    
    for i in range(10):
        Y_hat = conv2d(X)
        l = (Y_hat - Y) **2
        conv2d.zero_grad()
        l.sum().backward()
        conv2d.weight.data[:] -=3e-2 * conv2d.weight.grad
        if(i + 1)% 2 == 0:
            print(f'batch{i + 1}, loss {l.sum():.3f}')
    

    所学卷积核权重

    conv2d.weight.data.reshape((1,2))
    

    5.1.3、边缘检测

    利用卷积层检测 图像中的不同边缘

    输入

    X = torch.ones((6,8))
    X[:, 2:6]  =0
    X
    

    核矩阵

    K = torch.tensor([[1,-1]])
    

    输出

    Y  = corr2d(X,K)
    Y
    

    只能检测垂直边缘

    将核矩阵一起转置

    Y  = corr2d(X.t(),K.t())
    Y
    

    5.2、填充和步幅

    5.2.1、理论部分

    填充操作

    更大的卷积核可以更快地减小输出大小。

    如果不想结果太小,也可以通过填充实现输出更大尺寸的X,实现控制输出形状的减少量。

    在这里插入图片描述

    填充 p h p_h ph p w p_w pw列,输出形状:

    ( n h − k h + p h + 1 ) × ( n w − k w + p w + 1 ) (n_h -k_h +p_h +1)×(n_w - k_w + p_w +1) nhkh+ph+1×nwkw+pw+1

    步幅

    步幅指行/列滑动步长。

    下图为高3宽2步幅示意图:

    在这里插入图片描述

    给定步幅,高度 s h s_h sh宽度 s w s_w sw,输出形状:

    ⌊ ( n h − k h + p h + s h ) / s h ⌋ × ⌊ ( n w − k w + p w + s w ) / s w ⌋ ⌊(n_h - k_h + p_h + s_h)/s_h⌋ ×⌊(n_w - k_w + p_w + s_w)/s_w⌋ ⌊(nhkh+ph+sh)/sh×⌊(nwkw+pw+sw)/sw

    5.2.2、代码实现

    所有侧边填充一个像素

    import torch
    from torch import nn
    
    def comp_conv2d(conv2d, X):
        X = X.reshape((1,1) + X.shape)
        Y =conv2d(X)
        return Y.reshape(Y.shape[2:])
    
    conv2d = nn.Conv2d(1,1,kernel_size=3,padding=1)
    X= torch.rand(size=(8,8))
    comp_conv2d(conv2d,X).shape
    

    填充相同高度宽度

    import torch
    from torch import nn
    
    def comp_conv2d(conv2d, X):
        X = X.reshape((1,1) + X.shape)
        #执行一次卷积操作
        Y =conv2d(X)
        return Y.reshape(Y.shape[2:])
    #padding=1 在输入数据的边界填充一行和一列的零值
    conv2d = nn.Conv2d(1,1,kernel_size=3,padding=1)
    X= torch.rand(size=(8,8))
    comp_conv2d(conv2d,X).shape
    

    不同高度宽度

    conv2d = nn.Conv2d(1,1,kernel_size=(5,3),padding=(2,1))
    comp_conv2d(conv2d,X).shape
    

    增设步幅,其宽高为2

    conv2d = nn.Conv2d(1,1,kernel_size=3,padding=1,stride =2)
    comp_conv2d(conv2d,X).shape
    

    5.3、多输入多输出通道

    5.3.1、理论部分

    彩色RGB图片,是三通道输入数据。

    每个通道都有一个卷积核,结果为各通道卷积的和。

    在这里插入图片描述

    1×1卷积层

    不识别空间,用途是融合通道。

    二维卷积层(多通道)

    Y = X ★ W + B Y = X ★ W + B Y=XW+B

  • W W W c o × c i × k h × k w c_o × c_i × k_h × k_w co×ci×kh×kw

  • 偏差 B B B c o × c i c_o × c_i co×ci

  • 输出 Y Y Y c o × m h × m w c_o × m_h × m_w co×mh×mw

  • ★:二维交叉操作子 | 外积

  • 怎么理解每个输出通道有独立的三维卷积核?

    具有三个维度:高度、宽度和通道数。

    5.3.2、代码实现

    (1)实现多通道互相关运算


    定义多通道输入

    import torch
    from d2l import torch as d2l
    #先遍历“X”和“K”的第0个维度(通道维度),再把它们加在一起
    def corr2d_multi_in(X,K):
        return sum(d2l.corr2d(x,k) for x,k in zip(X,K))
    

    定义X,K

    # X 6*3
    X = torch.tensor([[[0.0, 1.0, 2.0], [3.0, 4.0, 5.0], [6.0, 7.0, 8.0]],
                   [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]]])
    #K 4*2
    K = torch.tensor([[[0.0, 1.0], [2.0, 3.0]], [[1.0, 2.0], [3.0, 4.0]]])
    
    X,K,corr2d_multi_in(X, K)
    

    定义多通道输出

    def corr2d_multi_in_out(X,K):
        # 使用 PyTorch 的 torch.stack 函数,它将一组张量沿着指定的维度(这里是维度0)进行堆叠,生成一个新的张量。
        return torch.stack([corr2d_multi_in(X,k) for k in K],0)
    # K+1 K的每个值加一,K规模扩成了原来3倍。
    K = torch.stack((K,K+1,K+2),0)
    K,K.shape
    
    corr2d_multi_in_out(X,K)
    

    (2)实现1*1卷积核


    def corr2d_multi_in_out_1x1(X, K):
        c_i, h, w = X.shape
        c_o = K.shape[0]
        X = X.reshape((c_i, h * w))
        K = K.reshape((c_o, c_i))
        # 全连接层中的矩阵乘法
        Y = torch.matmul(K, X)
        return Y.reshape((c_o, h, w))
    
    X = torch.normal(0, 1, (3, 3, 3))
    K = torch.normal(0, 1, (2, 3, 1, 1))
    
    Y1 = corr2d_multi_in_out_1x1(X, K)
    Y2 = corr2d_multi_in_out(X, K)
    # 进行断言,验证使用 1x1 卷积操作得到的输出 Y1 与多通道卷积操作得到的输出 Y2 是否非常接近,以确保两种方法的结果一致
    assert float(torch.abs(Y1 - Y2).sum()) < 1e-6
    

    5.4、池化层 | 汇聚层

    5.4.1、理论部分

    最大池化,每个窗口最强的模式信号,它针对卷积对空间位置敏感(边缘检测案例),允许输入有一定的偏移。

    也有平均池化层。

    特点

    • 具有填充,步幅;
    • 没有可学习的参数;
    • 输出通道 = 输入通道,一一对应。

    5.4.2、代码实现

    池化层向前传播

    import torch
    from torch import nn
    from d2l import torch as d2l
    
    def pool2d(X, pool_size, mode='max'):
        p_h, p_w = pool_size
        Y = torch.zeros((X.shape[0] - p_h + 1, X.shape[1] - p_w + 1))
        for i in range(Y.shape[0]):
            for j in range(Y.shape[1]):
                if mode == 'max':
                    Y[i, j] = X[i: i + p_h, j: j + p_w].max()
                elif mode == 'avg':
                    Y[i, j] = X[i: i + p_h, j: j + p_w].mean()
        return Y
    

    使用内置的最大池化层

    X = torch.arange(16, dtype=torch.float32).reshape((1, 1, 4, 4))
    X
    
    pool2d = nn.MaxPool2d(3, padding=1, stride=2)#等价于nn.MaxPool2d((3,3), padding=(1,1), stride=(2,2))
    pool2d(X)
    
    pool2d = nn.MaxPool2d((2, 3), stride=(2, 3), padding=(0, 1))
    pool2d(X)
    

    验证多通道

    汇聚层在每个输入通道上单独运算,输出通道数与输入通道数相同。

    # 将两个张量 X, X + 1 进行拼接
    X = torch.cat((X, X + 1), 1)
    X
    
    pool2d = nn.MaxPool2d(3, padding=1, stride=2)
    pool2d(X)
    
    举报

    相关推荐

    0 条评论