Pytorch:定义自定义函数

时间:2017-10-01 03:50:18

标签: python pytorch

我想编写自己的激活功能,但是我遇到了问题。说矩阵乘法将调用.data。我搜索但得到的信息很少。任何帮助将不胜感激。错误信息是

 Traceback (most recent call last):
      File "defineAutogradFuncion.py", line 126, in <module>
        test = gradcheck(argmin, input, eps=1e-6, atol=1e-4)
      File "/home/zhaosl/.local/lib/python2.7/site-packages/torch/autograd/gradcheck.py", line 154, in gradcheck
        output = func(*inputs)
      File "defineAutogradFuncion.py", line 86, in forward
        output = output.mm(dismap).squeeze(-1)
      File "/home/zhaosl/.local/lib/python2.7/site-packages/torch/autograd/variable.py", line 578, in mm
        output = Variable(self.data.new(self.data.size(0), matrix.data.size(1)))
      File "/home/zhaosl/.local/lib/python2.7/site-packages/torch/tensor.py", line 374, in data
        raise RuntimeError('cannot call .data on a torch.Tensor: did you intend to use autograd.Variable?')
    RuntimeError: cannot call .data on a torch.Tensor: did you intend to use autograd.Variable?
    class Softargmin(torch.autograd.Function):
    """
    We can implement our own custom autograd Functions by subclassing
    torch.autograd.Function and implementing the forward and backward passes
    which operate on Tensors.
    """
    @staticmethod
    def forward(self, input):
        """
        In the forward pass we receive a Tensor containing the input and return a
        Tensor containing the output. You can cache arbitrary Tensors for use in the
        backward pass using the save_for_backward method.
        """
        #P = Fun.softmax(-input)
        inputSqueeze = input.squeeze(-1)
        P = Fun.softmax(-inputSqueeze)
        self.save_for_backward(P)

        output = P.permute(0,2,3,1)
        dismap = torch.arange(0,output.size(-1)+1).unsqueeze(1)
        output = output.mm(dismap).squeeze(-1)
       return output
    @staticmethod
    def backward(self, grad_output):
        """
        In the backward pass we receive a Tensor containing the gradient of the loss
        with respect to the output, and we need to compute the gradient of the loss
        with respect to the input.
        """
        P, = self.saved_tensors
        P = P.unsqueeze(-1)
        Pk = torch.squeeze(P,-1).permute(0,2,3,1)
        k = torch.arange(0,Pk.size(-1)+1).unsqueeze(1)
        sumkPk = Pk.mm(k)
        sumkPk = sumkPk.unsqueeze(1).expand(P.size())
        i = torch.arange(0,Pk.size(-1)+1).view(1,-1,1,1,1).expand(P.size())
        grad_output_expand =grad_output.unsqueeze(-1).unsqueeze(1).expand(P.size())
        grad_input = grad_output_expand*P*(sumkPk-i)
        return grad_input

3 个答案:

答案 0 :(得分:2)

PyTorch中最基本的元素是Tensor,它相当于numpy.ndarray,唯一的区别是可以将Tensor放到GPU上进行任何计算。

VariableTensor的包装,其中包含三个属性:datagradgrad_fndata包含原始Tensor; grad包含与此Variable相关的某个值的派生/梯度; grad_fn是指向创建此Function的{​​{1}}对象的指针。 Variable属性实际上是grad_fn正常工作的关键,因为PyTorch使用这些指针在每次迭代时构建计算图,并相应地对图中的所有autograd进行微分。这不仅仅是通过您正在创建的自定义Variables对象进行正确区分。

enter image description here

因此,无论何时在计算中创建一些需要区分的Function,请将其包装为Tensor。首先,这将使Variable能够在您调用Tensor后保存生成的派生/梯度值。其次,这有助于backward()构建正确的计算图。

另一件需要注意的事情是,每当您向计算图表中发送autograd时,使用此Variable计算的任何值都将自动为Variable。因此,您不必手动将所有Variable包装在计算图中。

您可能需要查看this

回到你的错误,找出真正导致问题的原因有点困难,因为你没有显示所有代码(比如你在自己的Tensors中使用这个自定义Function的信息计算图),但我怀疑最有可能发生的是你在一个需要区分的子图中使用了这个Function,当PyTorch在你的模型上使用数值梯度检查来判断区分是否正确时,它假设该子图中的每个节点都是Variable,因为这是通过该子图进行区分所必需的,然后它试图调用该data的{​​{1}}属性,很可能是因为该值在区分中的某处使用,并且失败,因为该节点实际上是Variable并且没有Tensor属性。

答案 1 :(得分:0)

你正在使用的pytorch张量应该包含在torch.Variable对象中,如此

v=torch.Variable(mytensor)

autograd假设张量包含在变量中,然后可以使用v.data访问数据。 Variable类是Autograd用于在向后传递期间执行数值导数的数据结构。确保您传递的数据张量包含在torch.Variable中。

-Mo

答案 2 :(得分:0)

以下是简单激活的示例,该示例内部使用了割炬激活功能,但可以正常使用,并且可以扩展为自定义。

import torch as pt
import torch.nn as nn
from torch.nn.modules import Module
# custom activation 
class Act(Module):
def forward(self, z):
    if(do_ratio > 0):
        return nn.functional.dropout(pt.tanh(z), do_ratio)
    else:
        return pt.tanh(z)
act_fn = Act()
model = pt.nn.Sequential(
    pt.nn.Linear(features, n_layer0, bias=enable_bias),
    act_fn,
    pt.nn.Linear(n_layer0, n_layer1, bias=enable_bias),
    act_fn,
    pt.nn.Linear(n_layer1, n_layer2, bias=enable_bias)
    )