56 votes

Pourquoi avons-nous besoin d'appeler explicitement zero_grad ()?

Pourquoi devons-nous explicitement mettre à zéro les gradients dans PyTorch? Pourquoi les gradients ne peuvent-ils pas être mis à zéro lorsque loss.backward() est appelé? Quel scénario est servi en conservant les gradients sur le graphique et en demandant à l'utilisateur de mettre à zéro explicitement les gradients?

63voto

danche Points 1225

Nous avons explicitement besoin d'appeler zero_grad() parce que, après l' loss.backward() (lorsque les gradients sont calculés), nous avons besoin d'utiliser optimizer.step() pour passer de descente de gradient. Plus précisément, les gradients ne sont pas automatiquement mis à zéro, parce que ces deux opérations, loss.backward() et optimizer.step(), sont séparés, et optimizer.step() nécessite la juste calculé dégradés.

En outre, parfois, nous avons besoin d'accumuler de dégradé entre certains lots; pour ce faire, il suffit de l'appeler backward plusieurs fois et d'optimiser la fois.

8voto

prosti Points 4630

Il y a un cycle dans PyTorch:

  • Avant quand nous arrivons à la sortie ou à l' y_hat à partir de l'entrée,
  • Le calcul de la perte où loss = loss_fn(y_hat, y)
  • loss.backward lorsque nous calculer les gradients
  • optimizer.step lorsque nous mettons à jour les paramètres

Ou le code:

for mb in range(10): # 10 mini batches
    y_pred = model(x)
    loss = loss_fn(y_pred, y)
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

Si nous ne serait pas clair dégradés après l' optimizer.step, ce qui est l'étape appropriée ou juste avant le prochain backward() gradients permettrait de s'accumuler. Voici un exemple montrant l'accumulation:

import torch
w = torch.rand(5)
w.requires_grad_()
print(w) 
s = w.sum() 
s.backward()
print(w.grad) # tensor([1., 1., 1., 1., 1.])
s.backward()
print(w.grad) # tensor([2., 2., 2., 2., 2.])
s.backward()
print(w.grad) # tensor([3., 3., 3., 3., 3.])
s.backward()
print(w.grad) # tensor([4., 4., 4., 4., 4.])

loss.backward() n'ont aucun moyen de définir ce.

torch.autograd.backward(tensors, grad_tensors=None, retain_graph=None, create_graph=False, grad_variables=None)

De toutes les options que vous pouvez spécifier on n'est pas à zéro les gradients manuellement. Comme ça dans les précédents mini exemple:

w.grad.zero_()

Il y a des discussions sur le fait de faire zero_grad() à chaque fois avec backward() (évidemment précédente dégradés) et de garder les diplômés avec preserve_grads=True, mais ce n'est jamais venu à la vie.

7voto

twrichar Points 51

J'ai un cas d'utilisation pour la configuration actuelle dans PyTorch.

Si l'on utilise un réseau de neurones récurrent (RNN), qui est de faire des prédictions, à chaque étape, on peut avoir envie d'avoir un hyper-paramètre qui permet d'accumuler des gradients dans le temps. Pas de réinitialisation de la dégradés à chaque pas de temps permet une utilisation de back-propagation à travers le temps (BPTT) intéressante et originale.

Si vous souhaitez plus d'info sur BPTT ou RNNs voir l'article de Réseaux de Neurones Récurrents Tutoriel, Partie 3 – Les à Travers le Temps et la Disparition des Gradients ou de La Déraisonnable Efficacité des Réseaux de Neurones Récurrents.

4voto

Laisser les dégradés en place avant d'appeler .step() est utile si vous souhaitez accumuler le dégradé sur plusieurs lots (comme d'autres l'ont mentionné).

C'est également utile pour après avoir appelé .step() si vous souhaitez mettre en œuvre l'élan pour SGD, et diverses autres méthodes peuvent dépendre des valeurs du dégradé de la mise à jour précédente.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X