简体   繁体   English

我在 Pytorch 中的自定义损失函数无法训练

[英]My custom loss function in Pytorch does not train

My custom loss function in Pytorch does not update during training.我在 Pytorch 中的自定义损失函数在训练期间没有更新。 The loss stays exactly the same.损失保持完全相同。 I am trying to write this custom loss function based on the false positive and negative rates.我正在尝试根据误报率和负率编写这个自定义损失函数。 I am giving you a simplified version of the code.我给你一个简化版的代码。 Any idea what could be happening?知道会发生什么吗? Does the backpropagation turns to 0?反向传播是否变为 0? Is this not the correct way of defining a custom loss function?这不是定义自定义损失函数的正确方法吗?

I have already checked that during backpropagation the Gradient always stays TRUE (assert requires_grad).我已经检查过,在反向传播过程中,梯度始终保持为 TRUE(断言 requires_grad)。 I have also tried to make a class (torch.nn.module) of the function false_pos_neg_rate, but that did not work.我还尝试创建函数 false_pos_neg_rate 的类 (torch.nn.module),但这不起作用。 The Assert Requires_grad turned out to be negative and I left it out afterwards. Assert Requires_grad 结果是否定的,后来我把它省略了。 There is no error, the training does continue.没有错误,训练会继续。

def false_pos_neg_rate(outputs, truths):
    y = truths
    y_predicted = outputs
    cut_off= torch.tensor(0.5, requires_grad=True)
    y_predicted =torch.where(y_predicted <= cut_off, zeros, ones)
    tp, fp, tn, fn = confusion_matrix(y_predicted, y)
    fp_rate = fp / (fp+tn).float()
    fn_rate = fn / (fn+tp).float()
    loss = fn_rate + fp_rate
    return loss

for i, (samples, truths) in enumerate(train_loader):
    samples = Variable(samples)
    truths = Variable(truths)    
    outputs = model(samples) 
    loss = false_pos_neg_rate_torch(outputs, truths)
    loss.backward()                  
    optimizer.step()

I expect the loss function to update the model and be smaller every training step.我希望损失函数更新模型并在每个训练步骤中变小。 Instead the loss stays exactly the same and nothing happens.相反,损失保持完全相同,什么也没有发生。

Please help me, what happens?请帮帮我,会发生什么? Why does the model not train during training steps?为什么模型在训练步骤中没有训练?

As pointed out by Umang Gupta your loss function is not differentiable.正如Umang Gupta所指出的,您的损失函数是不可微的。 If you write, mathematically, what you are trying to do you'll see that your loss has zero gradient almost everywhere and it behaves like a "step function".如果你从数学上写出你想要做的事情,你会发现你的损失几乎到处都是零梯度,它的行为就像一个“阶跃函数”。
In order to train models using gradient-descent methods you must have meaningful gradients for the loss function.为了使用梯度下降方法训练模型,您必须为损失函数设置有意义的梯度。

Based on your tips, I updated my Loss Function.根据您的提示,我更新了我的损失函数。 I made a dummy so you can check the first 2 functions as well.我做了一个假人,所以你也可以检查前两个功能。 I added the rest, so you can see how it is implemented.我添加了其余的,所以你可以看到它是如何实现的。 However, still somewhere the gradient turns out to be zero.然而,仍然在某处梯度结果为零。 What is now the step where the gradient turns zero, or how can I check this?现在梯度变为零的步骤是什么,或者我该如何检查? Please I would like to know how I can fix this :).请我想知道如何解决这个问题:)。

I tried providing you with more information so you can play around as well, but if you miss anything please do let me know!我尝试为您提供更多信息,以便您也可以玩耍,但如果您错过任何内容,请告诉我!

y = Variable(torch.tensor((0, 0, 0, 1, 1,1), dtype=torch.float), requires_grad = True)
y_pred = Variable(torch.tensor((0.333, 0.2, 0.01, 0.99, 0.49, 0.51), dtype=torch.float), requires_grad = True)

def binary_y_pred(y_pred):
    y_pred.register_hook(lambda grad: print(grad))
    y_pred = y_pred+torch.tensor(0.5, requires_grad=True, dtype=torch.float)
    y_pred = y_pred.pow(5)  # this is my way working around using torch.where() 
    y_pred = y_pred.pow(10)
    y_pred = y_pred.pow(15)
    m = nn.Sigmoid()
    y_pred = m(y_pred)
    y_pred = y_pred-torch.tensor(0.5, requires_grad=True, dtype=torch.float)
    y_pred = y_pred*2
    y_pred.register_hook(lambda grad: print(grad))
    return y_pred

def confusion_matrix(y_pred, y):
    TP = torch.sum(y*y_pred)
    TN = torch.sum((1-y)*(1-y_pred))
    FP = torch.sum((1-y)*y_pred)
    FN = torch.sum(y*(1-y_pred))

    k_eps = torch.tensor(1e-12, requires_grad=True, dtype=torch.float)
    FN_rate = FN/(TP + FN + k_eps)
    FP_rate = FP/(TN + FP + k_eps)
    cost = FN_rate + FP_rate
    return cost

class FeedforwardNeuralNetModel(nn.Module):
    def __init__(self, input_dim, hidden_dim, output_dim):
        super(FeedforwardNeuralNetModel, self).__init__()
        self.fc1 = nn.Linear(input_dim, hidden_dim) 
        self.relu1 = nn.ReLU()
        self.fc2 = nn.Linear(hidden_dim, output_dim)
        self.sigmoid = nn.Sigmoid()

     def forward(self, x):
        out = self.fc1(x)
        out = self.relu1(out)
        out = self.fc2(out)
        out = self.sigmoid(out)
        return out

model = FeedforwardNeuralNetModel(input_dim, hidden_dim, output_dim)

optimizer = torch.optim.Adam(model.parameters(), lr=0.0001, betas=[0.9, 0.99], amsgrad=True)
criterion = torch.nn.BCELoss(weight=None, size_average=None, reduce=None, reduction='mean')


    samples= Variable(samples)
    truths = Variable(truths)    
    outputs = model(samples) 
    loss = confusion_matrix(outputs, truths)
    loss.backward()                  
    optimizer.step()

derive your loss as class from torch.autograd.Function and write your own backward() function. 从torch.autograd.Function派生您的损失作为类,并编写您自己的forward()函数。

the following link can help you 以下链接可以为您提供帮助

https://pytorch.org/docs/master/notes/extending.html https://pytorch.org/docs/master/notes/extending.html

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM