Pytouch逆伝搬における詳細-勾配計算時のデフォルトのアキュムレータ動作
Pytoch逆伝搬計算勾配はデフォルトのアキュムレータです。
今日はpytouchを勉強して簡単なリニア回帰を実現して、pytouchの逆方向伝播を発見しました。勾配を計算するために採用されたアキュムレータメカニズムを発見しました。そこで、多くのブログでアキュムレータメカニズムを説明しましたが、多くはこのアキュムレータメカニズムが一体何の影響があるかを説明していません。
pytochはリニア回帰を実現します。
まずテストコードを添付して感じてみます。
w.grad:tenssor(-74.6861))
b.grad:tenssor(-12.5532)
w.grad:tenssor([-122.95])
b.grad:tenssor(-20.9364)
それから、私は2行のコードを少し入れます。つまり、逆伝搬の上に、手動で勾配クリア操作のコードを追加して、結果を感じます。
b.grad:tenssor(-12.5532)
w.grad:tenssor(-48.2813)
b.grad:tenssor(-8.3831)
上から、pytouchが逆方向に伝播する時、確かにデフォルトで前回求めた勾配を積算しました。前回の勾配が自分の今回の勾配に影響を与えたくないなら、手動でクリアする必要があります。
しかし、手動でゼロをクリアしないとどうなりますか?私は今回の線形回帰試験で、遭遇した結果はloss値の繰り返しの揺れが収束しないことです。以下で感じてみます。
次に、手動でゼロをクリアした注釈を開いて、反復後の手動クリアを行います。
これこそ理想的な逆伝搬コンダクタンスであり、パラメータを更新して得られるloss値の変化が見られます。
締め括りをつける
今回は主に、pytouchが逆伝搬計算勾配を行っている時のアキュムレータメカニズムはいったいどうなっているかを記録します。なぜこのような仕組みを採用したのかについても調べてみました。
しかし、積算したくないなら、手動でゼロをクリアする方式を採用してもいいです。反復のたびに加算すればいいです。
以上は個人の経験ですので、参考にしていただければと思います。
今日はpytouchを勉強して簡単なリニア回帰を実現して、pytouchの逆方向伝播を発見しました。勾配を計算するために採用されたアキュムレータメカニズムを発見しました。そこで、多くのブログでアキュムレータメカニズムを説明しましたが、多くはこのアキュムレータメカニズムが一体何の影響があるかを説明していません。
pytochはリニア回帰を実現します。
まずテストコードを添付して感じてみます。
torch.manual_seed(6)
lr = 0.01 #
result = []
#
x = torch.rand(20, 1) * 10
y = 2 * x + (5 + torch.randn(20, 1))
#
w = torch.randn((1), requires_grad=True)
b = torch.zeros((1), requires_grad=True)
# , pytorch ,
for iteration in range(2):
#
wx = torch.mul(w, x)
y_pred = torch.add(wx, b)
# MSE loss
loss = (0.5 * (y - y_pred) ** 2).mean()
#
loss.backward()
#
print("w.grad:", w.grad)
print("b.grad:", b.grad)
#
b.data.sub_(lr * b.grad)
w.data.sub_(lr * w.grad)
上記のコードは比較的簡単で、2回繰り返しました。計算の勾配結果を見てください。w.grad:tenssor(-74.6861))
b.grad:tenssor(-12.5532)
w.grad:tenssor([-122.95])
b.grad:tenssor(-20.9364)
それから、私は2行のコードを少し入れます。つまり、逆伝搬の上に、手動で勾配クリア操作のコードを追加して、結果を感じます。
torch.manual_seed(6)
lr = 0.01
result = []
#
x = torch.rand(20, 1) * 10
#print(x)
y = 2 * x + (5 + torch.randn(20, 1))
#print(y)
#
w = torch.randn((1), requires_grad=True)
#print(w)
b = torch.zeros((1), requires_grad=True)
#print(b)
for iteration in range(2):
#
wx = torch.mul(w, x)
y_pred = torch.add(wx, b)
# MSE loss
loss = (0.5 * (y - y_pred) ** 2).mean()
# pytorch , , , 0
if iteration > 0:
w.grad.data.zero_()
b.grad.data.zero_()
#
loss.backward()
#
print("w.grad:", w.grad)
print("b.grad:", b.grad)
#
b.data.sub_(lr * b.grad)
w.data.sub_(lr * w.grad)
w.grad:tenssor(-74.6861))b.grad:tenssor(-12.5532)
w.grad:tenssor(-48.2813)
b.grad:tenssor(-8.3831)
上から、pytouchが逆方向に伝播する時、確かにデフォルトで前回求めた勾配を積算しました。前回の勾配が自分の今回の勾配に影響を与えたくないなら、手動でクリアする必要があります。
しかし、手動でゼロをクリアしないとどうなりますか?私は今回の線形回帰試験で、遭遇した結果はloss値の繰り返しの揺れが収束しないことです。以下で感じてみます。
torch.manual_seed(6)
lr = 0.01
result = []
#
x = torch.rand(20, 1) * 10
#print(x)
y = 2 * x + (5 + torch.randn(20, 1))
#print(y)
#
w = torch.randn((1), requires_grad=True)
#print(w)
b = torch.zeros((1), requires_grad=True)
#print(b)
for iteration in range(1000):
#
wx = torch.mul(w, x)
y_pred = torch.add(wx, b)
# MSE loss
loss = (0.5 * (y - y_pred) ** 2).mean()
# print("iteration {}: loss {}".format(iteration, loss))
result.append(loss)
# pytorch , , , 0
#if iteration > 0:
# w.grad.data.zero_()
# b.grad.data.zero_()
#
loss.backward()
#
b.data.sub_(lr * b.grad)
w.data.sub_(lr * w.grad)
if loss.data.numpy() < 1:
break
plt.plot(result)
上のコードの中で、手動でゼロをクリアしていません。1000回繰り返して、毎回のlossをresultに入れて、画像を描きます。結果を感じてください。次に、手動でゼロをクリアした注釈を開いて、反復後の手動クリアを行います。
これこそ理想的な逆伝搬コンダクタンスであり、パラメータを更新して得られるloss値の変化が見られます。
締め括りをつける
今回は主に、pytouchが逆伝搬計算勾配を行っている時のアキュムレータメカニズムはいったいどうなっているかを記録します。なぜこのような仕組みを採用したのかについても調べてみました。
しかし、積算したくないなら、手動でゼロをクリアする方式を採用してもいいです。反復のたびに加算すればいいです。
w.grad.data.zero_()
b.grad.data.zero_()
また、資料を検索する時、ブログで2つの悪くない線形回帰を見た時のpytouchの計算図をここで借ります。以上は個人の経験ですので、参考にしていただければと思います。