PyTorch 解决方案
嗯,实际上我已经浏览了文档,您确实可以简单地使用 pos_weight。
这个参数赋予每个类的正样本权重,因此如果你有 270 类,你应该传递 torch.Tensor 形状 (270,) 定义每个类的权重。
这里是从documentation略微修改的sn-p:
# 270 classes, batch size = 64
target = torch.ones([64, 270], dtype=torch.float32)
# Logits outputted from your network, no activation
output = torch.full([64, 270], 0.9)
# Weights, each being equal to one. You can input your own here.
pos_weight = torch.ones([270])
criterion = torch.nn.BCEWithLogitsLoss(pos_weight=pos_weight)
criterion(output, target) # -log(sigmoid(0.9))
自制解决方案
在权重方面,没有内置的解决方案,但您可以很容易地自己编写一个解决方案:
import torch
class WeightedMultilabel(torch.nn.Module):
def __init__(self, weights: torch.Tensor):
self.loss = torch.nn.BCEWithLogitsLoss()
self.weights = weights.unsqueeze()
def forward(outputs, targets):
return self.loss(outputs, targets) * self.weights
Tensor 的长度必须与多标签分类中的类别数 (270) 相同,每个类别都为您的具体示例赋予权重。
计算权重
您只需添加数据集中每个样本的标签,除以最小值并在最后取反。
sn-p 之类的:
weights = torch.zeros_like(dataset[0])
for element in dataset:
weights += element
weights = 1 / (weights / torch.min(weights))
使用这种方法,出现最少的类会产生正常损失,而其他类的权重会小于1。
但它可能会在训练期间导致一些不稳定,因此您可能想稍微尝试一下这些值(也许log 变换而不是线性?)
其他方法
您可能会考虑上采样/下采样(尽管此操作很复杂,因为您还会添加/删除其他类,因此我认为需要高级启发式)。