Pytorch:涉及端到端雅可比矩阵范数的自定义损失
我想使用一个修改的损失函数来训练一个网络,该函数既有典型的分类损失(例如,Pytorch:涉及端到端雅可比矩阵范数的自定义损失,pytorch,loss-function,autodiff,Pytorch,Loss Function,Autodiff,我想使用一个修改的损失函数来训练一个网络,该函数既有典型的分类损失(例如,nn.CrossEntropyLoss),也有对端到端雅可比矩阵的Frobenius范数的惩罚(即,如果f(x)是网络的输出,\nabla_x f(x)) 我已经实现了一个模型,可以使用nn.CrossEntropyLoss成功地学习。然而,当我尝试添加第二个损失函数(通过两次向后传球)时,我的训练循环运行,但模型从未学习。此外,如果我计算端到端雅可比矩阵,但不将其包含在损失函数中,那么模型也永远不会学习。在较高级别上,我
nn.CrossEntropyLoss
),也有对端到端雅可比矩阵的Frobenius范数的惩罚(即,如果f(x)是网络的输出,\nabla_x f(x))
我已经实现了一个模型,可以使用nn.CrossEntropyLoss
成功地学习。然而,当我尝试添加第二个损失函数(通过两次向后传球)时,我的训练循环运行,但模型从未学习。此外,如果我计算端到端雅可比矩阵,但不将其包含在损失函数中,那么模型也永远不会学习。在较高级别上,我的代码执行以下操作:
yhat
yhat.backward(火炬式火炬(适当形状),retain\u graph=True)
x.grad.data.norm(2)
loss.backward()
backward()
在运行两次时是如何工作的,但我还没有找到任何好的资源来澄清这一点
生成一个工作示例需要太多,因此我尝试提取相关代码:
def train_model(model, train_dataloader, optimizer, loss_fn, device=None):
if device is None:
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.train()
train_loss = 0
correct = 0
for batch_idx, (batch_input, batch_target) in enumerate(train_dataloader):
batch_input, batch_target = batch_input.to(device), batch_target.to(device)
optimizer.zero_grad()
batch_input.requires_grad_(True)
model_batch_output = model(batch_input)
loss = loss_fn(model_output=model_batch_output, model_input=batch_input, model=model, target=batch_target)
train_loss += loss.item() # sum up batch loss
loss.backward()
optimizer.step()
及
编辑1:我将以前的实现与.backward()
交换为autograd.grad
,它显然有效!有什么区别
def end_to_end_jacobian_loss(model_output, model_input):
jacobian = autograd.grad(
outputs=model_output['penultimate_layer'],
inputs=model_input,
grad_outputs=torch.ones(*model_output['penultimate_layer'].shape),
retain_graph=True,
only_inputs=True)[0]
jacobian_norm = jacobian.norm(2)
return jacobian_norm
def end_to_end_jacobian_loss(model_output, model_input):
jacobian = autograd.grad(
outputs=model_output['penultimate_layer'],
inputs=model_input,
grad_outputs=torch.ones(*model_output['penultimate_layer'].shape),
retain_graph=True,
only_inputs=True)[0]
jacobian_norm = jacobian.norm(2)
return jacobian_norm