【MLP 深層学習】第3章 確率的勾配降下法

深層学習、通称青イルカ本の学習メモ。

深層学習 (機械学習プロフェッショナルシリーズ)

深層学習 (機械学習プロフェッショナルシリーズ)

知らなかったことや重要だと思ったところをQ&A形式にして自分が復習しやすい形にしてある。

勾配降下法ではどのパラメータに対して勾配を計算する?

すべてのパラメータに対する勾配を計算し、
誤差関数を最小化するように、パラメータを更新していく。

非線形関数の最小化手法の中から勾配降下法を使う場合とは?

非線形関数の最小化手法の中では,
勾配降下法は単純なアルゴリズムで,収束が遅い.
またハイパーパラメータの設定により,収束が大きく変化するという使いにくい点も持つ。

他にも目的関数の二次微分を利用するニュートン法などがあるのだから、
通常は勾配降下法をわざわざ使わない.
使うとしたら,問題の規模が大きく,目的関数の二次微分の計算が難しい場合など.
DNNはその場合に相当する.

バッチ学習と比較して、確率的勾配降下法SGD)の利点は?

訓練データに冗長性がある場合、
計算効率が向上し、学習を速く実行できる。

また、局所解にトラップされるリスクを低減できる。
バッチ学習の場合、最小化する目的関数はつねに同じなので、
望まない局所解にトラップされると、二度とそこから抜け出せない。
しかし、SGDでは目的関数が更新ごとに異なるため、そのようなリスクが小さくなる。

ではなぜミニバッチ学習をするのか?

SGDには欠点もあるため。

たとえばある更新で、利用する訓練データが外れ値の場合、おかしな方向にパラメータを調整してしまう。
なので、複数の訓練データをサンプルとして利用することで、「大体正しい方向にパラメータを動かす」ことを目指す。
ただし、バッチで使う訓練データを増やしすぎると、上記で述べたような極小解にトラップされるので、
そのハイパーパラメータの調整は必要。

ネットワークの自由度が高いほど、学習時に誤差関数の浅い局所解にトラップされやすくなるのはなぜ?

ネットワークの自由度が大きいときというのは、パラメータが多いとき。

定性的に考えてみるとわかる。
1変数のときでも局所解にはまる恐れはある。
でも2変数のときは1変数のときよりももっと局所解にはまりやすい。
局所解を浅い穴、最適解を深い穴とすると、変数が増えるにつれ、浅い穴が増えるイメージ。

パラメータが多いとそれだけ、浅い穴にハマる可能性が高くなる。

過適合(局所解にトラップされるの)を防ぐための重みの正則化とは?

過適合を防ぐために重みの正則化を行う。
最も簡単な正則化は、重みになんらかの制約を加えること。
よく使われるのが次のように、誤差関数に重みの二乗和を加えて、これを最小化すること。
{} $$ E_t(w) \equiv \frac{1}{N_t}\sum_{n \in D_t} E_n(w) + \frac{\lambda}{2} || w ||^2 $$

{lambda}正則化の強さを制御するハイパーパラメータで、一般に{lambda=} 0.01や0.00001程度から選ぶ。

重みが極端な値になってしまうと、そのノードの影響が支配的になってしまい、層を重ねて表現力を上げる目的が達せなくなってしまう。 この状態を防ぐために、重みを大きくならないようにすれば過適合を防げるという理屈(と理解した)

白色化とはなにか?

成分間の相関を0にする変換のこと

Adagradとはなにか?

ニューラルネットの学習では学習係数${\eta}$の調整が重要 学習係数の減衰(learning rate decay)が常套手段 最初は大きく学習して、次第に小さく学習するようにする

学習係数の減衰をさらに発展させたのがAdaGrad Adagradでは1つ1つのパラメータに対して,オーダーメイドの値を設定する

  • {
h \leftarrow h + \frac{\partial L}{\partial W} \odot \frac{\partial L}{\partial W}
}
    {
W \leftarrow W - \eta \frac{1}{\sqrt{h}} \frac{\partial L}{\partial W}
}

{h} は,これまで経験した勾配の二乗和を保持 パラメータ更新の際に,{\frac{1}{\sqrt{h}}}を乗算することで学習のスケールを調整 パラメータの要素の中でよく動いた要素は,学習係数が小さくなる.

重みの初期化はどうすればよい?

学習開始時に重みの初期値を決める必要があるが、その一般的な方法は正規分布から生成したランダム値を初期値とする方法。 ただその場合にガウス分布標準偏差 {\sigma} をどう選ぶかで学習結果に影響を与える。 この {\sigma}をちょうどよい大きさでないと、活性化関数の出力がその値域の中でちょうどよい範囲にこなくなるから。

基準としては、 あるユニットへの総入力 {u_j = \sum_i w_{ji} x_i}がちょうどよい分散を持つように {\sigma} を決めるのがよいといえる。 あるユニットへの挿入力の分散を {\sigma_u^{2}}にしたいときには、 {} $$ σ = σ_{u} / M^{½} $$

とするように値をとるのがよい。ただしMはあるユニットへの入力結合の数。

yusuke-ujitoko.hatenablog.com

【MLP 深層学習】第2章 順伝播型ネットワーク

深層学習、通称青イルカ本の学習メモ。

深層学習 (機械学習プロフェッショナルシリーズ)

深層学習 (機械学習プロフェッショナルシリーズ)

知らなかったことや重要だと思ったところをQ&A形式にして自分が復習しやすい形にしてある。

活性化関数にシグモイド関数やロジスティック関数を使われてきたのはなぜ?

ニューラルネットは、ヒトの神経細胞を模擬したものであり、 生物の神経細胞が持つ性質をモデル化するとこうなる。

Rectified linear function(ReLU関数)の利点は?

{} $$ f(u) = max(u, 0) $$

上記がReLU関数。
シグモイド関数などよりも、単純な関数のため計算量が小さい。
またシグモイド関数では入力の変動の大きさに気を使う必要がある。
(大きすぎると出力がほとんどの場合0か1になってしまう)

NNでは各ユニットの活性化関数が非線形性を持つことが本質的に重要なのはなぜ?

層間は線形変換されるため、 非線形領域を分類するためには、その役目を活性化関数がになる必要があると考えられるため。

事後確率(条件付き確率)とはなにか?

事後確率とは, 事象Aが起こった条件下において,事象Bが起こる確率のこと. 例えば

  • 雨が降る確率をP(雨)
  • 交通事故の発生確率をP(事故)

としたとき,雨が降っている日に(= 雨が降っているという条件下において),
交通事故が発生する確率を

P(事故|雨) と表すことに決める. これが事後確率である.

事後確率の定義は以下のようになる。 {} $$ P(B|A) = \frac{P(B, A)}{P(A)} $$

多クラス分類問題のときになぜ誤差関数を交差エントロピーで置くのか?

他クラス分類問題のときには、
ある層での入力に対する出力の活性化関数を、softmax functionとする。
なぜかというと、全ニューロンの和を1にでき、各ニューロンの出力を確率とみなせるため。 {} $$ y_k = \frac{\exp(u_k)}{\sum_{j=1} \exp(u_j)} $$

そして、{y_k}を「与えられた入力{x}がクラス{C_k}に属する事後確率」とみなす。
このとき事後分布は、 {} $$ p(d|x) = \prod_{k=1}^K p(C_k|x)^{d_k} $$

この尤度の対数をとり符号を反転すると、交差エントロピーの式になる。 {} $$ E(w) = - \sum_{n=1}^N \sum_{k=1}^K d_{nk} \log y_{k} (x_n;w) $$

yusuke-ujitoko.hatenablog.com yusuke-ujitoko.hatenablog.com

【MLP 深層学習】第1章 はじめに

深層学習、通称青イルカ本の学習メモ。

深層学習 (機械学習プロフェッショナルシリーズ)

深層学習 (機械学習プロフェッショナルシリーズ)

知らなかったことや重要だと思ったところをQ&A形式にして自分が復習しやすい形にしてある。

80年台に誤差逆伝播法を使ったときに、多層のNNだと汎化性能があがらなかったのはどんな理由?

入力層から離れた深い層では勾配が急速に小さくなったり、急速に大きくなって発散する「勾配消失問題」が起こったため。

自己符号化器(autoencoder)ってなに?

入力に対し計算される出力が、入力になるべく近くなるように訓練されるNNのこと。
自己符号化器の目標出力は入力そのものであり、したがってその学習は教師なし学習で行われる。

近年、多層NNが高い性能を発揮できるようになった理由は?

現実の問題は複雑であり、その問題を特にはその複雑さに見合う規模のNNが必要。
そんな大きなNNが過学習を起こさず学習できるためには、一定以上の規模のデータを要する。
90年台と違って今は、十分な学習データを集められる。

また一方で、GPUやメニーコア化されたCPUなど、計算機の計算能力が飛躍的に向上していることも大きな理由。

yusuke-ujitoko.hatenablog.com yusuke-ujitoko.hatenablog.com

LeNetのパラメータの可視化

LeNetは1998のLeCunによって発表されたネットワーク。
MNISTに対して、このLeNetの類似ネットワークを適用した時の、パラメータを可視化してみるというのが本記事の主旨。

今回使ったネットワーク構成を示す。
畳み込み層2つに、全結合層が2つ連なったもの。
畳み込み層の直後にMaxプーリング層がある。

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1 (Conv2D)            (None, 28, 28, 20)        520       
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 14, 14, 20)        0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 10, 10, 50)        25050     
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 5, 5, 50)          0         
_________________________________________________________________
flatten_1 (Flatten)          (None, 1250)              0         
_________________________________________________________________
dense_1 (Dense)              (None, 500)               625500    
_________________________________________________________________
dense_2 (Dense)              (None, 10)                5010      
=================================================================
Total params: 656,080.0
Trainable params: 656,080.0
Non-trainable params: 0.0
_________________________________________________________________
Test loss: 0.0360684088513
Test accuracy: 0.9908

今回は2つの畳込み層のパラメータをそれぞれ可視化する。
第一層の畳み込み層は、カーネルサイズは5×5で、カーネルは全部で20個。
第三層の畳み込み層は、カーネルサイズは5×5で、カーネルは全部で50個。

可視化

予め訓練したモデルとモデルのパラメータをロードしておく。
そして可視化する。

%matplotlib inline
import matplotlib.pyplot as plt
from sklearn.preprocessing import MinMaxScaler
import numpy as np

def visualize_filter(model, nb_layer, nb_visualize_kernels):
    W = model.layers[nb_layer].get_weights()[0]
    print(W.shape)
    
    nb_filters = W.shape[3]
    nb_kernel = W.shape[0]
    
    for i in range(nb_filters):
        if i >= nb_visualize_kernels:
            continue
        im = W[:, :, :, i]
        im = im[:,:,0]
        scaler = MinMaxScaler(feature_range=(0,255))
        im = scaler.fit_transform(im)
        plt.subplot(4, 5, i+1)
        plt.axis('off')
        plt.imshow(im, cmap='gray')
    plt.show()

visualize_filter(model, 0, 20)
visualize_filter(model, 2, 20)

第一層目の重みパラメータは以下のように可視化された。

f:id:yusuke_ujitoko:20170320180015p:plain

一方、第三層目の重みパラメータは以下のように可視化された。
第一層目の数に合わせて、先頭の20個のカーネルのみ抽出してある。

f:id:yusuke_ujitoko:20170320180025p:plain

この2つを比較しても、あまり差が無いように見える。
若干第三層目の方が、複雑なパラメータ配置となっているか…?