Тензорным значениям рассчитывают свои градиенты, если они
- Имеют
requires_grad == True
- Используются для вычисления некоторого значения (обычно потери), для которого вы вызываете
.backward()
.
Затем градиенты будут накапливаться в их параметре .grad
.Вы можете использовать их вручную для выполнения произвольных вычислений (включая оптимизацию).Предопределенные оптимизаторы принимают итерацию с параметрами , а model.parameters()
делает именно это - возвращает итерируемые параметры.Если у вас есть некоторые пользовательские «плавающие» параметры, вы можете передать их как
my_params = [my_param_1, my_param_2]
optim = torch.optim.Adam(my_params)
, а также объединить их с итерациями других параметров, как показано ниже:
model_params = list(model.parameters())
my_params = [my_param_1, my_param_2]
optim = torch.optim.Adam(model_params + my_params)
На практикеоднако, вы можете обычно структурировать свой код, чтобы избежать этого.Есть класс nn.Parameter
, который упаковывает тензоры.Все подклассы nn.Module
имеют свои __setattr__
переопределенные, так что всякий раз, когда вы назначаете экземпляр nn.Parameter
в качестве его свойства, он становится частью итераций Module
.parameters()
.Другими словами,
class MyModule(nn.Module):
def __init__(self):
super(MyModule, self).__init__()
self.my_param_1 = nn.Parameter(torch.tensor(...))
self.my_param_2 = nn.Parameter(torch.tensor(...))
позволит вам написать
module = MyModule()
optim = torch.optim.Adam(module.parameters())
и иметь optim
update module.my_param_1
и module.my_param_2
.Это предпочтительный способ, так как он помогает сохранить ваш код более структурированным
- Вам не нужно будет вручную включать все ваши параметры при создании оптимизатора
- Вы можете вызвать
module.zero_grad()
и обнуляем градиент для всех его дочерних элементов nn.Parameter
с. - Вы можете вызывать такие методы, как
module.cuda()
или module.double()
, который, опять же, работает на всех дочерних элементах nn.Parameter
s вместо необходимости вручную выполнять их итерацию.