¿Por qué necesitamos llamar explícitamente a zero_grad ()?

¿Por qué necesitamos poner a cero explícitamente los gradientes en PyTorch? ¿Por qué no se pueden poner a cero los gradientes cuando se llama a loss.backward() ? ¿Qué escenario se presenta al mantener los gradientes en el gráfico y pedirle al usuario que ponga a cero explícitamente los gradientes?

Necesitamos explícitamente llamar a zero_grad() porque, después de loss.backward() (cuando se calculan los gradientes), necesitamos usar optimizer.step() para proceder al descenso del gradiente. Más específicamente, los gradientes no se ponen a cero automáticamente porque estas dos operaciones, loss.backward() y optimizer.step() , están separadas, y optimizer.step() requiere los gradientes calculados justamente.

Además, a veces, necesitamos acumular gradiente entre algunos lotes; para hacer eso, podemos simplemente backward varias veces y optimizar una vez.

Tengo un caso de uso para la configuración actual en PyTorch.

Si uno está usando una neural network recurrente (RNN) que realiza predicciones en cada paso, es posible que desee tener un hiperparámetro que le permita acumular gradientes en el tiempo. No poner a cero los gradientes en cada paso de tiempo permite que uno use la propagación hacia atrás a través del tiempo (BPTT) de formas interesantes y novedosas.

Si desea obtener más información sobre BPTT o RNN, consulte el artículo Tutorial sobre redes neuronales recurrentes, Parte 3: Backpropagation Through Time and Danishing Gradients o La efectividad irrazonable de las redes neuronales recurrentes .

Dejar los gradientes en su lugar antes de llamar .step() es útil en caso de que desee acumular el gradiente en varios lotes (como han mencionado otros).

También es útil para después de llamar a .step() en caso de que desee implementar un impulso para SGD, y varios otros métodos pueden depender de los valores del gradiente de la actualización anterior.

Porque, loss.backward() no tiene ninguna manera de especificar esto.

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

De todas las opciones que puede especificar, no hay manera de poner a cero los gradientes manualmente.

Hubo cierta discusión sobre hacer zero_grad() cada vez con backward() y mantener a los graduados con preserve_grads=True , pero esto nunca se hizo realidad.