我在youtube上观看了一系列关于深度学习的教程,我遇到了一个让我很困惑的问题。
X = torch.tensor([1,2,3,4], dtype = torch.float32)
Y = torch.tensor([2,4,6,8], dtype = torch.float32)
w = torch.tensor(0.0, dtype = torch.float32, requires_grad=True)
def forward(x):
return w*x;
def loss(y, y_predicted):
return ((y-y_predicted)**2).mean()
print(f'Prediction before training: f(5) = {forward(5):.3f}')
learning_rate= 0.01
epoch = 20
for i in range(epoch):
y_pred = forward(X)
l = loss(Y, y_pred)
l.backward()
with torch.no_grad():
w = w - learning_rate * w.grad
# (w -= learning_rate * w.grad) # would not cause error in the following line
w.grad.zero_() #error : 'NoneType' object has no attribute 'zero_'
if i % 1 ==0:
print(f'weight : {w}, loss : {l}')
我真的很想知道">w = w - learning_rate * w.g grad";and ">w -= learning_rate * w.g grad";因为在我的经验中,这两者是一样的。谢谢!
正如评论中指出的那样,问题在于Pytorch如何计算/存储梯度。事实上,
w-= learning_rate * w.grad
是一个就地操作,它将使w保持其初始属性(requires_grad=True)。通常在Pytorch中,我们会避免就地操作,因为它可能会破坏Autograd使用的计算图(参见Pytorch论坛帖子)。
但对你来说,这是:
w = w - learning_rate * w.grad
不合适。因此,w被赋值给一个新的副本,并且由于torch.no_grad()语句,该副本将没有.grad属性。
虽然操作符在python
中具有特定的行为,但对于pytorch
框架并不总是如此。对于普通的python
解释,我们可以看到A -= B
的减法赋值与A = A - B
语法是等价的。此外,每次想给变量赋值时都可以使用python操作符。事实上,我们在python
中称之为语法糖,它可以用来简化代码。然而,pytorch
框架的工作方式不同。
l.backward()
之后分配的。因此,它没有grad
值。此外,由于torch.no_grad()
条件,w赋值没有requires_grad
。
现在,让我们考虑一下你的例子:
w = w - learning_rate * w.grad
在pytorch
框架中,它相当于:
w[...] = w - learning_rate * w.grad
虽然w[...] = w - learning_rate * w.grad
和w -= learning_rate * w.grad
看起来是相等的,但它们并不遵循相同的结构。因此,他们促进不同的行为。一方面,w -= learning_rate * w.grad
表达式被认为是一个原地操作。这意味着它直接改变了给定张量()的内容。,w[...]
)不复制。另一方面,requires_grad=True
属性使w保持其初始属性。因此,不更新它的状态。