python - 如何在pytorch中使用带有自定义损失的反向传播?
问题描述
我正在尝试在两个图像之间实现一个排名损失的连体网络。如果我定义自己的损失,我可以按如下方式执行反向传播步骤吗?当我运行它时,有时在我看来它给出的结果与单个网络给出的结果相同。
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)
解决方案
您有几行代码可以从构造函数或转换为另一种数据类型生成新的张量。当你这样做时,你断开了你希望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 设置为 None (也断开图表):
rankLoss = Variable(rankLossPrev,requires_grad=True)
假设您的critereon
函数是可微的,那么梯度当前仅通过loss1
和向后流动loss2
。您的其他渐变只会mult
在调用type()
. 这与您的观察一致,即您的自定义损失不会改变您的神经网络的输出。
为了让梯度在您的自定义损失中反向流动,您必须编写相同的逻辑,同时避免type()
强制转换并rankLoss
在不使用列表推导的情况下进行计算。
推荐阅读
- asp.net-mvc - MVC 将捕获的网络摄像头图像保存到数据库
- sql - 在查询中完全按月分组?
- git - How to push work to my own private repo while still pulling updates from Github?
- go - 如何使用 Protobuf 的时间戳库和 Go 的时间库
- dart - 如何将 RevealedOffset 转换为颤振飞镖中的数字
- linux - 发生上游错误时如何从标准输入回滚 Vertica 副本?
- forms - 单击时如何更改动态单选按钮样式
- r - 取出适合图案的部分字符串
- c# - 使用 C# getter 属性重复反序列化
- elasticsearch - ElasticSearch 配置文件 API `time_in_nanoseconds` 值高于 `took` 时间