精华内容
下载资源
问答
  • pytorch task05 卷积神经网络 文章目录pytorch task05 卷积神经网络1.卷积神经网络基础1.1二卷积层1.2填充和步幅1.3多输入通道和多输出通道1.4卷积层与全连接层的对比1.5池化2 经典模型LeNet-5AlexNetVGGGoogLeNet...
  • 本文为大家讲解了pytorch实现CNN卷积神经网络,供大家参考,具体内容如下 我对卷积神经网络的一些认识  卷积神经网络是时下最为流行的种深度学习网络,由于其具有局部感受野等特性,让其与人眼识别图像具有相似性...
  • 互相关(cross-correlation)运算的输入是个二输入数组和个二维核(kernel)数组,输出也是个二数组,其中核数组通常称为卷积核或过滤器(filter)。卷积核的尺寸通常小于输入数组,卷积核在输入数组...
  • Task05-pyTorch卷积神经网络基础、LeNet、卷积神经网络进阶) 卷积神经网络基础 二互相关运算 二互相关(cross-correlation)运算的输入是个二输入数组和个二维核(kernel)数组,输出也是个二数组...

    Task05-pyTorch(卷积神经网络基础、LeNet、卷积神经网络进阶)

    卷积神经网络基础

    二维互相关运算
    在这里插入图片描述

    二维互相关(cross-correlation)运算的输入是一个二维输入数组和一个二维核(kernel)数组,输出也是一个二维数组,其中核数组通常称为卷积核或过滤器(filter)。卷积核的尺寸通常小于输入数组,卷积核在输入数组上滑动,在每个位置上,卷积核与该位置处的输入子数组按元素相乘并求和,得到输出数组中相应位置的元素。

    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
    

    二维卷积层

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

    互相关运算与卷积运算

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

    特征图与感受野
    在这里插入图片描述
    在这里插入图片描述

    填充
    在这里插入图片描述
    在这里插入图片描述

    步幅

    在这里插入图片描述
    在这里插入图片描述

    多输入通道与多输出通道

    多输入通道
    在这里插入图片描述

    多输出通道
    在这里插入图片描述
    在这里插入图片描述

    卷积层与全连接层对比

    1、一是全连接层把图像展平成一个向量,在输入图像上相邻的元素可能因为展平操作不再相邻,网络难以捕捉局部信息。而卷积层的设计,天然地具有提取局部信息的能力。

    2、二是卷积层的参数量更少。不考虑偏置的情况下,一个形状为(ci,co,h,w)的卷积核的参数量是ci×co×h×w,与输入图像的宽高无关。假如一个卷积层的输入和输出形状分别是(c1,h1,w1)和(c2,h2,w2),如果要用全连接层进行连接,参数数量就是c1×c2×h1×w1×h2×w2。使用卷积层可以以较少的参数数量来处理更大的图像。

    X = torch.rand(4, 2, 3, 5)
    print(X.shape)
    
    conv2d = nn.Conv2d(in_channels=2, out_channels=3, kernel_size=(3, 5), stride=1, padding=(1, 2))
    Y = conv2d(X)
    

    池化

    池化层主要用于缓解卷积层对位置的过度敏感性。同卷积层一样,池化层每次对输入数据的一个固定形状窗口(又称池化窗口)中的元素计算输出,池化层直接计算池化窗口内元素的最大值或者平均值,该运算也分别叫做最大池化或平均池化。

    X = torch.arange(32, dtype=torch.float32).view(1, 2, 4, 4)
    pool2d = nn.MaxPool2d(kernel_size=3, padding=1, stride=(2, 1))
    Y = pool2d(X)
    

    LeNet

    使用全连接层的局限性:

    • 图像在同一列邻近的像素在这个向量中可能相距较远。它们构成的模式可能难以被模型识别。
    • 对于大尺寸的输入图像,使用全连接层容易导致模型过大。

    使用卷积层的优势:

    • 卷积层保留输入形状。
    • 卷积层通过滑动窗口将同一卷积核与不同位置的输入重复计算,从而避免参数尺寸过大。
      在这里插入图片描述

    卷积层块里的基本单位是卷积层后接平均池化层:卷积层用来识别图像里的空间模式,如线条和物体局部,之后的平均池化层则用来降低卷积层对位置的敏感性。

    激活函数:Sigmoid

    Modern CNN

    深度卷积神经网络(AlexNet)

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

    LeNet: 在大的真实数据集上的表现并不尽如⼈意。
    1.神经网络计算复杂。
    2.还没有⼤量深⼊研究参数初始化和⾮凸优化算法等诸多领域。

    特点:

    1. 8层变换,其中有5层卷积和2层全连接隐藏层,以及1个全连接输出层。
    2. 将sigmoid激活函数改成了更加简单的ReLU激活函数。
    3. 用Dropout来控制全连接层的模型复杂度。
    4. 引入数据增强,如翻转、裁剪和颜色变化,从而进一步扩大数据集来缓解过拟合。
      在这里插入图片描述

    使用重复基础块的网络(VGG)

    在这里插入图片描述

    网络中的网络(NiN)

    LeNet、AlexNet和VGG:先以由卷积层构成的模块充分抽取 空间特征,再以由全连接层构成的模块来输出分类结果。

    NiN:串联多个由卷积层和“全连接”层构成的小⽹络来构建⼀个深层⽹络。

    “全连接”:由1x1卷积核等效的全连接层,保证输入和输出维度相等。
    在这里插入图片描述

    1×1卷积核作用
    1.放缩通道数:通过控制卷积核的数量达到通道数的放缩。
    2.增加非线性。1×1卷积核的卷积过程相当于全连接层的计算过程,并且还加入了非线性激活函数,从而可以增加网络的非线性。
    3.计算参数少

    def nin_block(in_channels, out_channels, kernel_size, stride, padding):
        blk = nn.Sequential(nn.Conv2d(in_channels, out_channels, kernel_size, stride, padding),
                            nn.ReLU(),
                            nn.Conv2d(out_channels, out_channels, kernel_size=1),
                            nn.ReLU(),
                            nn.Conv2d(out_channels, out_channels, kernel_size=1),
                            nn.ReLU())
        return blk
    

    GoogLeNet

    在这里插入图片描述

    1. 由Inception基础块组成。

    2. Inception块相当于⼀个有4条线路的⼦⽹络。它通过不同窗口形状的卷积层和最⼤池化层来并⾏抽取信息,并使⽤1×1卷积层减少通道数从而降低模型复杂度。

    3. 可以⾃定义的超参数是每个层的输出通道数,我们以此来控制模型复杂度

      class Inception(nn.Module):
          # c1 - c4为每条线路里的层的输出通道数
          def __init__(self, in_c, c1, c2, c3, c4):
              super(Inception, self).__init__()
              # 线路1,单1 x 1卷积层
              self.p1_1 = nn.Conv2d(in_c, c1, kernel_size=1)
              # 线路2,1 x 1卷积层后接3 x 3卷积层
              self.p2_1 = nn.Conv2d(in_c, c2[0], kernel_size=1)
              self.p2_2 = nn.Conv2d(c2[0], c2[1], kernel_size=3, padding=1)
              # 线路3,1 x 1卷积层后接5 x 5卷积层
              self.p3_1 = nn.Conv2d(in_c, c3[0], kernel_size=1)
              self.p3_2 = nn.Conv2d(c3[0], c3[1], kernel_size=5, padding=2)
              # 线路4,3 x 3最大池化层后接1 x 1卷积层
              self.p4_1 = nn.MaxPool2d(kernel_size=3, stride=1, padding=1)
              self.p4_2 = nn.Conv2d(in_c, c4, kernel_size=1)
      
          def forward(self, x):
              p1 = F.relu(self.p1_1(x))
              p2 = F.relu(self.p2_2(F.relu(self.p2_1(x))))
              p3 = F.relu(self.p3_2(F.relu(self.p3_1(x))))
              p4 = F.relu(self.p4_2(self.p4_1(x)))
              return torch.cat((p1, p2, p3, p4), dim=1)  # 在通道维上连结输出
      

      完整模型

      p3 = F.relu(self.p3_2(F.relu(self.p3_1(x))))
      p4 = F.relu(self.p4_2(self.p4_1(x)))
      return torch.cat((p1, p2, p3, p4), dim=1) # 在通道维上连结输出

      
      **完整模型**
      

    在这里插入图片描述

    展开全文
  • 卷积神经网络基础 本节我们介绍卷积神经网络的基础概念,主要是卷积层和池化层,并解释填充、步幅、输入通道和输出通道的含义。 二卷积层 本节介绍的是最常见的二卷积层,常用于处理图像数据。 二互相关运算 ...
  • Pytorch搭建卷积神经网络基础 ,卷积层构建 1,1D卷积层构建 torch.nn.Conv1d(in_channels, out_channels, kernel_size, stride:= 1, padding= 0, dilation= 1, groups1, bias= True, padding_mode = 'zeros') ...

    Pytorch搭建卷积神经网络基础

    感谢pytorch详解nn.Module类,children和modules方法区别

    一,卷积层构建

    1,1D卷积层构建

    torch.nn.Conv1d(in_channels, out_channels, kernel_size, stride:= 1, padding= 0, dilation= 1, groups1, bias= True, padding_mode = 'zeros')

    对输入信号上应用一维卷积 。输入信号尺寸(N, C_{\text{in}}, L),卷积后的输出信号尺寸(N, C_{\text{out}}, L_{\text{out}})。N 是batch size, C表示通道数,L信号的序列长度。

    卷积运算过程:

    \text{out}(N_i, C_{\text{out}_j}) = \text{bias}(C_{\text{out}_j}) + \sum_{k = 0}^{C_{in} - 1} \text{weight}(C_{\text{out}_j}, k) \star \text{input}(N_i, k)

    group:设置卷积的分组

    group=1:所有的输入信号卷积为输出

    group=2:等效于两个并排的卷积层,每一个看到一半的输入通道,产生一半的输出通道。最后 concatenated.

    groups= in_channels:每一个输入通道都和一个滤波器卷积,滤波器的尺寸为\left\lfloor\frac{out\_channels}{in\_channels}\right\rfloor

    一维卷积需要合适的padding来保证所有的输入 

    如果groups=in_channels,一维卷积是depthwise convolution,输出通道一定是输入通道的K倍。如果输入信号尺寸为(N, C_{in}, L_{in}),depthwise 乘法器K的深度卷积的输出信号尺寸为(C_\text{in}=C_{in}, C_\text{out}=C_{in} \times K, ..., \text{groups}=C_{in})

    输入信号:(N, C_{in}, L_{in})

    输出信号:(N, C_{out}, L_{out})

    ID卷积运算:

    L_{out} = \left\lfloor\frac{L_{in} + 2 \times \text{padding} - \text{dilation} \times (\text{kernel\_size} - 1) - 1}{\text{stride}} + 1\right\rfloor

    2,2D卷积层构建

    class torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True)

    参数:

    • in_channels(int) – 输入信号的通道
    • out_channels(int) – 卷积产生的通道
    • kerner_size(int or tuple) - 卷积核的尺寸
    • stride(int or tupleoptional) - 卷积步长,卷积核在图像窗口上每次平移的间隔

    padding(int or tupleoptional) - 输入的每一条边补充0的层数,填充包括图像的上下左右,以padding = 1为例,若原始图像大小为32x32,那么padding后的图像大小就变成了34x34,而不是33x33。

    • dilation(int or tupleoptional) – 卷积核元素之间的间距
    • groups(intoptional) – 从输入通道到输出通道的阻塞连接数
    • bias(booloptional) - 如果bias=True,添加偏置

     参数kernel_sizestride,paddingdilation也可以是一个int的数据,此时卷积height和width值相同;也可以是一个tuple数组,tuple的第一维度表示height的数值,tuple的第二维度表示width的数值

    (eg:kernel_size=3,卷积核为3×3;kernel_size=(3,5),卷积核为3×5.

    对图像卷积,N一次输入的Batch数

    3,Conv3d

    torch.nn.Conv3d(in_channels: int, out_channels: int, kernel_size: Union[T, Tuple[T, T, T]], stride: Union[T, Tuple[T, T, T]] = 1, padding: Union[T, Tuple[T, T, T]] = 0, dilation: Union[T, Tuple[T, T, T]] = 1, groups: int = 1, bias: bool = True, padding_mode: str = 'zeros')

    3D卷积层的输入尺寸(N, C_{in}, D, H, W),输出尺寸 (N, C_{out}, D_{out}, H_{out}, W_{out})

    out(N_i, C_{out_j}) = bias(C_{out_j}) + \sum_{k = 0}^{C_{in} - 1} weight(C_{out_j}, k) \star input(N_i, k)

    \star3D互相关运算

    Input: (N, C_{in}, D_{in}, H_{in}, W_{in})

    Output:(N, C_{out}, D_{out}, H_{out}, W_{out})

    D_{out} = \left\lfloor\frac{D_{in} + 2 \times \text{padding}[0] - \text{dilation}[0] \times (\text{kernel\_size}[0] - 1) - 1}{\text{stride}[0]} + 1\right\rfloor

    H_{out} = \left\lfloor\frac{H_{in} + 2 \times \text{padding}[1] - \text{dilation}[1] \times (\text{kernel\_size}[1] - 1) - 1}{\text{stride}[1]} + 1\right\rfloor

    W_{out} = \left\lfloor\frac{W_{in} + 2 \times \text{padding}[2] - \text{dilation}[2] \times (\text{kernel\_size}[2] - 1) - 1}{\text{stride}[2]} + 1\right\rfloor

    二,定义神经网络 

    1,搭建基础自定义模型

    Pytyotch中继承nn.Module类实现自定义模型类有两种方式:

    1)高层API方法:使用torch.nn.****来实现;,这些接口都是类,类可以存储参数,比如全连接层的权值矩阵、偏置矩阵等都可以作为类的属性存储着,当对这些接口类创建对象后再作为自定义模型类的属性,就实现了存储参数

    2)低层API方法:使用低层函数方法,torch.nn.functional.****来实现;,从名称就看出是一些函数接口,实现函数的运算功能,没办法保存这些信息,若是用它创建有学习参数的层,需要自己再实现保存参数的部分。

    在自定义模型时必须重新实现构造函数__init__构造函数和forward这两个方法。

    • 一般把网络中具有可学习参数的层(如全连接层、卷积层等)放在构造函数__init__()方法中,当然也可以把不具有参数的层也放在__init__方法里面;
    • 不具有可学习参数的层(如ReLU、dropout、BatchNormanation层)可放在构造函数__init__中,也可不放在构造函数__init__中,如果不放在构造函数__init__里面,则在forward方法里面可以使用nn.functional来代替, 因为搭建时将没有训练参数的层 没有放在构造函数里面了(当然就没有这些属性了),所以这些层就不会出现在model里面(打印或可视化model)
    • forward方法是必须要重写的,它是实现模型的功能,实现各个层之间的连接关系的核心。
    class Net1(torch.nn.Module):
        def __init__(self):
            # 必须调用父类的构造函数,因为想要使用父类的方法,这也是继承Module的目的
            super(Net, self).__init__()
            self.conv1 = torch.nn.Conv2d(3, 32, 3, 1, 1)
            self.relu1 = torch.nn.ReLU()
            self.max_pooling1 = torch.nn.MaxPool2d(2, 1)
            self.conv2 = torch.nn.Conv2d(3, 32, 3, 1, 1)
            self.relu2 = torch.nn.ReLU()
            self.max_pooling2 = torch.nn.MaxPool2d(2, 1)
            self.dense1 = torch.nn.Linear(32 * 3 * 3, 128)
            self.dense2 = torch.nn.Linear(128, 10)
    
        def forward(self, x):
            x = self.conv1(x)
            x = self.relu1(x)
            x = self.max_pooling1(x)
            x = self.conv2(x)
            x = self.relu2(x)
            x = self.max_pooling2(x)
            x = self.dense1(x)
            x = self.dense2(x)
            return x
    

     2,利用torch.nn.Sequential()容器

    利用torch.nn.Sequential()容器,模型的各层被顺序添加到容器中。

    class Net2(torch.nn.Module):
        def __init__(self):
            super(Net2, self).__init__()
            self.conv = torch.nn.Sequential(
                torch.nn.Conv2d(3, 32, 3, 1, 1),
                torch.nn.ReLU(),
                torch.nn.MaxPool2d(2))
            self.dense = torch.nn.Sequential(
                torch.nn.Linear(32 * 3 * 3, 128),
                torch.nn.ReLU(),
                torch.nn.Linear(128, 10)
            )
    
        def forward(self, x):
            conv_out = self.conv1(x)
            res = conv_out.view(conv_out.size(0), -1)
            out = self.dense(res)
            return out
    
    
    print("Method 2:")
    model2 = Net2()
    print(model2)
    print(model2.conv[2])  # 先获取属性,再下标索引,
    '''
    Net2(
      (conv): Sequential(
        (0): Conv2d(3, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
        (1): ReLU()
        (2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
      )
      (dense): Sequential(
        (0): Linear(in_features=288, out_features=128, bias=True)
        (1): ReLU()
        (2): Linear(in_features=128, out_features=10, bias=True)
      )
    )
    可看出模型有两个属性分别是conv和dense, 且他们都是Sequential类型
    

    3,参考Module.children() vs Module.modules()

    • children()返回的是最外层的元素
    • modules方法将整个模型的所有构成(包括包装层Sequential、单独的层、自定义层等)由浅入深依次遍历出来,直到最深处的单层
    class Net3(torch.nn.Module):
        def __init__(self):
            super(Net3, self).__init__()
            self.conv = torch.nn.Sequential(
                OrderedDict(
                    [
                        ("conv1", torch.nn.Conv2d(3, 32, 3, 1, 1)),
                        ("relu1", torch.nn.ReLU()),
                        ("pool1", torch.nn.MaxPool2d(2))
                    ]
                ))
    
            self.dense = torch.nn.Sequential(
                OrderedDict([
                    ("dense1", torch.nn.Linear(32 * 3 * 3, 128)),
                    ("relu2", torch.nn.ReLU()),
                    ("dense2", torch.nn.Linear(128, 10))
                ])
            )
    
        def forward(self, x):
            conv_out = self.conv1(x)
            res = conv_out.view(conv_out.size(0), -1)
            out = self.dense(res)
            return out
    
    
    print("Method :")
    model = Net3()
    Net3(
      (conv): Sequential(
        (conv1): Conv2d(3, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
        (relu1): ReLU()
        (pool1): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
      )
      (dense): Sequential(
        (dense1): Linear(in_features=288, out_features=128, bias=True)
        (relu2): ReLU()
        (dense2): Linear(in_features=128, out_features=10, bias=True)
      )
    )
    ==============================
    
    
    
    
    # children()方法其实就是获取模型的属性,可看到构造函数有两个属性
    for i in model.children():
        print(i)
        print(type(i))
    print('==============================')
    # named_children()方法也是获取模型的属性,同时获取属性的名字
    for i in model.named_children():
        print(i)
        print(type(i))
    
    
    '''
    Sequential(
      (conv1): Conv2d(3, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
      (relu1): ReLU()
      (pool1): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    )
    <class 'torch.nn.modules.container.Sequential'>
    Sequential(
      (dense1): Linear(in_features=288, out_features=128, bias=True)
      (relu2): ReLU()
      (dense2): Linear(in_features=128, out_features=10, bias=True)
    )
    <class 'torch.nn.modules.container.Sequential'>
    
    ==============================-----------------------------------------------
    ('conv', Sequential(
      (conv1): Conv2d(3, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
      (relu1): ReLU()
      (pool1): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    ))
    <class 'tuple'>
    ('dense', Sequential(
      (dense1): Linear(in_features=288, out_features=128, bias=True)
      (relu2): ReLU()
      (dense2): Linear(in_features=128, out_features=10, bias=True)
    ))
    <class 'tuple'>
    '''
    
    
    
    for i in model.modules():
        print(i)
        print('==============================')
    print('=============华丽分割线=================')
    # named_modules()同上,但是返回的每一个元素是一个元组,第一个元素是名称,第二个元素才是层对象本身。
    for i in model.named_modules():
        print(i)
        print('==============================')
    '''
    离模型最近即最浅处,就是模型本身
    
    由浅入深,到模型的属性
    Sequential(
      (conv1): Conv2d(3, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
      (relu1): ReLU()
      (pool1): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    )
    ==============================
    由浅入深,再到模型的属性的内部
    Conv2d(3, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    ==============================
    由浅入深,再到模型的属性的内部,依次将这个属性遍历结束
    ReLU()
    ==============================
    MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    由浅入深,再到模型的属性的内部,依次将这个属性遍历结束,再遍历另个属性
    ==============================
    Sequential(
      (dense1): Linear(in_features=288, out_features=128, bias=True)
      (relu2): ReLU()
      (dense2): Linear(in_features=128, out_features=10, bias=True)
    )
    ==============================
    Linear(in_features=288, out_features=128, bias=True)
    ==============================
    ReLU()
    ==============================
    Linear(in_features=128, out_features=10, bias=True)
    ==============================
    =============华丽分割线=================------------------------------------
    ('', Net4(
      (conv): Sequential(
        (conv1): Conv2d(3, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
        (relu1): ReLU()
        (pool1): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
      )
      (dense): Sequential(
        (dense1): Linear(in_features=288, out_features=128, bias=True)
        (relu2): ReLU()
        (dense2): Linear(in_features=128, out_features=10, bias=True)
      )
    ))
    ==============================
    ('conv', Sequential(
      (conv1): Conv2d(3, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
      (relu1): ReLU()
      (pool1): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    ))
    ==============================
    ('conv.conv1', Conv2d(3, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)))
    ==============================
    ('conv.relu1', ReLU())
    ==============================
    ('conv.pool1', MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False))
    ==============================
    ('dense', Sequential(
      (dense1): Linear(in_features=288, out_features=128, bias=True)
      (relu2): ReLU()
      (dense2): Linear(in_features=128, out_features=10, bias=True)
    ))
    ==============================
    ('dense.dense1', Linear(in_features=288, out_features=128, bias=True))
    ==============================
    ('dense.relu2', ReLU())
    ==============================
    ('dense.dense2', Linear(in_features=128, out_features=10, bias=True))
    ==============================
    '''

     

     

    展开全文
  • pytorch卷积神经网络

    2021-03-19 16:19:25
    torch.nn.Conv2d() ...也可以是一个tuple数组,tuple的第一维表示height的数值,tuple的第二维表示width的数值。 Hout和Wout的计算H_{out} 和 W_{out} 的计算Hout​和Wout​的计算: 参数说明 in_channels

    本文是我在参阅了多方面的博客资源之后的笔记整理,相信我,不需要再寻找其他的资源,只需要认认真真,完完整整的看我这篇博客的内容以及提及的资源,理解torch.nn.Conv1d()和torch.nn.Conv2d()就完全足够。本博客的目的,就是节省你的学习时间,一篇就全!不懂的可以随时评论,帮助解答~

    1. 卷积层的理解

    卷积层是用一个固定大小的矩形区去席卷原始数据,将原始数据分层一个个和卷积核大小相同的小块,然后将这些小块和卷积核相乘之后再相加输出一个卷积值(注意,这里是一个单独的数值,不再是矩阵了)。

    卷积的本质就是使用卷积核的参数来提取原始数据的特征,通过矩阵的点乘运算,提取出和卷积核特征一致的值,如果卷积层有多个卷积核,就会提取多个特征,神经网络会自动学习卷积核的参数值,使得每个卷积核代表一个特征。
    【这里可以通过线性代数来理解,将每个卷积核看做是一组特征向量的基,然后通过线性变换,就可以得到在这组特征向量基下获取到的特征】

    2. torch.nn.Conv2d()

    官方文档文档
    中文文档

    • 输入格式
      在这里插入图片描述注意下面的说明:
      在这里插入图片描述
      即参数kernel_size, string, padding, dilation 也可以是一个int的数据,此时卷积height和weight的数值相同;也可以是一个tuple数组,tuple的第一维表示height的数值,tuple的第二维表示width的数值。

    • HoutWoutH_{out} 和 W_{out} 的计算
      在这里插入图片描述

    • 参数说明
      在这里插入图片描述

    in_channels (int):输入信号的通道数
    out_channels (int): 卷积产生的通道数
    kerner_size (int or tuple, 可选): 卷积核的尺寸 (注意看一下上面的说明)
    stride (int or tuple,可选): 卷积的步长
    padding (int or tuple,可选):输入的每一条边补充0的个数
    dilation (int or tuple,可选): 卷积核元素之间的间距
    groups (int,可选), 从输入通道到输出通道的阻塞连接数
    bias(bool,可选):如果bias=True,添加偏置,默认为True。

    默认情况:

    def __init__(self, in_channels, out_channels, kernel_size, stride=1,
                     padding=0, dilation=1, groups=1, bias=True):
    
    • 变量(可读取和调用)
      在这里插入图片描述
    • 示例:
      在这里插入图片描述![在这里插入图片描述](https://img-blog.csdnimg.cn/20210319230512910.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTA2MjY5Mzc=,size_16,color_FFFFFF,t_70#pic_center

    3. 特别说明

    3.1 pytroch 中nn.Conv2d的padding操作

    不同的深度学习框架中padding补0的策略是不同的。可以单独去查相关的使用说明比如看一下这里

    关于padding的理解:
    (1)保持边界信息,如果没有加padding的话,输入图片最边缘的像素点信息只会被卷积核操作一次,但是图像中间的像素点会被扫描很多遍,那么就会在一定程度上降低边界信息的参考程度,但是在加入padding之后,在实际处理过程中就会从新的边界(加入padding后的边界,这里也就说明了,padding操作是在卷积之前进行的)进行操作,就从一定程度上解决了这个问题。

    如下图所示,对6x6的原图像使用3x3的卷积核进行卷积操作后得到的图像是一个4x4的图像(6-3+1=4),也就是说每次进行卷积后,原始图像都会变小失真,所以没有办法设计层数足够多的深度神经网络,除此之外还有另一个重要的原因是,原始图像中的边缘像素永远都不会位于卷积核的中心,只有原始图像的4x4的像素会位于中心,这样会使得边缘像素对网络的影响小于位于中心点的像素的影响,不利于抽取特征。

    在这里插入图片描述所以,为了解决这个问题,一般会在原始图像的周围填充一圈像素,如下图所示,将原来的输入图像(率),四周各填充一圈0之后吧,就变成了底部的蓝色图,这个时候,原图像的边缘的位置就可以位于卷积核中心了。
    在这里插入图片描述
    另外还有一些其他的用途:
    (2)可以在利用padding对属兔尺寸有差异的图片进行不起,使得输入图片尺寸一致。
    (3)在卷积神经网络的卷积层加入padding,可以使得卷积层的输入维度和输出维度一致(这只是其中的一个用途,真正的作用还是(1));在卷积神经网络的池化层加入padding,一般就是保持边界信息。

    3.2 通道(channel)的理解

    一般的图像都是三通道,分别是R,G, B,所以卷积核也应该为三个通道,通过卷积核作用后生成的图像也会有三个,如图所示:
    在这里插入图片描述
    得到三个图像后,然后把这三个图像通过矩阵相加的计算,最后得到一个“合成”图像,如图所示:
    在这里插入图片描述
    最后,将这个图像与一个偏置项(bias)向加后就会得到一个最终的结果,偏置项不影响结果的矩阵形状,只是影响矩阵的值,如图,
    在这里插入图片描述
    进一步理解:
    如果对于一个三通道即:32x32x3的图像,使用一个:5x5x3的卷积核,最终会得到一个:28x28x1的特征图,如图:
    在这里插入图片描述
    如果使用两个:
    5x5x3的卷积核,最终会得到两个:28x28x1的特征图,即:28x28x2,如图:在这里插入图片描述
    如果使用六个:5x5x3的卷积核,最终会得到六个:28x28x1的特征图,即:28x28x6,如图:在这里插入图片描述
    请记住:
    卷积过程中,输入层有多少个通道,卷积核就有多少个通道,但是卷积核的数量是任意的,卷积核的数量决定了卷积后特征图的数量。

    4. torch.nn.Conv1d()

    其实我们平时最常用的就是二维卷积,所以要掌握好二维卷积的用法,一维卷积和三维卷积和二维卷积很相似,论说,应该从一维卷积开始介绍,但是由于二维卷积使用的最多,所以放在前面了;一般来说,一维卷积用于文本数据,二维卷积用于图像数据,三维卷积用于视频数据。
      一维卷积可以用于文本数据,只对宽度进行卷积,对高度不卷积。通常,输入大小为word_embedding_dim*max_length,其中word_embedding_dim为词向量的维度大小,max_length为最大句子长度。一维卷积核在句子长度的方向上活动,进行卷积操作。
      其参数和二维卷积torch.nn.Conv2d()参数是一样的,其默认形式如下:

    class torch.nn.Conv1d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True)

    • 官网介绍
      在这里插入图片描述

    • 值得注意的地方:
      在这里插入图片描述

    • 参数
      在这里插入图片描述在使用方面,和Conv2d()的最大不同之处在于in_channels、out_channels、kernel_size的大小。
      在这里插入图片描述

    • 示例
      在这里插入图片描述
      在这里插入图片描述在这里插入图片描述其实,一维的卷积可以看做是高度为1的二维卷积,举例说明一下:
      在这里插入图片描述

    进一步应用实例说明

    一维卷积 torch.nn.Conv1d()在文本上的应用

    class torch.nn.Conv1d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True)

    • in_channels:z在文本应用中,即为词向量的维度。
    • out_channels:卷积产生的通道数,有多少个out_channels, 就需要多少个一维卷积(也就是卷积核的数据量);
    • kernel_size:卷积核的尺寸;卷积核的第二个维度由in_channels决定,所以实际上卷积核的大小为kernel_size*in_channels
    • padding:对输入的每一条边,补充0的层数。

    任务:
    输入:批大小为32,句子最大长度为35,词向量的维度为256;
    目标:句子分类,共2类。

    #基于卷积的文本分类实例
    import torch
    import torch.nn as nn
    import torch.nn.functional as F
    
    #这句coding定义了多个窗口的卷积
    convs=nn.ModuleList([nn.Sequential(nn.Conv1d(in_channels=5,out_channels=100,kernel_size=h),
                                       nn.ReLU(),
                                       nn.MaxPool1d(kernel_size=35-h+1))
                                       for h in [2,3,4]])
    #conv1=nn.Conv1d(in_channels=256,out_channels=100,kernel_size=(2,3,4))
    fc=nn.Linear(in_features=100*3,out_features=2)
    input=torch.randn(32,35,256)
    print(input.shape)
    input=input.permute(0,2,1)
    print(input.shape)
    output=[conv(input) for conv in convs]
    print(output[0].shape)
    print([out.shape for out in output])
    output=torch.cat(output,dim=1)
    print(output.shape)
    output=output.view(-1,output.size(1))
    out=F.dropout(input=output,p=0.3)
    out=fc(out)
    print(out.shape)
    

    假设window_size = [2,3, 4],即共有四个卷积核,基于上述代码,具体计算过程如下:

    1. 原始输入大小为(32, 35, 256),经过permute(0, 2, 1)操作后,输入的大小变为(32, 256, 35);
    2. 使用1个卷积核进行卷积,可得到1个大小为32 x 100 x 1的输出,共4个卷积核,故共有4个大小为32 x 100 x 1的输出;
    3. 将上一步得到的4个结果在dim = 1上进行拼接,输出大小为32 x 300 x 1;
    4. view操作后,输出大小变为32 x 300;
    5. 全连接,最终输出大小为32 x 2,即分别预测为2类的概率大小。

    一维卷积的图解过程

    Yoon Kim在2014年发表的论文Convolutional Neural Networks for Sentence Classification中,给出了一个非常形象的图,诠释了文本卷积模型的框架,如下所示。

    在这里插入图片描述

    二维卷积torch.nn.Conv2d()在图像上的应用。

    class torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True)

    任务:
    假设现有大小为32 x 32的图片样本,输入样本的channels为1,该图片可能属于10个类中的某一类。
    我们假设整体的网络结构为:[conv + relu +pooling]2 +FC3
    原始输入样本的大小为:[1,1,32,32]:batch数为1,通道数为1,高度为32,宽度为32
    代码如下:

    #基于卷积的图片分类,这次以类函数的方式给出,比较符合平时的实验设计
    import torch
    import torch.nn as nn
    import torch.nn.functional as F
    
    class CNN(nn.Module):
        def __init__(self):
            nn.Module.__init__(self)
            self.conv1=nn.Conv2d(1,6,5)#第一个卷积层
            self.conv2=nn.Conv2d(6,16,5)#第二个卷积层
            self.fc1=nn.Linear(5*5*16,120)
            self.fc2=nn.Linear(120,84)
            self.fc3=nn.Linear(84,10)
            
        def forward(self,x):
            #输入x -> conv1 -> relu ->2*2 窗口的最大池化
            x=self.conv1(x)
            x=F.relu(x)
            x=F.max_pool2d(x,2)
            
            #输入x ->conv2 ->relu ->2*2窗口的最大池化
            x=self.conv2(x)
            x=F.relu(x)
            x=F.max_pool2d(x,2)
            x=x.view(x.size()[0],-1)
            x=F.relu(self.fc1(x))
            x=F.relu(self.fc2(x))
            x=self.fc3(x)
            return x
        
    x=torch.randn(1,1,32,32)
    model=CNN()
    y=model(x)
    print(y.shape)
    
    

    二维卷积的图解过程

    在这里插入图片描述
    #注意

    • 在pytorch 中,池化操作默认的stride大小与卷积核的大小一致;
    • 如果池化核的大小为一个方阵,则仅需要指明一个数,即,kenel_size参数为常数n,表示池化核大小为n*n。
    展开全文
  • 卷积神经网络:CNN 先说个小知识,助于理解代码中各个层之间维度是怎么变换的。 卷积函数:一般只用来改变输入数据的维度,例如3到16。 Conv2d() Conv2d(in_channels:int,out_channels:int,kernel_size:...

    卷积神经网络:CNN

    先说一个小知识,助于理解代码中各个层之间维度是怎么变换的。

    卷积函数:一般只用来改变输入数据的维度,例如3维到16维。

    Conv2d()

    Conv2d(in_channels:int,out_channels:int,kernel_size:Union[int,tuple],stride=1,padding=o):   
    """   
    :param in_channels: 输入的维度    
    :param out_channels: 通过卷积核之后,要输出的维度    
    :param kernel_size: 卷积核大小    
    :param stride: 移动步长    
    :param padding: 四周添多少个零  
    """

    一个小例子:

    import torch
    import torch.nn
    # 定义一个16张照片,每个照片3个通道,大小是28*28
    x= torch.randn(16,3,32,32)
    # 改变照片的维度,从3维升到16维,卷积核大小是5
    conv= torch.nn.Conv2d(3,16,kernel_size=5,stride=1,padding=0)
    res=conv(x)
    
    print(res.shape)
    # torch.Size([16, 16, 28, 28])
    # 维度升到16维,因为卷积核大小是5,步长是1,所以照片的大小缩小了,变成28

    卷积神经网络实战之Lenet5:

    下面放一个示例图,代码中的过程就是根据示例图进行的

    • 1.经过一个卷积层,从刚开始的[b,3,32,32]-->[b,6,28,28]
    • 2.经过一个池化层,从[b,6,28,28]-->[b,6,14,14]
    • 3.再经过一个卷积层,从[b,6,14,14]-->[b,16,10,10]
    • 4.再经过一个池化层,从[b,16,10,10]-->[b,16,5,5]
    • 5.经过三个个全连接层,将数据[b,16,5,5]-->[b,120]-->[b,84]-->[b,10]

    定义一个名为lenet5.py的文件,代码如下

    import torch
    from torch import nn
    import torch.optim
    import torch.nn
    from torch.nn import functional as F
    
    
    class Lenet5(nn.Module):
        # for cifar10 dataset.
        def __init__(self):
            super(Lenet5, self).__init__()
    
            # 卷积层 Convolutional
            self.conv_unit = nn.Sequential(
                # x:[b,3,32,32]==>[b,6,28,28]
                nn.Conv2d(3, 6, kernel_size=5, stride=1, padding=0),
                # x:[b,6,28,28]==>[b,6,14,14]
                nn.MaxPool2d(kernel_size=2, stride=2, padding=0),
                #[b,6,14,14]==>[b,16,10,10]
                nn.Conv2d(6,16,kernel_size=5,stride=1,padding=0),
                # x:[b,16,10,10]==>[b,16,5,5]
                nn.MaxPool2d(kernel_size=2,stride=2,padding=0),
    
            )
    
            # 全连接层fully connected
            self.fc_unit=nn.Sequential(
                nn.Linear(16*5*5,120),
                nn.ReLU(),
                nn.Linear(120,84),
                nn.ReLU(),
                nn.Linear(84,10)
            )
    
        def forward(self,x):
            """
            :param x:[b,3,32,32]
            :return:
            """
            batchsz=x.size(0)
            # 卷积层池化层运算 [b,3,32,32]==>[b,16,5,5]
            x=self.conv_unit(x)
    
            # 对数据进行打平,方便后边全连接层进行运算[b,16,5,5]==>[b,16*5*5]
            x=x.view(batchsz,16*5*5)
    
            # 全连接层[b,16*5*5]==>[b,10]
            logits=self.fc_unit(x)
    
            return logits
            # loss=self.criteon(logits,y)
    
    
    def main():
        net=Lenet5()
        # [b,3,32,32]
        temp = torch.randn(2, 3, 32, 32)
        out = net(temp)
        # [b,16,5,5]
        print("lenet_out:", out.shape)
    
    if __name__ == '__main__':
        main()

    定义一个名为main.py的文件,代码如下

    import torch
    from torchvision import datasets
    from torchvision import transforms
    from torch.utils.data import DataLoader
    from torch import nn,optim
    from visdom import Visdom
    from lenet5 import  Lenet5
    
    def main():
        batch_siz=32
        cifar_train = datasets.CIFAR10('cifar',True,transform=transforms.Compose([
            transforms.Resize((32,32)),
            transforms.ToTensor(),
            transforms.Normalize(mean=[0.485, 0.456, 0.406],
                                 std=[0.229, 0.224, 0.225])
        ]),download=True)
        cifar_train=DataLoader(cifar_train,batch_size=batch_siz,shuffle=True)
    
        cifar_test = datasets.CIFAR10('cifar',False,transform=transforms.Compose([
            transforms.Resize((32,32)),
            transforms.ToTensor(),
            transforms.Normalize(mean=[0.485, 0.456, 0.406],
                                 std=[0.229, 0.224, 0.225])
        ]),download=True)
        cifar_test=DataLoader(cifar_test,batch_size=batch_siz,shuffle=True)
    
        x,label = iter(cifar_train).next()
        print('x:',x.shape,'label:',label.shape)
    
        # 指定运行到cpu //GPU
        device=torch.device('cpu')
        model = Lenet5().to(device)
    
        # 调用损失函数use Cross Entropy loss交叉熵
        # 分类问题使用CrossEntropyLoss比MSELoss更合适
        criteon = nn.CrossEntropyLoss().to(device)
        # 定义一个优化器
        optimizer=optim.Adam(model.parameters(),lr=1e-3)
        print(model)
    
        viz=Visdom()
        viz.line([0.],[0.],win="loss",opts=dict(title='Lenet5 Loss'))
        viz.line([0.],[0.],win="acc",opts=dict(title='Lenet5 Acc'))
    
        # 训练train
        for epoch in range(1000):
            # 变成train模式
            model.train()
            # barchidx:下标,x:[b,3,32,32],label:[b]
            for barchidx,(x,label) in enumerate(cifar_train):
                # 将x,label放在gpu上
                x,label=x.to(device),label.to(device)
                # logits:[b,10]
                # label:[b]
                logits = model(x)
                loss = criteon(logits,label)
    
                # viz.line([loss.item()],[barchidx],win='loss',update='append')
                # backprop
                optimizer.zero_grad()
                loss.backward()
                optimizer.step()
            viz.line([loss.item()],[epoch],win='loss',update='append')
            print(epoch,'loss:',loss.item())
    
    
            # 变成测试模式
            model.eval()
            with torch.no_grad():
                #  测试test
                # 正确的数目
                total_correct=0
                total_num=0
                for x,label in cifar_test:
                    # 将x,label放在gpu上
                    x,label=x.to(device),label.to(device)
                    # [b,10]
                    logits=model(x)
                    # [b]
                    pred=logits.argmax(dim=1)
                    # [b] = [b'] 统计相等个数
                    total_correct+=pred.eq(label).float().sum().item()
                    total_num+=x.size(0)
                acc=total_correct/total_num
                print(epoch,'acc:',acc)
    
                viz.line([acc],[epoch],win='acc',update='append')
                # viz.images(x.view(-1, 3, 32, 32), win='x')
    
    
    if __name__ == '__main__':
        main()

    测试结果

    准确率刚开始是有一定的上升的,最高可达64%,后来准确率就慢慢的下降。

    展开全文
  • Task5卷积神经网络卷积层卷积层应用二互相关运算互相关运算与卷积运算特征图与感受野填充和步幅LeNet 卷积神经网络 本节我们介绍卷积神经网络的基础概念,主要是卷积层和池化层,并解释填充、步幅、输入通道和...
  • 卷积神经网络基础 二卷积层 介绍的是最常见的二卷积层,常用于处理图像数据。 二互相关运算 二互相关(cross-correlation)运算的输入是个二输入数组和个二维核(kernel)数组,输出也是个二数组...
  • PyTorch入门总结51 卷积1.1 一维卷积 1 卷积 1.1 一维卷积
  • 卷积神经网络基础 本节我们介绍卷积神经网络的基础概念,主要是卷积层和池化层,并解释填充、步幅、输入通道和输出通道的含义。 二卷积层 本节介绍的是最常见的二卷积层,常用于处理图像数据。 二互相关运算 ...
  • 卷积神经网络基础 卷积神经网络包括卷积层和池化层。 二卷积层 最常见的是二卷积层,常用于处理图像数据。 二互相关运算 二互相关(cross-correlation)运算的输入是个二输入数组和个二维核(kernel)...
  • 卷积函数:一般只用来改变输入数据的维度,例如3到16。 Conv2d() Conv2d(in_channels:int,out_channels:int,kernel_size:Union[int,tuple],stride=1,padding=o): """ :param in_channels: 输入的...
  • 1 卷积神经网络基础 1.1 二维卷积 本小节介绍了二维卷积,主要用于图像数据(刚好是二维的数据)处理。 二维卷积通过输入二维数据和二维核数据的运算(卷积),得到个小于输入数据的二维输出数据,但是该输出数据...
  • 卷积函数:一般只用来改变输入数据的维度,例如3到16。 Conv2d() Conv2d(in_channels:int,out_channels:int,kernel_size:Union[int,tuple],stride=1,padding=o): """ :param in_channels: 输入的...
  • :手写二维卷积的实现 要求: 手写二维卷积的实现,并从至少个数据集上进行实验,这里我选取了车辆分类数据集(后面的实验都是用的车辆分类数据集),主要根据数据集的大小,手动定义二维卷积操作,如:自定义单...
  • 卷积神经网络(CNN)是类特殊的神经网络,它可以包含多个卷积层。 多个输入和输出通道使模型在每个空间位置可以获取图像的多方面特征。 5.1 二卷积层 5.1.1 二互相关运算 输出大小等于输入
  • 在学习完卷积神经网络后,我们用CNN来处理下mnist手写字数据集,以此来学习CNN的搭建方法。 1.知识回顾 1.1 mnist手写字数据集 手写字数据集mnist的每个样本是个28×28的矩阵,每个点表示该点的灰度值。在用全连接...
  • 上两节博客,分别学习了卷积神经网络的基础知识和处理手写字数据集,具体的可以看前边两篇博客: CNN基础知识 CNN处理mnist数据集 mnist只是单一高度(channel)的数据集,使用卷积处理时的卷积核是二平面形状,而...
  • 感受野:在卷积神经网络中,决定某层输出结果中一个元素所对应的输入层的区域大小,即特征映射上的个元素所对应的输入图的区域大小。 转置卷积 作用:将特征图放大恢复到原来的尺寸 转置卷积是卷积的方向过程,...
  • 本章中介绍的卷积神经网络均使用最常见的二卷积层。它有高和宽两个空间维度,常用来处理图像数据。 二互相关(cross-correlation)运算的输入是个二输入数组和个二维核(kernel)数组,输出也是个二...
  • '''二卷积层''' '''该函数计算二互相关运算''' def corr2d(X,K): h,w=K.shape #首先构造出运算过后的矩阵形状并用0填充 Y=torch.zeros((X.shape[0]-h+1,X.shape[1]-w+1)) for i in range(Y.shap...
  • 也有类似的概念,他们还使用一维卷积神经网络提取基于频谱图。 其他GPU音频处理工具是和 。 但是他们没有使用神经网络方法,因此不能训练傅立叶基础。 作为PyTorch 1.6.0,torchaudio仍然很难在Windows环境下,...
  • 一定会出现在不同的像素位置,因此导致同个边缘的输出会在总的卷积输出Y 的不同同位置,造成模式识别的不便 而池化层的提出是为了缓解卷积层对位置的过度敏感性 ''' #%% '''二最大池化函数和平均池化层''' ...

空空如也

空空如也

1 2 3 4 5
收藏数 97
精华内容 38
关键字:

pytorch一维卷积神经网络