我正在尝试实现一个Siamese网络,两个图像之间的排名损失。如果我定义自己的损失,我可以按如下方式进行反向传播步骤吗?当我运行它时,在我看来,它给出了与单个网络相同的结果。
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)
您有几行可以从构造函数生成新的Tensors,或者从另一种数据类型生成强制转换。执行此操作时,断开您希望通过backwards()
命令区分的操作链。
此转换会断开图形,因为转换是不可微分的:
w_r = w_r.type(torch.LongTensor)
从构造函数构建Tensor将断开图形:
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)
从文档中,将Tensor包装在变量中会将grad_fn设置为None(也会断开图形):
rankLoss = Variable(rankLossPrev,requires_grad=True)
假设你的critereon
函数是可微分的,那么渐变目前只能通过loss1
和loss2
向后流动。你的其他渐变只会在他们被mult
召唤停止之前流到type()
。这与您的观察结果一致,即您的自定义丢失不会改变神经网络的输出。
要允许渐变向后流过自定义丢失,您必须编写相同的逻辑,同时避免使用type()
强制转换并计算rankLoss
而不使用列表推导。
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变量并将requires_grad设置为True是没有意义的,因为权重只是常量。请升级到pytorch 0.4.1,其中您不必使用Variable包装所有内容