Пользовательская функция потери в PyTorch

у меня есть три простых вопроса.

  1. что произойдет, если моя пользовательская функция потери не дифференцируема? Будет ли pytorch по ошибке или что-то еще?
  2. если я объявляю переменную потерь в своей пользовательской функции, которая будет представлять окончательную потерю модели, я должен поставить requires_grad = True для этой переменной? или это не имеет значения? Если это не имеет значения, то почему?
  3. Я видел, как люди иногда пишут отдельный слой и вычисляют потерю в

1 ответов


Дайте мне попробовать.

  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() метод соответствующей деятельности сразу.

  2. это не важно. Использование requires_gradчтобы избежать ненужных вычислений градиентов для подгр. Если есть один вход для операции, требующей градиента, его выход также потребует градиента. И наоборот, только если все входы не требуют градиента, выход также не требовать этого. Обратное вычисление никогда не выполняется в подграфах, где все переменные не требуют градиентов.

    поскольку, скорее всего, есть некоторые Variables (например, параметры подкласса nn.Module()), код loss переменная также потребует градиентов автоматически. Однако, следует заметить, что именно как requires_grad работает (см. выше снова), вы можете изменить только requires_grad для листовых переменных вашего графика в любом случае.

  3. все пользовательские функции потери PyTorch являются подклассами _Loss который является подклассом nn.Module. см. здесь. если вы хотите придерживаться этого соглашения, вы должны подкласс _Loss при определении пользовательской функции потерь. Помимо согласованности, одним из преимуществ является то, что ваш подкласс поднимет AssertionError, если вы не отметили целевые переменные как volatile или requires_grad = False. Еще одно преимущество заключается в том, что вы можете вложить свою функцию потерь в nn.Sequential(), потому что nn.Module I по этим причинам рекомендовал бы использовать такой подход.