Пользовательская функция потери в 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 TypeErrorb) вы реализовали свою собственную операцию, но не определили
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.ModuleI по этим причинам рекомендовал бы использовать такой подход.