如何在pytorch中使用自定义丢失的反向传播?

时间:2018-08-28 13:43:54

标签: python machine-learning conv-neural-network pytorch backpropagation

我正在尝试使用两个图像之间的排名损失实现连体网络。如果我定义自己的损失,是否可以按以下步骤进行反向传播步骤?当我运行它时,有时在我看来,它所提供的结果与单个网络所提供的结果相同。

with torch.set_grad_enabled(phase == 'train'):
    outputs1 = model(inputs1)
    outputs2 = model(inputs2)
    preds1 = outputs1;
    preds2 = outputs2;

    alpha = 0.02;
    w_r = torch.tensor(1).cuda(async=True);

    y_i, y_j, predy_i, predy_j = labels1,labels2,outputs1,outputs2;
    batchRankLoss =  torch.tensor([max(0,alpha - delta(y_i[i], y_j[i])*predy_i[i] - predy_j[i])) for i in range(batchSize)],dtype = torch.float)
    rankLossPrev = torch.mean(batchRankLoss)                                             
    rankLoss = Variable(rankLossPrev,requires_grad=True)

    loss1 = criterion(outputs1, labels1)
    loss2 = criterion(outputs2, labels2)


    #total loss = loss1 + loss2 + w_r*rankLoss
    totalLoss = torch.add(loss1,loss2)
    w_r = w_r.type(torch.LongTensor)
    rankLossPrev = rankLossPrev.type(torch.LongTensor)
    mult = torch.mul(w_r.type(torch.LongTensor),rankLossPrev).type(torch.FloatTensor)
    totalLoss = torch.add(totalLoss,mult.cuda(async = True));

     # backward + optimize only if in training phase
         if phase == 'train':
            totalLoss.backward()
            optimizer.step()

            running_loss += totalLoss.item() * inputs1.size(0)

2 个答案:

答案 0 :(得分:1)

您需要在几行代码中从构造函数或强制转换为另一种数据类型的位置生成新的张量。执行此操作时,您断开了希望通过backwards()命令进行区分的操作链。

此强制转换会断开图形连接,因为强制转换是不可微的:

w_r = w_r.type(torch.LongTensor)

从构造函数构建张量将断开图形:

batchRankLoss = torch.tensor([max(0,alpha - delta(y_i[i], y_j[i])*predy_i[i] - predy_j[i])) for i in range(batchSize)],dtype = torch.float)

在文档中,将张量包装在变量中会将grad_fn设置为“无”(也会断开图形连接):

rankLoss = Variable(rankLossPrev,requires_grad=True)

假设您的critereon函数是可微的,则当前渐变仅通过loss1loss2向后流动。您的其他渐变只会流到mult,然后再通过调用type()停止。这与您的观察结果相符,即您的自定义损失不会更改神经网络的输出。

要允许梯度在您的自定义损失中向后流动,您必须编码相同的逻辑,同时避免进行type()强制转换,并在不使用列表推导的情况下计算rankLoss

答案 1 :(得分:0)

   rank_loss = torch.mean([torch.max(0,alpha - delta(y_i[i], y_j[i])*predy_i[i] - predy_j[i])) for i in range(batchSize)], dim=0)
   w_r = 1.0
   loss1 = criterion(outputs1, labels1)
   loss2 = criterion(outputs2, labels2)
   total_loss = loss1 + loss2 + w_r  * rank_loss 
   if phase == 'train':
       total_loss .backward()
       optimizer.step()

您不必一遍又一遍地创建张量。如果每种损失的权重都不同,并且权重只是常数,则可以简单地写:

total_loss = weight_1 * loss1 + weight_2 * loss2 + weight_3  * rank_loss

无论如何,这是不可训练的常量,创建A变量并将require_grad设置为True是没有意义的,因为权重只是常量。 请升级到pytorch 0.4.1,在其中不必用Variable包裹所有内容