精华内容
下载资源
问答
  • 所谓的一维卷积,也就是卷积核是一维的。原理和2D Conv类似,只不过1D Conv的卷积核移动方向只有一个。 而且每组卷积核个数也等于输入人间的通道数。 实际操作中,以点云文件为例:包含nx3的数据,进行卷积前...
    • 所谓的一维卷积,也就是卷积核是一维的。原理和2D Conv类似,只不过1D Conv的卷积核移动方向只有一个,从滑动窗口的直观角度来看,多通道一维卷积核在数据长度方向上滑动

    • 而且每卷积核个数也等于输入数据的通道数。

    • 设定多少的输出通道,就会有多少卷积核

    • 实际操作中,以点云文件为例:包含nx3的数据,进行卷积前首先要交换样本个数与通道。

    • ##代码备份##

    import torch
    import torch.nn as nn
    from numpy import *
    
    
    # Args:
    #         in_channels (int): Number of channels in the input image  {输入通道数}
    #         out_channels (int): Number of channels produced by the convolution  {输出通道}
    #         kernel_size (int or tuple): Size of the convolving kernel
    #         stride (int or tuple, optional): Stride of the convolution. Default: 1
    #         padding (int or tuple, optional): Zero-padding added to both sides of
    #             the input. Default: 0
    #         padding_mode (string, optional): ``'zeros'``, ``'reflect'``,
    #             ``'replicate'`` or ``'circular'``. Default: ``'zeros'``
    #         dilation (int or tuple, optional): Spacing between kernel
    #             elements. Default: 1
    #         groups (int, optional): Number of blocked connections from input
    #             channels to output channels. Default: 1
    #         bias (bool, optional): If ``True``, adds a learnable bias to the
    #             output. Default: ``True``
    #
    
    conv1 = nn.Conv1d(3, 2, 2, 1)  # in, out, k_size, stride
    
    a = torch.ones(1, 5, 3)  # b_size, n, 3  # 点云格式
    a = a.permute(0, 2, 1)
    # a = torch.ones(3)
    print('a:\n', a)
    
    b = conv1(a)
    print('b:\n', b)
    print(b.shape)  # b_size, ch, length
    
    
    
    展开全文
  • Pytorch中二维卷积nn.Conv2d的理解

    千次阅读 2019-09-07 16:40:13
    目录函数定义例子第卷积 函数定义 class torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True) 例子 以MNIST数据集手写数字识别为例,网络定义...

    函数定义

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

    例子

    以MNIST数据集手写数字识别为例,网络定义如下:

    class ConvNet(nn.Module):
        def __init__(self):
            super().__init__()
            # 1,28x28
            self.conv1=nn.Conv2d(1,10,5) # 10, 24x24
            self.conv2=nn.Conv2d(10,20,3) # 128, 10x10
            self.fc1 = nn.Linear(20*10*10,500)
            self.fc2 = nn.Linear(500,10)
        def forward(self,x):
            in_size = x.size(0)
            out = self.conv1(x) #24
            out = F.relu(out)
            out = F.max_pool2d(out, 2, 2)  #12
            out = self.conv2(out) #10
            out = F.relu(out)
            out = out.view(in_size,-1)
            out = self.fc1(out)
            out = F.relu(out)
            out = self.fc2(out)
            out = F.log_softmax(out,dim=1)
            return out
    

    网络的整体结构为:conv -> relu -> max_pool -> conv -> relu -> fc -> relu -> fc -> log_softmax
    原始输入样本的大小:28 x 28 x 1
    以上网络图解如下:

    第一次卷积

    使用10个大小为5 x 5的卷积核,故卷积核的规模为(5 x 5) x 10;卷积操作的stride参数默认值为1 x 1,28 - 5 + 1 = 24,并且使用ReLU对第一次卷积后的结果进行非线性处理,输出大小为24 x 24 x 10。

    池化

    kernel_size为2 x 2,stride为2(不指定的情况下,在PyTorch中,池化操作默认的stride大小与卷积核的大小一致,即为2)输出大小变为12 x 12 x 10。(12 = 14 / 2)

    第二次卷积

    使用20组规模为(3 x 3) x 10的卷积核;卷积操作的stride参数默认值为1 x 1,12 - 3 + 1 = 10,并且使用ReLU对第一次卷积后的结果进行非线性处理,输出大小为10 x 10 x 20。

    第一次全连接

    将上一步得到的结果铺平成一维向量形式,10 x 10 x 20 = 2000,即输入大小为2000 x 1,W大小为500 x 2000,输出大小为500 x 1。然后使用ReLu进行非线性处理。

    第二次全连接

    输入大小为500 x 1,W大小为10 x 500,输出大小为10x 1。然后使用log_softmax处理。

    展开全文
  • 公众号关注“Python遇见机器学习”设为“星标”,第时间知晓最新干货~作者丨史开杰来源丨GiantPandaCV本文重点介绍了Pytorch卷积的实现,并为实现过程中可能出现的问题给出解决方案。文末列出了相关代码,读者可...

    公众号关注 “Python遇见机器学习

    设为“星标”,第一时间知晓最新干货~

    b7b97bffe22ae5048c1382016051dde4.png作者丨史开杰来源丨 GiantPandaCV本文重点介绍了Pytorch中卷积的实现,并为实现过程中可能出现的问题给出解决方案。文末列出了相关代码,读者可对照代码进行实践。

    Dynamic Convolution: Attention over Convolution Kernels

    paper地址:arxiv.org/pdf/1912.0345代码实现地址:https://github.com/kaijieshi7/Dynamic-convolution-Pytorch

    其中包含一维,二维,三维的动态卷积;分别可以用于实现eeg的处理,正常图像的处理,医疗图像中三维脑部的处理等等。

    一句话描述下文的内容: 0a9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg 的大小视为分组卷积里面的组的大小进行动态卷积。如 0c9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg ,那么就转化成 0e9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 109d37fa-1f4e-eb11-8da9-e4434bdf6706.svg 的分组卷积。

    简单回顾

    这篇文章主要是改进传统卷积,让每层的卷积参数在推理的时候也是随着输入可变的,而不是传统卷积中对任何输入都是固定不变的参数。由于本文主要说明的是代码如何实现,所以推荐给大家一个讲解论文的链接:https://zhuanlan.zhihu.com/p/142381725
    e9c2481b6fa4cf478ff7bfd73a34ba12.png推理的时候:红色框住的参数是固定的,黄色框住的参数是随着输入的数据不断变化的。
    对于卷积过程中生成的一个特征图 129d37fa-1f4e-eb11-8da9-e4434bdf6706.svg ,先对特征图做几次运算,生成 149d37fa-1f4e-eb11-8da9-e4434bdf6706.svg 个和为 169d37fa-1f4e-eb11-8da9-e4434bdf6706.svg 的参数 189d37fa-1f4e-eb11-8da9-e4434bdf6706.svg ,然后对 149d37fa-1f4e-eb11-8da9-e4434bdf6706.svg 个卷积核参数进行线性求和,这样推理的时候卷积核是随着输入的变化而变化的。(可以看看其他的讲解文章,本文主要理解怎么写代码)下面是attention代码的简易版本,输出的是[ 0a9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 149d37fa-1f4e-eb11-8da9-e4434bdf6706.svg ]大小的加权参数。 149d37fa-1f4e-eb11-8da9-e4434bdf6706.svg 对应着要被求和的卷积核数量。
    class attention2d(nn.Module):def __init__(self, in_planes, K,):super(attention2d, self).__init__()self.avgpool = nn.AdaptiveAvgPool2d(1)self.fc1 = nn.Conv2d(in_planes, K, 1,)self.fc2 = nn.Conv2d(K, K, 1,)def forward(self, x):
    x = self.avgpool(x)
    x = self.fc1(x)
    x = F.relu(x)
    x = self.fc2(x).view(x.size(0), -1)return F.softmax(x, 1)
    下面是文章中 149d37fa-1f4e-eb11-8da9-e4434bdf6706.svg 个卷积核求和的公式。
    92fa132b8f8bd488355ac983bb04c431.png
    其中 129d37fa-1f4e-eb11-8da9-e4434bdf6706.svg 是输入, 299d37fa-1f4e-eb11-8da9-e4434bdf6706.svg 是输出;可以看到 129d37fa-1f4e-eb11-8da9-e4434bdf6706.svg 进行了两次运算,一次用于求注意力的参数(用于生成动态的卷积核),一次用于被卷积。但是,写代码的时候如果直接将 149d37fa-1f4e-eb11-8da9-e4434bdf6706.svg 个卷积核求和,会出现问题。接下来我们先回顾一下Pytorch里面的卷积参数,然后描述一下可能会出现的问题,再讲解如何通过分组卷积去解决问题。

    Pytorch卷积的实现

    我会从维度的视角回顾一下Pytorch里面的卷积的实现(大家也可以手写一下,几个重点:输入维度、输出维度、正常卷积核参数维度、分组卷积维度、动态卷积维度、attention模块输出维度)。输入:输入数据维度大小为[0a9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 2f9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 309d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 329d37fa-1f4e-eb11-8da9-e4434bdf6706.svg ]。输出:输出维度为[ 0a9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 359d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 309d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 329d37fa-1f4e-eb11-8da9-e4434bdf6706.svg ]。卷积核:正常卷积核参数维度为[ 359d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 2f9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 3c9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 3c9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg ]。(在Pytorch中,2d卷积核参数应该是固定这种维度的)这里我们可以注意到,正常卷积核参数的维度是不存在 0a9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg 的。因为对于正常的卷积来说,不同的输入数据,使用的是相同的卷积核,卷积核的数量与一次前向运算所输入的 0a9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg 大小无关(相同层的卷积核参数只需要一份)。

    可能会出现的问题

    这里描述一下实现动态卷积代码的过程中可能因为 0a9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg 大于1而出现的问题。对于图中attention模块最后softmax输出的 149d37fa-1f4e-eb11-8da9-e4434bdf6706.svg 个数,他们的维度为[ 0a9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 149d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 169d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 169d37fa-1f4e-eb11-8da9-e4434bdf6706.svg ],可以直接.view成[ 0a9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 149d37fa-1f4e-eb11-8da9-e4434bdf6706.svg ],紧接着 149d37fa-1f4e-eb11-8da9-e4434bdf6706.svg 作用于 149d37fa-1f4e-eb11-8da9-e4434bdf6706.svg 卷积核参数上(形成动态卷积)。问题所在:正常卷积,一次输入多个数据,他们的卷积核参数是一样的,所以只需要一份网络参数即可;但是对于动态卷积而言,每个输入数据用的都是不同的卷积核,所以需要 0a9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg 份网络参数,不符合Pytorch里面的卷积参数格式,会出错。看下维度运算[ 0a9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 149d37fa-1f4e-eb11-8da9-e4434bdf6706.svg ]*[ 149d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 359d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 2f9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 3c9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 3c9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg ],生成的动态卷积核是[ 0a9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 359d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 2f9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 3c9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 3c9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg ],不符合Pytorch里面的规定,不能直接参与运算(大家可以按照这个思路写个代码看看,体会一下,光看可能感觉不出来问题),最简单的解决办法就是 0a9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg 等于1,不会出现错误,但是慢啊!总之, 0a9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg 大于1会导致中间卷积核参数不符合规定。

    分组卷积以及

    如何通过分组卷积

    实现 0a9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg 大于1的动态卷积

    一句话描述分组卷积:对于多通道的输入,将他们分成几部分各自进行卷积,结果concate。组卷积过程用废话描述:对于输入的数据[ 0a9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 2f9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 309d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 329d37fa-1f4e-eb11-8da9-e4434bdf6706.svg ],假设 2f9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg 为 6d9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg ,那么分组卷积就是将他分为两个 2f9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg 为 6f9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg 的数据(也可以用其他方法分),那么维度就是[ 0a9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 5x2 , 309d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 329d37fa-1f4e-eb11-8da9-e4434bdf6706.svg ],换个维度换下视角,[ 759d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 6f9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 309d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 329d37fa-1f4e-eb11-8da9-e4434bdf6706.svg ],那么 7a9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg 为2的组卷积可以看成 759d37fa-1f4e-eb11-8da9-e4434bdf6706.svg 的正常卷积。(如果还是有点不了解分组卷积,可以阅读其他文章仔细了解一下。)巧妙的转换:上面将 0a9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg 翻倍即可将分组卷积转化成正常卷积,那么反向思考一下,将 0a9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg 变为1,是不是可以将正常卷积变成分组卷积?我们将 0a9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg 大小看成分组卷积中 7a9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg 的数量,令 0a9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg 所在维度直接变为 169d37fa-1f4e-eb11-8da9-e4434bdf6706.svg !!!直接将输入数据从[ 0a9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 919d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 309d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 329d37fa-1f4e-eb11-8da9-e4434bdf6706.svg ]变成[1, 9b9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 309d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 329d37fa-1f4e-eb11-8da9-e4434bdf6706.svg ],就可以用分组卷积解决问题了!!!详细描述实现过程:将输入数据的维度看成[1, 9b9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 309d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 329d37fa-1f4e-eb11-8da9-e4434bdf6706.svg ](分组卷积的节奏);卷积权重参数初始化为[ 149d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , a99d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 2f9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 3c9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 3c9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg ],attention模块生成的维度为[ 0a9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 149d37fa-1f4e-eb11-8da9-e4434bdf6706.svg ],直接进行正常的矩阵乘法[ 0a9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 149d37fa-1f4e-eb11-8da9-e4434bdf6706.svg ]*[ 149d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 359d37fa-1f4e-eb11-8da9-e4434bdf6706.svg *2f9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg * 3c9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg * 3c9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg ]生成动态卷积的参数,生成的动态卷积权重维度为[ 0a9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 359d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 2f9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 3c9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 3c9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg ],将其看成分组卷积的权重[ c89d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 2f9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 3c9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 3c9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg ](过程中包含reshape)。这样的处理就完成了,输入数据[ 169d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , d59d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 309d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 329d37fa-1f4e-eb11-8da9-e4434bdf6706.svg ],动态卷积核[ c89d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 2f9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 3c9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg , 3c9d37fa-1f4e-eb11-8da9-e4434bdf6706.svg ],直接是 e79d37fa-1f4e-eb11-8da9-e4434bdf6706.svg 的分组卷积,问题解决。具体代码如下:
    class Dynamic_conv2d(nn.Module):def __init__(self, in_planes, out_planes, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True, K=4,):super(Dynamic_conv2d, self).__init__()assert in_planes%groups==0self.in_planes = in_planesself.out_planes = out_planesself.kernel_size = kernel_sizeself.stride = strideself.padding = paddingself.dilation = dilationself.groups = groupsself.bias = biasself.K = Kself.attention = attention2d(in_planes, K, )self.weight = nn.Parameter(torch.Tensor(K, out_planes, in_planes//groups, kernel_size, kernel_size), requires_grad=True)if bias:self.bias = nn.Parameter(torch.Tensor(K, out_planes))else:self.bias = Nonedef forward(self, x):#将batch视作维度变量,进行组卷积,因为组卷积的权重是不同的,动态卷积的权重也是不同的
    softmax_attention = self.attention(x)
    batch_size, in_planes, height, width = x.size()
    x = x.view(1, -1, height, width)# 变化成一个维度进行组卷积
    weight = self.weight.view(self.K, -1)# 动态卷积的权重的生成, 生成的是batch_size个卷积参数(每个参数不同)
    aggregate_weight = torch.mm(softmax_attention, weight).view(-1, self.in_planes, self.kernel_size, self.kernel_size)if self.bias is not None:
    aggregate_bias = torch.mm(softmax_attention, self.bias).view(-1)
    output = F.conv2d(x, weight=aggregate_weight, bias=aggregate_bias, stride=self.stride, padding=self.padding,
    dilation=self.dilation, groups=self.groups*batch_size)else:
    output = F.conv2d(x, weight=aggregate_weight, bias=None, stride=self.stride, padding=self.padding,
    dilation=self.dilation, groups=self.groups * batch_size)
    output = output.view(batch_size, self.out_planes, output.size(-2), output.size(-1))return output
    完整的代码在github.com/kaijieshi7/D,大家觉得有帮助的话,求点个星星。纸上得来终觉浅,绝知此事要躬行。试下代码,方能体会其中妙处。

    重磅!

    Python遇见机器学习交流群已成立!

    额外赠送福利资源!邱锡鹏深度学习与神经网络,pytorch官方中文教程,利用Python进行数据分析,机器学习学习笔记,pandas官方文档中文版,effective java(中文版)等20项福利资源

    22f4b580c3fa26f4dfbb146f00869a77.png

    获取方式:进入群后点开群公告即可领取下载链接

    5252a47875da56a41167677cde4abb3a.png

    注意:请大家添加时修改备注为

    [学校/公司 + 姓名 + 方向]

    例如 —— 哈工大+张三+对话系统。

    号主,微商等广告请自觉绕道。谢谢!

    推荐阅读

    •  基于机器学习的文本分类!

    •  七种回归分析方法,个 个 经 典

    •  15分钟入门蒙特卡洛 Monte Carlo

    •  四两拨千斤!2020深度主动学习综述

    •  Python 200个标准库汇总!

    •  总结 27 类深度学习主要神经网络:结构图及应用

    •  深度神经网络模型训练中的 tricks(原理与代码汇总)

    •  深度学习的发展方向: 深度强化学习!

    •  教育部建议采纳:给予导师决定硕博士能否毕业的自主权!

    •  目标检测Loss大盘点

    •  关于ELMo,面试官们都怎么问

    •  多模态深度学习:用深度学习的方式融合各种信息

    3580e3f01a9b2c30f9754de25ca5474a.png

    展开全文
  • ​概述在PyTorch中构建自己的卷积神经网络(CNN)的实践教程我们将研究个图像分类问题——CNN的个经典和广泛使用的应用我们将以实用的格式介绍深度学习概念介绍我被神经网络的力量和能力所吸引。在机器学习和深度...

    ​概述

    • 在PyTorch中构建自己的卷积神经网络(CNN)的实践教程
    • 我们将研究一个图像分类问题——CNN的一个经典和广泛使用的应用
    • 我们将以实用的格式介绍深度学习概念

    介绍

    我被神经网络的力量和能力所吸引。在机器学习和深度学习领域,几乎每一次突破都以神经网络模型为核心。这在计算机视觉领域尤为普遍。无论是简单的图像分类还是更高级的东西(如对象检测),神经网络开辟了处理图像数据的可能性。简而言之,对于像我这样的数据科学家来说,这是一座金矿!

    7715eaaafccf2c90d10ff5d3f94dc3ba.png

    当我们使用深度学习来解决一个图像分类问题时,简单的神经网络总是一个好的起点。但是,它们确实有局限性,而且模型的性能在达到一定程度后无法得到改善。这就是卷积神经网络(CNNs)改变了竞争环境的地方。它们在计算机视觉应用中无处不在。老实说,我觉得每一个计算机视觉爱好者都应该可以很快学会这个概念。我将向你介绍使用流行的PyTorch框架进行深度学习的新概念。在本文中,我们将了解卷积神经网络是如何工作的,以及它如何帮助我们改进模型的性能。我们还将研究在PyTorch中CNNs的实现。

    目录

    1.简要介绍PyTorch、张量和NumPy 2.为什么选择卷积神经网络(CNNs)? 3.识别服装问题 4.使用PyTorch实现CNNs

    一、简要介绍PyTorch、张量和NumPy

    让我们快速回顾一下第一篇文章中涉及的内容。我们讨论了PyTorch和张量的基础知识,还讨论了PyTorch与NumPy的相似之处。PyTorch是一个基于python的库,提供了以下功能:

    • 用于创建可序列化和可优化模型的TorchScript
    • 以分布式训练进行并行化计算
    • 动态计算图,等等

    c8fcc05ac27a317c186714125b104fbb.png

    PyTorch中的张量类似于NumPy的n维数组,也可以与gpu一起使用。在这些张量上执行操作几乎与在NumPy数组上执行操作类似。这使得PyTorch非常易于使用和学习。在本系列的第1部分中,我们构建了一个简单的神经网络来解决一个案例研究。使用我们的简单模型,我们在测试集中获得了大约65%的基准准确度。现在,我们将尝试使用卷积神经网络来提高这个准确度。

    二、为什么选择卷积神经网络(CNNs)?

    在我们进入实现部分之前,让我们快速地看看为什么我们首先需要CNNs,以及它们是如何工作的。

    我们可以将卷积神经网络(CNNs)看作是帮助从图像中提取特征的特征提取器。

    在一个简单的神经网络中,我们把一个三维图像转换成一维图像,对吧?让我们看一个例子来理解这一点:

    fdf7003a99cbecbf0510d188aedb6490.png

    你能认出上面的图像吗?这似乎说不通。现在,让我们看看下面的图片:

    1b5eca87df181c9969165aa0ddd83495.png

    我们现在可以很容易地说,这是一只狗。如果我告诉你这两个图像是一样的呢?相信我,他们是一样的!唯一的区别是第一个图像是一维的,而第二个图像是相同图像的二维表示。

    空间定位

    人工神经网络也会丢失图像的空间方向。让我们再举个例子来理解一下:

    6b4ada18eb37843ac7b1e098ed609e17.png

    你能分辨出这两幅图像的区别吗?至少我不能。由于这是一个一维的表示,因此很难确定它们之间的区别。现在,让我们看看这些图像的二维表示:

    d7ae3de51bda182d331e5674595f0359.png

    在这里,图像某些定位已经改变,但我们无法通过查看一维表示来识别它。这就是人工神经网络的问题——它们失去了空间定位。

    大量参数

    神经网络的另一个问题是参数太多。假设我们的图像大小是28*28*3 -所以这里的参数是2352。如果我们有一个大小为224*224*3的图像呢?这里的参数数量为150,528。这些参数只会随着隐藏层的增加而增加。因此,使用人工神经网络的两个主要缺点是: 1.丢失图像的空间方向 2.参数的数量急剧增加那么我们如何处理这个问题呢?如何在保持空间方向的同时减少可学习参数?这就是卷积神经网络真正有用的地方。CNNs有助于从图像中提取特征,这可能有助于对图像中的目标进行分类。它首先从图像中提取低维特征(如边缘),然后提取一些高维特征(如形状)。

    我们使用滤波器从图像中提取特征,并使用池技术来减少可学习参数的数量。

    在本文中,我们不会深入讨论这些主题的细节。如果你希望了解滤波器如何帮助提取特征和池的工作方式,我强烈建议你从头开始学习卷积神经网络的全面教程。

    三、理解问题陈述:识别服装

    理论部分已经铺垫完了,开始写代码吧。我们将讨论与第一篇文章相同的问题陈述。这是因为我们可以直接将我们的CNN模型的性能与我们在那里建立的简单神经网络进行比较。你可以从这里下载“识别”Apparels问题的数据集。https://datahack.analyticsvidhya.com/contest/practice-problem-identify-the-apparels/?utm_source=blog&utm_medium=building-image-classification-models-cnn-pytorch让我快速总结一下问题陈述。我们的任务是通过观察各种服装形象来识别服装的类型。我们总共有10个类可以对服装的图像进行分类:LabelDescription

    0T-shirt/top1Trouser2Pullover3Dress4Coat5Sandal6Shirt7Sneaker8Bag9Ankle boot数据集共包含70,000张图像。其中60000张属于训练集,其余10000张属于测试集。所有的图像都是大小(28*28)的灰度图像。数据集包含两个文件夹,—一个用于训练集,另一个用于测试集。每个文件夹中都有一个.csv文件,该文件具有图像的id和相应的标签;准备好开始了吗?我们将首先导入所需的库:

    # 导入库
    import pandas as pd
    import numpy as np
    
    # 读取与展示图片
    from skimage.io import imread
    import matplotlib.pyplot as plt
    %matplotlib inline
    
    # 创建验证集
    from sklearn.model_selection import train_test_split
    
    # 评估模型
    from sklearn.metrics import accuracy_score
    from tqdm import tqdm
    
    # Pytorch的相关库
    import torch
    from torch.autograd import Variable
    from torch.nn import Linear, ReLU, CrossEntropyLoss, Sequential, Conv2d, MaxPool2d, Module, Softmax, BatchNorm2d, Dropout
    from torch.optim import Adam, SGD
    

    加载数据集

    现在,让我们加载数据集,包括训练,测试样本:

    # 加载数据集
    train = pd.read_csv('train_LbELtWX/train.csv')
    test = pd.read_csv('test_ScVgIM0/test.csv')
    
    sample_submission = pd.read_csv('sample_submission_I5njJSF.csv')
    
    train.head()
    

    07985353a898b22a9cc08a836db4e69c.png
    • 该训练文件包含每个图像的id及其对应的标签
    • 另一方面,测试文件只有id,我们必须预测它们对应的标签
    • 样例提交文件将告诉我们预测的格式

    我们将一个接一个地读取所有图像,并将它们堆叠成一个数组。我们还将图像的像素值除以255,使图像的像素值在[0,1]范围内。这一步有助于优化模型的性能。让我们来加载图像:

    # 加载训练图像
    train_img = []
    for img_name in tqdm(train['id']):
        # 定义图像路径
        image_path = 'train_LbELtWX/train/' + str(img_name) + '.png'
        # 读取图片
        img = imread(image_path, as_gray=True)
        # 归一化像素值
        img /= 255.0
        # 转换为浮点数
        img = img.astype('float32')
        # 添加到列表
        train_img.append(img)
    
    # 转换为numpy数组
    train_x = np.array(train_img)
    # 定义目标
    train_y = train['label'].values
    train_x.shape
    

    850921f40c1de80acd6e0c2c7ab09db9.png

    如你所见,我们在训练集中有60,000张大小(28,28)的图像。由于图像是灰度格式的,我们只有一个单一通道,因此形状为(28,28)。现在让我们研究数据和可视化一些图像:

    # 可视化图片
    i = 0
    plt.figure(figsize=(10,10))
    plt.subplot(221), plt.imshow(train_x[i], cmap='gray')
    plt.subplot(222), plt.imshow(train_x[i+25], cmap='gray')
    plt.subplot(223), plt.imshow(train_x[i+50], cmap='gray')
    plt.subplot(224), plt.imshow(train_x[i+75], cmap='gray')
    

    4add5f093db567148a09a600940e14e3.png

    以下是来自数据集的一些示例。我鼓励你去探索更多,想象其他的图像。接下来,我们将把图像分成训练集和验证集。

    创建验证集并对图像进行预处理

    # 创建验证集
    train_x, val_x, train_y, val_y = train_test_split(train_x, train_y, test_size = 0.1)
    (train_x.shape, train_y.shape), (val_x.shape, val_y.shape)
    

    f3934c36da4fe333d9c81379d49ad832.png

    我们在验证集中保留了10%的数据,在训练集中保留了10%的数据。接下来将图片和目标转换成torch格式:

    # 转换为torch张量
    train_x = train_x.reshape(54000, 1, 28, 28)
    train_x  = torch.from_numpy(train_x)
    
    # 转换为torch张量
    train_y = train_y.astype(int);
    train_y = torch.from_numpy(train_y)
    
    # 训练集形状
    train_x.shape, train_y.shape
    

    553aef640b9309509394e2a569ec53f6.png

    同样,我们将转换验证图像:

    # 转换为torch张量
    val_x = val_x.reshape(6000, 1, 28, 28)
    val_x  = torch.from_numpy(val_x)
    
    # 转换为torch张量
    val_y = val_y.astype(int);
    val_y = torch.from_numpy(val_y)
    
    # 验证集形状
    val_x.shape, val_y.shape
    

    5c6abd7ad9fd3ff7ef68fb1d4a976750.png

    我们的数据现在已经准备好了。最后,是时候创建我们的CNN模型了!

    四、使用PyTorch实现CNNs

    我们将使用一个非常简单的CNN架构,只有两个卷积层来提取图像的特征。然后,我们将使用一个完全连接的Dense层将这些特征分类到各自的类别中。让我们定义一下架构:

    class Net(Module):   
        def __init__(self):
            super(Net, self).__init__()
    
            self.cnn_layers = Sequential(
                # 定义2D卷积层
                Conv2d(1, 4, kernel_size=3, stride=1, padding=1),
                BatchNorm2d(4),
                ReLU(inplace=True),
                MaxPool2d(kernel_size=2, stride=2),
                # 定义另一个2D卷积层
                Conv2d(4, 4, kernel_size=3, stride=1, padding=1),
                BatchNorm2d(4),
                ReLU(inplace=True),
                MaxPool2d(kernel_size=2, stride=2),
            )
    
            self.linear_layers = Sequential(
                Linear(4 * 7 * 7, 10)
            )
    
        # 前项传播
        def forward(self, x):
            x = self.cnn_layers(x)
            x = x.view(x.size(0), -1)
            x = self.linear_layers(x)
            return x
    

    现在我们调用这个模型,定义优化器和模型的损失函数:

    # 定义模型
    model = Net()
    # 定义优化器
    optimizer = Adam(model.parameters(), lr=0.07)
    # 定义loss函数
    criterion = CrossEntropyLoss()
    # 检查GPU是否可用
    if torch.cuda.is_available():
        model = model.cuda()
        criterion = criterion.cuda()
    
    print(model)
    

    d3d8e7f670b81ef55f8058aa392238db.png

    这是模型的架构。我们有两个卷积层和一个线性层。接下来,我们将定义一个函数来训练模型:

    def train(epoch):
        model.train()
        tr_loss = 0
        # 获取训练集
        x_train, y_train = Variable(train_x), Variable(train_y)
        # 获取验证集
        x_val, y_val = Variable(val_x), Variable(val_y)
        # 转换为GPU格式
        if torch.cuda.is_available():
            x_train = x_train.cuda()
            y_train = y_train.cuda()
            x_val = x_val.cuda()
            y_val = y_val.cuda()
    
        # 清除梯度
        optimizer.zero_grad()
    
        # 预测训练与验证集
        output_train = model(x_train)
        output_val = model(x_val)
    
        # 计算训练集与验证集损失
        loss_train = criterion(output_train, y_train)
        loss_val = criterion(output_val, y_val)
        train_losses.append(loss_train)
        val_losses.append(loss_val)
    
        # 更新权重
        loss_train.backward()
        optimizer.step()
        tr_loss = loss_train.item()
        if epoch%2 == 0:
            # 输出验证集loss
            print('Epoch : ',epoch+1, 't', 'loss :', loss_val)
    

    最后,我们将对模型进行25个epoch的训练,并存储训练和验证损失:

    # 定义轮数
    n_epochs = 25
    # 空列表存储训练集损失
    train_losses = []
    # 空列表存储验证集损失
    val_losses = []
    # 训练模型
    for epoch in range(n_epochs):
        train(epoch)
    

    6c9468d6f1c08656d1c6f5aca1a7a0a1.png

    可以看出,随着epoch的增加,验证损失逐渐减小。让我们通过绘图来可视化训练和验证的损失:

    # 画出loss曲线
    plt.plot(train_losses, label='Training loss')
    plt.plot(val_losses, label='Validation loss')
    plt.legend()
    plt.show()

    ec7abf0c99fc4fd403d20c24fd740e08.png

    啊,我喜欢想象的力量。我们可以清楚地看到,训练和验证损失是同步的。这是一个好迹象,因为模型在验证集上进行了很好的泛化。让我们在训练和验证集上检查模型的准确性:

    bbf697c8e7a630bb14fca49057f2bfe9.png
    # 训练集预测
    with torch.no_grad():
        output = model(train_x.cuda())
    
    softmax = torch.exp(output).cpu()
    prob = list(softmax.numpy())
    predictions = np.argmax(prob, axis=1)
    
    # 训练集精度
    accuracy_score(train_y, predictions)
    

    651e254165e11e63196d9b5cd39e44c4.png

    训练集的准确率约为72%,相当不错。让我们检查验证集的准确性:

    # 验证集预测
    with torch.no_grad():
        output = model(val_x.cuda())
    
    softmax = torch.exp(output).cpu()
    prob = list(softmax.numpy())
    predictions = np.argmax(prob, axis=1)
    
    # 验证集精度
    accuracy_score(val_y, predictions)
    

    651e254165e11e63196d9b5cd39e44c4.png

    正如我们看到的损失,准确度也是同步的-我们在验证集得到了72%的准确度。

    为测试集生成预测

    最后是时候为测试集生成预测了。我们将加载测试集中的所有图像,执行与训练集相同的预处理步骤,最后生成预测。所以,让我们开始加载测试图像:

    # 载入测试图
    test_img = []
    for img_name in tqdm(test['id']):
        # 定义图片路径
        image_path = 'test_ScVgIM0/test/' + str(img_name) + '.png'
        # 读取图片
        img = imread(image_path, as_gray=True)
        # 归一化像素
        img /= 255.0
        # 转换为浮点数
        img = img.astype('float32')
        # 添加到列表
        test_img.append(img)
    
    # 转换为numpy数组
    test_x = np.array(test_img)
    test_x.shape
    

    219ae1869643a083a78ad25748b205dc.png

    现在,我们将对这些图像进行预处理步骤,类似于我们之前对训练图像所做的:

    # 转换为torch格式
    test_x = test_x.reshape(10000, 1, 28, 28)
    test_x  = torch.from_numpy(test_x)
    test_x.shape
    

    455be1dcdc885dc2c8c4c2e9b32f8c52.png

    最后,我们将生成对测试集的预测:

    # 生成测试集预测
    with torch.no_grad():
        output = model(test_x.cuda())
    
    softmax = torch.exp(output).cpu()
    prob = list(softmax.numpy())
    predictions = np.argmax(prob, axis=1)
    

    用预测替换样本提交文件中的标签,最后保存文件并提交到排行榜:

    # 用预测替换
    sample_submission['label'] = predictions
    sample_submission.head()
    

    20cc1c60822d50bfc8e9a6aaa6f13ca1.png
    # 保存文件
    sample_submission.to_csv('submission.csv', index=False)
    

    你将在当前目录中看到一个名为submission.csv的文件。你只需要把它上传到问题页面的解决方案检查器上,它就会生成分数。链接:https://datahack.analyticsvidhya.com/contest/practice-problem-identify-the-apparels/?utm_source=blog&utm_medium=building-image-classification-models-cnn-pytorch我们的CNN模型在测试集上给出了大约71%的准确率,这与我们在上一篇文章中使用简单的神经网络得到的65%的准确率相比是一个很大的进步。

    结尾

    在这篇文章中,我们研究了CNNs是如何从图像中提取特征的。他们帮助我们将之前的神经网络模型的准确率从65%提高到71%,这是一个重大的进步。你可以尝试使用CNN模型的超参数,并尝试进一步提高准确性。要调优的超参数可以是卷积层的数量、每个卷积层的滤波器数量、epoch的数量、全连接层的数量、每个全连接层的隐藏单元的数量等。

    展开全文
  • pytorch 卷积 分组卷积 及其深度卷积

    千次阅读 2018-11-15 20:49:05
    先来看看pytorch维卷积的操作API                                           现在继续讲讲几个卷积是如何操作的。 . 普通卷积 torch.nn.Conv2d(in_channels, out...
  • 互相关(cross-correlation)运算的输入是个二输入数组和个二维核(kernel)数组,输出也是个二数组,其中核数组通常称为卷积核或过滤器(filter)。卷积核的尺寸通常小于输入数组,
  •  对一维信号,通常采取的方法有两种,第一,直接对其做一维卷积,第二,反映到时频图像上,这就变成了图像识别,此前一直都在利用keras搭建网络,最近学了pytroch搭建cnn的方法,进行一下代码的尝试。所用数据为...
  • pytorch中的卷积与池化

    2021-02-08 09:44:58
    前言 使用pytorch搭建TextCNN时,需要使用卷积层与池化层,以下对pytorch中的卷积及池化层的...一维卷积是指卷积核张量是一维,其调用形式为: torch.nn.Conv1d(in_channels: int, out_channels: int, kernel_size:
  • PyTorch——二维卷积

    2021-03-07 12:39:00
    参考链接 ... 二互相关计算 虽然卷积层得名于卷积(convolution)运算...在二卷积层中,个二输入数组和个二维核(kernel)数组通过互相关运算输出个二数组。 def corr2d(X, K): h, w = K.shape Y = torch
  • 本文为大家讲解了pytorch实现CNN卷积神经网络,供大家参考,具体内容如下我对卷积神经网络的一些认识卷积...对一维信号,通常采取的方法有两种,第一,直接对其做一维卷积,第二,反映到时频图像上,这就变成了图像...
  • 代码实现地址,其中包含一维,二维,三维的动态卷积;分别可以用于实现eeg的处理,正常图像的处理,医疗图像中三维脑部的处理等等(水漫金山)。https://github.com/kaijieshi7/Dynamic-convolution-Pytorch,大家...
  • 互相关(cross-correlation)运算的输入是个二输入数组和个二维核(kernel)数组,输出也是个二数组,其中核数组通常称为卷积核或过滤器(filter)。卷积核的尺寸通常小于输入数组,卷积核在输入数组...
  • 从至少个数据集上进行实验,同理,这里我选取了车辆分类数据集(后面的实验都是用的车辆分类数据集),主要在之前利用torch.nn实现二维卷积的基础上,为解决感受野比较的问题,将普通的卷积修改为空洞卷积,并且卷...
  • 卷积神经网络基础 本节我们...二互相关运算 二互相关(cross-correlation)运算的输入是个二输入数组和个二维核(kernel)数组,输出也是个二数组,其中核数组通常称为卷积核或过滤器(filter)。卷积核的...
  • 在CNN中,有个重要的操作成为卷积,尤其是在图像处理中使用的最多,这里是对torch中nn模块的二维卷积的介绍。 torch.nn.Conv2d()函数详解 这里是个计算公式,是比较复杂的计算公式,正常的话输出形状为图像和...
  • 步骤如下:使用torchvision 加载并预处理CIFAR-10数据集定义网络定义损失函数和优化器训练网络并更新网络参数测试网络注意:文章末尾含有项目jupyter notebook实战教程下载可供大家课后实战操作、CIFAR-...
  • 种Kernel如果分成多个通道上的子Kernel做卷积运算,最后运算结果还要加在一起后,再加偏置。nn.Conv2d(类式接口)基本用法:import torch from torch import nn """2的卷积层,用于图片的卷积""" # 输入图像的...
  • 卷积神经网络基础我们介绍卷积神经网络的卷积层和池化层,并解释填充、步幅、输入通道和输出通道的含义。import torch from torch.autograd import Variable a=Variable(torch.FloatTensor([[2.,4.]]),requires_grad...
  • 以3通道100行200列的幅图像img为例,期望输出16通道卷积特征,卷积核为3行3列,则 (1)函数调用: conv =nn.Conv2d(3, 16, 3) out = conv(img) 其中,nn.Conv2d函数中 第个参数表示输入图像的通道数 第二个...
  • 一维卷积 torch.nn.Conv1d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True, padding_mode=‘zeros’) 这个函数用来对输入张量做一维卷积 in_channel和out_...
  • 维卷积解读及其pytorch实现

    千次阅读 2020-07-31 00:09:10
    实验表明三维卷积深度神经网络是种能够同时模拟外观和运动的良好的特征学习器。 发现3x3x3在探索的架构中效果最好。 在4个不同的任务和6个不同的基准上,这个模型所学习的特征优于或接近目前的最好的方法。 探索...
  • (1)卷积运算(二维卷积) 以下是pytorch官网上的API 第种情况 如上图所示,输入图片为4*4,卷积核为3*3,步长为1,零填充。 代码表示: 第二种情况 如上图所示,输入图片为5*5,卷积核为4*4,...
  • pytorch方法测试——卷积一维

    千次阅读 2018-06-12 19:22:48
    结论:一维卷积第一个输出 =  m.weight[ 0 ][ 0 ][ 0 ] * input[ 0 ][ 0 ][ 0 ] + m.weight[ 0 ][ 0 ][ 1 ] * input[ 0 ][ 0 ][ 1 ] + m.weight[ 0 ][ 1 ][ 0 ] * input[ 0 ][ 1 ][ 0 ] + m.weight[ 0 ][ 1 ][ 1 ]...
  • 本章代码:...1D/2D/3D 卷积卷积有一维卷积、二维卷积、三维卷积。一般情况下,卷积核在几个维度上滑动,就是几维卷积。比如在图片上的卷积就是二维卷...
  • PyTorch入门总结51 卷积1.1 一维卷积 1 卷积 1.1 一维卷积
  • torch.nn.Conv1d及一维卷积详解

    万次阅读 多人点赞 2019-11-06 16:25:09
    近日在搞wavenet,期间遇到了一维卷积,在这里对一维卷积以及其pytorch中的API进行总结,方便下次使用 之前对二维卷积是比较熟悉的,在初次接触一维卷积的时候,我以为是一个一维的卷积核在一条线上做卷积,但是这种...
  • Pytorch搭建卷积神经网络基础 一,卷积层构建 1,1D卷积层构建 ...对输入信号上应用一维卷积。输入信号尺寸,卷积后的输出信号尺寸。N 是batch size,C表示通道数,L信号的序列长度。 卷积运算过程: ..

空空如也

空空如也

1 2 3 4 5 ... 11
收藏数 209
精华内容 83
关键字:

pytorch一维卷积