Пользовательская функция потери в PyTorch
у меня есть три простых вопроса.
- что произойдет, если моя пользовательская функция потери не дифференцируема? Будет ли pytorch по ошибке или что-то еще?
- если я объявляю переменную потерь в своей пользовательской функции, которая будет представлять окончательную потерю модели, я должен поставить
requires_grad = True
для этой переменной? или это не имеет значения? Если это не имеет значения, то почему? - Я видел, как люди иногда пишут отдельный слой и вычисляют потерю в
1 ответов
Дайте мне попробовать.
-
это зависит от того, что вы подразумеваете под "недифференцируемой". Первое определение, которое имеет смысл здесь, заключается в том, что PyTorch не знает, как вычислять градиенты. Если вы все же попытаетесь вычислить градиенты, это вызовет ошибку. Возможны два сценария:
a) вы используете пользовательскую операцию PyTorch, для которой градиенты не были реализованы, например
torch.svd()
. В этом случае вы получитеTypeError
:import torch from torch.autograd import Function from torch.autograd import Variable A = Variable(torch.randn(10,10), requires_grad=True) u, s, v = torch.svd(A) # raises TypeError
b) вы реализовали свою собственную операцию, но не определили
backward()
. В этом случае, вы получитеNotImplementedError
:class my_function(Function): # forgot to define backward() def forward(self, x): return 2 * x A = Variable(torch.randn(10,10)) B = my_function()(A) C = torch.sum(B) C.backward() # will raise NotImplementedError
второе определение, которое имеет смысл, является "математически недифференцируемым". Ясно, что операция, которая математически не дифференцируема, также не должна иметь
backward()
способ реализован или разумный суб-градиент. Рассмотрим, например,torch.abs()
чейbackward()
метод возвращает субградиент 0 при 0:A = Variable(torch.Tensor([-1,0,1]),requires_grad=True) B = torch.abs(A) B.backward(torch.Tensor([1,1,1])) A.grad.data
для этих случаев, вы должны обратиться к документации PyTorch непосредственно и выкопать
backward()
метод соответствующей деятельности сразу. -
это не важно. Использование
requires_grad
чтобы избежать ненужных вычислений градиентов для подгр. Если есть один вход для операции, требующей градиента, его выход также потребует градиента. И наоборот, только если все входы не требуют градиента, выход также не требовать этого. Обратное вычисление никогда не выполняется в подграфах, где все переменные не требуют градиентов.поскольку, скорее всего, есть некоторые
Variables
(например, параметры подклассаnn.Module()
), кодloss
переменная также потребует градиентов автоматически. Однако, следует заметить, что именно какrequires_grad
работает (см. выше снова), вы можете изменить толькоrequires_grad
для листовых переменных вашего графика в любом случае. все пользовательские функции потери PyTorch являются подклассами
_Loss
который является подклассомnn.Module
. см. здесь. если вы хотите придерживаться этого соглашения, вы должны подкласс_Loss
при определении пользовательской функции потерь. Помимо согласованности, одним из преимуществ является то, что ваш подкласс подниметAssertionError
, если вы не отметили целевые переменные какvolatile
илиrequires_grad = False
. Еще одно преимущество заключается в том, что вы можете вложить свою функцию потерь вnn.Sequential()
, потому чтоnn.Module
I по этим причинам рекомендовал бы использовать такой подход.