[PYTHON] [PyTorch Tutorial ②] Autograd: Automatische Differenzierung

Einführung

Dies ist die zweite Ausgabe von PyTorch Official Tutorial nach Last time. Dieses Mal möchte ich mit [Autograd: Automatic Differentiation] fortfahren (https://pytorch.org/tutorials/beginner/blitz/autograd_tutorial.html).

Inhaltsverzeichnis

1.Autograd 2.Tensor 3. Farbverlauf 4.You can do many crazy things with autograd! 5. Schließlich Geschichte

1.Autograd

PyTorch verfügt über eine Autograd-Funktion. Die Gradienteninformationen werden in Tensor gespeichert und der Gradient wird mit der Methode backward () für den definierten Berechnungsgraphen (Ausdruck) berechnet. Schauen wir uns Autograd mit einem konkreten Beispiel an.

2.Tensor

Der Tensor von PyTorch zeichnet den Verlauf auf, indem das Attribut require_grad auf True gesetzt wird. Wenn Sie den Farbverlauf mit backward () berechnen, bleibt der Farbverlauf im grad-Attribut des Tensors erhalten.

Die folgende Beschreibung definiert Tensor. Geben Sie require_grad = True an, damit der Verlauf aufgezeichnet wird.

import torch
x = torch.ones(2, 2, requires_grad=True)
print(x)
tensor([[1., 1.],
        [1., 1.]], requires_grad=True)

Erstellen Sie ein Berechnungsdiagramm (Formel) y.

y = x + 2
print(y)
tensor([[3., 3.],
        [3., 3.]], grad_fn=<AddBackward0>)

Wenn ich drucke, habe ich grad_fn in der Ausgabe. Dies zeigt, dass ein Berechnungsgraph erstellt wurde, um den Gradienten zu berechnen.

print(y.grad_fn)
<AddBackward0 object at 0x7f8cc977e5c0>

Verwenden Sie y, um weitere Berechnungsdiagramme (Formeln) z und out zu erstellen.

z = y * y * 3
out = z.mean()

print(z, out)
tensor([[27., 27.],
        [27., 27.]], grad_fn=<MulBackward0>) tensor(27., grad_fn=<MeanBackward0>)

[Referenzinformationen] Sie können das Attribut require_grad mit tensor.requires_grad_ () ändern.

a = torch.randn(2, 2)
a = ((a * 3) / (a - 1))
print(a.requires_grad)
a.requires_grad_(True)
print(a.requires_grad)
b = (a * a).sum()
print(b.grad_fn)
False
True
<SumBackward0 object at 0x7fcb2ba0a3c8>

3. Farbverlauf

Berechnen Sie den Gradienten mit out.backward ().

out.backward()

Gibt d (out) / dx aus, was eine teilweise Differenzierung von out durch x ist.

print(x.grad)
tensor([[4.5000, 4.5000],
        [4.5000, 4.5000]])

Da out out = z.mean () und z z = y * y * 3 ist, lautet die Formel wie folgt.

out = \frac{1}{4}\sum_{i=1}^{4}z_i
 、 
z_i = 3(x_i + 2)^2
 、 
z_i\bigr\rvert_{x_i=1} = 27 

Wenn also out teilweise durch x differenziert ist,

\begin{align}
\frac{\partial out}{\partial x_i} &= \frac{3}{2}(x_i+2)\\
&= \frac{9}{2} = 4.5
\end{align}

Sie können sehen, dass es automatisch differenziert wird.

4.You can do many crazy things with autograd!

Ich bin mir nicht sicher, was der folgende Code bedeutet, aber schauen wir uns das an.

x = torch.randn(3, requires_grad=True)

y = x * 2
while y.data.norm() < 1000:
    y = y * 2

print(y)
tensor([ -492.4446, -1700.8485,  -339.7951], grad_fn=<MulBackward0>)

x ist ein standardisierter Zufallswert (0 Mittelwert, 1 Standardabweichung). y.data.norm () wird auch in Wikipedia erklärt. Der Abstand im Vektorraum, der der folgenden euklidischen Norm entspricht.

Euklidische Norm= \sqrt{|x_1|^2+\cdots+|x_n|^2} \\

Bei zwei Dimensionen entspricht die Formel dem Abstand zwischen zwei Punkten, also genau dem Abstand. Wenn Sie versuchen, den Wert von x und norm () auszugeben, wird das Ergebnis der obigen Formel als Norm zurückgegeben.

\begin{eqnarray}
Euklidische Norm&=& \sqrt{|-0.9618|^2+|-3.3220|^2+|-0.6637|^2}\\
&=& 3.5215
\end{eqnarray}
print(x)
print(x.data.norm())
tensor([-0.9618, -3.3220, -0.6637], requires_grad=True)
tensor(3.5215)

Der obige Code drückt also den Ausdruck aus, dass x sich so lange verdoppelt, bis die Norm von x 1.000 ist.

Ich möchte den Gradienten von y mit y.backward () berechnen, aber da y kein Skalar ist, kann er nicht so berechnet werden, wie er ist. Tatsächlich führt das Ausführen von y.backward () zu einem Fehler.

y.backward()
RuntimeError: grad can be implicitly created only for scalar outputs

Der Gradient wird durch Einstellen eines geeigneten Vektors berechnet.

gradients = torch.tensor([0.1, 1.0, 0.0001], dtype=torch.float)
y.backward(gradients)

print(x.grad)
tensor([5.1200e+01, 5.1200e+02, 5.1200e-02])

Überlegen Sie, was dieses Tutorial bedeutet. Wie in diesem Tutorial erwähnt, kann der Gradient durch eine Jacobi-Matrix dargestellt werden.

\begin{split}J=\left(\begin{array}{ccc}
 \frac{\partial y_{1}}{\partial x_{1}} & \cdots & \frac{\partial y_{1}}{\partial x_{n}}\\
 \vdots & \ddots & \vdots\\
 \frac{\partial y_{m}}{\partial x_{1}} & \cdots & \frac{\partial y_{m}}{\partial x_{n}}
 \end{array}\right)\end{split}

Es gibt auch eine Aussage, dass Autograd ein Motor zur Berechnung des Produkts der Jacobi-Matrix und eines gegebenen Vektors ist.

\begin{split}J^{T}\cdot v=\left(\begin{array}{ccc}
 \frac{\partial y_{1}}{\partial x_{1}} & \cdots & \frac{\partial y_{m}}{\partial x_{1}}\\
 \vdots & \ddots & \vdots\\
 \frac{\partial y_{1}}{\partial x_{n}} & \cdots & \frac{\partial y_{m}}{\partial x_{n}}
 \end{array}\right)\left(\begin{array}{c}
 \frac{\partial l}{\partial y_{1}}\\
 \vdots\\
 \frac{\partial l}{\partial y_{m}}
 \end{array}\right)=\left(\begin{array}{c}
 \frac{\partial l}{\partial x_{1}}\\
 \vdots\\
 \frac{\partial l}{\partial x_{n}}
 \end{array}\right)\end{split}

Aufgrund dieser Informationen werde ich sie auf diesen Fall anwenden. Von hier aus ist es möglicherweise nicht richtig, weil es meine eigene Vorstellungskraft enthält.

x = torch.randn(3, requires_grad=True)

Da x 3 Zufallsvariablen ist, ist der Index n von x 3.

x_1 ,  x_2 , x_3

Betrachten Sie y. Die Definition von y ist wie folgt.

y = x * 2
while y.data.norm() < 1000:
    y = y * 2

Schauen wir uns zunächst das erste y = x * 2 an. Wenn man sich auf die Anzahl der Variablen konzentriert, ist y x * 2, was einfach verdoppelt wird, sodass sich die Anzahl der Variablen nicht ändert. Auch nach der Konvertierung mit y bleibt der Wert drei. Daher ist m auch 3 und die Größe der Jacobi-Matrix ist 3 × 3.

{\begin{split}J=\left(\begin{array}{ccc}
 \frac{\partial y_{1}}{\partial x_{1}} & \frac{\partial y_{1}}{\partial x_{2}} & \frac{\partial y_{1}}{\partial x_{3}}\\
 \frac{\partial y_{2}}{\partial x_{1}} & \frac{\partial y_{2}}{\partial x_{2}} & \frac{\partial y_{2}}{\partial x_{3}}\\
 \frac{\partial y_{3}}{\partial x_{1}} & \frac{\partial y_{3}}{\partial x_{2}} & \frac{\partial y_{3}}{\partial x_{3}}\\
 \end{array}\right)\end{split}
}

Die Druckwerte (x) über [-0,9618, -3,3220, -0,6637] gelten für [x1, x2, x3]. Wenn dieser Wert auf y = x * 2 angewendet wird, wird er zu [-1,9236, -6,644, -1,3274], was zu [y1, y2, y3] wird. Es war nicht notwendig, den numerischen Wert anzuwenden, aber die Umrechnungsformel für x und y lautet wie folgt.

y_1 = 2x_1\\
y_2 = 2x_2\\
y_3 = 2x_3\\

Die teilweise Differenzierung dieser Gleichung durch x1, x2 bzw. x3 ergibt Folgendes.

\frac{\partial y_{1}}{\partial x_{1}} = 2 , 
\frac{\partial y_{1}}{\partial x_{2}} = 0 , 
\frac{\partial y_{1}}{\partial x_{3}} = 0\\
\frac{\partial y_{2}}{\partial x_{1}} = 0 , 
\frac{\partial y_{2}}{\partial x_{2}} = 2 , 
\frac{\partial y_{2}}{\partial x_{3}} = 0\\
\frac{\partial y_{3}}{\partial x_{1}} = 0 , 
\frac{\partial y_{3}}{\partial x_{2}} = 0 , 
\frac{\partial y_{3}}{\partial x_{3}} = 2\\

Daher ist die Jacobi-Matrix wie folgt. während J1 verwendet wird, um die erste Umwandlung (y = x * 2) vorher darzustellen.

{\begin{split}J_1=\left(\begin{array}{ccc}
 2 & 0 & 0\\
 0 & 2 & 0\\
 0 & 0 & 2\\
 \end{array}\right)\end{split}
}

Betrachten Sie das zweite y. y = y * 2 nach while ist das zweite y. Da die Formel dieselbe wie beim ersten Mal ist, ist die Jacobi-Matrix von y zum zweiten Mal dieselbe wie zuvor und lautet wie folgt. Nennen wir es J2, um die zweite Yakobi-Matrix von y darzustellen.

{\begin{split}J_2=\left(\begin{array}{ccc}
 2 & 0 & 0\\
 0 & 2 & 0\\
 0 & 0 & 2\\
 \end{array}\right)\end{split}
}

Wiederholen Sie dies. Da der Anfangswert x.data.norm () "3.5215" und y.data.norm () <1000 ist, wird die Schleife 8 Mal ausgeführt und y 9 Mal definiert. Insgesamt sieht es so aus:

Formel Wert von x1 Wert von x2 Wert von x3
- x1 x2 x3
Konvertieren Sie mit dem ersten y 2 * x1 2 * x2 2 * x3
Konvertieren Sie mit dem zweiten y 4 * x1 4 * x2 4 * x3
Konvertiere zum dritten Mal mit y 8 * x1 8 * x2 8 * x3
Konvertieren Sie zum 4. Mal mit y 16 * x1 16 * x2 16 * x3
Zum fünften Mal mit y konvertieren 32 * x1 32 * x2 32 * x3
Zum sechsten Mal mit y konvertieren 64 * x1 64 * x2 64 * x3
Konvertiere zum siebten Mal mit y 128 * x1 128 * x2 128 * x3
Konvertieren Sie zum 8. Mal mit y 256 * x1 256 * x2 256 * x3
Konvertieren Sie mit dem 9. y 512 * x1 512 * x2 512 * x3

Schließlich wird y eine zusammengesetzte Funktion dieser neun Transformationen. Wie in Diese Mathe-Site beschrieben, kann die Jacobi-Matrix der zusammengesetzten Funktion durch die Gleichung der Matrix ausgedrückt werden. y Die gesamte Jacobi-Matrix J.

\begin{eqnarray}
J &=& J_9 \times J_8 \times J_7 \times J_6 \times J_5 \times J_4 \times J_3 \times J_2 \times J_1\\\\
&=&
\left(
    \begin{array}{ccc}
      2 & 0 & 0 \\
      0 & 2 & 0 \\
      0 & 0 & 2
    \end{array}
\right) 
\left(
    \begin{array}{ccc}
      2 & 0 & 0 \\
      0 & 2 & 0 \\
      0 & 0 & 2
    \end{array}
\right) 
\cdots
\left(
    \begin{array}{ccc}
      2 & 0 & 0 \\
      0 & 2 & 0 \\
      0 & 0 & 2
    \end{array}
\right) 
\left(
    \begin{array}{ccc}
      2 & 0 & 0 \\
      0 & 2 & 0 \\
      0 & 0 & 2
    \end{array}
\right) \\\\
&=&
\left(
    \begin{array}{ccc}
      512 & 0 & 0 \\
      0 & 512 & 0 \\
      0 & 0 & 512
    \end{array}
\right) 

\end{eqnarray}

Wird sein.

Wenden wir dies auf die folgende Berechnung an.

gradients = torch.tensor([0.1, 1.0, 0.0001], dtype=torch.float)
y.backward(gradients)

print(x.grad)

Gradienten sind Vektoren, die die Jacobi-Matrix multiplizieren. Wenn es auf die oben berechnete Jacobi-Matrix angewendet wird, wird es wie folgt.

{\begin{split}x.grad=\left(\begin{array}{ccc}
 512 & 0 & 0\\
 0 & 512 & 0\\
 0 & 0 & 512\\
 \end{array}\right)\left(\begin{array}{c}
 0.1\\
 1.0\\
 0.0001
 \end{array}\right)=\left(\begin{array}{c}
 51.2\\
 512\\
 0.0512
 \end{array}\right)\end{split}
}

Ist Autograd (automatische Differenzierung) zusammenfassend das folgende Bild?

Die Geschichte ändert sich hier, und wenn Sie wie folgt in den Block torch.no_grad () schreiben, können wir Änderungen in der Funktion nicht mehr verfolgen. (x ** 2) wird nicht verfolgt.

print(x.requires_grad)
print((x ** 2).requires_grad)

with torch.no_grad():
    print((x ** 2).requires_grad)
True
True
False

Separate () kopiert auch die Tensorvariablen, erbt jedoch nicht den Gradienten.

print(x.requires_grad)
y = x.detach()
print(y.requires_grad)
print(x.eq(y).all())
True
False
tensor(True)

5. Schließlich

Das ist alles für PyTorchs zweites Tutorial, Autograd: Automatic Differentiation. Der Inhalt war anders als im ersten Tutorial. In der zweiten Hälfte gibt es einen Teil der Vorstellungskraft, so dass es falsch sein kann. Ich würde es begrüßen, wenn Sie darauf hinweisen könnten.

Nächstes Mal möchte mit dem dritten Tutorial "NEURAL NETWORKS" fortfahren.

Geschichte

28.02.2020 Erstausgabe veröffentlicht 2020/04/22 Nächster Link hinzugefügt

Recommended Posts

[PyTorch Tutorial ②] Autograd: Automatische Differenzierung
[PyTorch] Tutorial (japanische Version) ② ~ AUTOGRAD ~
[PyTorch Tutorial ①] Was ist PyTorch?
[PyTorch] Beispiel ③ ~ TENSOREN UND AUTOGRAD ~
[PyTorch Tutorial ④] AUSBILDUNG EINES KLASSIFIERERS
[PyTorch] Beispiel ④ ~ Definieren neuer Autograd-Funktionen (Definition der automatischen Differentialfunktionen) ~
[PyTorch] Tutorial (japanische Version) ① ~ Tensol ~
Tutorial zum neuronalen Netz von Pytorch (CNN) 1.3.1.
[PyTorch Tutorial ②] Autograd: Automatische Differenzierung
Einführung in die Thano-Funktionsdefinition und automatische Differenzierung
[PyTorch Tutorial ⑤] PyTorch anhand von Beispielen lernen (Teil 2)
[PyTorch Tutorial ⑤] PyTorch anhand von Beispielen lernen (Teil 1)
[PyTorch Tutorial ⑥] Was ist torch.nn wirklich?