[メモ]ゼロから作るDeep Learning 5章・6章・7章・8章

· ·

ゼロから作る Deep Learning ―Python で学ぶディープラーニングの理論と実装」は以前途中まで読んでいたけれども復習もかねて。

5 章 誤差逆伝播法 🔗

  • 誤差逆伝播法 : 重みパラメータの勾配の計算を効率よく行う手法
  • 順伝播(forward propagation) < - > 逆伝播(backward propagation)
  • 合成関数 : 複数の関数によって構成される関数
  • 連鎖律の原理 : ある関数が合成関数で表される場合、その合成関数の微分は、合成関数を構成するそれぞれの関数の微分の積によって表すことができる
  • 例 $$z = t^2$$ $$t = x + y$$
  • この場合の $$\frac{\partial{z}}{\partial{x}} = \frac{\partial{z}}{\partial{t}}\frac{\partial{t}}{\partial{x}} = 2t * 1 = 2(x + y)$$
  • ReLU(復習含む)

$$y = \begin{cases}x (x > 0)\\ 0 (x \leq 0)\end{cases}$$ $$\frac{\partial{y}}{\partial{x}} = \begin{cases}1(x > 0)\\0(x \leq 0)\end{cases}$$

  • Sigmoid(復習)

$$y = \frac{1}{1+exp(-x)}$$

  • Sigmoid 関数の右辺を微分していく。なんで $y^2$ とステップ 1 で再び y を登場させたんだろう…と思ったけど、最後に式を簡易化するためということで良いのかな。

  • $\frac{1}{x}$ の微分は$-\frac{1}{x^2}$、$e^x$ の微分は変わらず $e^x$ であることを利用。(L は最終的なアウトプット) $$\frac{\partial{L}}{\partial{y}}y^{2}exp(-x)$$

  • さらに簡易に表現すると… $$\frac{\partial{L}}{\partial{y}}y(1-y)$$

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class Sigmoid:
    def __init__(self):
        self.out = None

    def forward(self, x):
        out = 1 / (1 + np.exp(-x)) # forwardの場合は単純なSigmoid関数
        self.out = out # 変数を保持
        return out

    def backward(self, dout):
        dx = dout * (1.0 - self.out) * self.out #後ろから引き継いだ微分値に対してsigmoidの微分簡易式を入れる
        return dx
  • Affine
  • Sigmoid のときと同様に行列式を微分して逆伝播の式を求める
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
class Affine:
    def __init__(self, W, b):
        self.W = W
        self.b = b
        self.x = None
        self.dW = None
        self.db = None

    def forward(self, x):
        self.x = x
        out = np.dot(x, self.W) + self.b
        return out

    def backward(self, dout):
        dx = np.dot(dout, self.W.T)
        self.dW = np.dot(self.x.T, dout)
        self.db = np.sum(dout, axis=0)
        return dx
  • 「ソフトマックス関数」の損失関数として「交差エントロピー誤差」を用いると逆伝播がキレイな形となる。そうなるように交差エントロピー誤差という関数が設計された
  • 「恒等関数」の損失関数として「2 乗和誤差」を用いるのも同様の理由で、逆伝播がキレイな形となる
  • Softmax with loss
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
class SoftmaxWithLoss:
    def __init__(self):
        self.loss = None # 損失
        self.y = None # softmaxの出力
        self.t = None # 教師データ(one-hot vector)

    def forward(self, x, t):
        self.t = t
        self.y = softmax(x)
        self.loss = cross_entropy_error(self.y, self.t)
        return self.loss

    def backward(self, dout = 1):
        batch_size = self.t.shape[0]
        dx = (self.y - self.t) / batch_size
        return dx

6 章 学習に関するテクニック 🔗

確率的勾配降下法(SGD) 🔗

$$\mathbb{W} \leftarrow \mathbb{W} - \eta\frac{\partial{L}}{\partial{\mathbb{W}}}$$

1
2
3
4
5
6
7
class SGD:
    def __init__(self, lr=0.01):
        self.lr = lr # 学習係数

    def update(self, params, grads):
        for key in params.keys():
            params[key] -= self.lr * grads[key] # params['W1'], grads['W1']のような勾配が格納されたディクショナリ変数

Momentum 🔗

$$\mathbb{v} \leftarrow \alpha\mathbb{v} - \eta\frac{\partial{L}}{\partial{\mathbb{W}}}$$ $$\mathbb{W} \leftarrow \mathbb{W} + \mathbb{v}$$

  • $\mathbb{v}$ : 物理でいう速度
  • $\eta$ : 学習係数
  • $\alpha\mathbb{v}$ : 勾配がない時に徐々に減速するための役割。($\alpha$ は 0.9 などを設定)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
class Momentum:
    def __init__(self, lr = 0.01, momentum = 0.9):
        self.lr = lr
        self.momentum = momentum
        self.v = None

    def update(self, params, grads):
        if self.v is None:
            self.v = {}
            for key, val in params.items():
                self.v[key] = np.zeros_like(val)

        for key in params.keys():
            self.v[key] = self.momentum * self.v[key] - self.lr * grads[key]
            params[key] += self.v[key]

AdaGrad 🔗

  • 学習係数の減衰(learning rate decay) : 学習が進むに連れて学習係数を小さくする $$h \leftarrow h + \frac{\partial{L}}{\partial{\mathbb{W}}}\odot\frac{\partial{L}}{\partial{\mathbb{W}}}$$ $$\mathbb{W} \leftarrow \mathbb{W} - \eta\frac{1}{\sqrt{h}}\frac{\partial{L}}{\partial{\mathbb{W}}}$$

  • $\mathbb{W}$ : 更新する重みパラメータ

  • $\frac{\partial{L}}{\partial{\mathbb{W}}}$ : $\mathbb{W}$ に関する損失関数の勾配

  • $\eta$ : 学習係数

  • AdaGrad の場合学習を進めるほど更新度合いは小さくなり最終的に 0 となってしまう。これを改善したものが RMSProp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
class AdaGrad:
    def __init__(self, lr = 0.01):
        self.lr = lr
        self.h = None

    def update(self, params, grads):
        if self.h is None:
            self.h = {}
            for key, val in params.items():
                self.h[key] = np.zeros_like(val)

        for key in params.keys():
            self.h[key] += grads[key] * grads[key]
            params[key] -= self.lr * grads[key] / (np.sqrt(self.h[key])+ 1e-7)

Adam 🔗

  • Momentum と AdaGrad の融合
  • 一般的に SGD よりも他の 3 つの手法のほうが早く学習でき、時には最終的な認識性能も高くなる

その他 🔗

  • アクティベーション : 活性化関数の後の出力データ
  • sigmoid 関数や tanh 関数は重みの初期設定に「Xavier の初期値」を用いることで勾配消失や表現力の制限といった問題が起きにくくなる
  • ReLU 関数の場合は「He の初期値」が推奨されている
  • Batch Normalization が広く利用される理由
    • 学習を早く進行させることが出来る(学習係数を大きくすることが出来る)
    • 初期値にそれほど依存しない(初期値に対してそこまで神経質にならなくて良い)
    • 過学習を抑制する(Dropout などの必要性を減らす)
  • Batch Normalization : 学習を行う際のミニバッチを単位として、ミニバッチごとに正規化する

$$\mu_{B} \leftarrow \frac{1}{m}\sum^{m}{i=1}{x_i}$$ $$\sigma^2_B \leftarrow \frac{1}{m}\sum^{m}{i=1}{(x_i - \mu_B)^2}$$ $$\hat{x_i} \leftarrow \frac{x_i - \mu_B}{\sqrt{\sigma^2_B + \varepsilon}}$$

  • $B = \{x_1, x_2, \cdots , x_m\}$ という$m$ 個の入力データの集合に対して、平均 $\mu_B$ 、分散 $\sigma^2_B$ を求める
  • $\varepsilon$ : 分母が 0 とならないための小さな値(例えば 10e-7 など)
  • すなわち、ミニバッチの入力データを平均 0、分散 1 のデータにへんかんしているだけ
  • 更に Batch Normalization レイヤでは正規化されたデータに対して、固有スケールとシフトで変換を行う

$$y_i \leftarrow \gamma\hat{x_i} + \beta$$

  • パラメータ $\gamma = 1$ 、$\beta = 0$ からスタートして学習で調整されていく
  • 過学習が起こる原因
    • パラメータを大量に持ち、表現力の高いモデルであること
    • 訓練データがすくないこと
  • 過学習は重みパラメータが大きな値を取ることによって発生することが多くあるため荷重減衰(Weight decay)という手法を利用することがある。重みの 2 乗ノルム(L2 ノルム)を損失関数に加算するなど。
  • 重みを $\mathbb{W}$ とすると、L2 ノルムの Weight decay は $\frac{1}{2}\lambda\mathbb{w}^2$
  • ニューラルネットワークのモデルが複雑になってくると、Weight decay だけでは対応が困難となってくるため Dropout が利用される
  • Dropout はニューロンをランダムに選び出し、その選びだしたニューロンを消去すること
  • データは訓練、検証、テストデータの 3 つに分割することが大事
  • ハイパーパラメータ最適化手順
    1. ハイパーパラメータの範囲を設定
    2. 設定されたハイパーパラメータの範囲からランダムにサンプリング
    3. 2.でサンプリングされたハイパーパラメータの値を使用して学習を行い、検証データで認識制度を評価(エポック数は小さく設定)
    4. 2.と 3.をある回数(100 回など)繰り返し、それらの認識制度の結果から、ハイパーパラメータの範囲を狭める

7 章 畳み込みニューラルネットワーク 🔗

  • 畳み込み演算は要素積どうしを乗算し、その和を求める
  • パディングで埋められる場所は 0 埋め
  • 入力サイズ$(H, W)$、フィルターサイズ$(FH, FW)$、出力サイズ$(OH, OW)$、パディング$P$、ストライド$S$とした場合出力サイズは以下の通り計算する $$OH = \frac{H + 2P - FH}{S} + 1$$ $$OW = \frac{W + 2P - FW}{S} + 1$$
  • 一般的にプーリングのウィンドウワイズとストライドは同じ値に設定する

8 章 ディープラーニング 🔗

  • 層を深くすることの重要性については、理論的にはそれほど多くのことが分かっていないが…
  • 層を深くすることで、より少ないパラメータで同レベル(もしくは、それ以上)の表現力を達成できる
  • 層を深くすることで、学習の効率性も向上する
  • 層を深くすることで、階層的に情報を渡すことが出来、エッヂを抽出した情報を利用できたりと「解きやすいシンプルな問題」へと分解することが出来る
  • 転移学習 : 学習済みの(の一部)を別のニューラルネットワークにコピーして再学習(fine tuning)を行うこと
  • マルチモーダル処理 : 画像と自然言語といった複数の種類の情報を組み合わせて処理すること
comments powered by Disqus