ネットワークをトレーニングするときは、ネットワークパラメータの一部を変更せずに、パラメータの一部のみを調整するか、ブランチネットワークの一部のみをトレーニングし、その勾配がメインネットワークの勾配に影響を与えないようにすることができます。一部のブランチの逆伝播を遮断するには、detach()関数を使用する必要があります。
一、デタッチ()[ソース]
現在の計算グラフから分離されているが、元の変数の保存場所を指している新しいものVariable
を返します。唯一の違いは、requires_gradがfalseであるということです。取得されたものは、勾配を計算する必要がなく、gradがありません。Variable
後でrequirements_gradをtrueにリセットしても、勾配gradはありません。
このようにして、この新しい変数を引き続き計算に使用します。後で逆伝播を実行すると、detach()の呼び出しVariable
が停止し、前方への伝播を続行できなくなります。
ソースコードは次のとおりです。
デフデタッチ(自己): 。現在のグラフから切り離さ「」 "を返し、新たな変数、 結果は、勾配を必要とすることはありません入力が揮発性である場合、出力は。 あまりにも揮発性になります。 。注:: 返される変数の用途に同じデータを元のテンソル、および それらのいずれかでのインプレース変更が表示され 、正確性チェックでエラーが発生する可能性があります。 "" " result = NoGrad()(self)#バージョンカウンターの 結果をマージするため、これが必要です。._grad_fn =なし 戻り結果
可視関数によって実行される操作は次のとおりです。
- grad_fnをNoneに設定します
将Variable
のrequires_grad设置为False
を入力した場合は volatile=True(即不需要保存记录,当只需要结果而不需要更新参数时这么设置来加快运算速度)
、を返しVariable
ます。(非volatile
=True
推奨)volatile
注意:
返されるものは
Variable
元のVariable
ものと同じdata tensor
です。in-place函数
変更は両方Variable
に同時に反映され(共有されているためdata tensor
)、backward()を呼び出すときにエラーが発生する可能性があります。
例えば:
通常の例:
import torch
a = torch.tensor([1, 2, 3.], requires_grad=True)
print(a.grad)
out = a.sigmoid()
out.sum().backward()
print(a.grad)
戻り値:
None
tensor([0.1966, 0.1050, 0.0452])
detach()が使用されているが変更が行われていない場合、backward()には影響しません。
import torch
a = torch.tensor([1, 2, 3.], requires_grad=True)
print(a.grad)
out = a.sigmoid()
print(out)
#添加detach(),c的requires_grad为False
c = out.detach()
print(c)
#这时候没有对c进行更改,所以并不会影响backward()
out.sum().backward()
print(a.grad)
戻り値:
None
tensor([0.7311, 0.8808, 0.9526], grad_fn=<SigmoidBackward>)
tensor([0.7311, 0.8808, 0.9526])
tensor([0.1966, 0.1050, 0.0452])
cとoutの違いは、cには勾配がなく、outには勾配があることがわかります。
ここでcをsum()操作とbackward()に使用すると、エラーが報告されます。
import torch
a = torch.tensor([1, 2, 3.], requires_grad=True)
print(a.grad)
out = a.sigmoid()
print(out)
#添加detach(),c的requires_grad为False
c = out.detach()
print(c)
#使用新生成的Variable进行反向传播
c.sum().backward()
print(a.grad)
戻り値:
None
tensor([0.7311, 0.8808, 0.9526], grad_fn=<SigmoidBackward>)
tensor([0.7311, 0.8808, 0.9526])
Traceback (most recent call last):
File "test.py", line 13, in <module>
c.sum().backward()
File "/anaconda3/envs/deeplearning/lib/python3.6/site-packages/torch/tensor.py", line 102, in backward
torch.autograd.backward(self, gradient, retain_graph, create_graph)
File "/anaconda3/envs/deeplearning/lib/python3.6/site-packages/torch/autograd/__init__.py", line 90, in backward
allow_unreachable=True) # allow_unreachable flag
RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn
この時点でcが変更された場合、この変更はautogradによって追跡され、out.sum()でbackward()が実行されると、この時点での値に対してbackward()によって取得された勾配が間違っているため、エラーが報告されます。
import torch
a = torch.tensor([1, 2, 3.], requires_grad=True)
print(a.grad)
out = a.sigmoid()
print(out)
#添加detach(),c的requires_grad为False
c = out.detach()
print(c)
c.zero_() #使用in place函数对其进行修改
#会发现c的修改同时会影响out的值
print(c)
print(out)
#这时候对c进行更改,所以会影响backward(),这时候就不能进行backward(),会报错
out.sum().backward()
print(a.grad)
戻り値:
None
tensor([0.7311, 0.8808, 0.9526], grad_fn=<SigmoidBackward>)
tensor([0.7311, 0.8808, 0.9526])
tensor([0., 0., 0.])
tensor([0., 0., 0.], grad_fn=<SigmoidBackward>)
Traceback (most recent call last):
File "test.py", line 16, in <module>
out.sum().backward()
File "/anaconda3/envs/deeplearning/lib/python3.6/site-packages/torch/tensor.py", line 102, in backward
torch.autograd.backward(self, gradient, retain_graph, create_graph)
File "/anaconda3/envs/deeplearning/lib/python3.6/site-packages/torch/autograd/__init__.py", line 90, in backward
allow_unreachable=True) # allow_unreachable flag
RuntimeError: one of the variables needed for gradient computation has been modified by an inplace operation
二、データ
上記の操作で.dataを使用すると、効果が異なります。
ここでの違いは、.dataの変更はautogradによって追跡されないため、backward()の実行時にエラーが報告されず、誤った後方値が取得されることです。
import torch
a = torch.tensor([1, 2, 3.], requires_grad=True)
print(a.grad)
out = a.sigmoid()
print(out)
c = out.data
print(c)
c.zero_() #使用in place函数对其进行修改
#会发现c的修改同时也会影响out的值
print(c)
print(out)
#这里的不同在于.data的修改不会被autograd追踪,这样当进行backward()时它不会报错,回得到一个错误的backward值
out.sum().backward()
print(a.grad)
戻り値:
None
tensor([0.7311, 0.8808, 0.9526], grad_fn=<SigmoidBackward>)
tensor([0.7311, 0.8808, 0.9526])
tensor([0., 0., 0.])
tensor([0., 0., 0.], grad_fn=<SigmoidBackward>)
tensor([0., 0., 0.])
上記の内容の原則は次のとおりです。インプレースの正確性チェック
すべて
Variable
が記録され、それらで使用されますin-place operations
。1つで使用するために保存pytorch
されていることが検出されたが、変更されている場合。このような場合は、エラーが発生します。このメカニズムにより、使用してもプロセスでエラーが報告されない場合、勾配計算が正しくなります。variable
Function
backward
in-place operations
backward
pytorch
in-place operations
backward
変更はsum()の結果であり、中間値a.sigmoid()は影響を受けないため、次の結果は正しいです。したがって、勾配には影響しません。
import torch
a = torch.tensor([1, 2, 3.], requires_grad=True)
print(a.grad)
out = a.sigmoid().sum() #但是如果sum写在这里,而不是写在backward()前,得到的结果是正确的
print(out)
c = out.data
print(c)
c.zero_() #使用in place函数对其进行修改
#会发现c的修改同时也会影响out的值
print(c)
print(out)
#没有写在这里
out.backward()
print(a.grad)
戻り値:
None
tensor(2.5644, grad_fn=<SumBackward0>)
tensor(2.5644)
tensor(0.)
tensor(0., grad_fn=<SumBackward0>)
tensor([0.1966, 0.1050, 0.0452])
三、デタッチ_()[ソース]
Variable
それを作成したグラフから1つを分離し、リーフとして設定しますvariable
実際、変数間の関係は元々x-> m-> yであり、リーフ変数はxですが、このとき、.detach_()操作はmに対して実行されます。実際には、次の2つの操作が実行されます。
- mのgrad_fnの値をNoneに設定すると、mは前のノードxに関連付けられなくなり、ここでの関係はx、m-> yになり、この時点でmはリーフノードになります。
- 次に、mのrequirements_gradがFalseに設定されるため、yでbackward()を実行したときにmの勾配が計算されません。
このように、detach()とdetach_()は非常に似ています。2つの違いは、detach_()はそれ自体への変更であり、detach()は新しい変数を生成することです。
たとえば、x-> m-> yで、mがdetach()の場合、後で後悔したい場合は、元の計算グラフを操作できます。
ただし、detach_()を実行すると、元の計算グラフも変更され、元に戻すことはできません。
転送元:https://blog.csdn.net/weixin_34363171/article/details/94236818