Rabbit Challenge 3-2
深層学習 DAY2 勾配消失問題、最適化アルゴリズム、CNN他
目的
Rabbit Challengeの課題レポートとして、
学習内容をまとめる
1.勾配消失問題と対策
2.最適化アルゴリズム
3.過学習と対策
4.畳み込みニューラルネットワーク(CNN)
5.実装演習 github情報
1.1 勾配消失問題
正解率
エポック数
正解率
エポック数
エポック数が増えるごとに正解率が上昇
→正常に学習が進んでいる
エポック数が増えても正解率が横ばい
→勾配消失が生じている可能性が高い
→パラメータがほとんど変わっていない状態
1.2 対策1:活性化関数の改善
出力
シグモイド関数は、微分すると最大0.25
→これが何層も掛け合わされると
ゼロに近くなる
入力
シグモイド関数:𝑓 𝑢 =
1
1+ⅇ−𝑢
微分
入力
0.25
微分
1.2 対策1:活性化関数の改善
出力
シグモイド関数は、微分すると最大0.25
→これが何層も掛け合わされると
ゼロに近くなる
入力
シグモイド関数:𝑓 𝑢 =
1
1+ⅇ−𝑢
微分
入力
0.25
Relu関数:𝑓 𝑢 =
𝑢 𝑢 ≥ 0
0 𝑢 < 0
出力
入力
微分
微分 1 中間層ではRelu関数を使うことで、
勾配消失を防止することができる
※スパース化(不要なところがゼロになる)にも貢献する
1.3 対策2:重みの初期値改善
※シグモイドやtanhを活性化関数に使った場合の出力は0 or 1
に偏りがちになる。これを微分した結果は0に近い値になる。
Xavierで初期化するとある程度のばらつきを持った値になる
名称 Xavier(ザビエル)※ He(ヒー)
内容 重みの初期値𝑤0を前の層のノード数
𝑛の平方根で除算した値にする
𝑤0 =
1
𝑛
重みの初期値𝑤0を前の層のノード数𝑛の
逆数を2倍した平方根にする
𝑤0 =
2
𝑛
使用される
活性化関数
シグモイド関数
tanh関数
Relu関数
1.4 対策3:バッチ正規化
入力値の偏りを抑制するためミニバッチ単位で正規化する
以下、その手順を示す
①ミニバッチの平均を取る 𝜇𝑡 =
1
𝑁𝑡
𝑖
𝑁𝑡
𝑥𝑖
②ミニバッチの分散を計算
σ𝑡
2
=
1
𝑁𝑡
𝑖
𝑁𝑡
(𝑥𝑖 − 𝜇𝑡)2
③ミニバッチの正規化 𝑥𝑛𝑖
=
𝑥𝑛𝑖
− 𝜇𝑡
𝜎𝑡
2
+ 𝜃
④変倍の移動 𝑦𝑛𝑖
= 𝛾𝑥𝑛𝑖
+ 𝛽
mu = X.mean(axis=0)
xc = X - mu
var = np.mean(xc**2, axis=0)
std = np.sqrt(var + 1e-7)
xn = xc/std
out = gamma*xn + beta
実装例
1.勾配消失問題と対策
2.最適化アルゴリズム
3.過学習と対策
4.畳み込みニューラルネットワーク(CNN)
5.実装演習 github情報
2.1 学習最適化の指針
勾配降下法による重み更新
𝒘𝑘+1 = 𝒘𝑘 − ε
𝜕𝐸 𝒘
𝜕𝒘
=𝒘𝑘 − ε𝛻𝐸
重み更新の最適化の指針
初期の学習率εを大きく、その後徐々に小さくしていき、パラメータごとに学習率を変化させることで、
学習をスムーズに進める
2.2 モメンタム
𝑽𝑘 = 𝜇𝑽𝑘−1 − ε𝛻𝐸
前回の𝐰の変化量に𝜇を掛けて加算する。移動平均のような動きをする。
局所解に停滞しにくい
𝒘𝑘+1 = 𝒘𝑘 + 𝑽𝑘
参考
【機械学習】パラメータ更新の最適化#モメンタム
(𝜇を慣性項という)
v[k] = momentum * v[k] - learning_rate * grad[k]
実装例
w[k] += v[k]
2.3 AdaGrad
ℎ𝑡 = ℎ𝑡−1+(𝛻𝐸)2
勾配の緩やかな斜面に対して学習が進みやすいが、
大域最適解にたどり着かず、鞍点問題を引き起こしやすい(学習率が徐々に小さくなるため)
𝒘𝑡+1 = 𝒘𝑡 − 𝜀
1
ℎ𝑡
𝛻𝐸
参考
【機械学習】パラメータ更新の最適化#AdaGrad
これまでの重みの更新の記憶
h[k] += grad[k]**2
実装例
w[k] - = (learning_rate * grad[k]) / np.sqrt(h[k] + 1e-7)
2.4 RMSProp
ℎ𝑡 = 𝛼ℎ𝑡−1+(1 − 𝛼)(𝛻𝐸)2
AdaGradの鞍点問題に陥りやすいデメリットを改善
AdaGradの場合の初期値をうまく調整する必要があったのに対し、
RMSPropはその調整が簡単になった。
𝒘𝑡+1 = 𝒘𝑡 − 𝜀
1
ℎ𝑡
𝛻𝐸
𝛼ℎ𝑡−1前回の重みの更新の記憶
(1 − 𝛼)(𝛻𝐸)2
今回の重み更新
h[k] *= decay_rate
実装例
w[k] - = (learning_rate * grad[k]) / np.sqrt(h[k] + 1e-7)
こちらはAdaGradと一緒
#𝛼ℎ𝑡−1
h[k] +=(1 - decay_rate)*grad[k]**2 #(1 − 𝛼)(𝛻𝐸)2
2.5 Adam
𝑚𝑡 = 𝛽1𝑚𝑡−1+(1 − 𝛽1)𝛻𝐸
モメンタム + RMSPropの良いところ取り
𝒘𝑡+1 = 𝒘𝑡 − 𝜀
1
𝑣𝑡
𝑚𝑡
勾配の1乗の記憶
m[k] += (1-beta1)*(grad[k] - m[k])
実装例
w[k] - = (learning_rate * m[k]) / np.sqrt(v[k] + 1e-7)
こちらはAdaGradやRMSPropと類似
(𝛻𝐸が前回の記憶値𝑚𝑡に代わっている)
𝑣𝑡 = 𝛽2𝑣𝑡−1+(1 − 𝛽2)(𝛻𝐸)2 勾配の2乗の記憶
m[k] = m[k] + (1-beta1)*(grad[k]) - (1-beta1)*m[k]
= beta1*m[k] + (1-beta1)*(grad[k])
v[k] += (1-beta2)*(grad[k]**2 - v[k])
2.6 各種アルゴリズムのまとめ
https://postd.cc/optimizing-gradient-descent/
1.勾配消失問題と対策
2.最適化アルゴリズム
3.過学習と対策
4.畳み込みニューラルネットワーク(CNN)
5.実装演習 github情報
3.1 過学習とは
訓練誤差とテスト誤差の乖離
誤差
エポック数
訓練誤差
テスト誤差
例えば、自分で買った問題集で100点が取れるようになって、
いざ、本番の試験に臨んだ時に50点しか取れないような状態
原因:パラメータ数やノードが多すぎる(NNの自由度が高すぎる)
データ数が少ない
3.2 正則化
NNの自由度を抑制する方法の一つ
あるノードの重みが大きい=学習において重要な点である
=特定の重みがあまりに強調されすぎると過学習に陥る
正則化項を追加することで、重みを抑制し、かつ重みの大きさに多様性を持たせる
𝐸 𝑤 +
1
𝑝
𝜆 𝑤 𝑝
※𝑝ノルム : 𝑥 𝑝 = 𝑥1
𝑝
+ ⋯ + 𝑥𝑛
𝑝
1
𝑝
誤差関数に𝑝ノルム 𝑤 𝑝(※)を加える
𝑝 = 1 のときL1正規化 (Lasso、スパース推定)
𝑝 = 2 のときL2正規化 (Ridge、縮小推定)
p2ノルムはユークリッド距離 𝑤1
2
+ 𝑤2
2
𝑤1
𝑤2
p1ノルムはマンハッタン距離𝑤1+ 𝑤2
まとめて誤差と考えて最小化する
3.3 正則化 実装例
s[k] = np.sign(w[k])
L1ノルム(Lasso)実装例
grad[k] += rate * s[k]
1
𝑝
𝜆 𝑤 𝑝 で𝑝 = 1ならば、𝑤は一次のみなので、
勾配すなわち微分を求めると𝜆 × ±1となる。
L2ノルム(Ridge)実装例
1
𝑝
𝜆 𝑤 𝑝 で𝑝 = 2ならば、𝑤は二次のみなので、
勾配すなわち微分を求めると𝜆 × 𝑤となる。
ここで、微分で出てきた係数は𝜆に吸収されると考えて良い
grad[k] += rate * w[k]
3.4 ドロップアウト
NNの自由度を抑制する方法の一つ
ノード自体をランダムに削除する
誤差
エポック数
誤差(ドロップアウト後)
誤差(ドロップアウト前) 過学習は抑制されるが、
ノードが減る事でデータ数が増えたことと同義となり
収束が遅くなることがある
1.勾配消失問題と対策
2.最適化アルゴリズム
3.過学習と対策
4.畳み込みニューラルネットワーク(CNN)
5.実装演習 github情報
4.1 CNN全体像
入力層 畳込み
層
プーリ
ング層
プーリ
ング層
畳込み
層
全結合
層
出力層
CNNのひとつLeNetの例
吹き出し内は人間による作業イメージ
(32,32) (28,28,6) (14,14,6) (10,10,16) (5,5,16) (120,)
全結合
層
(84,) (10,)
http://yann.lecun.com/exdb/publis/pdf/lecun-99.pdf
6人が
それぞれの感覚で特徴を
28x28の意見にまとめる
32x32画像
それぞれの人が
14x14に要約する
その要約を使って
今度は16人で特徴を
10x10の意見にまとめる
それぞれの人が
5x5に要約する
全員の要約意見を
一つにまとめる
10つのクラスのど
れに該当するか結
果を示す
4.2 畳み込み層(1)
元の画像の と、 との積・加算により を抽出
特徴マップ
フィルタ(カーネル)
画素値
1 2 3
1 0 0
1 0 0
1 4 5
0 3 1
1 1 4
1 2 3
1 0 0
1 0 0
フィルタ(カーネル)
1 4 5 2 1 3
0 3 1 3 2 0
1 1 4 5 1 2
3 0 2 4 0 3
1 0 1 1 4 5
画像のpixel値
× = 1×1 + 4×2 + 5×3 + 0×1+ 3×0 +1×0 + 1×1 + 1×0 + 4×0
= 25
26
特徴マップ
各要素ごとの積を加算
フィルタは複数用意される
フィルタ数はチャンネルという
重みとして学習で更新されていく
25 + 1 𝑓 𝑢
バイアス 活性化関数
4.2 畳み込み層(2)
元の画像の と、 との積・加算により を抽出
特徴マップ
フィルタ(カーネル)
画素値
1 2 3
1 0 0
1 0 0
4 5
3 1
1 4
1 2 3
1 0 0
1 0 0
フィルタ(カーネル)
1 4 5 2 1 3
0 3 1 3 2 0
1 1 4 5 1 2
3 0 2 4 0 3
1 0 1 1 4 5
画像のpixel値
× = 4×1 + 5×2 + 2×3 + 3×1+ 1×0 +3×0 + 1×1 + 4×0 + 5×0
= 24
26 25
特徴マップ
24 + 1 𝑓 𝑢
バイアス 活性化関数
2
3
5
フィルタをずらしながら演算
このことで次元間のつながりが保たれる
ずらす幅をストライドという
ストライドが大きくなると出力画像は小さくなる
4.3 パディングと畳込み結果のサイズ
元画像の周囲にダミー画素を配置することをパディングという
メリット
①端の画素の特徴も畳み込み演算に入れられる
②畳み込みを繰り返すことで特徴マップが小さくなりすぎることを防ぐ
0
0
0
0
0
0
0
0
0
0
0 0 0 0 0 0 0
0
0 0 0 0 0 0 0
0
1 4 5 2 1 3
0 3 1 3 2 0
1 1 4 5 1 2
3 0 2 4 0 3
1 0 1 1 4 5
特徴マップのサイズ
特徴マップの幅(高さ)=
元画像の幅 高さ + パディング数×2− フィルタ幅(高さ)
ストライド幅(高さ)
+ 1
※基本的には、元画像の幅(高さ)がストライド幅で割られたサイズになる。
ただし、パディングされると両幅分だけ元画像が大きくなる。
最後にフィルタ幅分引いて、1加算する
4.4 プーリング層
プーリング=いくつかのグループを一つのグループにまとめること
CNNでは特徴マップをいくつかのグループに分けて代表値を選択しサイズを縮小する(次元削減する)こと
この部分に重みのような学習要素はない
1 2 3
1 0 0
1 0 0
フィルタ(カーネル)
1 4 5 2 1 3
0 3 1 3 2 0
1 1 4 5 1 2
3 0 2 4 0 3
1 0 1 1 4 5
画像のpixel値
25 24 17 21
13 15 19 16
19 24 20 18
特徴マップ
8 14 9 11
25 21
例:2x2の中の最大値を選択
(Maxプーリング)
24 20
プーリングのメリット
微小移動の影響を受けにくくなる
(同じオブジェクトでも少しだけずれただけで、全く別物として学習されてしまうのを防ぐ)
プーリング結果
プーリングの種類
Maxプーリング:フィルタ領域内の最大値
Averageプーリング:フィルタ領域内の平均値
4.5 全結合層
「畳み込み」、「プーリング」を何度か行った後にデータをフラット化し、
通常のディープニューラルネットワークと同じ手法で学習する
全てのニューロンが結合しているから「全結合層」
Affine層(線形変換なので)、Dense層(密結合なので)、FC層(Fully Connected)などとも呼ばれる
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
また、全結合層の代わりにGlobal Max Pooling/Global Average Poolingを用いることもある。
→これは、各チャネルの出力をPooling層同様、最大値、平均値でフィルタするものである。
1 2 3
1 0 0
1 0 0
例:最後のプーリング層の出力が、幅:3、高さ:3、層数:100だとして、
全結合層の入力は3×3×100=900となるが、
Global Max/Average Poolingだと、層数分が圧縮され3×3=9となる。
3
3
100
4.6 実装 畳込み層の高速化施策
1 4 5 2
0 3 1 3
1 1 4 5
3 0 2 4
1 4 5 0 3 1 1 1 4
4 5 2 3 1 3 1 4 5
0 3 1 1 1 4 3 0 2
3 1 3 1 4 5 0 2 4
畳み込みされる領域をフィルタのサイズで区切って一列に並べる
これにより、フィルタとの掛け算の和は単純な配列の積と和になる
def im2col(input_data, filter_h, filter_w, stride=1, pad=0):
N, C, H, W = input_data.shape
out_h = ( (H + 2*pad - filter_h) // stride ) + 1
out_w = ( (W + 2*pad - filter_w) // stride ) + 1
img = np.pad( input_data, [(0,0), (0,0), (pad, pad), (pad, pad)], 'constant')
col = np.zeros((N, C, filter_h, filter_w, out_h, out_w))
for y in range(filter_h):
y_max = y + stride * out_h
for x in range(filter_w):
x_max = x + stride * out_w
col[:, :, y, x, :, :] = img[:, :, y:y_max:stride, x:x_max:stride]
# (N, C, filter_h, filter_w, out_h, out_w) - > (N, filter_w, out_h, out_w, C, filter_h)
col = col.transpose(0, 4, 5, 1, 2, 3)
col = col.reshape(N * out_h * out_w, -1)
return col
畳み込みの出力データサイズを計算(上の例だと2×2)
元データにパディングを追加
この関数の出力配列(畳み込み領域を一列に並べた配列)
フィルタ幅高さ分だけ一つずつずらすため、
一回の取り出しサイズの上限を計算
(上の例だと、y_max,x_maxとも2,3,4)
元の画像を(x:x_max)×(y:y_max)で取り出す(stride分飛ばしながら)
フィルタサイズの幅高さに並べ替え、一列にreshape
4.7 実装 プーリング層の逆伝播
Poolingクラス
def forward(self, x):
N, C, H, W = x.shape
out_h = int(1 + (H - self.pool_h) / self.stride)
out_w = int(1 + (W - self.pool_w) / self.stride)
# xを行列に変換
col = im2col(x, self.pool_h, self.pool_w, self.stride, self.pad)
# プーリングのサイズに合わせてリサイズ
col = col.reshape(-1, self.pool_h*self.pool_w)
# 行ごとに最大値を求める
arg_max = np.argmax(col, axis=1)
out = np.max(col, axis=1)
# 整形
out = out.reshape(N, out_h, out_w, C).transpose(0, 3, 1, 2)
self.x = x
self.arg_max = arg_max
return out
def backward(self, dout):
dout = dout.transpose(0, 2, 3, 1)
pool_size = self.pool_h * self.pool_w
dmax = np.zeros((dout.size, pool_size))
dmax[np.arange(self.arg_max.size), self.arg_max.flatten()] = dout.flatten()
dmax = dmax.reshape(dout.shape + (pool_size,))
dcol = dmax.reshape(dmax.shape[0] * dmax.shape[1] * dmax.shape[2], -1)
dx = col2im(dcol, self.x.shape, self.pool_h, self.pool_w, self.stride, self.pad)
return dx
プーリングの出力データサイズを計算
高速化のために一行にする
Maxプーリング処理
(argmaxは一行の中の最大値のindexが入る。)
arg_max(index)の部分にdoutが入る
(Reluの微分のような感じ)
1.勾配消失問題と対策
2.最適化アルゴリズム
3.過学習と対策
4.畳み込みニューラルネットワーク(CNN)
5.実装演習 github情報
5.1 実装演習
2層DNN
MNISTデータをAffine-Relu-Affine-Softmaxで学習/検証
MNISTデータは所定の位置にある前提
モメンタム
最適化手法にモメンタムを使用
https://github.com/33quitykubby/Rabbit_DNN_1_2/blob/main/Rabbit_DNN_4_newtwork1.ipynb
https://github.com/33quitykubby/Rabbit_DNN_1_2/blob/main/Rabbit_DNN_6_newtwork1_optimize_momentum.ipynb
Adam
最適化手法にAdamを使用
https://github.com/33quitykubby/Rabbit_DNN_1_2/blob/main/Rabbit_DNN_7_newtwork1_optimize_adam.ipynb
5.2 実装演習
L2ノルム(Ridge)
過学習対策としてL2ノルムの適用
Dropout
過学習対策としてDropoutを適用
https://github.com/33quitykubby/Rabbit_DNN_1_2/blob/main/Rabbit_DNN_9_newtwork1_L2norm.ipynb
https://github.com/33quitykubby/Rabbit_DNN_1_2/blob/main/Rabbit_DNN_A_newtwork1_Dropout.ipynb
CNN
Convolution-Relu-Pooling-Affine-Relu-AffineのシンプルCNNの実装
https://github.com/33quitykubby/Rabbit_DNN_1_2/blob/main/Rabbit_CNN_1_simple.ipynb

Rabbit challenge 3 DNN Day2