繁体   English   中英

PyTorch 用于回归的 Autograd

[英]PyTorch Autograd for Regression

另一个 PyTorch 新手在这里试图了解他们的计算图和 autograd。

我正在学习以下关于势能和相应力的 model。

model = nn.Sequential(
    nn.Linear(1, 32),
    nn.Linear(32, 32), nn.Tanh(),
    nn.Linear(32, 32), nn.Tanh(),
    nn.Linear(32, 1)
)

optimizer = torch.optim.Adam(model.parameters())
loss = nn.MSELoss()
# generate data
r = torch.linspace(0.95, 3, 50, requires_grad=True).view(-1, 1)
E = 1 / r
F = -grad(E.sum(), r)[0]

inputs = r

for epoch in range(10**3):
    E_pred = model.forward(inputs)
    F_pred = -grad(E_pred.sum(), r, create_graph=True, retain_graph=True)[0]

    optimizer.zero_grad()
    error = loss(E_pred, E.data) + loss(F_pred, F.data)
    error.backward()
    optimizer.step()

但是,如果我将inputs = r更改为inputs = 1*r ,则训练循环中断并出现以下错误

RuntimeError: Trying to backward through the graph a second time (or directly access saved tensors after they have already been freed). Saved intermediate values of the graph are freed when you call .backward() or autograd.grad(). Specify retain_graph=True if you need to backward through the graph a second time or if you need to access saved tensors after calling backward.

你能解释一下为什么会这样吗?

在backward之后执行backward时会发生此错误。 这是示例代码。

output = model.forward(x)
loss = criterion(label, output)

optimizer.zero_grad()
loss.backward()

loss2 = criterion(loss, output2)
loss2.backward()

optimizer.step()

正如您在以下代码中看到的,如果您只是将 r 放入输入中,则会发生浅拷贝。 因此,当 r 的值发生变化时,输入的值也会发生变化。 但是,如果乘以 1,则成为深拷贝,即使 r 发生变化,值也不会变化。

r = torch.linspace(0.95, 3, 50).view(-1, 1)

inputs_1 = r
inputs_2 = 1 * r
r[0] = 100

print(inputs_1)
print(inputs_2)

E.data 的要求 grad 为 False。 因此,您可以认为由于输入而发生了错误。 此外,optimizer.zero_grad 仅重置 model 的梯度,不会重置 E 或输入的梯度。

print(E.data.requires_grad) # False
# You want to update only the parameters of the model......
optimizer = torch.optim.Adam(model.parameters())

前面说过,如果使用inputs = r,就会出现浅拷贝,如果使用inputs = 1 * r,就会出现深拷贝,所以出现下面的区别。

  1. 在浅拷贝的情况下,由于输入等于 r,梯度只是建立起来,没有错误发生。

  2. 但是由于 1 * r 是计算出来的值,所以这里多次使用backward会出错。

我认为将 r 的 requires_grad 设置为 false 会很好。 如果 requires_grad 设置为 True,则通过渐变更改该值。 这应该只用于参数。 但是,输入不需要更改其值。 用下面的代码检查一下。

代码:

# generate data
r = torch.linspace(0.95, 3, 50, requires_grad=False).view(-1, 1)
E = 1 / r
inputs = 1 * r

for epoch in range(10**3):
    E_pred = model.forward(inputs)
    optimizer.zero_grad()
    error = loss(E_pred, E.data)
    error.backward()
    optimizer.step()

print(model.forward(inputs))

如果您只想将 r 设置为 requires grad 为 true,请使用以下代码

# generate data
r = torch.linspace(0.95, 3, 50, requires_grad=True).view(-1, 1)
with torch.no_grad():
  E = 1 / r
  inputs = 1 * r

for epoch in range(10**3):
    E_pred = model.forward(inputs)
    optimizer.zero_grad()
    error = loss(E_pred, E.data)
    error.backward()
    optimizer.step()

print(model.forward(inputs))

当您使用inputs = 1 * r时,反向传播会尝试计算inputs变量的 grads。 然后问题就出现了。 因此,如果您想第二次计算梯度,那么您应该在 back backward(retain_graph=True)中使用retain_graph=True 因为在计算循环内的梯度后,中间梯度将被删除,但是当它超出循环时,它会尝试计算inputs的梯度,但没有任何中间梯度,因此会出现问题。

# generate data
r = torch.linspace(0.95, 3, 50, requires_grad=True).view(-1, 1)
E = 1 / r
F = -grad(E.sum(), r)[0]

# with torch.no_grad():
inputs = 1*r

for epoch in range(10**3):
    E_pred = model.forward(inputs)
    F_pred = -grad(E_pred.sum(), r, create_graph=True)[0]

    optimizer.zero_grad()
    error = loss(E_pred, E.data) + loss(F_pred, F.data)
    error.backward(retain_graph=True)
    optimizer.step()

是关于这个主题的讨论。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM