[PYTHON] Einführung in Deep Learning ~ Backpropagation ~

Zielperson

Dies ist eine Fortsetzung des vorherigen Artikels (# https://qiita.com/kuroitu/items/d22c8750e34d5d75fb6c). In diesem Artikel werden wir die Backpropagation anhand eines Berechnungsdiagramms kurz erläutern. Die Kettenregel wird in [hier] kurz erwähnt (# https://qiita.com/kuroitu/items/221e8c477ffdd0774b6b#chain-Regel), daher werde ich sie weglassen. Backpropagation hat in der Regel viele mathematische Formeln, aber ich möchte es mit der Implementierung erklären, damit es so intuitiv wie möglich verstanden werden kann.

Inhaltsverzeichnis

Backpropagation im Skalar

Beginnen wir wie im Beispiel mit der Backpropagation mit Skalaren. Die Rückausbreitung ist jedoch ziemlich schwierig, wenn Sie sie theoretisch auch mit Skalaren verfolgen. Ich werde es jedoch sehr kurz erklären.

Backpropagationstheorie im Skalar

Betrachten wir zunächst kurz das folgende Berechnungsdiagramm. backprop_neuron.png Wenn Sie die Vorwärtsausbreitung sorgfältig in die Abbildung schreiben

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

Es sieht aus wie das. Betrachten Sie diese Backpropagation. Betrachten Sie jede teilweise Differenzierung.

$\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)$
Es sieht so aus. Von hier aus sind dann die Eingabe $ x $ für die Ausgabe $ y $, das Gewicht $ w $ und die teilweise Differenzierung der Verzerrung $ b $ [Kettengesetz](https://qiita.com/kuroitu/items/221e8c477ffdd0774b6b#%E9%80%) Berechnen wir mit 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{}{}$

** << Achtung >> ** ** Da die Höhen zwangsweise ausgerichtet sind, wird an einigen Stellen "$ \ frac {} {} $" gemischt. Bitte lassen Sie mich wissen, ob es einen guten Weg gibt. Es gibt auch andere Möglichkeiten, der Formel Farbe hinzuzufügen ... **

Es wird sein. Wenn der Fehler $ E $ vom Upstream durchlaufen wird, ist die Rückausbreitung wie in der Abbildung gezeigt. Immerhin gibt es viele Formeln und es sieht kompliziert aus, das heißt, es multipliziert nur das partielle Differential, wenn es durch den ** Rechenknoten geht. ** ** ** Auch wenn dies ein Skalar ist, kann es einfacher sein.

Backpropagation-Implementierung im Skalar

Lassen Sie es uns implementieren. Code gemäß der Formel. Der Implementierungszielcode lautet [hier](https://qiita.com/kuroitu/items/884c62c48c2daa3def08#layer Modulcodevorbereitung).

baselayer.py


    def backward(self, grad):
        """
Implementierung der Backpropagation
        """
        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

Die mittlere Ebene ist in Ordnung, es ist jedoch erforderlich, eine gewisse Verarbeitung für die Ausgabeebene hinzuzufügen. Ich werde später darauf zurückkommen.

Backpropagation in einer Matrix

Als nächstes betrachten wir die Rückausbreitung in einer Matrix. Dies ist eine Menge Formeln und schwierig, aber Sie können es sehen, wenn Sie es richtig befolgen. Nach wie vor füge ich der Formel Farbe hinzu, damit sie auf einen Blick sichtbar ist. ~~ Ich fühle mich schwer ... ~~

Backpropagationstheorie in einer Matrix

Betrachten Sie das folgende Berechnungsdiagramm. backprop_layer.png Es ist dasselbe wie in [Forward Propagation](https://qiita.com/kuroitu/items/d22c8750e34d5d75fb6c# Forward Propagation in Matrix). Es ist ein Schichtmodell mit nur 2 Neuronen, aber wie Sie sehen können, gibt es ziemlich viele Formeln. Lassen Sie uns zunächst die teilweise Differenzierung jedes Teils wie im Fall des Skalars ermitteln.

$\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)$
Ich habe alle Formeln satt ... aber ich kann nichts dafür. Wenden wir das Kettengesetz an.
$\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}

Es sieht aus wie. Fügen Sie den Fehler aus dem Upstream zu diesen [Elementprodukten] hinzu (https://qiita.com/kuroitu/items/d22c8750e34d5d75fb6c#%E8%A1%8C%E5%88%97%E3%81%AE%E8%A6%81 Durch Multiplizieren mit% E7% B4% A0% E7% A9% 8D) wird der in der obigen Abbildung gezeigte Fehler weitergegeben. Wie Sie an der Tatsache sehen können, dass $ x_1 $ und $ x_2 $ verzweigt und die Werte an andere Berechnungsknoten gesendet wurden, müssen die fließenden Teildifferenzen addiert und berechnet werden. Also </ 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)

Es ist . Diese Formel repräsentiert intuitiv (und theoretisch) die Auswirkung der Eingabe $ x_1 $ und $ x_2 $ auf die Ausgabe $ y_1 $ und $ y_2 $. </ font>

Backpropagationstheorie in der Matrix-Batch-Betrachtungsversion

Übrigens wird bis zu diesem Punkt implizit die Stapelgröße $ N = 1 $ angenommen. Was passiert also, wenn es $ N \ ne 1 $ ist? Die Antwort ist einfach. Nur der Fehler in Bezug auf die Vorspannung $ B $ ändert sich. Schauen wir uns das mit einer Formel an. Geben Sie $ N \ mal L $ und $ N \ mal M $ </ font> ein

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

Es wird sein. Da der fließende Gradient zum Zeitpunkt der Eingabe mit jeder Form identisch sein muss, $ \ underbrace {\ boldsymbol {dW}} \ _ {L \ times M} $ und $ \ underbrace {\ boldsymbol {dB}} \ _ {1 \ times M} $, $ \ underbrace {\ boldsymbol {dX}} \ _ {N \ times L} $, davon $ \ underbrace {\ boldsymbol {dB}} \ _ {1 \ Die Formen stimmen nicht mit den Zeiten M} $ überein. Wenn also der Bias $ \ underbrace {\ boldsymbol {B}} _ {1 \ times M} $ vorwärts übertragen wird, wird die ** Broadcast-Funktion automatisch $ \ underbrace {\ boldsymbol {B}} \ Denken Sie daran, dass ** _ {N \ times M} $ sein sollte. Mit anderen Worten, das Anwenden der exakt gleichen Verzerrung auf alle Batchdaten ist gleichbedeutend mit ** Verzweigen der gleichen Verzerrung in $ N $ Stücke **. Wenn Sie also die Summe nehmen, Es wird gut sein **. </ 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)

Damit ist die Theorie zur Umsetzung abgeschlossen.

Backpropagation-Implementierung in einer Matrix

Lassen Sie es uns implementieren. Schreiben Sie die Implementierung in Skalar um.

baselayer.py


    def backward(self, grad):
        """
Implementierung der Backpropagation
        """
        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

Jedes hat sich zur Matrixberechnung geändert. Beachten Sie auch, dass die Funktion numpy.sum das Ergebnis des Hinzufügens aller Elemente zurückgibt, sofern Sie nicht axis = 0 angeben.

Überschreibung der Ausgabeebene

Der Rückausbreitung der Ausgabeschicht muss ein wenig Verarbeitung hinzugefügt werden.

outputlayer.py


    def backward(self, t):
        """
Implementierung der Backpropagation
        """
        #Wenn die Aktivierungsfunktion der Ausgangsschicht die Softmax-Funktion und die Verlustfunktion der Kreuzentropiefehler ist
        #Separate Fälle von Fehlerausbreitung
        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)

Der Inhalt der Überschreibung selbst ist einfach. Wenn die Aktivierungsfunktion der Ausgabeschicht eine Softmax-Funktion ist und die Verlustfunktion einen Kreuzentropiefehler verwendet, können Sie zum Fehler des Zurückpropagierens der Aktivierungsfunktion wie eines Codes springen. In anderen Fällen ist es notwendig, die Differenz der Verlustfunktion zu berechnen und den Fehler zu übergeben.

Implementierung der Methode __init __

Lassen Sie uns nun den Mitgliedern die oben erwähnte errfunc geben.

baselayer.py


    def __init__(self, *, prev=1, n=1, 
                 name="", wb_width=1,
                 act="ReLU", err_func="square",
                 **kwds):
        self.prev = prev  #Anzahl der Ausgänge der vorherigen Ebene=Anzahl der Eingaben in diese Ebene
        self.n = n        #Anzahl der Ausgänge in dieser Ebene=Anzahl der Eingaben in die nächste Ebene
        self.name = name  #Der Name dieser Ebene

        #Stellen Sie Gewicht und Vorspannung ein
        self.w = wb_width*np.random.randn(prev, n)
        self.b = wb_width*np.random.randn(n)

        #Aktivierungsfunktion(Klasse)Erhalten
        self.act = get_act(act)

        #Verlustfunktion(Klasse)Erhalten
        self.errfunc = get_errfunc(err_func)

Ich werde irgendwann einen Artikel über die Verlustfunktion schreiben.

abschließend

Ich frage mich, ob die Schwierigkeit, die Formeln zu färben, gelöst werden kann ...

Deep Learning-Serie

Recommended Posts