Почему я могу изменить значение тензора, не зная об этом графу вычислений в Pytorch с помощью функции detach? - PullRequest
1 голос
/ 16 июня 2020

Я могу изменить значение тензора, который требует grad, не зная об этом autograd:

def error_unexpected_way_to_by_pass_safety():
    import torch 
    a = torch.tensor([1,2,3.], requires_grad=True)
    # are detached tensor's leafs? yes they are
    a_detached = a.detach()
    #a.fill_(2) # illegal, warns you that a tensor which requires grads is used in an inplace op (so it won't be recorded in computation graph so it wont take the right derivative of the forward path as this op won't be in it)
    a_detached.fill_(2) # weird that this one is allowed, seems to allow me to bypass the error check from the previous comment...?!
    print(f'a = {a}')
    print(f'a_detached = {a_detached}')
    a.sum().backward()

это не вызывает ошибок. Тем не менее, я могу изменить содержимое a, тензора, который требует grad, не зная autograd. Это означает, что граф вычислений не знает об этой операции (заполнение 2). Это кажется неправильным. Может ли кто-нибудь пролить свет на то, что происходит?

Ответы [ 2 ]

3 голосов
/ 16 июня 2020

.detach дает вам представление о тех же данных, поэтому изменение данных отдельного тензора изменяет данные оригинала. Вы можете проверить это так:

a.data_ptr() == a_detached.data_ptr() # True

Что касается почему именно так реализован .detach (в отличие от выполнения защитной копии), это вопрос дизайна, который только Авторы PyTorch знают ответ на. Я предполагаю, что это делается для сохранения ненужных копий, но пользователи должны знать, что они должны сами копировать тензоры, если они хотят изменить отдельные тензоры на месте.

Обратите внимание, что вы также можете изменить не -отделенный тензор, если вы действительно хотите:

a.data.fill_(2)

PyTorch не пытается помешать вам "взломать" автограда; пользователи по-прежнему должны знать, как правильно использовать тензоры, чтобы градиенты отслеживались правильно.

1 голос
/ 16 июня 2020

Добавление к существующему здесь ответу. Причина, по которой detach не копирует данные, определенно состоит в том, чтобы сохранить ненужные копии - если вы хотите получить полную копию, вы всегда можете иметь a.clone().detach() версию a (или a.detach().clone()). Вы можете сделать только один из них (например, просто clone или просто detach), и все они имеют смысл в некоторых ситуациях.

Самая важная причина, по которой можно было бы использовать detach без clone потому что это способ реализовать так называемую операцию «StopGradient» в pytorch (stop_gradient в tf). Представьте себе ситуацию, когда вы хотите использовать тензор a в своей NN дважды таким образом, чтобы градиенты распространялись в одном случае и не распространялись в другом (и никто не ожидал, что никто не изменит тензор на месте).

Что касается clone без detach - это кажется немного необычным, но я видел такие примеры (в основном люди хотели убедиться, что исходный тензор не будет обновляться, но градиенты будут распространяться к нему).

Обычно вам следует избегать изменения тензоров на месте (кроме шагов оптимизатора). В любом случае вам придется проявлять крайнюю осторожность при этом, поскольку это простой способ сделать граф вычислений недействительным по отношению к вычислению градиента.

...