PyTorch で zero_grad() を呼び出す必要があるのはなぜですか? 質問する

PyTorch で zero_grad() を呼び出す必要があるのはなぜですか? 質問する

どしてzero_grad()トレーニング中に呼び出す必要がありますか?

|  zero_grad(self)
|      Sets gradients of all model parameters to zero.

ベストアンサー1

PyTorch、訓練段階中の各ミニバッチでは、通常、バックプロパゲーション(重みとバイアスの更新)を開始する前に勾配を明示的にゼロに設定する必要があります。これは、PyTorch後続バックワードパスで勾配を蓄積するためですこの蓄積動作は、RNNを訓練するときや、複数のミニバッチにわたって合計された損失の勾配を計算するときに便利です。したがって、デフォルトのアクションは次のように設定されています。勾配を累積する(つまり合計する)すべての通話でloss.backward()

このため、トレーニングループを開始するときは、理想的にはzero out the gradientsパラメータ更新を正しく実行できるようにします。そうしないと、勾配は、モデルパラメータの更新に既に使用した古い勾配と新しく計算された勾配の組み合わせになります。したがって、最小値最大化目標の場合は最大値)に向かう意図した方向とは異なる方向を指すことになります。

以下に簡単な例を示します。

import torch
from torch.autograd import Variable
import torch.optim as optim

def linear_model(x, W, b):
    return torch.matmul(x, W) + b

data, targets = ...

W = Variable(torch.randn(4, 3), requires_grad=True)
b = Variable(torch.randn(3), requires_grad=True)

optimizer = optim.Adam([W, b])

for sample, target in zip(data, targets):
    # clear out the gradients of all Variables 
    # in this optimizer (i.e. W, b)
    optimizer.zero_grad()
    output = linear_model(sample, W, b)
    loss = (output - target) ** 2
    loss.backward()
    optimizer.step()

あるいは、通常の勾配降下法を実行する場合は、次のようになります。

W = Variable(torch.randn(4, 3), requires_grad=True)
b = Variable(torch.randn(3), requires_grad=True)

for sample, target in zip(data, targets):
    # clear out the gradients of Variables 
    # (i.e. W, b)
    W.grad.data.zero_()
    b.grad.data.zero_()

    output = linear_model(sample, W, b)
    loss = (output - target) ** 2
    loss.backward()

    W -= learning_rate * W.grad.data
    b -= learning_rate * b.grad.data

注記

  • 勾配の累積(つまり合計)は.backward()lossテンソルで呼び出される
  • バージョン1.7.0では、Pytorchは勾配をリセットするオプションを提供しています。None optimizer.zero_grad(set_to_none=True)ゼロのテンソルで埋める代わりに、この設定を使用します。ドキュメントでは、この設定によりメモリ要件が削減され、パフォーマンスがわずかに向上するが、慎重に処理しないとエラーが発生しやすくなる可能性があると主張しています。

おすすめ記事