Это происходит потому, что .to
возвращает новый тензор, не являющийся листовым. Вы должны установить requires_grad
после перехода на желаемое устройство. Кроме того, интерфейс Variable
устарел уже давно, еще до появления pytorch 1.0. Он ничего не делает (за исключением того, что в этом случае действует как слишком сложный способ установки requires_grad
).
Рассмотрим
W1 = Variable(torch.randn(embedding_dims, vocabulary_size).float(), requires_grad=True).to(device)
Проблема в том, что есть два разных тензора . Разбив его, мы могли бы переписать то, что вы делаете, как
W1a = Variable(torch.randn(embedding_dims, vocabulary_size).float(), requires_grad=True)
W1 = W1a.to(device)
Обратите внимание, что W1a
требует градиента, но W1
происходит от W1a
, поэтому он не считается листовым тензором, поэтому атрибут .grad
для W1a
будет обновлен, а W1
- нет. В вашем коде у вас больше нет прямой ссылки на W1a
, поэтому у вас не будет доступа к градиентам.
Вместо этого вы можете сделать
W1 = torch.randn(embedding_dims, vocabulary_size).float().to(device)
W1.required_grad_(True)
, который правильно установит W1
быть листовым тензором после передачи на другое устройство.
Обратите внимание, что для вашего случая c мы также могли бы просто использовать аргументы device
, dtype
и requires_grad
для torch.randn
и просто сделать
W1 = torch.randn(embedding_dims, vocabulary_size, dtype=torch.float, device=device, requires_grad=True)
Большинство Функции pytorch, которые инициализируют новые тензоры, поддерживают эти три аргумента, которые могут помочь избежать проблем, с которыми вы столкнулись.
Чтобы ответить на дополнительный вопрос OP в комментариях:
Есть ли хорошее место, которое я бы нашел в документации?
AFAIK, документация не решает конкретно эту проблему. Это своего рода комбинация того, как работают переменные в python и как работает механика автограда в pytorch.
Предполагая, что вы хорошо разбираетесь в переменных в python, вы можете прийти к выводам из этого ответа самостоятельно, при первом чтении Tensor.is_leaf
, в частности
, они будут листовыми тензорами, если они были созданы пользователем. Это означает, что они не являются результатом операции , поэтому grad_fn
равно Нет.
И, кроме того, документация для Tensor.to
, в которой говорится
Если тензор self
уже имеет правильные torch.dtype
и torch.device
, то возвращается self
. В противном случае возвращаемый тензор является копией self
с желаемыми torch.dtype
и torch.device
.
Поскольку Tensor.to
возвращает копию, а копия операции, то из документации должно быть ясно, что тензор W1
в исходном коде не является тензорным листом.