美文网首页
Pytorch搭建网络

Pytorch搭建网络

作者: _Cooper_ | 来源:发表于2018-07-01 09:02 被阅读403次

    面向对象编程

    面向对象编程——类class和对象object

    • class是一种类型(Type),object是类的实例(Instance)
    • 每一个类方法都必须在参数列表开头有一个固定参数self,当调用该方法时python会自动加上self这个参数。因此如果方法没有参数,也必须加上self
    • init方法:__init__方法会在对象被实例化时自动运行(初始化)

    继承:

    • 要想使用继承,在定义类时我们需要在类后面跟一个包含基类名称的元组。
    • 如果子类中定义了__init__方法,则基类中的__init__方法将不会被自动调用,需要手动调用,此时需要显示调用self;相反,如果子类中未定义__init__方法,则子类的__init__方法将被自动调用。
    class Student(SchoolMember):
        '''代表一位学生。'''
        def __init__(self, name, age, marks):
            SchoolMember.__init__(self, name, age)
    
    • 在子类中调用父方法,都需要显式调用self
    • super(),先简单认为成继承父类
      super(子类, self).父类方法(参数),相当于父类.方法(self, 参数)

    类和对象

    在面向对象编程中,理解和认出类和对象十分重要
    程序中有很多类的结构,一般都要建立该类的对象。例如在LeNet项目中,LeNet5是一个class,在main.py中有net = LeNet5(),即是创建了LeNet5的对象net。
    又如输入时MNIST是类,trainset是对象;Dataloader是类,trainloader是对象等等。
    面向对象编程并不是全部由类和对象组建程序的,也有函数,和普通变量

    • 变量:有普通数值型变量和Tensor,普通型例如train_loss,大部分都是Tensor型变量
    • 函数:例如torch.max(output),可以写作output.max(),这是函数的应用

    总结 - 再看类和对象

    class ConvReLU(nn.Module):
        def __init__(self, in_channels, out_channels, kernel_size=3, stride=1, padding=0):
            super(ConvReLU, self).__init__()
            self.conv = nn.Conv2d(in_channels, out_channels, kernel_size=kernel_size, stride=stride, padding=padding)
    
        def forward(self, x):
            x = self.conv(x)
            x = F.relu(x)
            return x
    
    1. 定义了ConvReLU()类,继承了nn.Module父类。
    2. 定义了__init()__方法,在实例化ConvReLU()类时自动调用__init()__方法。
      2.1 输入参数除了必须有的self,还有要想实例化一个{ConvReLU()}的对象需要的参数
      2.2 因为子类定义了__init()__方法,父类的__init()__方法不再自动执行,需要显式执行,nn.Module父类的__init()__方法不需要输入参数,所以super调用不需要输入参数
      2.3 定义了对象变量self.conv,属性是{nn.Conv2d()}对象,实际上self.conv{nn.Conv2d()}类的实例化,实例化时需要参数。
    3. 定义了forward()方法,对输入进行操作
      3.1 对数据操作需要函数,第一行x = self.conv(x)实际上为x = self.conv.forward(x),调用了nn.Conv2d()forward()函数,由于大家都继承了nn.Module父类,根据nn.Module的使用方法,.forward()不写,直接写object(input)
      3.2 第二行x = F.relu(x)直接调用了函数,对输入进行操作

    循环与迭代

    batchsize:在深度学习中,一般采用SGD训练,即每次训练在训练集中取batchsize个样本训练;
    iteration:中文翻译为迭代,1个iteration等于使用batchsize个样本训练一次;
    一个迭代 = 一个正向通过+一个反向通过
    epoch:迭代次数,1个epoch等于使用训练集中的全部样本训练一次;
    一个epoch = 所有训练样本的一个正向传递和一个反向传递

    举个例子,训练集有1000个样本,batchsize=10,那么:
    训练完整个样本集需要:
    100次iteration,1次epoch。

    Moudle class

    搭建网络的整个过程都需要继承Moduleclass

    Base class for all neural network modules.

    Your models should also subclass this class.

    Module类中最重要的方法是forward

    Defines the computation performed at every call.
    Should be overridden by all subclasses.
    .. note::
    Although the recipe for forward pass needs to be defined within
    this function, one should call the :class:Module instance afterwards
    instead of this since the former takes care of running the
    registered hooks while the latter silently ignores them.

    forward实现了每次调用网络的操作,每个网络子类都必须重写forward方法。
    注意:调用网络操作时应当调用Module()类而非Module.forward()方法。
    即:output = net(img)
    而非output = net.forward(img)

    torch.nn.XX VS torch.nn.functional.XX

    既有torch.nn.Conv2d,又有torch.nn.Functional.Conv2d,区别在于:
    nn.Module实现的layer是由class Layer(nn.Module)定义的特殊类,会自动提取可学习参数nn.Parameter;nn.functional中的函数更像是纯函数,由def function(input)定义

    • nn.Conv2d是一个类,把卷积当作一个层时使用
    • F.conv2d()是一个函数,把卷积当作一个运算函数时使用
    • nn.Conv2d的forward()函数实现是用F.conv2d()实现的。
    class Conv2d(_ConvNd):
        def forward(self, input):
            return F.conv2d(input, self.weight, self.bias, self.stride,
                            self.padding, self.dilation, self.groups)
    

    在调用Conv2d()操作时执行forward方法,可以看到真正进行操作的还是F.conv2d()函数

    参考1
    参考2
    参考3

    pytorch的图像预处理包

    pytorch中transform函数

    import 和from... import

    • 可以import的单位是packagemodule

    .py文件是一个Module

    可以from...import...的单位是package,moduleclass/function

    • 导入文件将导入所有的class,用某个class时需要package.class
      导入类可以直接使用该类

    例如:torchvisonpakage有3个package和一个module

    import torchvision

    导入class

    在导入MNIST数据集时需要用class MNIST,这个class包含于torchvison.datasets.mnist文件中,因此正确引用的方式有:
    from torchvision.datasets.mnist import MNIST,使用时直接用MNIST
    import torchvision.datasets.mnist as mnist,使用时用mnist.MNIST

    导入module

    from torchvision import datasets
    import torchvion.datasets as datasets

    init.py

    此外,通过package的__init__.py文件,可以将package中的class提到package级别
    参考
    例如class Dataloadertorchvision.datasets.folder.py中,但是因为在torchvision.datasetspackage中的__init__.py中有
    from .folder import ImageFolder, DatasetFolder
    Datafolder被提到了package级别,可以在package级别引用
    from torchvision.datasets import ImageFolder

    # in your __init__.py
    from .folder import ImageFolder, DatasetFolder
    
    # now import File from package
    from torchvision.datasets import ImageFolder
    

    真正要使用的时候肯定是使用一个class,没法使用整个package
    可以直接引入class,或先引入package再package.class

    net中input的维度

    应有四个维度:batch_size, channels, size_len, size_width,如果读取单张图片没有batch_size维度,需要手动添加
    image = image.view(1, image.size(0), image.size(1), image.size(2))

    trick - 建一个class ConvReLU()

    把Conv2d和ReLU()合起来做

    class ConvReLu(nn.Module):
        def __init__(self, in_channels, out_channels, kernel_size, stride=1, padding=0):
            super(ConvReLu, self).__init__()
            self.conv = nn.Conv2d(in_channels, out_channels, kernel_size=kernel_size, stride=stride, padding=padding)
    
        def forward(self, x):
            x = self.conv(x)
            x = F.relu(x)
            return x
    

    使用方法:

    class Layer1and2(nn.Module):
        def __init__(self):
            super(Layer1and2, self).__init__()
            self.op = nn.Sequential(
                ConvReLu(3, 64, 7, 2, 2),
                nn.MaxPool2d(3, 2),
                nn.BatchNorm2d(64),
                ConvReLu(64, 64, 1, 1),
                ConvReLu(64, 192, 3, 1, 1),
                nn.BatchNorm2d(192),
                nn.MaxPool2d(3, 2)
            )
    
        def forward(self, x):
            x = self.op(x)
            return x
    

    把ConvReLU当作一个整体来用

    好处

    1. 省事,提高代码结构化
    2. 在调试的时候可以看到卷积之后的效果,只有forward()中的操作可以调试跟踪,在__init()__nn.Sequential中的操作是无法跟踪的。

    trick - forward函数中尽量别把许多步骤合成一个Sequential

    否则没办法调试跟踪每一步之后的结果

    nn.Sequential()最后一个元素别加逗号

    否则最后一个元素将被忽略,为什么?

    Python魔术方法getitemsetitemdelitemlen

    CSDN

    相关文章

      网友评论

          本文标题:Pytorch搭建网络

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