美文网首页
pytorch入门_网络架构/训练/保存提取

pytorch入门_网络架构/训练/保存提取

作者: conson_wm | 来源:发表于2018-08-14 10:52 被阅读0次

    1. 用nn.Module搭建网络架构

    import torch.nn as nn
    import torch.nn.functional as F
    
    class Net(nn.Module):
        def __init__(self):
            super(Net, self).__init__()
            self.conv1 = nn.Conv2d(1, 6, 5) # 1 input image channel, 6 output channels, 5x5 square convolution kernel
            self.conv2 = nn.Conv2d(6, 16, 5)
            self.fc1   = nn.Linear(16*5*5, 120) # an affine operation: y = Wx + b
            self.fc2   = nn.Linear(120, 84)
            self.fc3   = nn.Linear(84, 10)
    
        def forward(self, x):
            x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2)) # Max pooling over a (2, 2) window
            x = F.max_pool2d(F.relu(self.conv2(x)), 2) # If the size is a square you can only specify a single number
            x = x.view(-1, self.num_flat_features(x))
            x = F.relu(self.fc1(x))
            x = F.relu(self.fc2(x))
            x = self.fc3(x)
            return x
        
        def num_flat_features(self, x):
            size = x.size()[1:] # all dimensions except the batch dimension
            num_features = 1
            for s in size:
                num_features *= s
            return num_features
    
    net = Net()
    net
    
    '''神经网络的输出结果是这样的
    Net (
      (conv1): Conv2d(1, 6, kernel_size=(5, 5), stride=(1, 1))
      (conv2): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1))
      (fc1): Linear (400 -> 120)
      (fc2): Linear (120 -> 84)
      (fc3): Linear (84 -> 10)
    )
    '''
    

      上面这段是LeNet的架构, 需要说明的是

    1.1 重要的函数有两个, 一个是_init_(), 一个是forward()

      其他的可以根据需要再加, _init_()是用来定义网络中需要的模块, 比如基本的conv, fc的模块的大小都在这里面定义好, forward()是用来定义前向的架构, 就是顺序地堆叠模块就可以了, 这个和keras没有什么区别, 我觉得Pytorch的这套架构比较有整体性, 就是把一个模型封装在一个类里面, 包含module和architecture都用这个类体现出来了


    1.2 在_init_()里开头的那一句

    super(Net, self).__init__()
    

      这句的意思是_init_()函数继承自父类nn.Module
      super()函数是用于调用父类的一个方法, super(Net, self)首先找到Net的父类(就是nn.Module), 然后把类Net的对象转换为类nn.Module的对象, 具体的可以看一下
    http://www.runoob.com/python/python-func-super.html


    1.3 conv和fc模块的入参

    self.conv1 = nn.Conv2d(1, 6, 5) # 1 input image channel, 6 output channels, 5x5 square convolution kernel
    self.fc1   = nn.Linear(16*5*5, 120) # an affine operation: y = Wx + b
    

      conv的入参有三个, 分别是输入channel, 输出channel, 以及kernel的大小(5就代表5x5)
      fc的入参只有两个, 分别就是输入的结点数, 输出的结点数


    1.4 torch.nn.functional as F

      这个是通常写法, 我们用到的激活函数, pool函数都在这个F里面(损失函数还有conv/fc等层在nn里面), 这个要注意一下, 那BN/dropout是在nn还是在F里面?


    2. 如何开始训练

    1中是把网络定义好了, 那离能够训练这个网络还有几步呢?我们需要想一下训练一个神经网络需要一些什么基本的步骤

    • 输入值格式(就是patch的格式)
    • Optimizer
    • loss fucntion
    • 梯度更新过程

    2.1 输入值格式

      我们的应用都是图片输入, 那pytorch有没有keras那种直接一个文件夹输入作为训练集或测试集(ImageDataGenerator())的那种方法呢?是有的, 就是Dataloader()

    import torchvision
    import torchvision.transforms as transforms
    
    
    # torchvision数据集的输出是在[0, 1]范围内的PILImage图片。
    # 我们此处使用归一化的方法将其转化为Tensor,数据范围为[-1, 1]
    
    transform=transforms.Compose([transforms.ToTensor(),
                                  transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),
                                 ])
    trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)
    trainloader = torch.utils.data.DataLoader(trainset, batch_size=4, 
                                              shuffle=True, num_workers=2)
    
    testset = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform)
    testloader = torch.utils.data.DataLoader(testset, batch_size=4, 
                                              shuffle=False, num_workers=2)
    classes = ('plane', 'car', 'bird', 'cat',
               'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
    '''注:这一部分需要下载部分数据集 因此速度可能会有一些慢 同时你会看到这样的输出
    
    Downloading http://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz to ./data/cifar-10-python.tar.gz
    Extracting tar file
    Done!
    Files already downloaded and verified
    '''
    

      这段代码就是用DataLoader()来生成patch的方法, 这个和keras的ImageDataGenerator()就很像了, 生成的trainloader是一个包含tensor的迭代器, 在训练的过程中就可以直接从迭代器里去除tensor, 然后装入Variable中作为神经网络的输入, 这就是输入值格式
      当然, 这只是一种简单的从数据集中得到batch的方法, 要是我们的数据是从某个文件夹来还得经过点pre-process的话(比如SR)会更复杂一些, 我们会在SR benchmark笔记里面再详细说

    2.2 Optimizer

    import torch.optim as optim
    # create your optimizer
    optimizer = optim.SGD(net.parameters(), lr = 0.01)
    
    # in your training loop:
    optimizer.zero_grad() # zero the gradient buffers
    optimizer.step()
    

      Optimizer的定义和Keras差不多, 可以用参数定义lr, momentum, weight_decay等, 这个去查文档就好, optimizer.zero_grad()的意思是初始化所有的梯度buffer为0, 这个是在每一次计算梯度更新之前做的, optimizer.step()就是根据你定义的optimizer执行梯度更新


    2.3 loss function

    import torch.optim as optim
    # make your loss function
    criterion = nn.MSELoss()
    
    # in your training loop:
    output = net(input)
    loss = criterion(output, target)
    loss.backward()
    

      criterion定义了loss function, 然后在训练的loop中loss就根据criterion不停去算, loss是一个Variable, 它具有backward属性, 就是在训练过程中可以直接用.backward来计算loss对每个weight的梯度值


    2.4 训练过程

      有了输入, loss function和Optimizer, 我们就可以开始进行训练了, 过程就是从迭代器trainloader把input tensor送入网络, 然后算output, 根据loss function算loss, 从loss再反过去算梯度, 根据Optimizer去更新权重

    for epoch in range(2): # loop over the dataset multiple times
        
        running_loss = 0.0
        for i, data in enumerate(trainloader, 0):
            # get the inputs
            inputs, labels = data
            
            # wrap them in Variable
            inputs, labels = Variable(inputs), Variable(labels)
            
            # zero the parameter gradients
            optimizer.zero_grad()
            
            # forward + backward + optimize
            outputs = net(inputs)
            loss = criterion(outputs, labels)
            loss.backward()        
            optimizer.step()
            
            # print statistics
            running_loss += loss.data[0]
            if i % 2000 == 1999: # print every 2000 mini-batches
                print('[%d, %5d] loss: %.3f' % (epoch+1, i+1, running_loss / 2000))
                running_loss = 0.0
    print('Finished Training')
    

    2.5 神经网络的快速搭建方法

      除了上面提到的搭建神经网络的方法之外, pytorch还提供了另一种更快速的搭建方法, 有点类似于Keras的Sequentiao模型
    http://keras-cn.readthedocs.io/en/latest/getting_started/sequential_model/

    net = torch.nn.Sequential(
      torch.nn.Linear(2,10),
      torch.nn.ReLU,
      torch.nn.Linear(10,2),
    )
    # fast implementation of FC 2->10->2
    

    3. 保存和提取训练结果

      保存和加载网络模型有两种方法, 一种是把模型和参数一起save(相当于keras的save()), 还有一种就是只save参数(相当于keras的save_weight())

    # 保存和加载整个模型  
    torch.save(model_object, 'model.pth')  
    model = torch.load('model.pth')  
     
    # 仅保存和加载模型参数  
    torch.save(model_object.state_dict(), 'params.pth')  
    model_object.load_state_dict(torch.load('params.pth')) 
    

      当网络比较大的时候, 用第一种方法会花比较多的时间, 同时所占的存储空间也比较大
      还有一个问题就是存储模型的时候, 有的时候会存成.pkl格式, 应该是没有本质区别, 都是Pickle格式, 后续在用C来读取网络的时候, 也从Pickle的C实现来考虑直接解析Pytorch的模型
    https://www.zhihu.com/question/274533811

    相关文章

      网友评论

          本文标题:pytorch入门_网络架构/训练/保存提取

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