Моя кастомная функция потерь в Pytorch не тренируется - PullRequest
0 голосов
/ 01 июля 2019

Моя функция потери в Pytorch не обновляется во время тренировки.Потеря остается точно такой же.Я пытаюсь написать эту пользовательскую функцию потерь, основанную на ложных положительных и отрицательных ставках.Я даю вам упрощенную версию кода.Есть идеи, что может случиться?Возвращается ли обратное распространение на 0?Разве это не правильный способ определения пользовательской функции потерь?

Я уже проверял, что во время обратного распространения градиент всегда остается TRUE (assert require_grad).Я также попытался создать класс (torch.nn.module) для функции false_pos_neg_rate, но это не сработало.Assert require_grad оказался отрицательным, и впоследствии я его пропустил.Ошибок нет, обучение продолжается.

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()

Я ожидаю, что функция потерь будет обновлять модель и уменьшаться с каждым шагом обучения.Вместо этого потеря остается точно такой же, и ничего не происходит.

Пожалуйста, помогите мне, что происходит?Почему модель не тренируется во время тренировочных шагов?

Ответы [ 2 ]

0 голосов
/ 03 июля 2019

На основании ваших советов я обновил свою функцию потери. Я сделал манекен, чтобы вы также могли проверить первые две функции. Я добавил остальное, чтобы вы могли видеть, как это реализовано. Однако все же где-то градиент оказывается равным нулю. Какой сейчас шаг, когда градиент обнуляется или как это проверить? Пожалуйста, я хотел бы знать, как я могу это исправить:).

Я пытался предоставить вам больше информации, чтобы вы тоже могли поиграть, но если вы что-то упустили, пожалуйста, дайте мне знать!

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()
0 голосов
/ 02 июля 2019

Как указывает Уманг Гупта ваша функция потери не дифференцируема. Если вы математически напишите, что вы пытаетесь сделать, вы увидите, что у вашей потери почти нулевой градиент, и она ведет себя как «ступенчатая функция».
Чтобы обучать модели с использованием методов градиентного спуска, вы должны иметь значимые градиенты для функции потерь.

...