zoukankan      html  css  js  c++  java
  • PyTorch之前向传播函数自动调用forward

    参考:1. pytorch学习笔记(九):PyTorch结构介绍

    2.pytorch学习笔记(七):pytorch hook 和 关于pytorch backward过程的理解

    3.Pytorch入门学习(三):Neural Networks

    4.forward

    神经网络的典型处理如下所示:

    1. 定义可学习参数的网络结构(堆叠各层和层的设计);
    2. 数据集输入;
    3. 对输入进行处理(由定义的网络层进行处理),主要体现在网络的前向传播;
    4. 计算loss ,由Loss层计算;
    5. 反向传播求梯度;
    6. 根据梯度改变参数值,最简单的实现方式(SGD)为:
       weight = weight - learning_rate * gradient
    下面是利用PyTorch定义深度网络层(Op)示例:
     

    1.  
      class FeatureL2Norm(torch.nn.Module):
    2.  
      def __init__(self):
    3.  
      super(FeatureL2Norm, self).__init__()
    4.  
       
    5.  
      def forward(self, feature):
    6.  
      epsilon = 1e-6
    7.  
      # print(feature.size())
    8.  
      # print(torch.pow(torch.sum(torch.pow(feature,2),1)+epsilon,0.5).size())
    9.  
      norm = torch.pow(torch.sum(torch.pow(feature,2),1)+epsilon,0.5).unsqueeze(1).expand_as(feature)
    10.  
      return torch.div(feature,norm)
    1.  
      class FeatureRegression(nn.Module):
    2.  
      def __init__(self, output_dim=6, use_cuda=True):
    3.  
      super(FeatureRegression, self).__init__()
    4.  
      self.conv = nn.Sequential(
    5.  
      nn.Conv2d(225, 128, kernel_size=7, padding=0),
    6.  
      nn.BatchNorm2d(128),
    7.  
      nn.ReLU(inplace=True),
    8.  
      nn.Conv2d(128, 64, kernel_size=5, padding=0),
    9.  
      nn.BatchNorm2d(64),
    10.  
      nn.ReLU(inplace=True),
    11.  
      )
    12.  
      self.linear = nn.Linear(64 * 5 * 5, output_dim)
    13.  
      if use_cuda:
    14.  
      self.conv.cuda()
    15.  
      self.linear.cuda()
    16.  
       
    17.  
      def forward(self, x):
    18.  
      x = self.conv(x)
    19.  
      x = x.view(x.size(0), -1)
    20.  
      x = self.linear(x)
    21.  
      return x

    由上例代码可以看到,不论是在定义网络结构还是定义网络层的操作(Op),均需要定义forward函数,下面看一下PyTorch官网对PyTorch的forward方法的描述:

    那么调用forward方法的具体流程是什么样的呢?具体流程是这样的:

    以一个Module为例:
    1. 调用module的call方法
    2. module的call里面调用module的forward方法
    3. forward里面如果碰到Module的子类,回到第1步,如果碰到的是Function的子类,继续往下
    4. 调用Function的call方法
    5. Function的call方法调用了Function的forward方法。
    6. Function的forward返回值
    7. module的forward返回值
    8. 在module的call进行forward_hook操作,然后返回值
    上述中“调用module的call方法”是指nn.Module 的__call__方法。定义__call__方法的类可以当作函数调用,具体参考Python的面向对象编程。也就是说,当把定义的网络模型model当作函数调用的时候就自动调用定义的网络模型的forward方法。nn.Module 的__call__方法部分源码如下所示:
     

    1.  
      def __call__(self, *input, **kwargs):
    2.  
      result = self.forward(*input, **kwargs)
    3.  
      for hook in self._forward_hooks.values():
    4.  
      #将注册的hook拿出来用
    5.  
      hook_result = hook(self, input, result)
    6.  
      ...
    7.  
      return result

    可以看到,当执行model(x)的时候,底层自动调用forward方法计算结果。具体示例如下:

    1.  
      class Function:
    2.  
      def __init__(self):
    3.  
      ...
    4.  
      def forward(self, inputs):
    5.  
      ...
    6.  
      return outputs
    7.  
      def backward(self, grad_outs):
    8.  
      ...
    9.  
      return grad_ins
    10.  
      def _backward(self, grad_outs):
    11.  
      hooked_grad_outs = grad_outs
    12.  
      for hook in hook_in_outputs:
    13.  
      hooked_grad_outs = hook(hooked_grad_outs)
    14.  
      grad_ins = self.backward(hooked_grad_outs)
    15.  
      hooked_grad_ins = grad_ins
    16.  
      for hook in hooks_in_module:
    17.  
      hooked_grad_ins = hook(hooked_grad_ins)
    18.  
      return hooked_grad_ins

    model = LeNet()
    y = model(x)
    如上则调用网络模型定义的forward方法。

  • 相关阅读:
    hdu5360 Hiking(水题)
    hdu5348 MZL's endless loop(欧拉回路)
    hdu5351 MZL's Border(规律题,java)
    hdu5347 MZL's chemistry(打表)
    hdu5344 MZL's xor(水题)
    hdu5338 ZZX and Permutations(贪心、线段树)
    hdu 5325 Crazy Bobo (树形dp)
    hdu5323 Solve this interesting problem(爆搜)
    hdu5322 Hope(dp)
    Lightoj1009 Back to Underworld(带权并查集)
  • 原文地址:https://www.cnblogs.com/jfdwd/p/11196711.html
Copyright © 2011-2022 走看看