Congélation de poids dans pytorch pour param_groups
réglage.
Donc, si l'on veut geler des poids pendant l'entraînement:
for param in child.parameters():
param.requires_grad = False
l'optimiseur doit également être mis à jour pour ne pas inclure les poids non dégradés:
optimizer = torch.optim.Adam(filter(lambda p: p.requires_grad, model.parameters()), lr=opt.lr, amsgrad=True)
Si l'on veut utiliser différents weight_decay
/taux d'apprentissage pour les biais et les pondérations/cela permet également des taux d'apprentissage différents:
param_groups = [{'params': model.module.bias_parameters(), 'weight_decay': args.bias_decay},
{'params': model.module.weight_parameters(), 'weight_decay': args.weight_decay}]
param_groups
une liste de dics est définie et passée dans SGD
comme suit:
optimizer = torch.optim.Adam(param_groups, args.lr,
betas=(args.momentum, args.beta))
Comment cela peut-il être obtenu en gelant des poids individuels? Exécuter le filtre sur une liste de photos ou existe-t-il un moyen d'ajouter des tenseurs à l'optimiseur séparément?
En fait, je pense que vous n'avez pas à mettre à jour le optimizer
. Les Parameters
remis aux optimizer
ne sont que des références.
Ainsi, lorsque vous modifiez l'indicateur requires_grad
, Il sera immédiatement mis à jour.
Mais même si ce n'est pas le cas pour une raison quelconque - dès que vous définissez le drapeau requires_grad
Sur False
, vous ne pouvez plus calculer de dégradés ( nouveaux dégradés (voir en bas avec None
et zéro dégradés) pour ce poids, donc le gradient ne changera plus et si vous utilisez optimizer.zero_grad()
il restera simplement zero
.
Donc, s'il n'y a pas de gradient, il n'est pas non plus nécessaire de les exclure du optimizer
. Parce que sans gradient, le optimizer
ne fera rien, quel que soit le taux d'apprentissage que vous utilisez.
Voici un petit exemple pour montrer ce comportement:
import torch
import torch.nn as nn
import torch.optim as optim
n_dim = 5
p1 = nn.Linear(n_dim, 1)
p2 = nn.Linear(n_dim, 1)
optimizer = optim.Adam(list(p1.parameters())+list(p2.parameters()))
p2.weight.requires_grad = False
for i in range(4):
dummy_loss = (p1(torch.Rand(n_dim)) + p2(torch.Rand(n_dim))).squeeze()
optimizer.zero_grad()
dummy_loss.backward()
optimizer.step()
print('p1: requires_grad =', p1.weight.requires_grad, ', gradient:', p1.weight.grad)
print('p2: requires_grad =', p2.weight.requires_grad, ', gradient:', p2.weight.grad)
print()
if i == 1:
p1.weight.requires_grad = False
p2.weight.requires_grad = True
Production:
p1: requires_grad = True , gradient: tensor([[0.8522, 0.0020, 0.1092, 0.8167, 0.2144]])
p2: requires_grad = False , gradient: None
p1: requires_grad = True , gradient: tensor([[0.7635, 0.0652, 0.0902, 0.8549, 0.6273]])
p2: requires_grad = False , gradient: None
p1: requires_grad = False , gradient: tensor([[0., 0., 0., 0., 0.]])
p2: requires_grad = True , gradient: tensor([[0.1343, 0.1323, 0.9590, 0.9937, 0.2270]])
p1: requires_grad = False , gradient: tensor([[0., 0., 0., 0., 0.]])
p2: requires_grad = True , gradient: tensor([[0.0100, 0.0123, 0.8054, 0.9976, 0.6397]])
Ici, vous pouvez voir qu'aucun dégradé n'est calculé. Vous avez peut-être remarqué que le gradient pour p2
Est None
au début et plus tard, il est tensor([[0., 0., 0., 0., 0.]])
pour p1
Au lieu de None
après avoir désactivé les dégradés.
C'est le cas car p1.weight.grad
N'est qu'une variable qui est modifiée par backward()
et optimizer.zero_grad()
.
Donc au début, p1.weight.grad
Est juste initialisé avec None
, après que les dégradés soient écrits ou accumulés dans cette variable, ils ne seront pas effacés automatiquement. Mais comme optimizer.zero_grad()
est appelé, ils sont mis à zéro et restent ainsi puisque backward()
ne peut plus calculer de nouveaux gradients avec requires_grad=False
.
Vous pouvez également modifier le code de l'instruction if
- en:
if i == 1:
p1.weight.requires_grad = False
p1.weight.grad = None
p2.weight.requires_grad = True
Ainsi, une fois réinitialisés sur None
, ils restent inchangés et restent None
:
p1: requires_grad = True , gradient: tensor([[0.2375, 0.7528, 0.1501, 0.3516, 0.3470]])
p2: requires_grad = False , gradient: None
p1: requires_grad = True , gradient: tensor([[0.5181, 0.5178, 0.6590, 0.6950, 0.2743]])
p2: requires_grad = False , gradient: None
p1: requires_grad = False , gradient: None
p2: requires_grad = True , gradient: tensor([[0.4797, 0.7203, 0.2284, 0.9045, 0.6671]])
p1: requires_grad = False , gradient: None
p2: requires_grad = True , gradient: tensor([[0.8344, 0.1245, 0.0295, 0.2968, 0.8816]])
J'espère que cela a du sens pour vous!