Элемент мудрого расчета ломает автоград - PullRequest
0 голосов
/ 06 февраля 2019

Я использую Pytorch для расчета потерь для логистической регрессии (я знаю, Pytorch может сделать это автоматически, но я должен сделать это сам).Моя функция определена ниже, но приведение к torch.tensor нарушает autograd и дает мне w.grad = None.Я новичок в pytorch, поэтому мне жаль

logistic_loss = lambda X,y,w: torch.tensor([torch.log(1 + torch.exp(-y[i] * torch.matmul(w, X[i,:]))) for i in range(X.shape[0])], requires_grad=True)

1 Ответ

0 голосов
/ 06 февраля 2019

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

import torch

# unroll the one-liner to have an easier time understanding what's going on
def logistic_loss(X, y, w):
    elementwise = []
    for i in range(X.shape[0]):
        mm = torch.matmul(w, X[i, :])
        exp = torch.exp(-y[i] * mm)
        elementwise.append(torch.log(1 + exp))

    return torch.tensor(elementwise, requires_grad=True)

# I assume that's the excepted dimensions of your input
X = torch.randn(5, 30, requires_grad=True)
y = torch.randn(5)
w = torch.randn(30)

# I assume you backpropagate from a reduced version
# of your sum, because you can't call .backward on multi-dimensional
# tensors
loss = logistic_loss(X, y, w).mean()
loss.mean().backward()
print(X.grad)

Самое простое решение вашей проблемы - заменить torch.tensor(elementwise, requires_grad=True) на torch.stack(elementwise).Вы можете думать о torch.tensor как о конструкторе для совершенно новых тензоров, если ваш тензор является в большей степени результатом некоторого математического выражения, вы должны использовать такие операции, как torch.stack или torch.cat.

.этот код все еще крайне неэффективен, потому что вы делаете зацикливание вручную i.Вместо этого вы могли бы просто написать

def logistic_loss_vectorized(X, y, w):
    mm = torch.matmul(X, w)
    exp = torch.exp(-y * mm)

    return torch.log(1 + exp)

, который математически эквивалентен, но на практике будет на намного быстрее, потому что он обеспечивает лучшее распараллеливание из-за отсутствия явного зацикливания.

Обратите внимание, что с этим кодом по-прежнему существует числовая проблема - вы берете логарифм экспоненты, но промежуточный результат, называемый exp, может достичь очень высоких значений, что приведет к потере точности.Для этого есть обходные пути, поэтому функции потери, предоставляемые PyTorch, предпочтительнее.

...