こんにちは!
現役パラレルワーカー フクコです。
前回の記事↓に続き
来年の2月の試験に向けてE資格試験勉強中のため
E資格とは?の記事はコチラ↓
ゼロつくシリーズでおなじみ
オーライリーから出版されている
ディープラーニングの本格的な入門書でよくおススメされる
「ゼロからつくる Deep Learning」本
この本↑を毎日5ページずつコツコツこなすと
約2か月間で今年中に終了するので
来年のE資格試験までにこれで基礎力をつけることにしました。(^^)
ついつい私は何もないとだらけてしまうので(笑)
毎日5ページ終わった後の記録とまとめを書いていこうと思います。
と、まとめに入る前に…
やる気を出すためのコトバをシェアします!!(主に私のやる気を出すために 笑)
「悔しいなぁ
何か一つできるようになっても
またすぐ目の前に 分厚い壁があるんだ。
すごい人はもっとずっと先のところで戦っているのに
俺はまだそこに行けない。」
by 炭治郎
私の大好きな「鬼滅の刃」から
炭治郎の名言です。
そうなんですよ!
何かを新しく学んでるときって学んでも学んでも
どんどん新しいカベが立ちふさがってくるんですよね。
(>ー<)
そして、
すでにカベを越えたヒト達がとてもまぶしく見えて、うらやましすぎて
もう早くそっちに行きたいのに、なかなか行けない…
じりじり、やるせないもどかしい思い…
そんな時唯一できることは
ひたすら反復基礎練習!!
夢中でコツコツこなしていると
いつの間にか「カベを越えたヒト達」の仲間入りをしていたりするんですよね。
炭治郎、どうもありがとう! (^0^)
今日もやる気が出てきました!
よし!! 今日も頑張るぞ~! お~!!
というコトで、
今日もコツコツゼロから基礎練習、私はノルマをこなしますよ! 笑
ではでは、いい加減まとめに入ります。笑
その前に本の目次の紹介です。
ゼロつくディープラーニングは、下記↓の合計8章で構成されています。
本の目次
- 1章 Python入門
- 2章 パーセプトロン
- 3章 ニューラルネットワーク
- 4章 ニューラルネットワークの学習
- 5章 誤差伝播法
- 6章 学習に関するテクニック
- 7章 畳み込みニューラルネットワーク
- 8章 ディープラーニング
ちなみに…
ゼロつくディープラーニングの第1章はPython入門のセクション(20ページ分)なので、
とりあえず今回私は飛ばし、第2章からまとめています。
現在は、第6章からで~す。
第6章 学習に関するテクニックつづき
ニューラルネットワークの学習において
キーとなる重要なアイディアを説明する。
ニューラルネットワークの学習を効率的に進め、認識精度を高める手法を紹介。
6.2.2 隠れ層のアクティベーション分布
隠れ層のアクティベーション(活性化関数の後の出力データ)の分布を観察することで
多くの知見を得られる。
5層のニューラルネットワークに、
ランダムに生成した入力データを流し、
各層のアクティベーションデータ分布をヒストグラムで描画する。
Pythonで実装してみると↓のとおり。
# 6.2.2 隠れ層のアクティベーション分布 # 5層のニューラルネットワークに、ランダムに生成した入力データを流し、 # 各層のアクティベーションデータ分布をヒストグラムで描画する。 # ライブラリインポート import numpy as np import matplotlib.pyplot as plt # sigmoid関数定義 def sigmoid(x): return 1 / (1 + np.exp(-x)) # Relu関数定義 def ReLU(x): return np.maximum(0, x) # tanh関数定義 def tanh(x): return np.tanh(x) input_data = np.random.randn(1000, 100) #1000個のランダムデータ,正規分布の乱数生成 node_num = 100 #各隠れ層のノード(ニューロン)の数 hidden_layer_size = 5 #隠れ層が5層 activations = {}#←ココにアクティベーションの結果が格納される x = input_data for i in range(hidden_layer_size): if i != 0:#「!=」は「==」の反対 x = activations[i-1] #初期値の値を色々変えて実験してみる w = np.random.randn(node_num, node_num) * 1 # w = np.random.randn(node_num, node_num) * 0.01 # w = np.random.randn(node_num, node_num) * np.sqrt(1.0 / node_num) # w = np.random.randn(node_num, node_num) * np.sqrt(2.0 / node_num) a = np.dot(x, w) #活性化関数の種類も変えて実験してみる z = sigmoid(a) #z = ReLU(a) #z = tanh(a) activations[i] = z #ヒストグラムを描画 for i, a in activations.items(): plt.subplot(1, len(activations), i+1) plt.title(str(i+1) + "-layer") if i != 0: plt.yticks([],[]) #plt.xlim(0.1, 1) #plt.ylim(0, 7000) plt.hist(a.flatten(), 30, range = (0,1)) plt.show()
5つの層があり、それぞれの層は100個のニューロンを持つものとする。
入力データとして、1000個のデータをガウス分布でランダムに生成。
活性化関数にはシグモイド関数を利用。
各層のアクティベーション結果を[text: activations]という変数に格納。
そして、
Pythonでそれぞれを実装結果の図が↓のとおり。
この図↑を見ると、
各層のアクティベーションは、0と1に偏った分布になっている。
0と1に偏った分布になると、
その微分はどんどん0に近づいていく。
そのため、
逆伝播の勾配の値が、どんどん小さくなり、「勾配消失」(Gradient Vanishing)がおこる。
そこで、
↓のように、重みの標準偏差だけ0.01に差し替えて、もう一度Pythonで実装してみる。
#初期値の値を色々変えて実験してみる # w = np.random.randn(node_num, node_num) * 1 w = np.random.randn(node_num, node_num) * 0.01
そうすると実装結果の図が↓のとおり。
今度の結果は、0.5付近に集中する分布となった。
すると、
「勾配消失」のモンダイはもうない。
だが!
表現力の制限の点で大きなモンダイがある。
なぜなら、
せっかく複数のニューロンが存在しても、同じ値を出力するなら意味がない。
様々な活性化関数で層の次元や層数によらずに
出力の分散を保てるような初期化方法はないものなのか??
というコトで、
「Xavierの初期値」を使ってみる。
「Xavierの初期値」とは??
2010年にXavier氏などに提案された手法。
前層のノードの個数をnとした場合、
「Xavierの初期値」を用いると、
前層のノードの数が多ければ多いほど
対象ノードの初期値として設定する重みのスケールは小さくなる。
「Xavierの初期値」を使って、重みを初期化( )してみると
# 6.2.2 隠れ層のアクティベーション分布 # 5層のニューラルネットワークに、ランダムに生成した入力データを流し、 # 各層のアクティベーションデータ分布をヒストグラムで描画する。 # ライブラリインポート import numpy as np import matplotlib.pyplot as plt # sigmoid関数定義 def sigmoid(x): return 1 / (1 + np.exp(-x)) # Relu関数定義 def ReLU(x): return np.maximum(0, x) # tanh関数定義 def tanh(x): return np.tanh(x) input_data = np.random.randn(1000, 100) #1000個のランダムデータ,正規分布の乱数生成 node_num = 100 #各隠れ層のノード(ニューロン)の数 hidden_layer_size = 5 #隠れ層が5層 activations = {}#←ココにアクティベーションの結果が格納される x = input_data for i in range(hidden_layer_size): if i != 0:#「!=」は「==」の反対 x = activations[i-1] #初期値の値を色々変えて実験してみる # w = np.random.randn(node_num, node_num) * 1 # w = np.random.randn(node_num, node_num) * 0.01 w = np.random.randn(node_num, node_num) * np.sqrt(1.0 / node_num)#Xavierの初期値 # w = np.random.randn(node_num, node_num) * np.sqrt(2.0 / node_num) a = np.dot(x, w) #活性化関数の種類も変えて実験してみる z = sigmoid(a) #z = ReLU(a) #z = tanh(a) activations[i] = z #ヒストグラムを描画 for i, a in activations.items(): plt.subplot(1, len(activations), i+1) plt.title(str(i+1) + "-layer") if i != 0: plt.yticks([],[]) #plt.xlim(0.1, 1) #plt.ylim(0, 7000) plt.hist(a.flatten(), 30, range = (0,1)) plt.show()
結果は↓の図のとおり。
この結果↑を見ると、
ややいびつではあるが、これまでよりも広がりをもった分布なので、
表現力が制限されることなく、
効率的に学習されたことが期待される。
ちなみに…
↑の実装は、活性化関数=Sigmoid関数でXavier初期化での結果だが、
これを活性化関数=tanh関数でXavier初期化での結果にすると↓のとおり。
キレイな釣り鐘型になる!と本には書いてあったが、何だちょっとちがう。。ような。。。(苦笑)
私の写経がまちがってるのか、やり方が悪い?そうなの??
よいよい(T-T)後でチェックしないとですね。
今日のまとめ
ハイ、今日はここまで!!
第6章の学習に関するテクニックまだまだ続きます!(^^)
引き続き頑張りまっす。
最後まで読んでくださり、ありがとうございます!
フクコ
ディープラーニング入門書おススメ本
E資格とは?