深層学習入門 ~逆伝播編~

# 対象者
[前回の記事](#https://qiita.com/kuroitu/items/d22c8750e34d5d75fb6c)の続きです。
本記事では逆伝播について、計算グラフを用いて簡単に説明します。連鎖律については[ここ](#https://qiita.com/kuroitu/items/221e8c477ffdd0774b6b#連鎖律)で簡単に触れていますので省略します。
どうしても数式多くなりがちな逆伝播ですが、実装を交えて極力直感的な理解で済むように説明したいと思います。

次回の記事は[こちら](https://qiita.com/kuroitu/items/ab5ad4ac716ae7a04891)


# 目次
- [スカラでの逆伝播](#スカラでの逆伝播)
    - [スカラでの逆伝播理論](#スカラでの逆伝播理論)
    - [スカラでの逆伝播実装](#スカラでの逆伝播実装)
- [行列での逆伝播](#行列での逆伝播)
    - [行列での逆伝播理論](#行列での逆伝播理論)
    - [行列での逆伝播実装](#行列での逆伝播実装)
    - [行列での逆伝播理論バッチ考慮版](#行列での逆伝播理論バッチ考慮版)
- [`__init__`メソッドの実装](#__init__メソッドの実装)
- [おわりに](#おわりに)


# スカラでの逆伝播
例の如くまずはスカラでの逆伝播から見ていきます。とはいえスカラでもちゃんと理論的に追うとなかなか大変なのが逆伝播です。
が、ものすごく簡単に説明していきます。

## スカラでの逆伝播理論
まずは簡単に以下の計算グラフで考えていきましょう。
![backprop_neuron.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640911/eb7c124b-9483-de29-ca50-6d9819f85934.png)
図中の順伝播をまずは丁寧に書くと

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

のようになっていますね。この逆伝播を考えます。
それぞれの偏微分を考えてみます。
<font color="Blue">$\cfrac{\partial m}{\partial x} = w \quad \quad$</font> <font color="MediumPurple ">$\cfrac{\partial m}{\partial w} = x$</font>
<font color="Red">$\cfrac{\partial n}{\partial m} = 1 \quad \quad$</font> <font color="Coral">$\cfrac{\partial n}{\partial b} = 1$</font>
<font color="Lime">$\cfrac{\partial y}{\partial n} = \sigma'(n)$</font>
こんな感じですね。ではここから出力$y$に対する入力$x$と重み$w$、バイアス$b$の偏微分を[連鎖律](https://qiita.com/kuroitu/items/221e8c477ffdd0774b6b#%E9%80%A3%E9%8E%96%E5%BE%8B)を用いて計算してみましょう。
<font color="Black">$\cfrac{\partial y}{\partial x} = $</font> <font color="Lime">$\cfrac{\partial y}{\partial n}$</font> <font color="Black">$\cfrac{\partial n}{\partial x} = $</font> <font color="Lime">$\cfrac{\partial y}{\partial n}$</font> <font color="Red">$\cfrac{\partial n}{\partial m}$</font> <font color="Blue">$\cfrac{\partial m}{\partial x}$</font> <font color="Black">$=\cfrac{}{}$</font> <font color="Lime">$\sigma'(n) \cfrac{}{}$</font> <font color="Black">$\times \cfrac{}{} $</font> <font color="Red">$1 \cfrac{}{}$</font> <font color="Black">$\times\cfrac{}{} $</font> <font color="Blue">$w \cfrac{}{} $</font>
<font color="Black">$\cfrac{\partial y}{\partial w} = $</font> <font color="Lime">$\cfrac{\partial y}{\partial n}$</font> <font color="Black">$\cfrac{\partial n}{\partial w} = $</font> <font color="Lime">$\cfrac{\partial y}{\partial n}$</font> <font color="Red">$\cfrac{\partial n}{\partial m}$</font> <font color="MediumPurple">$\cfrac{\partial m}{\partial w}$</font> <font color="Black">$=\cfrac{}{}$</font> <font color="Lime">$\sigma'(n) \cfrac{}{}$</font> <font color="Black">$\times \cfrac{}{} $</font> <font color="Red">$1 \cfrac{}{}$</font> <font color="Black">$\times\cfrac{}{} $</font> <font color="MediumPurple">$x \cfrac{}{} $</font>
<font color="Black">$\cfrac{\partial y}{\partial b} = $</font> <font color="Lime">$\cfrac{\partial y}{\partial n}$</font> <font color="Coral">$\cfrac{\partial n}{\partial b}$</font> <font color="Black">$=\cfrac{}{}$</font> <font color="Lime">$\sigma'(n) \cfrac{}{}$</font> <font color="Black">$\times \cfrac{}{} $</font> <font color="Coral">$1 \cfrac{}{}$</font>

**<< 注意 >>**
**無理矢理高さを揃えているため「$\frac{}{}$」が所々混じってます。なにかいい方法あれば教えてください。あと数式に色を振る他の方法もぜひ...**

となりますね。これに上流からの誤差$E$を流せば図にあるような逆伝播になります。
やっぱり数式が多く複雑に見えますが、つまり**計算ノードを通る時に偏微分を乗算してるだけです。**
これでもスカラなので簡単な方だったりします。

## スカラでの逆伝播実装
では実装してみます。数式通りにコーディングしましょう。実装先のコードは[こちら](https://qiita.com/kuroitu/items/884c62c48c2daa3def08#レイヤーモジュールのコード準備)です。

```baselayer.py
    def backward(self, grad):
        """
        逆伝播の実装
        """
        dact = grad*self.act.backward(self.x, self.y)
        self.grad_w = dact*self.x
        self.grad_b = dact
        self.grad_x = dact*self.w

        return self.grad_x
```

中間層はこのままでOKですが、出力層については処理を一部追加する必要がありますね。
後ほど触れます。


# 行列での逆伝播
続いて行列での逆伝播を考えてみましょう。こちらは非常に数式が多く大変ですが、きちんと追いかけてみるとわかるはずです。
先ほどと同じように数式に色を振って、ぱっと見でわかるようにしようと思います。~~気が重い...~~

## 行列での逆伝播理論
以下の計算グラフを考えます。
![backprop_layer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640911/457f203f-1045-d4c4-1795-2566d0a7a4bd.png)
[順伝播](https://qiita.com/kuroitu/items/d22c8750e34d5d75fb6c#行列での順伝播)で使ったものと同じですね。2ニューロンしかないレイヤーモデルですが、これでもご覧の通りかなり数式が多くなります。
まずはスカラの時と同じようにそれぞれの部分の偏微分を求めておきましょう。
<font color="Blue">$\cfrac{\partial l}{\partial x_1} = w\_{1, 1} \quad$</font> <font color="MediumPurple ">$\cfrac{\partial l}{\partial w_{1, 1}} = x\_1$</font>
<font color="Red">$\cfrac{\partial m}{\partial l} = 1 \quad$</font> <font color="Coral">$\cfrac{\partial m}{\partial b_1} = 1 \quad$</font> <font color="DarkKhaki">$\cfrac{\partial m}{\partial r} = 1$</font>
<font color="Lime">$\cfrac{\partial n}{\partial x_1} = w\_{1, 2} \quad$</font> <font color="ForestGreen">$\cfrac{\partial n}{\partial w_{1, 2}} = x\_1 \quad$</font>
<font color="DarkCyan">$\cfrac{\partial y_1}{\partial m} = \sigma'\_1(m)$</font>
<font color="Aqua">$\cfrac{\partial p}{\partial x_2} = w\_{2, 2} \quad$</font> <font color="Navy">$\cfrac{\partial p}{\partial w_{2, 2}} = x\_2$</font>
<font color="Tan">$\cfrac{\partial q}{\partial p} = 1 \quad$</font> <font color="SaddleBrown">$\cfrac{\partial q}{\partial b_2} = 1 \quad$</font> <font color="HotPink">$\cfrac{\partial q}{\partial n} = 1$</font>
<font color="Magenta">$\cfrac{\partial r}{\partial x_2} = w\_{2, 1} \quad$</font> <font color="DarkGreen">$\cfrac{\partial r}{\partial w_{2, 1}} = x\_2$</font>
<font color="DarkTurquoise">$\cfrac{\partial y_2}{\partial q} = \sigma'\_2(q)$</font>

数式ばっかりでうんざりですね...とはいえ仕方ないです。
では連鎖律を適用してみましょう。
<font color="Black">$\cfrac{\partial y_1}{\partial w_{1, 1}} =$</font> <font color="DarkCyan">$\cfrac{\partial y_1}{\partial m}$</font> <font color="Red">$\cfrac{\partial m}{\partial l}$</font> <font color="MediumPurple ">$\cfrac{\partial l}{\partial w_{1, 1}}$</font> <font color="Black">$=\cfrac{}{}$</font> <font color="DarkCyan">$\sigma'\_1(m) \cfrac{}{}$</font> <font color="Black">$\times \cfrac{}{}$</font> <font color="Red">$1 \cfrac{}{}$</font> <font color="Black">$\times \cfrac{}{}$</font> <font color="MediumPurple ">$x\_1 \cfrac{}{}$</font>
<font color="Black">$\cfrac{\partial y_2}{\partial w_{1, 2}} =$</font> <font color="DarkTurquoise">$\cfrac{\partial y_2}{\partial q}$</font> <font color="HotPink">$\cfrac{\partial q}{\partial n}$</font> <font color="ForestGreen ">$\cfrac{\partial n}{\partial w_{1, 2}}$</font> <font color="Black">$=\cfrac{}{}$</font> <font color="DarkTurquoise">$\sigma'\_2(q) \cfrac{}{}$</font> <font color="Black">$\times \cfrac{}{}$</font> <font color="HotPink">$1 \cfrac{}{}$</font> <font color="Black">$\times \cfrac{}{}$</font> <font color="ForestGreen">$x\_1 \cfrac{}{}$</font>
<font color="Black">$\cfrac{\partial y_1}{\partial w_{2, 1}} =$</font> <font color="DarkCyan">$\cfrac{\partial y_1}{\partial m}$</font> <font color="DarkKhaki">$\cfrac{\partial m}{\partial r}$</font> <font color="DarkGreen ">$\cfrac{\partial r}{\partial w_{2, 1}}$</font> <font color="Black">$=\cfrac{}{}$</font> <font color="DarkCyan">$\sigma'\_1(m) \cfrac{}{}$</font> <font color="Black">$\times \cfrac{}{}$</font> <font color="DarkKhaki">$1 \cfrac{}{}$</font> <font color="Black">$\times \cfrac{}{}$</font> <font color="DarkGreen ">$x\_2 \cfrac{}{}$</font>
<font color="Black">$\cfrac{\partial y_2}{\partial w_{1, 2}} =$</font> <font color="DarkTurquoise">$\cfrac{\partial y_2}{\partial q}$</font> <font color="Tan">$\cfrac{\partial q}{\partial p}$</font> <font color="Navy ">$\cfrac{\partial p}{\partial w_{2, 2}}$</font> <font color="Black">$=\cfrac{}{}$</font> <font color="DarkTurquoise">$\sigma'\_2(q) \cfrac{}{}$</font> <font color="Black">$\times \cfrac{}{}$</font> <font color="Tan">$1 \cfrac{}{}$</font> <font color="Black">$\times \cfrac{}{}$</font> <font color="Navy">$x\_2 \cfrac{}{}$</font>

```math
\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'}
```

<font color="Black">$\cfrac{\partial y_1}{\partial b_1} =$</font> <font color="DarkCyan">$\cfrac{\partial y_1}{\partial m}$</font> <font color="Coral">$\cfrac{\partial m}{\partial b_1}$</font> <font color="Black">$=\cfrac{}{}$</font> <font color="DarkCyan">$\sigma'_1(m)\cfrac{}{}$</font> <font color="Black">$\times \cfrac{}{}$</font> <font color="Coral">$1\cfrac{}{}$</font></div>
<div><font color="Black">$\cfrac{\partial y_2}{\partial b_2} =$</font> <font color="DarkTurquoise">$\cfrac{\partial y_2}{\partial q}$</font> <font color="SaddleBrown">$\cfrac{\partial q}{\partial b_2}$</font> <font color="Black">$=\cfrac{}{}$</font> <font color="DarkTurquoise">$\sigma'_2(m)\cfrac{}{}$</font> <font color="Black">$\times \cfrac{}{}$</font> <font color="SaddleBrown">$1\cfrac{}{}$</font>

```math
\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)
```

<font color="Black">$\cfrac{\partial y_1}{\partial x_1} + \cfrac{\partial y_2}{\partial x_1} =$</font> <font color="DarkCyan">$\cfrac{\partial y_1}{\partial m}$</font> <font color="Red">$\cfrac{\partial m}{\partial l}$</font> <font color="MediumPurple">$\cfrac{\partial l}{\partial x_1}$</font> <font color="Black">$+\cfrac{}{}$</font> <font color="DarkTurquoise">$\cfrac{\partial y_2}{\partial q}$</font> <font color="HotPink">$\cfrac{\partial q}{\partial n}$</font> <font color="Lime">$\cfrac{\partial n}{\partial x_1}$</font> <font color="Black">$=\cfrac{}{}$</font> <font color="DarkCyan">$\sigma'_1(m) \cfrac{}{}$</font> <font color="Black">$\times \cfrac{}{}$</font> <font color="Red">$1 \cfrac{}{}$</font> <font color="Black">$\times \cfrac{}{}$</font> <font color="MediumPurple ">$w_{1, 1} \cfrac{}{}$</font> <font>$+\cfrac{}{}$</font> <font color="DarkTurquoise">$\sigma'_2(q) \cfrac{}{}$</font> <font color="Black">$\times \cfrac{}{}$</font> <font color="HotPink">$1 \cfrac{}{}$</font> <font color="Black">$\times \cfrac{}{}$</font> <font color="Lime">$w_{1, 2} \cfrac{}{}$</font></div>
<div><font color="Black">$\cfrac{\partial y_1}{\partial x_2} + \cfrac{\partial y_2}{\partial x_2} =$</font> <font color="DarkCyan">$\cfrac{\partial y_1}{\partial m}$</font> <font color="DarkKhaki">$\cfrac{\partial m}{\partial r}$</font> <font color="Magenta">$\cfrac{\partial r}{\partial x_2}$</font> <font color="Black">$+\cfrac{}{}$</font> <font color="DarkTurquoise">$\cfrac{\partial y_2}{\partial q}$</font> <font color="Tan">$\cfrac{\partial q}{\partial p}$</font> <font color="Aqua">$\cfrac{\partial p}{\partial x_2}$</font> <font color="Black">$=\cfrac{}{}$</font> <font color="DarkCyan">$\sigma'_1(m) \cfrac{}{}$</font> <font color="Black">$\times \cfrac{}{}$</font> <font color="DarkKhaki">$1 \cfrac{}{}$</font> <font color="Black">$\times \cfrac{}{}$</font> <font color="Magenta ">$w_{2, 1} \cfrac{}{}$</font> <font>$+\cfrac{}{}$</font> <font color="DarkTurquoise">$\sigma'_2(q) \cfrac{}{}$</font> <font color="Black">$\times \cfrac{}{}$</font> <font color="Tan">$1 \cfrac{}{}$</font> <font color="Black">$\times \cfrac{}{}$</font> <font color="Aqua">$w_{2, 2} \cfrac{}{}$</font>

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

のようになります。これらに上流からの誤差を[要素積](https://qiita.com/kuroitu/items/d22c8750e34d5d75fb6c#%E8%A1%8C%E5%88%97%E3%81%AE%E8%A6%81%E7%B4%A0%E7%A9%8D)で乗算することで上の図のような誤差が伝播します。
なお、$x_1$や$x_2$は分岐して他の計算ノードに値を流していたことからも分かる通り、流れてきた偏微分は足し合わせて計算する必要があります。なので

```math
\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)
```

となっているんですね。この式は直感的(そして理論的)には、出力$y_1$や$y_2$に対しての入力$x_1$や$x_2$の影響を表しています。

## 行列での逆伝播理論バッチ考慮版
さて、ここまではバッチサイズ$N=1$を暗に仮定していたりします。それでは$N \ne 1$の時はどうなるでしょうか？
答えは簡単です。バイアス$B$に関する誤差のみ変わります。
これを数式で見てみましょう。入力$N \times L$、出力$N \times M$とすると

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

となります。流れてくる勾配は入力時のそれぞれの形状と同じである必要があるため$\underbrace{\boldsymbol{dW}}\_{L \times M}$や$\underbrace{\boldsymbol{dB}}\_{1 \times M}$、$\underbrace{\boldsymbol{dX}}\_{N \times L}$となりますが、この中で$\underbrace{\boldsymbol{dB}}\_{1 \times M}$だけ形状が一致していません。
ではどうするのかというと、バイアス$\underbrace{\boldsymbol{B}}_{1 \times M}$が順伝播の際は**ブロードキャスト機能によって自動的に$\underbrace{\boldsymbol{B}}\_{N \times M}$とされていた**ことを思い出します。
つまり、全てのバッチデータに対して全く同じバイアスを適用しているということは、**同じバイアスを$N$個に分岐して流したのと同義**ですので、**和を取ればいい**ということになります。

```math
\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)
```

これで実装のための理論が終了しました。

## 行列での逆伝播実装
では実装していきます。スカラでの実装を書き換えます。

```baselayer.py
    def backward(self, grad):
        """
        逆伝播の実装
        """
        dact = grad*self.act.backward(self.u, self.y)
        self.grad_w = self.x.T@dact
        self.grad_b = np.sum(dact, axis=0)
        self.grad_x = dact@self.w.T

        return self.grad_x
```

それぞれ行列演算に変わっていますね。また、`numpy.sum`関数は`axis=0`と指定しないと全ての要素を足した結果を返してしまうため注意しましょう。


# 出力層のオーバーライド
出力層の逆伝播については少し処理を加える必要があります。

```outputlayer.py
    def backward(self, t):
        """
        逆伝播の実装
        """
        # 出力層の活性化関数がsoftmax関数で損失関数が交差エントロピー誤差の場合
        # 誤差の伝播を場合分けしておく
        if isinstance(self.act, type(get_act("softmax"))) \
        and isinstance(self.errfunc, type(get_err("Cross"))):
            dact = self.y - t
            self.grad_w = self.x.T@dact
            self.grad_b = np.sum(dact, axis=0)
            self.grad_x = dact@self.w.T

            return self.grad_x
        elif isinstance(self.act, type(get_act("sigmoid"))) \
         and isinstance(self.errfunc, type(get_err("Binary"))):
            dact = self.y - t
            self.grad_w = self.x.T@dact
            self.grad_b = np.sum(dact, axis=0)
            self.grad_x = dact@self.w.T

            return self.grad_x
        else:
            grad = self.errfunc.backward(self.y, t)
            return super().backward(grad)
```

オーバーライドの内容自体は簡単ですね。出力層の活性化関数がsoftmax関数で損失関数に交差エントロピー誤差を用いている場合は、活性化関数を逆伝播する誤差までコードのようにスキップできます。
また、出力層の活性化関数がsigmoid関数で損失関数に二値交差エントロピー誤差を用いている場合は、活性化関数を逆伝播する誤差までコードのようにスキップできます。
それ以外の場合は損失関数の微分を計算して誤差を流す必要がありますね。


# `__init__`メソッドの実装
さて、上記で出てきた`errfunc`をメンバに持たせておきましょう。

<details><summary>修正前</summary><div>

```baselayer.py
    def __init__(self, *, prev=1, n=1, 
                 name="", wb_width=1,
                 act="ReLU", err_func="square",
                 act_dict={}, **kwds):
        self.prev = prev  # 一つ前の層の出力数 = この層への入力数
        self.n = n        # この層の出力数 = 次の層への入力数
        self.name = name  # この層の名前
        
        # 重みとバイアスを設定
        self.w = wb_width*np.random.randn(prev, n)
        self.b = wb_width*np.random.randn(n)
        
        # 活性化関数(クラス)を取得
        self.act = get_act(act, **act_dict)
        
        # 損失関数(クラス)を取得
        self.errfunc = get_errfunc(err_func)
```
</div></details>

****
**2020/7/8修正**
`errfunc`を持たせるのは`BaseLayer`ではなく`OutputLayer`でした。

```outputlayer.py
    def __init__(self, *, err_func="Square", **kwds):
        # 損失関数(クラス)を取得
        self.errfunc = get_err(err_func)

        super().__init__(**kwds)
```

いずれ損失関数についても記事を書きます。


# おわりに
数式のカラーリングの大変さなんとかならないかな...


# 深層学習シリーズ
- [深層学習入門 ~基礎編~](https://qiita.com/kuroitu/items/221e8c477ffdd0774b6b)
- [深層学習入門 ~コーディング準備編~](https://qiita.com/kuroitu/items/884c62c48c2daa3def08)
- [深層学習入門 ~順伝播編~](https://qiita.com/kuroitu/items/d22c8750e34d5d75fb6c)
- [深層学習入門 ~逆伝播編~](https://qiita.com/kuroitu/items/ea6ed8f614e65ec44976)
- [深層学習入門 ~学習則編~](https://qiita.com/kuroitu/items/ab5ad4ac716ae7a04891)
- [深層学習入門 ~ローカライズと損失関数編~](https://qiita.com/kuroitu/items/a6725ac0139d8eeb1e19)
- [深層学習入門 ~関数近似編~](https://qiita.com/kuroitu/items/4a8badcf7d3139d9ec7b)
- [深層学習入門 ~畳み込みとプーリング編~](https://qiita.com/kuroitu/items/48bf6bc42e4dfee52cde)
- [深層学習入門 ~CNN実験編~](https://qiita.com/kuroitu/items/d4716e754594a29b059d)
- [深層学習外伝 ~GPUプログラミング編~](https://qiita.com/kuroitu/items/2618c598f46d6ab3889c)
- [深層学習入門 ~ドロップアウト編~](https://qiita.com/kuroitu/items/d1bed8c216950d87be74)
- [活性化関数一覧 (2020)](https://qiita.com/kuroitu/items/73cd401afd463a78115a)
- [勾配降下法一覧 (2020)](https://qiita.com/kuroitu/items/36a58b37690d570dc618)
- [見てわかる！最適化手法の比較 (2020)](https://qiita.com/kuroitu/items/6695e0c79e888543e150)
- [im2col徹底理解](https://qiita.com/kuroitu/items/35d7b5a4bde470f69570)
- [col2im徹底理解](https://qiita.com/kuroitu/items/7877c002e192955c7857)
- [numpy.pad関数完全理解](https://qiita.com/kuroitu/items/51f4c867c8a44de739ec)