[PYTHON] Introduction au Deep Learning ~ Rétropropagation ~

Personne cible

Ceci est une continuation de l'article précédent (# https://qiita.com/kuroitu/items/d22c8750e34d5d75fb6c). Dans cet article, nous expliquerons brièvement la rétropropagation à l'aide d'un graphe de calcul. La règle de chaîne est brièvement mentionnée dans [ici](# https://qiita.com/kuroitu/items/221e8c477ffdd0774b6b#chain rule), je vais donc l'omettre. La rétropropagation a tendance à avoir de nombreuses formules mathématiques, mais je voudrais l'expliquer avec l'implémentation afin qu'elle puisse être comprise aussi intuitivement que possible.

table des matières

Rétropropagation en scalaire

Comme dans l'exemple, commençons par la rétropropagation avec des scalaires. Cependant, la rétropropagation est assez difficile si vous la suivez théoriquement même avec des scalaires. Cependant, je vais l'expliquer très brièvement.

Théorie de la rétropropagation en scalaire

Tout d'abord, examinons brièvement le graphique de calcul suivant. backprop_neuron.png Si vous écrivez attentivement la propagation vers l'avant dans la figure

\begin{align}
  m &= wx \\
  n &= m + b \\
  y &= \sigma(n)
\end{align}

Ça ressemble à ça. Considérez cette rétropropagation. Considérez chaque différenciation partielle.

$\cfrac{\partial m}{\partial x} = w \quad \quad$ $\cfrac{\partial m}{\partial w} = x$ $\cfrac{\partial n}{\partial m} = 1 \quad \quad$ $\cfrac{\partial n}{\partial b} = 1$ $\cfrac{\partial y}{\partial n} = \sigma'(n)$
Cela ressemble à ceci. Ensuite, à partir d'ici, l'entrée $ x $ pour la sortie $ y $, le poids $ w $ et la différenciation partielle du biais $ b $ sont [Loi des chaînes](https://qiita.com/kuroitu/items/221e8c477ffdd0774b6b#%E9%80% Calculons en utilisant A3% E9% 8E% 96% E5% BE% 8B).
$\cfrac{\partial y}{\partial x} = $ $\cfrac{\partial y}{\partial n}$ $\cfrac{\partial n}{\partial x} = $ $\cfrac{\partial y}{\partial n}$ $\cfrac{\partial n}{\partial m}$ $\cfrac{\partial m}{\partial x}$ $=\cfrac{}{}$ $\sigma'(n) \cfrac{}{}$ $\times \cfrac{}{} $ $1 \cfrac{}{}$ $\times\cfrac{}{} $ $w \cfrac{}{} $
$\cfrac{\partial y}{\partial w} = $ $\cfrac{\partial y}{\partial n}$ $\cfrac{\partial n}{\partial w} = $ $\cfrac{\partial y}{\partial n}$ $\cfrac{\partial n}{\partial m}$ $\cfrac{\partial m}{\partial w}$ $=\cfrac{}{}$ $\sigma'(n) \cfrac{}{}$ $\times \cfrac{}{} $ $1 \cfrac{}{}$ $\times\cfrac{}{} $ $x \cfrac{}{} $
$\cfrac{\partial y}{\partial b} = $ $\cfrac{\partial y}{\partial n}$ $\cfrac{\partial n}{\partial b}$ $=\cfrac{}{}$ $\sigma'(n) \cfrac{}{}$ $\times \cfrac{}{} $ $1 \cfrac{}{}$

** << Attention >> ** ** Parce que les hauteurs sont alignées de force, "$ \ frac {} {} $" est mélangé à certains endroits. S'il vous plaît laissez-moi savoir s'il existe un bon moyen. De plus, il existe d'autres façons d'ajouter de la couleur à la formule ... **

Ce sera. Si l'erreur $ E $ de l'amont est passée par là, la propagation arrière sera comme indiqué sur la figure. Après tout, il existe de nombreuses formules et cela semble compliqué, c'est-à-dire qu'il ne multiplie le différentiel partiel qu'en passant par le nœud de calcul **. ** ** Même ceci est un scalaire, donc cela peut être plus facile.

Implémentation de la rétropropagation en scalaire

Mettons-le en œuvre. Codez selon la formule. Le code de destination de l'implémentation est [ici](https://qiita.com/kuroitu/items/884c62c48c2daa3def08#layer préparation du code du module).

baselayer.py


    def backward(self, grad):
        """
Mise en œuvre de la rétropropagation
        """
        dact = grad*self.act.backward(self.x, self.y)
        self.dw = dact*self.x
        self.db = dact
        self.dx = dact*self.w

        return self.dx

La couche intermédiaire est correcte telle quelle, mais il est nécessaire d'ajouter un traitement pour la couche de sortie. J'y reviendrai plus tard.

Rétropropagation dans une matrice

Ensuite, considérons la rétro-propagation dans une matrice. C'est beaucoup de formules et difficile, mais vous pouvez le voir si vous le suivez correctement. Comme précédemment, j'ajouterai de la couleur à la formule pour qu'elle soit visible en un coup d'œil. ~~ Je me sens lourd ... ~~

Théorie de la rétropropagation dans une matrice

Considérez le graphique de calcul suivant. backprop_layer.png C'est le même que celui utilisé dans [Forward Propagation](https://qiita.com/kuroitu/items/d22c8750e34d5d75fb6c# Forward Propagation in Matrix). C'est un modèle de couche avec seulement 2 neurones, mais comme vous pouvez le voir, il y a pas mal de formules. Tout d'abord, trouvons la différenciation partielle de chaque partie comme dans le cas du scalaire.

$\cfrac{\partial l}{\partial x_1} = w\_{1, 1} \quad$ $\cfrac{\partial l}{\partial w_{1, 1}} = x\_1$ $\cfrac{\partial m}{\partial l} = 1 \quad$ $\cfrac{\partial m}{\partial b_1} = 1 \quad$ $\cfrac{\partial m}{\partial r} = 1$ $\cfrac{\partial n}{\partial x_1} = w\_{1, 2} \quad$ $\cfrac{\partial n}{\partial w_{1, 2}} = x\_1 \quad$ $\cfrac{\partial y_1}{\partial m} = \sigma'\_1(m)$ $\cfrac{\partial p}{\partial x_2} = w\_{2, 2} \quad$ $\cfrac{\partial p}{\partial w_{2, 2}} = x\_2$ $\cfrac{\partial q}{\partial p} = 1 \quad$ $\cfrac{\partial q}{\partial b_2} = 1 \quad$ $\cfrac{\partial q}{\partial n} = 1$ $\cfrac{\partial r}{\partial x_2} = w\_{2, 1} \quad$ $\cfrac{\partial r}{\partial w_{2, 1}} = x\_2$ $\cfrac{\partial y_2}{\partial q} = \sigma'\_2(q)$
J'en ai marre de toutes les formules ... mais je n'y peux rien. Appliquons la loi des chaînes.
$\cfrac{\partial y_1}{\partial w_{1, 1}} =$ $\cfrac{\partial y_1}{\partial m}$ $\cfrac{\partial m}{\partial l}$ $\cfrac{\partial l}{\partial w_{1, 1}}$ $=\cfrac{}{}$ $\sigma'\_1(m) \cfrac{}{}$ $\times \cfrac{}{}$ $1 \cfrac{}{}$ $\times \cfrac{}{}$ $x\_1 \cfrac{}{}$ $\cfrac{\partial y_2}{\partial w_{1, 2}} =$ $\cfrac{\partial y_2}{\partial q}$ $\cfrac{\partial q}{\partial n}$ $\cfrac{\partial n}{\partial w_{1, 2}}$ $=\cfrac{}{}$ $\sigma'\_2(q) \cfrac{}{}$ $\times \cfrac{}{}$ $1 \cfrac{}{}$ $\times \cfrac{}{}$ $x\_1 \cfrac{}{}$ $\cfrac{\partial y_1}{\partial w_{2, 1}} =$ $\cfrac{\partial y_1}{\partial m}$ $\cfrac{\partial m}{\partial r}$ $\cfrac{\partial r}{\partial w_{2, 1}}$ $=\cfrac{}{}$ $\sigma'\_1(m) \cfrac{}{}$ $\times \cfrac{}{}$ $1 \cfrac{}{}$ $\times \cfrac{}{}$ $x\_2 \cfrac{}{}$ $\cfrac{\partial y_2}{\partial w_{1, 2}} =$ $\cfrac{\partial y_2}{\partial q}$ $\cfrac{\partial q}{\partial p}$ $\cfrac{\partial p}{\partial w_{2, 2}}$ $=\cfrac{}{}$ $\sigma'\_2(q) \cfrac{}{}$ $\times \cfrac{}{}$ $1 \cfrac{}{}$ $\times \cfrac{}{}$ $x\_2 \cfrac{}{}$
\Rightarrow
\boldsymbol{dW} =
\left(
  \begin{array}{cc}
    \cfrac{\partial y_1}{\partial w_{1, 1}} & \cfrac{\partial y_2}{\partial w_{1, 2}} \\
    \cfrac{\partial y_1}{\partial w_{2, 1}} & \cfrac{\partial y_2}{\partial w_{2, 2}}
  \end{array}
\right)
=
\left(
  \begin{array}{c}
    x_1 \\
    x_2
  \end{array}
\right)
\left(
  \begin{array}{cc}
    \sigma'_1(m) & \sigma'_2(q)
  \end{array}
\right)
=
\boldsymbol{X}^{\top}\boldsymbol{\sigma'}
$\cfrac{\partial y_1}{\partial b_1} =$ $\cfrac{\partial y_1}{\partial m}$ $\cfrac{\partial m}{\partial b_1}$ $=\cfrac{}{}$ $\sigma'_1(m)\cfrac{}{}$ $\times \cfrac{}{}$ $1\cfrac{}{}$
$\cfrac{\partial y_2}{\partial b_2} =$ $\cfrac{\partial y_2}{\partial q}$ $\cfrac{\partial q}{\partial b_2}$ $=\cfrac{}{}$ $\sigma'_2(m)\cfrac{}{}$ $\times \cfrac{}{}$ $1\cfrac{}{}$
\Rightarrow
\boldsymbol{dB} =
\left(
  \begin{array}{cc}
    \cfrac{\partial y_1}{\partial b_1} & \cfrac{\partial y_2}{\partial b_2}
  \end{array}
\right)
=
\left(
  \begin{array}{cc}
     \sigma'_1(m) & \sigma'_2(q)
  \end{array}
\right)
$\cfrac{\partial y_1}{\partial x_1} + \cfrac{\partial y_2}{\partial x_1} =$ $\cfrac{\partial y_1}{\partial m}$ $\cfrac{\partial m}{\partial l}$ $\cfrac{\partial l}{\partial x_1}$ $+\cfrac{}{}$ $\cfrac{\partial y_2}{\partial q}$ $\cfrac{\partial q}{\partial n}$ $\cfrac{\partial n}{\partial x_1}$ $=\cfrac{}{}$ $\sigma'_1(m) \cfrac{}{}$ $\times \cfrac{}{}$ $1 \cfrac{}{}$ $\times \cfrac{}{}$ $w_{1, 1} \cfrac{}{}$ $+\cfrac{}{}$ $\sigma'_2(q) \cfrac{}{}$ $\times \cfrac{}{}$ $1 \cfrac{}{}$ $\times \cfrac{}{}$ $w_{1, 2} \cfrac{}{}$
$\cfrac{\partial y_1}{\partial x_2} + \cfrac{\partial y_2}{\partial x_2} =$ $\cfrac{\partial y_1}{\partial m}$ $\cfrac{\partial m}{\partial r}$ $\cfrac{\partial r}{\partial x_2}$ $+\cfrac{}{}$ $\cfrac{\partial y_2}{\partial q}$ $\cfrac{\partial q}{\partial p}$ $\cfrac{\partial p}{\partial x_2}$ $=\cfrac{}{}$ $\sigma'_1(m) \cfrac{}{}$ $\times \cfrac{}{}$ $1 \cfrac{}{}$ $\times \cfrac{}{}$ $w_{2, 1} \cfrac{}{}$ $+\cfrac{}{}$ $\sigma'_2(q) \cfrac{}{}$ $\times \cfrac{}{}$ $1 \cfrac{}{}$ $\times \cfrac{}{}$ $w_{2, 2} \cfrac{}{}$
\Rightarrow
\boldsymbol{dX} =
\left(
  \begin{array}{cc}
    \cfrac{\partial y_1}{\partial x_1} + \cfrac{\partial y_2}{\partial x_1} & \cfrac{\partial y_1}{\partial x_2} + \cfrac{\partial y_2}{\partial x_2}
  \end{array}
\right)
=
\left(
  \begin{array}{cc}
    \sigma'_1(m) & \sigma'_2(q)
  \end{array}
\right)
\left(
  \begin{array}{cc}
    w_{1, 1} & w_{2, 1} \\
    w_{1, 2} & w_{2, 2}
  \end{array}
\right)
=
\boldsymbol{\sigma'}\boldsymbol{W}^{\top}

On dirait. Ajoutez l'erreur en amont à ces [élément produit](https://qiita.com/kuroitu/items/d22c8750e34d5d75fb6c#%E8%A1%8C%E5%88%97%E3%81%AE%E8%A6%81 En multipliant par% E7% B4% A0% E7% A9% 8D), l'erreur comme indiqué dans la figure ci-dessus se propage. Comme vous pouvez le voir du fait que $ x_1 $ et $ x_2 $ ont été branchés et que les valeurs ont été envoyées à d'autres nœuds de calcul, les différentiels partiels qui ont coulé doivent être ajoutés et calculés. Donc </ font>

\left(
  \begin{array}{cc}
    \cfrac{\partial y_1}{\partial x_1} + \cfrac{\partial y_2}{\partial x_1} & \cfrac{\partial y_1}{\partial x_2} + \cfrac{\partial y_2}{\partial x_2}
  \end{array}
\right)

C'est . Cette formule représente intuitivement (et théoriquement) l'effet des entrées $ x_1 $ et $ x_2 $ sur les sorties $ y_1 $ et $ y_2 $. </ font>

Théorie de la rétropropagation dans la version de prise en compte des lots de matrice

En passant, jusqu'à présent, la taille du lot $ N = 1 $ est implicitement supposée. Alors que se passe-t-il quand c'est $ N \ ne 1 $? La réponse est simple. Seule l'erreur concernant le biais $ B $ change. Regardons cela avec une formule. Entrez $ N \ fois L $ et sortez $ N \ fois M $ </ font>

\begin{align}
  \underbrace{\boldsymbol{dW}}_{L \times M} &= \underbrace{\boldsymbol{X}^{\top}}_{L \times N} \underbrace{\boldsymbol{\sigma'}}_{N \times M} \\
  \underbrace{\boldsymbol{dB}}_{1 \times M} &= \underbrace{\boldsymbol{\sigma'}}_{N\times M} \\
  \underbrace{\boldsymbol{dX}}_{N \times L} &= \underbrace{\boldsymbol{\sigma'}}_{N \times M} \underbrace{\boldsymbol{W}^{\top}}_{M \times L}
\end{align}

Ce sera . Puisque le dégradé fluide doit être identique à chaque forme au moment de la saisie, $ \ underbrace {\ boldsymbol {dW}} \ _ {L \ times M} $ et $ \ underbrace {\ boldsymbol {dB}} \ _ {1 \ times M} $, $ \ underbrace {\ boldsymbol {dX}} \ _ {N \ times L} $, dont $ \ underbrace {\ boldsymbol {dB}} \ _ {1 \ Les formes ne correspondent pas par temps M} $. Ensuite, ce qu'il faut faire est que lorsque le biais $ \ underbrace {\ boldsymbol {B}} _ {1 \ times M} $ est propagé en avant, ** la fonction de diffusion automatiquement $ \ underbrace {\ boldsymbol {B}} \ Rappelez-vous que ** était censé être _ {N \ fois M} $. En d'autres termes, appliquer exactement le même biais à toutes les données de lot est synonyme de ** ramifier le même biais en éléments $ N $ **, donc si vous prenez la somme, Ça va être bien **. </ font>

\underbrace{\boldsymbol{dB}}_{1 \times M} = \sum_{i=1}^{N}{\underbrace{\boldsymbol{\sigma'}_i}_{1\times M}} \xrightarrow{\textrm{coding}} \textrm{sum}(\boldsymbol{\sigma'}, \textrm{axis}=0)

Ceci conclut la théorie de la mise en œuvre.

Implémentation de la rétropropagation dans une matrice

Mettons-le en œuvre. Réécrivez l'implémentation en scalaire.

baselayer.py


    def backward(self, grad):
        """
Mise en œuvre de la rétropropagation
        """
        dact = grad*self.act.backward(self.x, self.y)
        self.dw = self.x.T@dact
        self.db = np.sum(dact, axis=0)
        self.dx = [email protected]

        return self.dx

Chacun est passé au calcul matriciel. Notez également que la fonction numpy.sum retournera le résultat de l'ajout de tous les éléments sauf si vous spécifiez ʻaxis = 0`.

Remplacement du calque de sortie

Un peu de traitement doit être ajouté à la propagation arrière de la couche de sortie.

outputlayer.py


    def backward(self, t):
        """
Mise en œuvre de la rétropropagation
        """
        #Lorsque la fonction d'activation de la couche de sortie est la fonction softmax et la fonction de perte est l'erreur d'entropie croisée
        #Cas séparés de propagation d'erreur
        if isinstance(self.act, Softmax) \
        and isinstance(self.errfunc, CrossEmtropy):
            dact = self.y - t
            self.dw = self.x.T@dact
            self.db = np.sum(dact, axis=0)
            self.dx = [email protected]
            
            return self.dx
        else:
            grad = self.errfunc.backward(self.y, t)
            return super().__init__(grad)

Le contenu du remplacement lui-même est simple. Si la fonction d'activation de la couche de sortie est une fonction softmax et que la fonction de perte utilise une erreur d'entropie croisée, vous pouvez passer à l'erreur de rétropropagation de la fonction d'activation comme un code. Dans d'autres cas, il est nécessaire de calculer le différentiel de la fonction de perte et de passer l'erreur.

Implémentation de la méthode __init __

Maintenant, faisons en sorte que les membres aient le ʻerrfunc` mentionné ci-dessus.

baselayer.py


    def __init__(self, *, prev=1, n=1, 
                 name="", wb_width=1,
                 act="ReLU", err_func="square",
                 **kwds):
        self.prev = prev  #Nombre de sorties de la couche précédente=Nombre d'entrées dans cette couche
        self.n = n        #Nombre de sorties dans cette couche=Nombre d'entrées vers la couche suivante
        self.name = name  #Le nom de cette couche

        #Définir le poids et le biais
        self.w = wb_width*np.random.randn(prev, n)
        self.b = wb_width*np.random.randn(n)

        #Fonction d'activation(classe)Avoir
        self.act = get_act(act)

        #Fonction de perte(classe)Avoir
        self.errfunc = get_errfunc(err_func)

J'écrirai éventuellement un article sur la fonction de perte.

en conclusion

Je me demande si la difficulté de colorer les formules peut être résolue ...

Série d'apprentissage en profondeur

Recommended Posts