Pytorch搭建网络

2018-07-01  本文已影响403人  _Cooper_

面向对象编程

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

继承:

class Student(SchoolMember):
    '''代表一位学生。'''
    def __init__(self, name, age, marks):
        SchoolMember.__init__(self, name, age)

类和对象

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

总结 - 再看类和对象

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)定义

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

.py文件是一个Module

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

例如: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

上一篇下一篇

猜你喜欢

热点阅读