如何训练一个模型,损失由pytorch中的另一个模型计算?
How to train a model with loss calculated by another model in pytorch?
有两个模型A和B,模型A输出一个城市所有站点的自行车投放计划,模型B以此计划为输入,给出每个站点的评价。
现在模型B已经预训练好了,我想用模型B给出的评价作为loss来优化模型A的参数
这里是示例代码。
A = modelA()
B = modelB()
optimizer = torch.optim.Adam(A.parameters())
def my_loss(deploy):
shape = deploy.size()
state = torch.zeros((shape[0], shape[1], 2 + shape[1]), dtype=torch.long)
# Notice: this step will copy deploy
state[:, :, 2:] = torch.reshape(deploy, (shape[0], 1, shape[1]))
state[:, :, 0] = torch.arange(0, shape[1])
state = torch.reshape(state, (-1, 2 + shape[1]))
eval = B(state)
eval = torch.reshape(eval, (shape[0], shape[1]))
return torch.mean(eval)
# Train model A
for epoch in range(EPOCHS):
for batch_idx, (x, useless_y) in enumerate(dataloader):
optimizer.zero_gard()
pred = A(x)
loss = my_loss(pred)
loss.backward()
optimizer.step()
但实际上,在训练过程中,没有任何反应,模型A的参数并没有更新。
我也试过了
optimizer = torch.optim.Adam([{'params': A.parameters()}, {'params': B.parameters(), 'lr':0}])
也没有任何反应。
有什么想法吗?
你A
的参数没有update是因为loss
,我的my_loss
的结果没有附在计算图上, 即 到模型 A
的输出。如果你看一下你的实现,情况显然是这样的:
state = torch.reshape(state_tensors, (-1, 2 + shape[1]))
eval = B(state)
eval = torch.reshape(eval, (shape[0], shape[1]))
变量 state
是从 state_tensors
定义的,而您的示例中没有定义它,因此它要么是拼写错误,要么是从 state
定义的。无论如何,生成的张量 my_loss
输出应该附加一个 grad_fn
。请确保是这种情况。这里的最后一个操作是一个平均值,所以你必须有这样的东西:
>>> my_loss(loss)
tensor(0.7742, grad_fn=<MeanBackward0>)
修复此问题后,您的梯度应该能够反向传播到模型 A
的参数。
计算图在state
处被截断,因此损失不会反向传播到A。
尝试;
state = torch.zeros((shape[0], shape[1], 2 + shape[1]), dtype=torch.long)
->
state = torch.zeros((shape[0], shape[1], 2 + shape[1]), requires_grad=True) # add requires_grad=True, dtype=torch.long may throw error
但是,我仍然认为它不适用于您的代码。
可选建议;
- 我认为
state_tensors
没有定义。
- 就地操作
state[:, :, 2:] =
可能不好。 (在我的例子中,这个抛出错误)要复制张量,.expand()
或 .repeat()
,
并扩展 dim,.unsqueeze()
可能有助于避免这种情况。
有两个模型A和B,模型A输出一个城市所有站点的自行车投放计划,模型B以此计划为输入,给出每个站点的评价。
现在模型B已经预训练好了,我想用模型B给出的评价作为loss来优化模型A的参数
这里是示例代码。
A = modelA()
B = modelB()
optimizer = torch.optim.Adam(A.parameters())
def my_loss(deploy):
shape = deploy.size()
state = torch.zeros((shape[0], shape[1], 2 + shape[1]), dtype=torch.long)
# Notice: this step will copy deploy
state[:, :, 2:] = torch.reshape(deploy, (shape[0], 1, shape[1]))
state[:, :, 0] = torch.arange(0, shape[1])
state = torch.reshape(state, (-1, 2 + shape[1]))
eval = B(state)
eval = torch.reshape(eval, (shape[0], shape[1]))
return torch.mean(eval)
# Train model A
for epoch in range(EPOCHS):
for batch_idx, (x, useless_y) in enumerate(dataloader):
optimizer.zero_gard()
pred = A(x)
loss = my_loss(pred)
loss.backward()
optimizer.step()
但实际上,在训练过程中,没有任何反应,模型A的参数并没有更新。 我也试过了
optimizer = torch.optim.Adam([{'params': A.parameters()}, {'params': B.parameters(), 'lr':0}])
也没有任何反应。
有什么想法吗?
你A
的参数没有update是因为loss
,我的my_loss
的结果没有附在计算图上, 即 到模型 A
的输出。如果你看一下你的实现,情况显然是这样的:
state = torch.reshape(state_tensors, (-1, 2 + shape[1]))
eval = B(state)
eval = torch.reshape(eval, (shape[0], shape[1]))
变量 state
是从 state_tensors
定义的,而您的示例中没有定义它,因此它要么是拼写错误,要么是从 state
定义的。无论如何,生成的张量 my_loss
输出应该附加一个 grad_fn
。请确保是这种情况。这里的最后一个操作是一个平均值,所以你必须有这样的东西:
>>> my_loss(loss)
tensor(0.7742, grad_fn=<MeanBackward0>)
修复此问题后,您的梯度应该能够反向传播到模型 A
的参数。
计算图在state
处被截断,因此损失不会反向传播到A。
尝试;
state = torch.zeros((shape[0], shape[1], 2 + shape[1]), dtype=torch.long)
->
state = torch.zeros((shape[0], shape[1], 2 + shape[1]), requires_grad=True) # add requires_grad=True, dtype=torch.long may throw error
但是,我仍然认为它不适用于您的代码。 可选建议;
- 我认为
state_tensors
没有定义。 - 就地操作
state[:, :, 2:] =
可能不好。 (在我的例子中,这个抛出错误)要复制张量,.expand()
或.repeat()
, 并扩展 dim,.unsqueeze()
可能有助于避免这种情况。