Зачем нам нужно клонировать grad_output и назначать его grad_input при определении функции автоградации ReLU?

Я просматриваю автоградную часть учебников по pytorch. У меня есть два вопроса:

  1. Зачем нам нужно клонировать grad_output и назначать его grad_input, кроме простого назначения во время обратного распространения?
  2. Какова цель grad_input[input < 0] = 0? Означает ли это, что мы не обновляем градиент, когда ввод меньше нуля?

Вот код:

class MyReLU(torch.autograd.Function):
    @staticmethod
    def forward(ctx, input):
        """
        In the forward pass we receive a Tensor containing the input and return
        a Tensor containing the output. ctx is a context object that can be used
        to stash information for backward computation. You can cache arbitrary
        objects for use in the backward pass using the ctx.save_for_backward method.
        """
        ctx.save_for_backward(input)
        return input.clamp(min=0)

    @staticmethod
    def backward(ctx, grad_output):
        """
        In the backward pass we receive a Tensor containing the gradient of the loss
        with respect to the output, and we need to compute the gradient of the loss
        with respect to the input.
        """
        input, = ctx.saved_tensors
        grad_input = grad_output.clone()
        grad_input[input < 0] = 0
        return grad_input

Ссылка здесь: https://pytorch.org/tutorials/beginner/pytorch_with_examples.html#pytorch-defining-new-autograd-functions

Заранее большое спасибо.


person Hoodythree    schedule 29.03.2020    source источник


Ответы (1)


Зачем нам нужно клонировать grad_output и назначать его grad_input, кроме простого назначения во время обратного распространения?

tensor.clone() создает копию тензора, который имитирует поле requires_grad исходного тензора. clone — это способ скопировать тензор, сохраняя при этом копию как часть вычислительного графа, из которого он был получен.

Итак, grad_input является частью того же графа вычислений, что и grad_output, и если мы вычислим градиент для grad_output, то то же самое будет сделано и для grad_input.

Так как мы вносим изменения в grad_input, сначала клонируем его.

Какова цель 'grad_input[input ‹ 0] = 0'? Означает ли это, что мы не обновляем градиент, когда ввод меньше нуля?

Это делается в соответствии с определением функции ReLU. Функция ReLU — f(x)=max(0,x). Это означает, что если x<=0, то f(x)=0, иначе f(x)=x. В первом случае, когда x<0, производная от f(x) по отношению к x равна f'(x)=0. Итак, выполняем grad_input[input < 0] = 0. Во втором случае это f'(x)=1, поэтому мы просто передаем grad_output в grad_input (работает как открытые ворота).

person Wasi Ahmad    schedule 29.03.2020
comment
Спасибо за ответ, вы мне очень помогли! - person Hoodythree; 29.03.2020
comment
В чем причина не делать просто return grad_output.clamp(min=0) или return F.relu(grad_output)? Является ли метод клонирования более эффективным? - person Thomas Ahle; 15.03.2021