深層学習day2
Section1: 勾配消失問題
深層学習の学習の流れ
①入力層に値を入力
②重み、バイアス、活性化関数で計算しながら値が伝わる
③出力層から値が伝わる
④出力層から出た値と正解値から、誤差関数を使って誤差を求める
⑤誤差を小さくするために重みやバイアスを更新する
*連鎖律の原理を使った計算例。dz/dxを求める
$$z=t^2$$
$$t=x+y$$
のとき
$$\frac{dz}{dt}=2t$$
$$\frac{dt}{dx}=1$$
連鎖律で積をとり
$$2t・1=2(x+y)$$
勾配消失問題
誤差逆伝播法が下位層に進んでいくに連れて、勾配がどんどん緩やかになっていく。そのため、勾配降下法による、更新では下位層のパラメータはほとんど変わらず、訓練は最適値に収束しなくなる。
勾配消失問題の解決法
活性化関数の選択、重みの初期値設定、バッチ正規化
活性化関数
シグモイド関数
0 ~ 1の間を緩やかに変化する関数で、ステップ関数ではON/OFFしかない状態に対し、信号の強弱を伝えられるようになり、予想ニューラルネットワーク普及のきっかけとなった。
大きな値では出力の変化が微小なため、勾配消失問題を引き起こす課題があった。
*シグモイド関数を微分したときの最大値は0.25
(入力が0のとき、出力は0.5となるため、代入すると0.5×0.5=0.25となる。)
$$f(u)=(1-sigmoid(u))\cdot sigmoid(u)$$
ReLU関数
今最も使われている活性化関数。
勾配消失問題の回避とスパース化に貢献することで良い成果をもたらしている。
初期値の設定方法
Xavier
各重みに対して前の層のノード数(ユニット数)の平方根で除算した値を初期値とする
Xavierの初期値を設定する際の活性化関数:ReLU関数、シグモイド(ロジスティック)関数、双曲線正接関数(tanh)
self.params['W1'] = np.random.randn(input_size, hidden_size) / nq.sqrt(input_layer_size)
self.params['W2'] = np.random.randn(hidden_size, output_size) / nq.sqrt(hidden_layer_size)
He
各重みに対して前の層のノード数(ユニット数)の平方根で除算した値に√2を掛けた値を初期値とする
Heの初期値を設定する際の活性化関数:Relu関数
self.params['W1'] = np.random.randn(input_size, hidden_size) / nq.sqrt(input_layer_size) * np.sqrt(2)
self.params['W2'] = np.random.randn(hidden_size, output_size) / nq.sqrt(hidden_layer_size) * np.sqrt(2)
*重みの初期値に0を設定すると、全てのパラメータが同じ値で伝搬していくため値の最適化がされず学習が進まなくなる問題が発生する。
バッチ正規化
バッチ正規化:ミニバッチ単位で、入力値のデータの偏りを抑制する手法
*勾配消失問題の抑制、計算の効率化といった効果がある
Section2: 学習率最適化手法
学習率最適化手法を利用して学習率を最適化する
モメンタム
物理法則に準ずる動きをする。
一期前の更新量を利用する。
$$V_{t}=\mu V_{t-1}-\epsilon\nabla E$$
$$w^{t+1}=w^{t}+V_{t}$$
class Momentum:
#lr : 学習係数
#momentm : モーメンタム係数
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
パラメータごとに学習率を適応させる方法。
学習が進むにつれて、見かけの学習率が減衰していく。
$$h_{0}=\theta$$
$$h_{t}=h_{t-1}+(\nabla E)^2$$
$$w^{t+1}=w^{t}-\epsilon\frac{1}{\sqrt{h_{t}}+\theta}\nabla E$$
lass Adagrad:
#lr : 学習係数
def __init__(self, lr=0.01):
self.lr = lr
self.h = None
self.epsilon = 1e-7
#重みの更新
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] / (self.epsilon + np.sqrt(self.h[key]) )
RMSProp
AdaGradの改良版。
勾配の2乗の移動平均を用いて、見かけの学習率を変化させていく。
一度学習率が0に近づくとほとんど変化しなくなるAdaGradの問題を改良したもの。
$$h_{t}=\alpha h_{t-1}+(1-\alpha)(\nabla E)^2$$
$$w^{t+1}=w^{t}-\epsilon\frac{1}{\sqrt{h_{t}}+\theta}\nabla E$$
class RMSProp:
#lr : 学習係数
#rho : 減衰率
def __init__(self, lr=0.01, rho=0.9):
self.lr = lr
self.h = None
self.rho = rho
self.epsilon = 1e-6
#重みの更新
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] = self.rho * self.h[key] + (1 - self.rho) * grads[key] * grads[key]
params[key] -= self.lr * grads[key] / (np.sqrt(self.h[key] + self.epsilon) )
Adam
モメンタムとRMSpropを組み合わせたような方法。
移動平均による振動の抑制と学習率の調整をしている。
class Adam:
def __init__(self, lr=0.001, rho1=0.9, rho2=0.999):
self.lr = lr
self.rho1 = rho1
self.rho2 = rho2
self.iter = 0
self.m = None
self.v = None
self.epsilon = 1e-8
def update(self, params, grads):
if self.m is None:
self.m, self.v = {}, {}
for key, val in params.items():
self.m[key] = np.zeros_like(val)
self.v[key] = np.zeros_like(val)
self.iter += 1
for key in params.keys():
self.m[key] = self.rho1*self.m[key] + (1-self.rho1)*grads[key]
self.v[key] = self.rho2*self.v[key] + (1-self.rho2)*(grads[key]**2)
# 重みの更新
params[key] -= self.lr * m / (np.sqrt(v) + self.epsilon)
Section3: 過学習
過学習:
特定の訓練サンプルに対して、
特化して学習することで、テスト誤差と訓練誤差とで学習曲線が乖離すること
正則化:
ネットワークの自由度(層数、ノード数、パラメータの値etc...)を制約すること
*リッジ回帰
線形モデルの正則化手法のひとつ
ハイパーパラメータを大きな値に設定すると、全ての重みが限りなく0に近づく
(0になるのはラッソ回帰)
荷重減衰:
重みが大きい値をとることで、過学習が発生することがある。
誤差に対して、正則化項を加算することで、重みを抑制する。
L1正則化
損失関数に次のL1ノルムを加えて誤差の最小化を行う。
$$λ\sum_{i=1}^n|w_i|$$
L2正則化
損失関数に次のL2ノルムを加えて誤差の最小化を行う。
$$\frac{λ}{2}sum_{i=1}^n|w_i|^2$$
*L1正則化は値を0にするスパース推定(図右)
ドロップアウト
ランダムにノードを削除して学習させること
データ量を変化させずに、異なるモデルを学習させていると解釈できる
Section4: 畳み込みニューラルネットワークの概念
畳み込み層
畳み込み層では、画像の場合、縦、横、チャンネルの3次元のデータをそのまま学習し、次に伝えることができる
パディング
画像の周囲に固定値(0を使うことが多い)を埋め込むこと。
パディングをすることで畳み込みにより元の画像より小さくなることを防ぎ、サイズを維持することができる。
また、画像の端の方の特徴を抽出できるようになる。
ストライド
フィルタをどれだけずらして畳み込みを行うかということ。
*サイズ6x6の入力画像をストライド1、パディング1で、サイズ2x2のフィルタで畳み込んだときの出力画像のサイズは7x7になる
高さ(幅)+2パディング-フィルタの高さ(幅)をストライドで割った値に1を足す。
(6+2*1-2/1)+1=7 今回は高さ、幅ともに同じため7x7
チャンネル
空間的な奥行き。
例えばカラー画像の場合、RGBの3チャンネル。
プーリング層
対象領域の中から1つの値を取得する層。
最大値プーリング:対象領域の中で最大値を取得
平均値プーリング:対象領域の中で平均値を取得
Section5: 最新のCNN
Alexnet
2012年に開かれた画像認識コンペティションで優勝したモデル。
5層の畳み込み層およびプーリング層、それに続く3層の全結合層から構成される。
過学習を防ぐ施策として、サイズ4096の全結合層の出力にドロップアウトが使用されている。
AlexNet
https://proceedings.neurips.cc/paper/2012/file/c399862d3b9d6b76c8436e924a68c45b-Paper.pdf
その他、最新のCNNについて以下を参照した。
畳み込みニューラルネットワークの最新研究動向 (〜2017)
https://qiita.com/yu4u/items/7e93c454c9410c4b5427
VGG
https://arxiv.org/pdf/1409.1556.pdf
ZFNet
https://arxiv.org/pdf/1311.2901v3.pdf
GoogleNet
https://arxiv.org/pdf/1409.4842.pdf
ResNet
https://arxiv.org/pdf/1512.03385.pdf
この記事の参考図書
「ゼロから作るDeepLearning」 斎藤康毅
「機械学習のエッセンス」加藤公一
~Fin~