[PYTHON] [Tutoriel PyTorch ②] Autograd: différenciation automatique

introduction

Ceci est le deuxième volet de PyTorch Tutoriel officiel après Dernière fois. Cette fois, je voudrais continuer avec Autograd: Automatic Differentiation.

table des matières

1.Autograd 2.Tensor 3. Dégradé 4.You can do many crazy things with autograd! 5. Enfin Histoire

1.Autograd

PyTorch a une fonction Autograd. Les informations de gradient sont stockées dans Tensor et le gradient est calculé par la méthode backward () pour le graphe de calcul défini (expression). Jetons un coup d'œil à Autograd avec un exemple concret ci-dessous.

2.Tensor

Le Tensor de PyTorch enregistrera le dégradé en définissant l'attribut requires_grad sur True. Lorsque vous calculez le dégradé avec backward (), le dégradé est conservé dans l'attribut grad du Tensor.

La description suivante définit Tensor. Spécifiez require_grad = True pour que le dégradé soit enregistré.

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

Créer un graphique de calcul (formule) y.

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

Lorsque j'imprime, j'ai grad_fn dans la sortie. Cela montre qu'un graphe de calcul a été construit pour calculer le gradient.

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

Utilisez y pour créer d'autres graphiques de calcul (formules) z et out.

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

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

[Informations de référence] Vous pouvez modifier l'attribut requires_grad avec tensor.requires_grad_ ().

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. Dégradé

Calculez le dégradé avec out.backward ().

out.backward()

Sorties d (out) / dx, qui est une différenciation partielle de out par x.

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

Puisque out est out = z.mean () et z est z = y * y * 3, la formule est la suivante.

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 

Par conséquent, si out est partiellement différencié par x,

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

Vous pouvez voir qu'il est automatiquement différencié.

4.You can do many crazy things with autograd!

Je ne sais pas ce que signifie le code ci-dessous, mais jetons un œil.

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 est une valeur aléatoire normalisée (0 moyenne, 1 écart type). y.data.norm () est également expliqué dans Wikipedia, La distance dans l'espace vectoriel, qui est la norme euclidienne suivante.

Norme euclidienne= \sqrt{|x_1|^2+\cdots+|x_n|^2} \\

Dans le cas de deux dimensions, la formule est la même que la distance entre deux points, c'est donc exactement la distance. En fait, si vous essayez de sortir la valeur de x et norm (), le résultat de la formule ci-dessus sera renvoyé comme norme.

\begin{eqnarray}
Norme euclidienne&=& \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)

Ainsi, le code ci-dessus exprime l'expression que x continue de doubler jusqu'à ce que la norme de x soit 1000.

Je veux calculer le gradient de y avec y.backward (), mais comme y n'est pas un scalaire, il ne peut pas être calculé tel quel. En fait, exécuter y.backward () donne une erreur.

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

Le gradient est calculé en définissant un vecteur approprié.

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])

Considérez ce que signifie ce tutoriel. Comme mentionné dans ce tutoriel, le dégradé peut être représenté par une matrice Jacobi.

\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}

Il y a aussi une déclaration selon laquelle autograd est un moteur pour calculer le produit de la matrice de Jacobi et d'un vecteur donné.

\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}

Sur la base de ces informations, je l'appliquerai à ce cas. À partir de là, ce n'est peut-être pas correct car il contient ma propre imagination.

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

Puisque x est 3 variables aléatoires, l'indice n de x est 3.

x_1 ,  x_2 , x_3

Considérez y. La définition de y est la suivante.

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

Tout d'abord, regardons le premier y = x * 2. En se concentrant sur le nombre de variables, y est x * 2, qui est simplement doublé, de sorte que le nombre de variables ne change pas. Ainsi, même après la conversion avec y, la valeur reste trois. Par conséquent, m est également 3 et la taille de la matrice de Jacobi est 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}
}

Les valeurs d'impression (x) supérieures à [-0,9618, -3,3220, -0,6637] s'appliquent à [x1, x2, x3]. De plus, lorsque cette valeur est appliquée à y = x * 2, elle devient [-1,9236, -6,644, -1,3274], qui devient [y1, y2, y3]. Il n'était pas nécessaire d'appliquer la valeur numérique, mais la formule de conversion pour x et y est la suivante.

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

La différenciation partielle de cette équation par x1, x2 et x3, respectivement, donne ce qui suit.

\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\\

Par conséquent, la matrice de Jacobi est la suivante. tandis que J1 est utilisé pour représenter la première conversion (y = x * 2) avant.

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

Considérez le deuxième y. y = y * 2 après while est le deuxième y. Puisque la formule est la même que la première fois, la matrice de Jacobi de y pour la deuxième fois est la même que précédemment et se présente comme suit. Appelons-le J2 pour représenter la deuxième matrice de Yakobi de y.

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

Répétez ceci. Puisque la valeur initiale x.data.norm () est "3,5215" et y.data.norm () <1000, la boucle est exécutée 8 fois et y est défini 9 fois. Dans son ensemble, cela ressemble à ceci:

formule Valeur de x1 Valeur de x2 Valeur de x3
- x1 x2 x3
Convertir avec le premier y 2 * x1 2 * x2 2 * x3
Convertir avec le deuxième y 4 * x1 4 * x2 4 * x3
Convertir avec y pour la troisième fois 8 * x1 8 * x2 8 * x3
Convertir avec y pour la 4ème fois 16 * x1 16 * x2 16 * x3
Convertir avec y pour la 5ème fois 32 * x1 32 * x2 32 * x3
Convertir avec y pour la 6ème fois 64 * x1 64 * x2 64 * x3
Convertir avec y pour la 7ème fois 128 * x1 128 * x2 128 * x3
Convertir avec y pour la 8e fois 256 * x1 256 * x2 256 * x3
Convertir avec le 9e y 512 * x1 512 * x2 512 * x3

Enfin y devient une fonction composite de ces neuf transformations. Comme décrit dans Ce site mathématique, la matrice de Jacobi de la fonction composite peut être exprimée par l'équation de la matrice. y Toute la matrice de Jacobi 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}

Sera.

Appliquons ceci au calcul suivant.

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

print(x.grad)

les gradients sont des vecteurs qui multiplient la matrice de Jacobi. Lorsqu'il est appliqué à la matrice de Jacobi calculée ci-dessus, il devient comme suit.

{\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}
}

En résumé, Autograd (différenciation automatique) est-elle l'image suivante?

L'histoire change ici, et en écrivant dans le bloc torch.no_grad () comme suit, nous ne pouvons plus suivre les changements dans la fonction. (x ** 2) n'est pas suivi.

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

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

De plus, detach () copie les variables de tenseur, mais n'hérite pas du gradient.

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

5. Enfin

C'est tout pour le deuxième tutoriel de PyTorch, Autograd: Différenciation automatique. Le contenu était différent du premier tutoriel. Dans la seconde moitié, il y a une part d'imagination, donc ça peut être faux. Je vous serais reconnaissant si vous pouviez le signaler.

La prochaine fois aimerait continuer avec le troisième tutoriel "NEURAL NETWORKS".

Histoire

2020/02/28 Première édition publiée 2020/04/22 Lien suivant ajouté

Recommended Posts

[Tutoriel PyTorch ②] Autograd: différenciation automatique
Tutoriel [PyTorch] (version japonaise) ② ~ AUTOGRAD ~
[Tutoriel PyTorch ①] Qu'est-ce que PyTorch?
[PyTorch] Exemple ③ ~ TENSEURS ET AUTOGRAD ~
[Tutoriel PyTorch ④] FORMATION D'UN CLASSIFICATEUR
Exemple [PyTorch] ④ ~ Définition de nouvelles fonctions d'autogradation (définition de fonctions différentielles automatiques) ~
Tutoriel [PyTorch] (version japonaise) ① ~ Tensol ~
Tutoriel sur le réseau neuronal (CNN) de Pytorch 1.3.1.
[Tutoriel PyTorch ②] Autograd: différenciation automatique
Introduction à la définition de la fonction Thano et à la différenciation automatique
[Tutoriel PyTorch ⑤] Apprentissage de PyTorch avec des exemples (Partie 2)
[Tutoriel PyTorch ⑤] Apprentissage de PyTorch avec des exemples (Partie 1)
[Tutoriel PyTorch ⑥] Qu'est-ce que torch.nn?