【问题标题】:How can I calculate the network gradients w.r.t weights for all inputs in PyTorch?如何计算 PyTorch 中所有输入的网络梯度 w.r.t 权重?
【发布时间】:2019-09-24 01:19:50
【问题描述】:

我试图弄清楚如何计算每个输入的网络梯度。我有点迷路了。本质上,我想要的是为输入 x 的所有值计算 d self.output/d weight1 和 d self.output/d weight2。因此,例如,我将有一个大小为 (1000, 5) 的矩阵。其中 1000 是输入 x 的大小,5 是层中的权重数。

我在下面包含的示例将权重返回为大小 (1,5)。这里具体计算的是什么?这是 x 的 1 个输入的 d self.output/ d weight1,还是所有输入的平均值?

其次,features.grad 和 weight1.grad 的 matmul 是否与我要问的相同? x 的所有值的 weight1 的所有梯度的矩阵。

class Network(torch.nn.Module):

    def __init__(self, iNode, hNode, oNode):
        super(Network, self).__init__()

        print("Building Model...")

        iNode = int(iNode) ; self.iNode = iNode
        hNode = int(hNode) ; self.hNode = hNode
        oNode = int(oNode) ; self.oNode = oNode

        self.fc1 = nn.Linear(iNode, hNode, bias=False)
        self.fc2 = nn.Linear(hNode, oNode, bias=False)

    def forward(self, x):
        self.hidden_probs = self.fc1(x)
        self.hidden = self.actFunc1(self.hidden_probs)
        self.output_probs = self.fc2(self.hidden)
        self.output = self.actFunc2(self.output_probs)
        return self.output

    def actFunc1(self, x):
        return 1.0/(1.0+torch.exp(-x))

    def actFunc2(self, x):
        return x

    def trainData(self, features, labels, epochs, alpha, optimisation, verbose=False):

        for epoch in range(0,epochs):
            net_pred = self.forward(features)
            net_pred.backward(gradient=torch.ones(features.size())) #calc. dout/dw for all w
print(features.grad.size()) #returns (1000,1)



            with torch.no_grad():
                for name, param in self.named_parameters():
                    if(param.requires_grad):
                        param -= alpha*param.grad

                for name, param in self.named_parameters():
                    if(param.requires_grad):
                        param.grad.zero_()


            sys.stdout.write("Epoch: %06i\r" % (epoch))
            sys.stdout.flush()
        sys.stdout.write("\n")


【问题讨论】:

    标签: python-3.x pytorch autograd


    【解决方案1】:

    我不确定您到底要达到什么目标,因为通常您只使用 (d 输出)/(d 参数) 的梯度总和,而不使用介于两者之间的任何其他梯度,因为 autograd 会处理这一点,但是让我试着回答。

    问题 1

    我在下面包含的示例将权重返回为大小 (1,5)。这里具体计算的是什么?这是 x 的 1 个输入的 d self.output/ d weight1,还是所有输入的平均值?

    您会得到大小 (1,5),因为训练是在小批量中完成的,这意味着每个数据点相对于 (5) 权重的梯度是在小批量中计算和求和的。 根据文档:

    这个属性默认是 None 并且在第一次调用 back() 计算 self 的梯度时成为一个张量。然后该属性将包含计算出的梯度,并且未来对 backward() 的调用会将梯度累积(添加)到其中。

    如果您明确需要每个数据点的梯度,则将您的小批量设置为 1。通常我们以小批量进行训练,因为在每个数据点之后更新可能不稳定,图像每次都朝不同的方向跳跃,而在批量中这会平均化。 另一方面,许多数据集太大而无法一次性计算梯度。

    问题 2

    一个例子可能会提供更多见解:

        import torch
        x = torch.tensor([1.5], requires_grad=True)
        a = torch.nn.Parameter(torch.tensor([2.]))
        b = torch.nn.Parameter(torch.tensor([10.]))
        y = x*a
        z = y+0.5*b
        temp = z.backward()
        print('gradients of a: %0.2f and b: %0.2f' % (a.grad.item(), b.grad.item()))
    

    我从ab这两个参数开始,计算z=a*x+0.5*b。 还没有计算梯度,pytorch 只记录操作的历史,所以所有的.grad 属性都是空的。 调用z.backward()时,会计算输出相对于参数的梯度,可以通过对参数调用grad来查看。

    然后可以像您已经在做的那样更新参数a -= alpha*a.grad

    【讨论】:

    • 您好,感谢您的快速回复!我为什么要在矩阵中使用 d out/dw 的梯度的唯一原因是因为我想实现自己的损失函数。我已经设法在纯 numpy 中做到这一点,但在 PyTorch 中这样做会更快,并且可以更有效地扩展。如果我只用 x 的 1 个输入进行前向传递,然后循环输入并将其存储在矩阵中,原则上可以吗?但我认为由于多次调用会很慢?
    • 如果您确保只使用 Torch 运算符,您可以将自己的损失函数定义为普通的 Python 函数。 Autograd 会为您处理渐变,然后在此函数返回的错误值上向后调用。
    猜你喜欢
    • 2019-01-10
    • 2018-06-16
    • 1970-01-01
    • 2021-04-01
    • 2018-10-14
    • 2017-04-26
    • 2017-06-30
    • 2022-01-13
    • 2021-07-07
    相关资源
    最近更新 更多