pytorch,梯度参数是什么
gradient-descent
neural-network
pytorch
torch
7
0

我正在阅读PyTorch的文档,并找到了他们编写的示例

gradients = torch.FloatTensor([0.1, 1.0, 0.0001])
y.backward(gradients)
print(x.grad)

其中x是初始变量,从中构造y(3矢量)。问题是,梯度张量的0.1、1.0和0.0001参数是什么?该文档不是很清楚。

参考资料:
Stack Overflow
收藏
评论
共 4 个回答
高赞 时间 活跃

说明

对于神经网络,我们通常使用loss来评估网络对输入图像(或其他任务)进行分类的学习程度。 loss项通常是标量值。为了更新网络的参数,我们需要计算loss wrt到参数的梯度,参数实际上是计算图中的leaf node (顺便说一下,这些参数主要是各个层的权重和偏差,例如卷积,线性等)。

根据链式规则,为了计算loss wrt到叶节点的梯度,我们可以计算一些中间变量的loss wrt的导数,以及中间变量wrt到叶子变量的梯度,做一个点积并将所有这些加起来。

使用Variable backward() Variable )的backward()方法的gradient参数来计算叶子变量的每个变量元素的加权和。这些权重只是中间变量中每个元素的最终loss的派生。

一个具体的例子

让我们以一个具体而简单的示例来理解这一点。

from torch.autograd import Variable
import torch
x = Variable(torch.FloatTensor([[1, 2, 3, 4]]), requires_grad=True)
z = 2*x
loss = z.sum(dim=1)

# do backward for first element of z
z.backward(torch.FloatTensor([[1, 0, 0, 0]]), retain_graph=True)
print(x.grad.data)
x.grad.data.zero_() #remove gradient in x.grad, or it will be accumulated

# do backward for second element of z
z.backward(torch.FloatTensor([[0, 1, 0, 0]]), retain_graph=True)
print(x.grad.data)
x.grad.data.zero_()

# do backward for all elements of z, with weight equal to the derivative of
# loss w.r.t z_1, z_2, z_3 and z_4
z.backward(torch.FloatTensor([[1, 1, 1, 1]]), retain_graph=True)
print(x.grad.data)
x.grad.data.zero_()

# or we can directly backprop using loss
loss.backward() # equivalent to loss.backward(torch.FloatTensor([1.0]))
print(x.grad.data)    

在上面的示例中,第一次print的结果是

2 0 0 0
[torch.FloatTensor大小为1x4]

这恰好是z_1 wrt到x的导数。

第二次print的结果是:

0 2 0 0
[torch.FloatTensor大小为1x4]

这是z_2 wrt对x的导数。

现在,如果使用权重[ 1*dz_1/dx + 1*dz_2/dx + 1*dz_3/dx + 1*dz_4/dx ]计算z wrt对x的导数,则结果为1*dz_1/dx + 1*dz_2/dx + 1*dz_3/dx + 1*dz_4/dx 。因此,不足为奇的是,第三个print的输出是:

2 2 2 2
[torch.FloatTensor大小为1x4]

应该注意的是,权重向量[1、1、1、1]恰好是loss wrt到z_1,z_2,z_3和z_4的导数。 loss wrt对x的导数计算如下:

d(loss)/dx = d(loss)/dz_1 * dz_1/dx + d(loss)/dz_2 * dz_2/dx + d(loss)/dz_3 * dz_3/dx + d(loss)/dz_4 * dz_4/dx

因此,第四print的输出与第三print的输出相同:

2 2 2 2
[torch.FloatTensor大小为1x4]

收藏
评论

通常,您的计算图只有一个标量输出,表示loss 。然后,您可以通过loss.backward()来计算权重( w )的loss梯度。其中backward()的默认参数是1.0

如果您的输出具有多个值(例如, loss=[loss1, loss2, loss3] ),则可以通过loss.backward(torch.FloatTensor([1.0, 1.0, 1.0])) loss=[loss1, loss2, loss3] ))来计算权重的损耗梯度。

此外,如果要为不同的损失添加权重或重要性,则可以使用loss.backward(torch.FloatTensor([-0.1, 1.0, 0.0001]))

这意味着要同时计算-0.1*d(loss1)/dw, d(loss2)/dw, 0.0001*d(loss3)/dw

收藏
评论

在这里,forward()的输出(即y)是一个3向量。

这三个值是网络输出处的梯度。如果y是最终输出,通常将它们设置为1.0,但也可以具有其他值,尤其是在y是较大网络的一部分的情况下。

例如。如果x是输入,则y = [y1,y2,y3]是中间输出,用于计算最终输出z,

然后,

dz/dx = dz/dy1 * dy1/dx + dz/dy2 * dy2/dx + dz/dy3 * dy3/dx

所以在这里,向后的三个值是

[dz/dy1, dz/dy2, dz/dy3]

然后backward()计算dz / dx

收藏
评论

我在PyTorch网站上找不到的原始代码了。

gradients = torch.FloatTensor([0.1, 1.0, 0.0001])
y.backward(gradients)
print(x.grad)

上面代码的问题没有基于计算梯度的函数。这意味着我们不知道有多少个参数(函数采用的参数)以及参数的维数。

为了完全理解这一点,我创建了几个与原始示例相似的示例:

范例1:

a = torch.tensor([1.0, 2.0, 3.0], requires_grad = True)
b = torch.tensor([3.0, 4.0, 5.0], requires_grad = True)
c = torch.tensor([6.0, 7.0, 8.0], requires_grad = True)

y=3*a + 2*b*b + torch.log(c)    
gradients = torch.FloatTensor([0.1, 1.0, 0.0001])
y.backward(gradients,retain_graph=True)    

print(a.grad) # tensor([3.0000e-01, 3.0000e+00, 3.0000e-04])
print(b.grad) # tensor([1.2000e+00, 1.6000e+01, 2.0000e-03])
print(c.grad) # tensor([1.6667e-02, 1.4286e-01, 1.2500e-05])

如您所见,我假设在第一个示例中,我们的函数是y=3*a + 2*b*b + torch.log(c) ,参数是带有三个元素的张量。

但是还有另一种选择:

范例2:

import torch

a = torch.tensor(1.0, requires_grad = True)
b = torch.tensor(1.0, requires_grad = True)
c = torch.tensor(1.0, requires_grad = True)

y=3*a + 2*b*b + torch.log(c)    
gradients = torch.FloatTensor([0.1, 1.0, 0.0001])
y.backward(gradients)

print(a.grad) # tensor(3.3003)
print(b.grad) # tensor(4.4004)
print(c.grad) # tensor(1.1001)

gradients = torch.FloatTensor([0.1, 1.0, 0.0001])是累加器。

下一个示例将提供相同的结果。

范例3:

a = torch.tensor(1.0, requires_grad = True)
b = torch.tensor(1.0, requires_grad = True)
c = torch.tensor(1.0, requires_grad = True)

y=3*a + 2*b*b + torch.log(c)

gradients = torch.FloatTensor([0.1])
y.backward(gradients,retain_graph=True)
gradients = torch.FloatTensor([1.0])
y.backward(gradients,retain_graph=True)
gradients = torch.FloatTensor([0.0001])
y.backward(gradients)

print(a.grad) # tensor(3.3003)
print(b.grad) # tensor(4.4004)
print(c.grad) # tensor(1.1001)

您可能会听到PyTorch autograd系统的计算与Jacobian乘积相同。

雅可比

如果您有一个像我们一样的功能:

y=3*a + 2*b*b + torch.log(c)

雅可比行将为[3, 4*b, 1/c] 。然而,这种雅可比行列式并不是PyTorch所做的事情来计算特定点处的梯度。

对于先前的函数,对于b=1b=1+ε其中ε小),PyTorch将执行δy δy/δb δb的操作。因此,没有像符号数学这样的东西。

如果不在y.backward()使用渐变:

例子4

a = torch.tensor(0.1, requires_grad = True)
b = torch.tensor(1.0, requires_grad = True)
c = torch.tensor(0.1, requires_grad = True)
y=3*a + 2*b*b + torch.log(c)

y.backward()

print(a.grad) # tensor(3.)
print(b.grad) # tensor(4.)
print(c.grad) # tensor(10.)

根据最初设置abc张量a ,您可以简单地在某个时刻获得结果。

注意如何初始化abc

范例5:

a = torch.empty(1, requires_grad = True, pin_memory=True)
b = torch.empty(1, requires_grad = True, pin_memory=True)
c = torch.empty(1, requires_grad = True, pin_memory=True)

y=3*a + 2*b*b + torch.log(c)

gradients = torch.FloatTensor([0.1, 1.0, 0.0001])
y.backward(gradients)

print(a.grad) # tensor([3.3003])
print(b.grad) # tensor([0.])
print(c.grad) # tensor([inf])

如果您使用torch.empty()而不使用pin_memory=True ,则每次可能会有不同的结果。

另外,音符梯度就像累加器,因此在需要时将它们归零。

范例6:

a = torch.tensor(1.0, requires_grad = True)
b = torch.tensor(1.0, requires_grad = True)
c = torch.tensor(1.0, requires_grad = True)
y=3*a + 2*b*b + torch.log(c)

y.backward(retain_graph=True)
y.backward()

print(a.grad) # tensor(6.)
print(b.grad) # tensor(8.)
print(c.grad) # tensor(2.)

最后,我只想说明PyTorch使用的一些术语:

PyTorch在计算梯度时会创建一个动态计算图 。这看起来很像一棵树。

因此,您经常会听到这棵树的叶子输入张量 ,而输出张量

通过从根到叶跟踪图并使用链法则将每个梯度相乘来计算梯度。

收藏
评论
新手导航
  • 社区规范
  • 提出问题
  • 进行投票
  • 个人资料
  • 优化问题
  • 回答问题

关于我们

常见问题

内容许可

联系我们

@2020 AskGo
京ICP备20001863号