1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

技術書一冊やり込もうAdvent Calendar 2024

Day 17

ゼロから作るDeepLearning #3 -出力層のこと-

Last updated at Posted at 2024-12-16

※以下の企画です

前回に続いてゼロつくやっていきます。
今回は3章-ニューラルネットワーク-の続きです。
前回は活性化関数のことをメインで学び、今回は実際に三層のNNを組んでいくという内容になりそうです。

それでは頑張っていきます〜

3章 ニューラルネットワーク

3層NN

ニューラルネットワークの計算は、各ノードへの入力値に重みを掛けて総和を取るだけ。
コードに落とし込むと、「各ノードへの重み×入力値の計算」を「ノード数×層」分繰り返すことになる。
ちょっと冗長なコードになりそうな印象だが、numpyライブラリを用いれば割とキレイに書くことができる(僕も本書を読んで知った)。

3層NN
def init_network():
  network = {}
  network['W1'] = np.array([[0.1, 0.3, 0.5], [0.2, 0.4, 0.6]])
  network['b1'] = np.array([0.1, 0.2, 0.3])
  
  network['W2'] = np.array([[0.1, 0.4], [0.2, 0.5], [0.3, 0.6]])
  network['b2'] = np.array([0.1, 0.2])
  
  network['W3'] = np.array([[0.1, 0.3], [0.2, 0.4]])
  network['b3'] = np.array([0.1, 0.2])

  return network

def identity_Function(x):
  return x

def forward(network, x):
  w1,w2,w3 = network['W1'], network['W2'], network['W3']
  b1,b2,b3 = network['b1'], network['b2'], network['b3']

  a1 = np.dot(x, w1) + b1
  z1 = sigmoid(a1)
  a2 = np.dot(z1, w2) + b2
  z2 = sigmoid(a2)
  a3 = np.dot(z2, w3) + b3

  y = identity_Function(a3)

  return y

コードはみたまんまの内容だが、a1 = np.dot(x, w1) + b1という部分が割とミソで、行列同士の席やベクトルの内積をサクッと計算してくれる関数。
これで繰り返し文をエッサホイサと記述する必要がなくなる。ありがたい。

また、identity_Functionという関数が最後に用いられている。
関数の中身を見ると、入力をそのまま出力に設定しているだけの謎関数に見えるが、これは後で出力層をイジイジするときに使うらしいのおいておく(これは恒等関数と言うらしい)

実行結果をみてみる。

3層NNの実行
network = init_network()
x = np.array([1.0, 0.5])
y = forward(network, x)
print(y)
実行結果
[0.31682708 0.69627909]

めっちゃ簡単!

出力層の設計

分類、回帰問題

出力層に用いていた恒等関数は回帰問題のときに用いて、分類問題のときにソフトマックス関数というものを用いるらしい。

ソフトマックス関数

まずは式から。

y_{k} = \frac{\exp(a_{k})}{\sum_{i=1}^{n}\exp(a_{i})}

出力層への入力が$n$個あって、$k$番目の出力$y_{k}$を求めるという計算。
また、指数感の計算は桁数がとんでもない数になるので、コンピュータでそのまま扱おうとするとエラーになるらしい。
なので、入力値の最大値を分母分子から引くという処理を行う。
これは、ある定数を分母分子に加えたとて、計算結果は変わらないという特徴を活用している。証明式は本書内にあるので興味のある人は是非とも読んでみてほしい!(怠惰)
※入力の最大値を使うのは、なんかそういう流れがあるからってだけらしい

ということで、それらも踏まえてソフトマックス関数をコードに落とし込んでみる。

ソフトマックス関数
def softmax(a):
  c = np.max(a) # 入力の最大値を確保
  exp_a = np.exp(a - c) #オーバーフロー対策
  sum_exp_a = np.sum(exp_a)
  y = exp_a / sum_exp_a

  return y

ソフトマックス関数の特徴としては、出力の総和が1になるという点。
これで何が言いたいかというと、これは「各出力の発生確率に置き換えられる」ということ。
だからソフトマックス関数は分類問題に用いられるということみたい。

ソフトマックス関数の動作
a = np.array([0.3, 2.9, 4.0])
y = softmax(a)
print(y)
実行結果
[0.01821127 0.24519181 0.73659691]
ソフトマックス関数の出力総和
np.sum(y)
実行結果
1.0

ここまでやっといて「え?」となったのが、ニューラルネットワークで分類問題を推論するときは、ソフトマックス関数を省略するらしい。草
というのも、指数関数を用いても入力された値のそもそもの大小関係は変わらず、単調増加するだけなので、重たい計算しなくても最大値を取るだけで大丈夫だってことらしい。
まぁたしかに。

まとめ

今回は出力層に用いる関数について学んだ。
ソフトマックスとか恒等関数とか、忘れかけていたものを改めて理解できて良かった。
次回はいよいよMNISTデータを用いてのテストになる。
こんな牛歩進捗で、月内に終わる気がしない
では、次回も頑張ります〜〜

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?