pytorch .detach()。detach_()和.data

ネットワークをトレーニングするときは、ネットワークパラメータの一部を変更せずに、パラメータの一部のみを調整するか、ブランチネットワークの一部のみをトレーニングし、その勾配がメインネットワークの勾配に影響を与えないようにすることができます。一部のブランチの逆伝播を遮断するには、detach()関数を使用する必要があります。


一、デタッチ()[ソース]

現在の計算グラフから分離されているが、元の変数の保存場所を指している新しいものVariable返します。唯一の違いは、requires_gradがfalseであるということです。取得されたものは、勾配を計算する必要がなく、gradがありません。Variable

後でrequirements_gradをtrueにリセットしても、勾配gradはありません。

このようにして、この新しい変数を引き続き計算に使用します。後で逆伝播を実行すると、detach()の呼び出しVariableが停止し、前方への伝播を続行できなくなります。

ソースコードは次のとおりです。

デフデタッチ(自己): 現在のグラフから切り離さ「」 "を返し、新たな変数、
        結果は、勾配を必要とすることはありません入力が揮発性である場合、出力は。
        あまりにも揮発性になります。
        。注::
          返される変数の用途に同じデータを元のテンソル、および
          それらのいずれかでのインプレース変更が表示され
          、正確性チェックでエラーが発生する可能性があります。
        "" " 
        result = NoGrad()(self)#バージョンカウンターの
        結果をマージするため、これが必要です。._grad_fn =なし
     戻り結果

可視関数によって実行される操作は次のとおりです。

  • grad_fnをNoneに設定します
  • 将Variablerequires_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 operations1つ使用するため保存pytorchされていることが検出されたが、変更ている場合このような場合はエラーが発生します。このメカニズムにより、使用してもプロセスでエラーが報告さない場合、勾配計算が正しくなります。variableFunctionbackwardin-place operationsbackwardpytorchin-place operationsbackward

変更は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

 

おすすめ

転載: blog.csdn.net/Answer3664/article/details/104314030