【问题标题】:Pytorch custom criterion depending on targetPytorch 自定义标准取决于目标
【发布时间】:2022-06-10 20:50:32
【问题描述】:

我正在做一个研究项目,我想根据目标创建自定义损失函数。 IE。我想用BCEWithLogitsLoss 加上一个超参数lambda 来惩罚。如果模型没有正确检测到一个类,我只想添加这个超参数。

更详细地说,我有一个预训练模型,我想重新训练冻结一些层。该模型以一定的概率检测图像中的人脸。如果某些图像被错误地用因子 lambda 分类,我想对它们进行惩罚(假设需要惩罚的图像名称中有特殊字符左右)

来自pytorch的源码:

import torch.nn.modules.loss as l

class CustomBCEWithLogitsLoss(l._Loss):
    def __init__(self, weight: Optional[Tensor] = None, size_average=None, reduce=None, reduction: str = 'mean',
                 pos_weight: Optional[Tensor] = None) -> None:
        super(BCEWithLogitsLoss, self).__init__(size_average, reduce, reduction)
        self.register_buffer('weight', weight)
        self.register_buffer('pos_weight', pos_weight)
        self.weight: Optional[Tensor]
        self.pos_weight: Optional[Tensor]

    def forward(self, input: Tensor, target: Tensor) -> Tensor:
        return F.binary_cross_entropy_with_logits(input, target,
                                                  self.weight,
                                                  pos_weight=self.pos_weight,
                                                  reduction=self.reduction)

这里,forward 有两个张量作为输入,所以我不知道如何在这里添加我想用 lambda 惩罚的图像的类。在构造函数中添加lambda是可以的,但是如果只允许张量,如何进行前向传递?

编辑: 为了澄清这个问题,假设我有一个包含图像的培训/测试文件夹。文件名中带有 @ 字符的文件是我想要正确分类的文件,而不是没有字符的文件,因子为 lambda

我如何以training a model in pytorch 的常规方式判断这些文件必须使用lambda 惩罚(假设损失函数是 lambda * BCEWithLogitLoss),但其他文件不是?我正在使用DataLoader

【问题讨论】:

  • “使用因子 lambda 分类错误”是什么意思
  • @Ivan 给定一个我想正确分类的图像 X_i,如果图像 X_i 属于特殊输入的某个子集(如果它们没有正确预测,我想额外惩罚的那些)应用一个因素lambda(正整数)到binary_cross_entropy_with_logits。否则只申请binary_cross_entropy_with_logitsloss。特殊输入应以某种形式标记,可能在文件名中带有特殊字符。这也是另一个我不知道如何解决的问题。

标签: python pytorch


【解决方案1】:

感谢您的提问。你为什么不做一个自定义的损失函数?你仍然限制自己使用 PyTorch 的功能;也许写下损失的自定义方程,有人会帮忙。 (这不是答案,但我还不能发表评论)

【讨论】:

    【解决方案2】:

    您可以在自定义损失函数的前向函数中添加一个附加参数,以便应用或不应用 pos_weight 值。

    应该这样做:

    class CustomBCEWithLogitsLoss(nn.BCEWithLogitsLoss):
        def __init__(self, weight: Optional[Tensor] = None, size_average=None, reduce=None, reduction: str = 'mean',
                     pos_weight: Optional[Tensor] = None) -> None:
            super(CustomBCEWithLogitsLoss).__init__(weight, size_average, reduction)
            
        def forward(self, input: Tensor, target: Tensor, weight: bool) -> Tensor:
            return F.binary_cross_entropy_with_logits(input, target,
                                                      self.weight,
                                                      pos_weight=self.pos_weight if weight else None,
                                                      reduction=self.reduction)
    

    【讨论】:

    • 但是这个答案并没有解释应该如何处理输入。如果x_i 没有检测到图像中的人脸,如果图像来自子集,我想要一个 lambda 额外惩罚因子。否则,正常处罚。如果图片是datasets.ImageFolder加载的,如何在训练阶段前向传递前进行区分?
    【解决方案3】:

    您在根据训练结果修改动态权重时似乎遇到了问题。我不确定你的公式(lambda 项),让我们采用pytorch document 中的数学公式,我假设你想要:

    l(xi,yi) = lambda * loss(i) if (xi>0.5==yi) else loss(i) # correct class condition

    如果不正确,我认为您可以轻松修改以适应您的项目

    import torch.nn.modules.loss as l
    from typing import Optional
    from torch import Tensor
    from torch.nn import functional as F
    
    class CustomBCEWithLogitsLoss(l._Loss):
        def __init__(self, alpha: float, weight: Optional[Tensor] = None, size_average=None, reduce=None, reduction: str = 'mean',
                     pos_weight: Optional[Tensor] = None) -> None:
            super(CustomBCEWithLogitsLoss, self).__init__(size_average, reduce, reduction)
            self.register_buffer('weight', weight)
            self.register_buffer('pos_weight', pos_weight)
    #         self.weight: Optional[Tensor]
            self.pos_weight: Optional[Tensor]
            
            self.alpha = alpha # replace lambda by alpha to avoid the unwanted bug with lambda function
            
        def forward(self, input: Tensor, target: Tensor) -> Tensor:
            reg = torch.ones_like(target, dtype=torch.float32)
            pred = input.ge(0.5).int()
            mask = pred == target
            reg[~mask] *= self.alpha # only apply to correct class
            return F.binary_cross_entropy_with_logits(input, target,
                                                      weight = reg, # replace weight by alpha
                                                      pos_weight=self.pos_weight,
                                                      reduction=self.reduction)
    

    【讨论】:

    • 不完全一样,请查看编辑
    【解决方案4】:

    应该可以使用 your_loader.dataset.samples[i] 元组访问文件名(假设在训练循环中使用 for i, (images, labels) in enumerate(your_loader)shuffle=False)并根据它乘以 lambda 损失,批量大小为 1 你甚至不需要自定义损失函数。

    理想的解决方案可能需要自定义 Dataset 继承自 ImageFolder 以返回 __getitem__() 中的附加功能并进一步传递。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多