zoukankan      html  css  js  c++  java
  • 5. 池化层、非线性激活和并搭建一个简单的神经网络

        本次,我们接着学习神经网络的知识,这里介绍池化层,和经典的非线性激活函数,并简要的介绍一下 pytorch 中的其它层次,最后我们使用搭建神经网络(并使用以下 torch.nn.Sequential)。

    Pooling Layers

      本小节,我们介绍一下池化层的相关知识。

         池化层的作用

      除了卷积层,卷积网络也经常使用池化层来缩减模型的大小,提高计算速度,同时提高所提取特征的鲁棒性。也就是池化层赋予了我们网络更快的运算速度和更高的鲁棒性。
      而且池化层是我们卷积神经网络中经常用到的层,基本每个网络都会有池化层,池化层也很简单。

    常见的池化层有 max-pooling 和 average-pooling,该两种操作一个是取卷积核中的 最大值,一个是取平均值

    Max Pooling是对某个Filter抽取到若干特征值,只取得其中最大的那个Pooling层作为保留值,其他特征值全部抛弃,值最大代表只保留这些特征中最强的,抛弃其他弱的此类特征。
    有以下几个优点:
    1、保证特征的位置与旋转不变性。对于图像处理这种特性是很好的。至于如何理解图像进行池化(pooling)后的平移不变性?
    手边没有图,我就抽象一点回答了。假如三个元素(1,5,3)取max就取到5,如果三个元素向右平移一下变成(0,1,5),那取max之后还是5,具备了平移不变性。大概就是这么个理。
    2、减少模型参数数量,缓解过拟合问题
    3、可以把变长的输入x整理成固定长度的输入。CNN往往最后连接全连接层,在训练过程中,神经元个数需要固定好,但是cnn输入x长度不确定,通过pooling操作,每个filter固定取一个值。有多少个Filter,Pooling就有多少个神经元,这样就可以把全连接层神经元固定住。

         pytorch 池化层帮助文档查看


    这里,我们详细查看以下 torch.nn.MaxPool2d 为例




         代码实例测试

      请注意看,他的帮助文档标注的是可以使 NCHW,也可以是 CHW 两种模式。

    请注意,我们这里的 stride 默认值是 kernel_size,这样也就达到了我们池化、采样的目的。
    import torch
    import torchvision
    from torch.utils.tensorboard import SummaryWriter
    
    
    my_data = torch.randn((1, 1, 7, 7))
    
    ceil_max_pool = torch.nn.MaxPool2d(kernel_size=3, ceil_mode=True)
    floor_max_pool = torch.nn.MaxPool2d(kernel_size=3, ceil_mode=False) # stride 默认值是kernel_size
    
    ceil_result = ceil_max_pool(my_data)
    floor_result = floor_max_pool(my_data)
    
    print(my_data)
    print(ceil_result)
    print(floor_result)
    

    运行结果:


    下面我们考虑采样一下CIFAR10 这个数据集的图片,并使用 average_pooling 和 max_pooling 试一下。

    import torch
    import torchvision
    from torch.utils.data import DataLoader
    from torch.utils.data import Dataset
    from torch.utils.tensorboard import SummaryWriter
    
    
    data_path = "../../data_cifar10"
    data_test = torchvision.datasets.CIFAR10(data_path, train=False, transform=torchvision.transforms.ToTensor(),
                                             download=True)
    data_loader = DataLoader(data_test, batch_size=64)
    
    
    class MyModel(torch.nn.Module):
        def __init__(self):
            super(MyModel, self).__init__()
            self.max_pool = torch.nn.MaxPool2d(kernel_size=3, ceil_mode=True)
            self.ave_pool = torch.nn.AvgPool2d(kernel_size=3, ceil_mode=True)
    
        def forward(self, img):
            return self.max_pool(img), self.ave_pool(img)
    
    
    writer = SummaryWriter(log_dir="../../logs")
    my_model = MyModel()
    step = 0
    for imgs, targets in data_loader:
        writer.add_images("images-original", imgs, step)
        imgs_max_pooling, imgs_ave_pooling = my_model(imgs)
        writer.add_images("images-max-pooling", imgs_max_pooling, step)
        writer.add_images("images-ave-pooling", imgs_ave_pooling, step)
    writer.close()
    

    Non-linear Activations

         非线性激活的作用

      总体来讲,激活函数是用来加入非线性因素的,解决线性模型所不能解决的问题。具体的一些详细的解释,请参考下述链接:
    参考资料知乎:神经网络激活函数的作用和原理?有没有形象解释?

         Non-linear Activations Doc

      介绍完非线性激活的作用之后,我们查看 pytorch 关于非线性激活的 API 和他们的帮助文档。这里,我们主要介绍的是 ReLU 和 Sigmoid 两个常见的激活函数。




         代码示范

    下面我们写一个代码查看一下 ReLU 和 Sigmoid 的效果

    import torch.nn as nn
    import torch
    import torchvision
    
    data = torch.randn((3, 3))
    print(data)
    
    my_relu = nn.ReLU()
    my_sigmoid = nn.Sigmoid()
    
    print(my_relu(data))
    print(my_sigmoid(data))
    

    运行结果如下所示:


    神经网络的其它层次介绍

      首先我们查阅 torch.nn 的官方帮助文档:


      可以看到,他有很多层次 layers 和 功能函数 function,但是我们已经将最最最经常使用的层给介绍过了。下面我建议各位小伙伴们选择几个喜欢的层次,练一练自己的官方文档阅读能力。
      我选择我比较喜欢的两个部分,一个是 Normalization Layers 和 Dropout Layers

         Normalization Layers



         Dropout Layers

    下面,我们简单写一个代码来进行测试一下看看,对CIFAR10 数据集首先进行 sigmod 操作,然后直接 Normalization 正则一下。

    import torch
    import torch.nn as nn
    import torchvision
    import torch.utils.data
    from torch.utils.tensorboard import SummaryWriter
    
    
    image_path = "../../data_cifar10"
    log_path = "../../logs"
    writer = SummaryWriter(log_dir=log_path)
    dataset = torchvision.datasets.CIFAR10(root=image_path, train=False, transform=torchvision.transforms.ToTensor(), download=True)
    dataloader = torch.utils.data.DataLoader(dataset, batch_size=64, drop_last=False)
    
    
    class MyModel(nn.Module):
        def __init__(self):
            super(MyModel, self).__init__()
            self.model = nn.Sequential(
                nn.Sigmoid(),
                nn.BatchNorm2d(num_features=3)
            )
    
        def forward(self, x):
            return self.model(x)
    
    
    my_model = MyModel()
    step = 0
    for images, targets in dataloader:
        model_images = my_model(images)
        writer.add_images("original-images", images, step)
        writer.add_images("sigmoid-norm-images", model_images, step)
        step += 1
    writer.close()
    

    运行 tensorboard 查看结果



         Dropout Layer

    打开 dropout 官方文档,pick了 nn.Dropout2d 进行查阅。



    下面,我写一个二维的卷积,续接这个 Dropout Layer 实例一下子:

    import torch
    import torch.nn as nn
    import torchvision
    import torch.utils.data
    from torch.utils.tensorboard import SummaryWriter
    
    
    image_path = "../../data_cifar10"
    log_path = "../../logs"
    writer = SummaryWriter(log_dir=log_path)
    dataset = torchvision.datasets.CIFAR10(root=image_path, train=False, transform=torchvision.transforms.ToTensor(), download=True)
    dataloader = torch.utils.data.DataLoader(dataset, batch_size=64, drop_last=False)
    
    
    class MyModel(nn.Module):
        def __init__(self):
            super(MyModel, self).__init__()
            self.model = nn.Sequential(
                nn.Conv2d(in_channels=3, out_channels=3, kernel_size=3, stride=1, padding=1),
                nn.Dropout(p=0.2, inplace=False)
            )
    
        def forward(self, x):
            return self.model(x)
    
    
    my_model = MyModel()
    step = 0
    for images, targets in dataloader:
        model_images = my_model(images)
        writer.add_images("read-original-images", images, step)
        writer.add_images("Con2d-Dropout-images", model_images, step)
        step += 1
    writer.close()
    

    tensorboard 查看图片



    搭建CIFAR 10 model

      这里,我们将神经网络的基本结果说的差不过了,下面我们尝试建立一下一个简单的神经网络
    在搭建一个神经网络之前,我们先介绍一下之前没有用过的两个函数。

    1. nn.Flatten()
    2. nn.linear()

         nn.Flatten() 函数

      该函数理解较为简单,帮助文档写的也是非常的简洁。


         nn.linear()函数

      挺简单的一个线性变换函数:


         CIFAR 10 Model 网络的构建

    首先查看网络的样子:


    然后根据网络之前的形态变换,将其转换成代码即可,主要看他们的 inchannel, outchannel,kernel 等等的信息。

    写出来的网络代码:

    import torch
    import torchvision
    import torch.nn as nn
    from torch.utils.data import DataLoader
    from torch.utils.tensorboard import SummaryWriter
    
    
    images_path = "../../data_cifar10"
    logs_path = "../../logs"
    dataset = torchvision.datasets.CIFAR10(root=images_path, train=False, transform=torchvision.transforms.ToTensor(),
                                           download=True)
    dataloader = DataLoader(dataset=dataset, batch_size=64, drop_last=False)
    
    
    class MyModel(torch.nn.Module):
        def __init__(self):
            super(MyModel, self).__init__()
            self.model = torch.nn.Sequential(
                nn.Conv2d(in_channels=3, out_channels=32, kernel_size=5, stride=1, padding=2),
                nn.MaxPool2d(kernel_size=2, padding=0),
                nn.Conv2d(in_channels=32, out_channels=32, kernel_size=5, stride=1, padding=2),
                nn.MaxPool2d(kernel_size=2, padding=0),
                nn.Conv2d(in_channels=32, out_channels=64, kernel_size=5, stride=1, padding=2),
                nn.MaxPool2d(kernel_size=2, padding=0),
                nn.Flatten(start_dim=1, end_dim=-1), # 将它展平之后, dimension0 是 batch,后面的特征需要改变
                nn.Linear(in_features=1024, out_features=64),
                nn.Linear(in_features=64, out_features=10)
            )
    
        def forward(self, x):
            return self.model(x)
    
    
    step = 0
    my_model = MyModel()
    tmp = torch.randn((1, 3, 32, 32))
    # tmp2 = my_model(tmp)
    writer = SummaryWriter(log_dir=logs_path)
    # for images, targets in dataloader:
    #     images_proceed = my_model(images)
    #     writer.add_images("original", images, step)
    #     writer.add_images("proceed", images_proceed, step) # 没办法的当图片写进入,应为规格不符要求
    #     step += 1
    writer.add_graph(my_model, input_to_model=tmp)
    writer.close()
    

    下面是看起来很有意思的运算图 graph


  • 相关阅读:
    github绑定host
    PHP安全过滤函数
    PHP界定符 <<<EOT
    file_get_contents模拟表单(POST/GET方式提交)
    排序算法(一)冒泡排序
    MySQL的limit查询优化
    SQL Server日期函数集合
    系统查找存储过程和触发器
    C#中跳转页面有那几种方法,简述其区别
    知道sql数据库中的哪个数据表最大
  • 原文地址:https://www.cnblogs.com/lucky-light/p/15543937.html
Copyright © 2011-2022 走看看