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