pytorch - 手动线性回归中第一个时期后梯度消失
问题描述
我是 Pytorch 的新手,我一直在学习教程并玩弄玩具示例。我只想制作一个超级简单的模型来更好地处理 autograd,但我遇到了问题。
我正在尝试训练线性回归模型,但我一直遇到以下错误,
----------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
<ipython-input-80-ba5ca34a3a54> in <module>()
9 loss = torch.dot(delta, delta)
10
---> 11 loss.backward()
12 with torch.no_grad():
13 w, b = w - learning_rate*w.grad.data, b - learning_rate*b.grad.data
/usr/local/lib/python3.6/dist-packages/torch/tensor.py in backward(self, gradient, retain_graph, create_graph)
91 products. Defaults to ``False``.
92 """
---> 93 torch.autograd.backward(self, gradient, retain_graph, create_graph)
94
95 def register_hook(self, hook):
/usr/local/lib/python3.6/dist-packages/torch/autograd/__init__.py in backward(tensors, grad_tensors, retain_graph, create_graph, grad_variables)
87 Variable._execution_engine.run_backward(
88 tensors, grad_tensors, retain_graph, create_graph,
---> 89 allow_unreachable=True) # allow_unreachable flag
90
91
RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn
作为参考,代码在这里,
# dataset for training
X = torch.randn(100, 3)
y = -3*X[:,0] + 2.2*X[:,1] + 0.002*X[:,2] + 1
w = torch.randn(3, requires_grad=True, dtype=torch.float) # model weights
b = torch.randn(1, requires_grad=True, dtype=torch.float) # model bias
num_epochs = 10
learning_rate = 1e-4
for i in range(num_epochs):
y_hat = torch.mv(X, w) + b
delta = y_hat - y
loss = torch.dot(delta, delta)
loss.backward()
with torch.no_grad():
w, b = w - learning_rate*w.grad, b - learning_rate*b.grad
问题似乎是在第一个时代之后,渐变属性设置为无,但我有点困惑为什么会这样。
如果我在更新权重后尝试将梯度归零,则会出现类似的错误。
解决方案
答案在于局部禁用梯度计算。正如您在第一个示例中看到的那样,使用torch.no_grad()
上下文管理器执行的计算会生成张量 which requires_grad == False
。由于您创建“新鲜”w
而b
不是就地更新它们,因此这些张量requires_grad
在第一次迭代后失去了属性,并且您在第二次迭代时得到错误。一个简单的解决方法是重新启用渐变
with torch.no_grad():
w, b = w - learning_rate*w.grad, b - learning_rate*b.grad
w.requires_grad_(True)
b.requires_grad_(True)
如果您在 pytorch 模块中查找优化器的来源optim
,例如SGD
,您会发现它们使用了就地运算符,例如add_
. 你可以用这种方式重写你的循环
with torch.no_grad():
w.sub_(learning_rate*w.grad)
b.sub_(learning_rate*b.grad)
这不会触及requires_grad
标志,因为张量保持其“身份” - 只需更改值。在这种情况下,您需要记住在每次迭代中调用w.zero_grad()
and ,否则梯度值将保持累加增长。b.zero_grad()
推荐阅读
- java - CORS Preflight Error in browser but postman request works
- jakarta-ee - OpenLiberty 21.0.0.5 中的 JMS 配置问题
- java - 在 Mac 上安装 Apache Spark 和运行 spark-shell 时出错
- javascript - 在 div 内定位标签
- javascript - 如何使用 javascript 从方法 selenium 获取快速 Web 服务
- django - django 查询使用注释获取额外数据
- python - 在 python Docstring 中编写双反斜杠
- java - 如何将返回值传递给方法并在java android retrofit中获取响应值
- c++ - 为什么我的冒泡排序函数将 0 添加到我的向量数组中,尽管它不在我的数组中?
- php - 未强制执行 PHP 函数参数类型声明