pytorch - loss.backward() 和 optimizer.step() 之间的连接
pytorch - connection between loss.backward() and optimizer.step()
optimizer
和 loss
之间的明确联系在哪里?
优化器如何知道在没有调用的情况下从哪里获得损失的梯度optimizer.step(loss)
?
-更多上下文-
当我最小化损失时,我不必将梯度传递给优化器。
loss.backward() # Back Propagation
optimizer.step() # Gardient Descent
无需深入研究 pytorch 的内部结构,我可以提供一个简单的答案:
回想一下,在初始化 optimizer
时,您明确告诉它应该更新模型的哪些参数(张量)。一旦您对损失调用 backward()
,梯度就会由张量本身“存储”(它们具有 grad
and a requires_grad
属性)。在计算模型中所有张量的梯度后,调用 optimizer.step()
使优化器遍历它应该更新的所有参数(张量)并使用它们内部存储的 grad
来更新它们的值。
有关计算图的更多信息和存储在 pytorch 张量中的附加“梯度”信息可在 中找到。
优化器引用参数有时会导致问题,例如,当模型被移动到 GPU 在 初始化优化器之后。
确保在构建优化器之前完成模型设置。有关详细信息,请参阅 this answer。
当您调用 loss.backward()
时,它所做的只是计算损失梯度 w.r.t 损失中具有 requires_grad = True
的所有参数,并将它们存储在 parameter.grad
属性中每个参数。
optimizer.step()
根据parameter.grad
更新所有参数
假设我们定义了一个模型:model
,损失函数:criterion
,我们有以下步骤序列:
pred = model(input)
loss = criterion(pred, true_labels)
loss.backward()
pred
将有一个 grad_fn
属性,该属性引用创建它的函数,并将其绑定回模型。因此,loss.backward()
将获得有关其正在使用的模型的信息。
尝试删除 grad_fn
属性,例如:
pred = pred.clone().detach()
那么模型梯度将为 None
,因此权重将不会更新。
并且优化器与模型相关联,因为我们在创建优化器时传递了 model.parameters()
。
简答:
loss.backward()
# 对我们设置的所有参数做梯度 required_grad= True
。参数可以是代码中定义的任何变量,例如 h2h
或 i2h
.
optimizer.step()
# 根据优化器函数(之前在我们的代码中定义),我们更新这些参数以最终获得最小损失(误差)。
也许这会稍微澄清 loss.backward
和 optim.step
之间的联系(尽管其他答案很重要)。
# Our "model"
x = torch.tensor([1., 2.], requires_grad=True)
y = 100*x
# Compute loss
loss = y.sum()
# Compute gradients of the parameters w.r.t. the loss
print(x.grad) # None
loss.backward()
print(x.grad) # tensor([100., 100.])
# MOdify the parameters by subtracting the gradient
optim = torch.optim.SGD([x], lr=0.001)
print(x) # tensor([1., 2.], requires_grad=True)
optim.step()
print(x) # tensor([0.9000, 1.9000], requires_grad=True)
loss.backward()
设置所有具有 requires_grad=True
的张量的 grad
属性
在损失为叶子的计算图中(在这种情况下只有x
)。
优化器只是遍历它在初始化时收到的参数列表(张量)以及张量具有 requires_grad=True
的任何地方,它减去存储在其 .grad
[=32 中的梯度值=](在 SGD 的情况下简单地乘以学习率)。它不需要知道计算梯度的损失是多少,它只想访问 .grad
属性 所以它可以 x = x - lr * x.grad
注意 如果我们在训练循环中这样做,我们会调用 optim.zero_grad()
因为在每个训练步骤中我们想要计算新的梯度 - 我们不关心前一批的梯度。不将梯度归零会导致批次之间的梯度累积。
有些答案解释的很好,但我想举个具体的例子来解释一下机制。
假设我们有一个函数:z = 3 x^2 + y^3。
zw.r.tx和y的更新梯度公式为:
初始值为 x=1 和 y=2。
x = torch.tensor([1.0], requires_grad=True)
y = torch.tensor([2.0], requires_grad=True)
z = 3*x**2+y**3
print("x.grad: ", x.grad)
print("y.grad: ", y.grad)
print("z.grad: ", z.grad)
# print result should be:
x.grad: None
y.grad: None
z.grad: None
然后计算x和y在当前值(x=1,y=2)中的梯度
# calculate the gradient
z.backward()
print("x.grad: ", x.grad)
print("y.grad: ", y.grad)
print("z.grad: ", z.grad)
# print result should be:
x.grad: tensor([6.])
y.grad: tensor([12.])
z.grad: None
最后,使用SGD优化器根据公式更新x和y的值:
# create an optimizer, pass x,y as the paramaters to be update, setting the learning rate lr=0.1
optimizer = optim.SGD([x, y], lr=0.1)
# executing an update step
optimizer.step()
# print the updated values of x and y
print("x:", x)
print("y:", y)
# print result should be:
x: tensor([0.4000], requires_grad=True)
y: tensor([0.8000], requires_grad=True)
optimizer
和 loss
之间的明确联系在哪里?
优化器如何知道在没有调用的情况下从哪里获得损失的梯度optimizer.step(loss)
?
-更多上下文-
当我最小化损失时,我不必将梯度传递给优化器。
loss.backward() # Back Propagation
optimizer.step() # Gardient Descent
无需深入研究 pytorch 的内部结构,我可以提供一个简单的答案:
回想一下,在初始化 optimizer
时,您明确告诉它应该更新模型的哪些参数(张量)。一旦您对损失调用 backward()
,梯度就会由张量本身“存储”(它们具有 grad
and a requires_grad
属性)。在计算模型中所有张量的梯度后,调用 optimizer.step()
使优化器遍历它应该更新的所有参数(张量)并使用它们内部存储的 grad
来更新它们的值。
有关计算图的更多信息和存储在 pytorch 张量中的附加“梯度”信息可在
优化器引用参数有时会导致问题,例如,当模型被移动到 GPU 在 初始化优化器之后。 确保在构建优化器之前完成模型设置。有关详细信息,请参阅 this answer。
当您调用 loss.backward()
时,它所做的只是计算损失梯度 w.r.t 损失中具有 requires_grad = True
的所有参数,并将它们存储在 parameter.grad
属性中每个参数。
optimizer.step()
根据parameter.grad
假设我们定义了一个模型:model
,损失函数:criterion
,我们有以下步骤序列:
pred = model(input)
loss = criterion(pred, true_labels)
loss.backward()
pred
将有一个 grad_fn
属性,该属性引用创建它的函数,并将其绑定回模型。因此,loss.backward()
将获得有关其正在使用的模型的信息。
尝试删除 grad_fn
属性,例如:
pred = pred.clone().detach()
那么模型梯度将为 None
,因此权重将不会更新。
并且优化器与模型相关联,因为我们在创建优化器时传递了 model.parameters()
。
简答:
loss.backward()
# 对我们设置的所有参数做梯度 required_grad= True
。参数可以是代码中定义的任何变量,例如 h2h
或 i2h
.
optimizer.step()
# 根据优化器函数(之前在我们的代码中定义),我们更新这些参数以最终获得最小损失(误差)。
也许这会稍微澄清 loss.backward
和 optim.step
之间的联系(尽管其他答案很重要)。
# Our "model"
x = torch.tensor([1., 2.], requires_grad=True)
y = 100*x
# Compute loss
loss = y.sum()
# Compute gradients of the parameters w.r.t. the loss
print(x.grad) # None
loss.backward()
print(x.grad) # tensor([100., 100.])
# MOdify the parameters by subtracting the gradient
optim = torch.optim.SGD([x], lr=0.001)
print(x) # tensor([1., 2.], requires_grad=True)
optim.step()
print(x) # tensor([0.9000, 1.9000], requires_grad=True)
loss.backward()
设置所有具有 requires_grad=True
的张量的 grad
属性
在损失为叶子的计算图中(在这种情况下只有x
)。
优化器只是遍历它在初始化时收到的参数列表(张量)以及张量具有 requires_grad=True
的任何地方,它减去存储在其 .grad
[=32 中的梯度值=](在 SGD 的情况下简单地乘以学习率)。它不需要知道计算梯度的损失是多少,它只想访问 .grad
属性 所以它可以 x = x - lr * x.grad
注意 如果我们在训练循环中这样做,我们会调用 optim.zero_grad()
因为在每个训练步骤中我们想要计算新的梯度 - 我们不关心前一批的梯度。不将梯度归零会导致批次之间的梯度累积。
有些答案解释的很好,但我想举个具体的例子来解释一下机制。
假设我们有一个函数:z = 3 x^2 + y^3。
zw.r.tx和y的更新梯度公式为:
初始值为 x=1 和 y=2。
x = torch.tensor([1.0], requires_grad=True)
y = torch.tensor([2.0], requires_grad=True)
z = 3*x**2+y**3
print("x.grad: ", x.grad)
print("y.grad: ", y.grad)
print("z.grad: ", z.grad)
# print result should be:
x.grad: None
y.grad: None
z.grad: None
然后计算x和y在当前值(x=1,y=2)中的梯度
# calculate the gradient
z.backward()
print("x.grad: ", x.grad)
print("y.grad: ", y.grad)
print("z.grad: ", z.grad)
# print result should be:
x.grad: tensor([6.])
y.grad: tensor([12.])
z.grad: None
最后,使用SGD优化器根据公式更新x和y的值:
# create an optimizer, pass x,y as the paramaters to be update, setting the learning rate lr=0.1
optimizer = optim.SGD([x, y], lr=0.1)
# executing an update step
optimizer.step()
# print the updated values of x and y
print("x:", x)
print("y:", y)
# print result should be:
x: tensor([0.4000], requires_grad=True)
y: tensor([0.8000], requires_grad=True)