Detaillierte Erklärung von .detach(), .data und .detach_()

Inhaltsverzeichnis

1. .detach()

1.1 Beispiel 1

1.2 Beispiel 2

1.3 Beispiel 3

1.4 Korrektheitsprüfung vor Ort

Zweitens, .data

3. .detach_()


Wenn wir das Netzwerk trainieren, möchten wir möglicherweise einige der Netzwerkparameter unverändert lassen und nur einige der Parameter anpassen; oder nur einen Teil des Zweignetzwerks trainieren und nicht zulassen, dass sein Gradient den Gradienten des Hauptnetzwerks beeinflusst Dieses Mal müssen wir die Funktion detach() verwenden, um die Backpropagation einiger Zweige zu unterbrechen.

1. .detach()

Geben Sie ein neues zurück Variable, das vom aktuellen Berechnungsdiagramm getrennt ist, aber immer noch auf den Speicherort der ursprünglichen Variablen verweist. Der einzige Unterschied besteht darin, dass require_grad falsch ist und das erhaltene Ergebnis niemals Variableseinen Gradienten berechnen muss und keinen Grad hat .

Auch wenn require_grad später wieder auf true gesetzt wird, hat es keinen Farbverlauf grad.

Variable进行计算,后面当我们进行Auf diese Weise wird der Aufruf von detach() Variablegestoppt , wenn wir diese neue Backpropagation weiterhin verwenden , und wir können die Weitergabe nach vorne nicht fortsetzen.

Der Quellcode ist:

def detach(self):
        """Returns a new Variable, detached from the current graph.
        Result will never require gradient. If the input is volatile, the output
        will be volatile too.
        .. note::
          Returned Variable uses the same data tensor, as the original one, and
          in-place modifications on either of them will be seen, and may trigger
          errors in correctness checks.
        """
        result = NoGrad()(self)  # this is needed, because it merges version counters
        result._grad_fn = None     return result

可见函数进行的操作有:

  • Setzen Sie grad_fn auf „Keine“.
  • 将Variablevonrequires_grad设置为False

Wenn eingegeben  volatile=True(即不需要保存记录,当只需要结果而不需要更新参数时,这么设置可以加快运算速度), was wird zurückgegeben Variable volatile=True? ( volatileveraltet)

注意:

Das zurückgegebene Exemplar hat dieselben Eigenschaften wie Variabledas Original . Änderungen wirken sich auf beide aus (da sie gemeinsam genutzt werden ), was zu Fehlern führen kann, wenn versucht wird, „backback()“ für sie aufzurufen.Variabledata tensorin-place函数Variabledata tensor

Bitte sehen Sie sich zum Verständnis das folgende Beispiel an.

1.1 Beispiel 1

Ein normales Beispiel ist beispielsweise:

import torch

a = torch.tensor([1, 2, 3.], requires_grad=True)
print(a.grad)
out = a.sigmoid()

out.sum().backward()
print(a.grad)

zurückkehren:

(deeplearning) userdeMBP:pytorch user$ python test.py 
None
tensor([0.1966, 0.1050, 0.0452])

Backward() ist nicht betroffen, wenn detach() verwendet wird, aber keine Änderungen vorgenommen werden:

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)

zurückkehren:

(deeplearning) userdeMBP:pytorch user$ python test.py 
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])

Es ist ersichtlich, dass der Unterschied zwischen c und out darin besteht, dass c keinen Gradienten und out einen Gradienten hat.

1.2 Beispiel 2

Wenn c hier für die Operation „sum()“ und „backback()“ verwendet wird, wird ein Fehler gemeldet:

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)

zurückkehren:

(deeplearning) userdeMBP:pytorch user$ python test.py 
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

1.3 Beispiel 3

Wenn zu diesem Zeitpunkt eine Änderung an c vorgenommen wird, wird diese Änderung von Autograd verfolgt, und es wird auch ein Fehler gemeldet, wenn „backward()“ für out.sum() ausgeführt wird, da der Gradient durch Ausführen von „backward()“ für den Wert erhalten wird zu diesem Zeitpunkt ist falsch:

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)

zurückkehren:

(deeplearning) userdeMBP:pytorch user$ python test.py 
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

 Das Prinzip der Umsetzung des oben genannten Inhalts ist:

1.4 Korrektheitsprüfung vor Ort

Alles Variablewird aufgezeichnet und auf ihnen verwendet  in-place operations. Wenn pytorchfestgestellt wird, dass variableeine FunctionDatei zur Verwendung gespeichert , aber später geändert backwardwurde . in-place operationsWenn dies geschieht, wird bei backwardein pytorchFehler gemeldet. Dieser Mechanismus stellt sicher, dass die Berechnung des Gradienten korrekt ist , wenn Sie ihn verwenden , während des Vorgangs in-place operationsjedoch kein Fehler gemeldet wird.backward

Zweitens, .data

Wenn der obige Vorgang .data verwendet, ist der Effekt unterschiedlich:

Der Unterschied besteht darin, dass die Änderung von .data nicht von Autograd verfolgt wird, sodass beim Ausführen von „backback()“ kein Fehler gemeldet wird und ein falscher Rückwärtswert angezeigt wird .

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)

zurückkehren:

(deeplearning) userdeMBP:pytorch user$ python test.py 
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.])

Das folgende Ergebnis ist korrekt, da das Ergebnis von sum() geändert wird und der Zwischenwert a.sigmoid() nicht betroffen ist, sodass er keinen Einfluss auf den Gradienten hat:

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)

 zurückkehren:

(deeplearning) userdeMBP:pytorch user$ python test.py 
None
tensor(2.5644, grad_fn=<SumBackward0>)
tensor(2.5644)
tensor(0.)
tensor(0., grad_fn=<SumBackward0>)
tensor([0.1966, 0.1050, 0.0452])

3. .detach_()

Trennen Sie a Variablevon dem Diagramm, das es erstellt hat, und legen Sie es als Blatt festvariable

Tatsächlich entspricht die Beziehung zwischen Variablen x -> m -> y. Die Blattvariable hier ist x, aber zu diesem Zeitpunkt wird die Operation .detach_() für m ausgeführt, bei der es sich tatsächlich um zwei Operationen handelt:

  • Setzen Sie den Wert von m's grad_fn auf None, sodass m nicht mehr mit dem vorherigen Knoten x verknüpft ist und die Beziehung hier zu x, m -> y wird und m zu diesem Zeitpunkt zu einem Blattknoten wird
  • Dann wird „requires_grad“ von m auf „False“ gesetzt, sodass der Gradient von m nicht gesucht wird, wenn „backward()“ für y ausgeführt wird

Aus dieser Sicht ist detach() tatsächlich detach_() sehr ähnlich. Der Unterschied zwischen den beiden besteht darin, dass detach_() eine Änderung an sich selbst ist und detach() eine neue Variable generiert.

Wenn beispielsweise detach() für m in x -> m -> y ausgeführt wird und Sie es später bereuen, möchten Sie immer noch das ursprüngliche Berechnungsdiagramm bearbeiten. Wenn jedoch detach_() ausgeführt wird, hat sich auch das ursprüngliche Berechnungsdiagramm geändert, und Sie können Ihr Wort nicht zurücknehmen.

おすすめ

転載: blog.csdn.net/weixin_45684362/article/details/131987689