Pytorchのtensorのrequires_gradがTrueになるとき
概要
Pytorchでニューラルネットワークの学習を行う際に重要な誤差逆伝播を行うためのメソッドとしてTensor.backward()があります。このbackwardを使用する場合には使用するTensorでrequires_grad=Trueを設定し、勾配を記録させておく必要があるということがPytorchのドキュメントにも書かれています。
Autograd mechanics — PyTorch 2.0 documentation
しかし、いろんなプログラムを見ると、requires_grad=Trueを設定せずにbackwardを使用している場合があり、なぜそれらが正しく動作しているのか疑問でした。
例えばこちらのプログラムのような例です。
今回はその理由について調べてみたことを記載しておこうと思います。
検証環境
Python 3.8.10
Pytorch 2.0.1
requires_gradがTrueでないとどうなるか
まず、requires_gradがTrueでない場合にbackwardを行うとどうなるかを試してみます。tensorを定義した際、デフォルトではrequires_gradはFalseになっています。
import torch
x = torch.tensor([[1., -1.], [1., -1.]])
y = x.sum()
print(y.requires_grad)
False
この状態でbackwardを行ってみます。
y.backward()
すると、以下のようなエラーが発生してbackwardを行うことができません。
RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn
しかし、Tensorを宣言する際にrequires_grad=Trueを設定しておくと、問題なくbackwardを行うことができます。例えば以下のようなコードの場合はエラーが発生しません。
import torch
x = torch.tensor([[1., -1.], [1., -1.]], requires_grad=True)
y = x.sum()
y.backward()
requires_grad=Trueを宣言しなくてもbackwardできる場合
しかし、冒頭で述べている通り、requires_grad=Trueを設定しなくてもbackwardできているコードがあります。例えば以下のようなコードはrequires_grad=Tureを最初のTensorで設定していませんが、backwardができます。
import torch
import torch.nn as nn
# requires_grad=Trueを設定していない
x = torch.tensor([[1., -1.], [1., -1.]])
model = nn.Sequential(
nn.Linear(2, 4),
nn.ReLU(),
nn.Linear(4, 1)
)
y = model(x).sum()
y.backward()
backwardできる理由としてはnn.Sequential()のおかげです。
nn.Sequential()を通すことでその出力のtensorが自動的にrequires_gradがTrueに設定されます。以下がその確認のコードです。
import torch
import torch.nn as nn
x = torch.tensor([[1., -1.], [1., -1.]])
print("x.requires_grad is ", x.requires_grad)
model = nn.Sequential(
nn.Linear(2, 4),
nn.ReLU(),
nn.Linear(4, 1)
)
print("model(x).requires_grad is ", model(x).requires_grad)
y = model(x).sum()
print("y.requires_grad is ", y.requires_grad)
y.backward()
x.requires_grad is False model(x).requires_grad is True y.requires_grad is True
このようにnn.Sequential()で定義したモデルの出力は自動的にrequires_grad=Trueになっていると思われます。そのため、わざわざtensor定義時に設定する必要がなくbackwardが動作します。