9
6

More than 5 years have passed since last update.

ゼロから作るDeepLearning第三章 ニューラルネットワーク

Last updated at Posted at 2018-02-25

-1. 第二章の振り返り

 前章である第二章では「パーセプトロン」について学んだのじゃ。
 パーセプトロン.png
 
 一つのパーセプトロンは、複数のニューロン(図中の○)で構成されていて、各ニューロンからの信号とバイアスを受け取るのじゃ。そしてその総和であるaを、活性化関数hを利用して、aを変換して出力値yを求めるのじゃな。
 式で表すと以下のようじゃったな。

a = x_1*w_1 + x_2*w_2 + b\\
y = h(a)

0 第三章について

 第三章では、パーセプトロンを組み合わせたニューラルネットワークについて見ていくのじゃ。
 たくさんのパーセプトロンを組み合わせることで、表現豊かな出力値を自動で求めることが出来るというわけなのじゃ。
しかも、ニューラルネットワークの一つ一つのパーツはパーセプトロンなのじゃから、パーセプトロンのパラメータを更新するだけでニューラルネットワークに多くの使いみちが出て一石二鳥?・・・なのじゃ。
 早速見ていこうと思うのじゃ!

1 ニューラルネットワーク

1.1 ニューラルネットワークとは

 何度も繰り返しになってしまうのじゃが、ニューラルネットワークとはたくさんのパーセプトロンで構成されているネットワークなのじゃ。
何層も何層もパーセプトロンが積み重なってできているらしいのじゃ。何事も積み重ねがやっぱ大事なのじゃな・・・

1.2 ニューラルネットワークの形

 ニューラルネットワーク.png

 上図がニューラルネットワークのイメージ図なのじゃ。
 なんとも言い難い形をしておるのじゃ・・・
 図を見て分かる通り、主に3つの層でできておるのじゃ。

1.2.1 入力層

 入力層は必ず一つしかないのじゃ。いろんな場所で入力してしまうと管理が大変じゃからなのじゃ。
 また、入力層のニューロンの数は使用するデータによって決まるのじゃ。
 なぜなら、使用するデータに合わせて入力層のニューロンの数を決めないと、データがはみ出したり足りなかったりしちゃうのじゃ。学校で1クラス30人が基本じゃのに、60人詰め込むと生徒ははみ出るし、10人しかいないと机ががら空きなのと同じ理屈なのじゃ。
例えば、20*20の400画素の画像をニューラルネットワークにぶち込む際には、入力層には400個のニューロンが用意されるはずなのじゃ。
 

1.2.2 中間層

 中間層はいくつあってもよいのじゃ。一つでも、十つでも、千つでもよいのじゃ。なんなら中間層はなくてもよいのじゃ。
 ・・・中間層がなくても良いなら、なぜ使用するのかという声が聞こえてきたのじゃ。
 中間層は別になくてもよいのじゃが、その場合は表現できる内容が減ったり、うまく学習できなかったりするのじゃ。
 中間層がある程度あればパラメータの数は中間層のニューロンの数だけ増加するので、表現力も莫大というわけじゃな!
 ・・・悲しいことにその分計算量も莫大になってしまうのじゃ

1.2.3 出力層

 出力層は一つのみで構成されておるのじゃ。
 出力層に含まれるニューロンの個数は、出力したいデータの個数に等しくなるのじゃ。
 あとでまた記述するのじゃが

  • 回帰問題ではニューロンは一つ
  • 分類問題では分類したい分の数

 になるんじゃな。

 例えば、回帰問題では、広告にかける費用と広告のクリック数の関係性などがあるのじゃ。広告にたくさんお金をかければかけるほどクリック数は増えそうであると予想できるのじゃ。その関係式を求めることができれば、どのくらいの費用でどのくらいのクリック数が得られるのか連続値で予想できるというわけじゃな。
 また、分類問題では、ラブライブ!のキャラの顔分類などがあるのじゃ。ニューラルネットワークが画像を読み込んで自動で学習し、一体どのキャラなのか分類してくれるようになるのじゃ。ラブライブ!の場合じゃと、9人おるのでニューロンはきっと9個じゃな。
 わらわもいつかアニメ画像の分類をやれるようになりたいのじゃ。

2 活性化関数

2.1 活性化関数とは

 活性化関数は、これまでの図でいうと関数hに当たるものなのじゃ。前の層から受け取った値の総和を活性化関数にくぐらせるのじゃ。
 活性化関数はニューラルネットワークには欠かせない存在で、ほとんどのニューロンで実行されるものなのじゃ。というか活性化関数がないとうまく成り立たないのじゃ。

2.2 活性化関数のメリット

 活性化関数を使用するのには理由があるのじゃ。
 それは、「線形性を防ぐ」に尽きると思うのじゃ。
 活性化関数がないと、すべてのニューロンで行われているのはただの足し算と掛け算なのじゃ。極論になってしまうのじゃが、活性化関数を使わないなら、ニューロンが一つでも、百つでも、一万つでも結果が変わらないらしいのじゃ。
 便利なものなんじゃな・・・

2.3 活性化関数の種類

 活性化関数はいっぱいあるらしいのじゃが、今回はわらわの知っている
- シグモイド関数
- Relu関数
 のみに絞って見ていこうと思うのじゃ。
 もっと知りたい方は他のサイト様を見ていだだくとすごいわかりやすいはずなのじゃ。

2.4 シグモイド関数

 出た!
 シグモイド関数なのじゃ!
 わらわが高校生じゃった頃は意味もわからず微分・積分を行っていたのじゃ!なんともあほらしいのじゃ!
 ・・・早速見ていこうと思うのじゃ。

2.4.1 シグモイド関数の式

 f(x)\quad=\quad1+(1+e^{-x})

 

2.4.2 シグモイド関数の図

sigmoid.png

 上図がシグモイド関数なのじゃ。

2.4.3 シグモイド関数の特徴

 特徴として

  • x=0のとき、y=0.5
  • xが負の方向に無限大のときは限りなくy=0
  • xがプラスの方向に無限大のときは限りなくy=1

 などがあるのじゃ。
 どんな値を入力したとしても、必ず0から1の値を取るので、確率としてもみることが出来るのが最大の特徴なのじゃ。

2.4.4 シグモイド関数のソースコード

 ソースコードは以下のようになるなのじゃ。

import numpy as np
import matplotlib.pyplot as plt

def sigmoid(x):
    return 1 / (1 + np.exp(-x))

x = np.arange(-5, 5, 0.1)
y = sigmoid(x)
plt.plot(x, y)
plt.show()

2.5 Relu関数

 Relu関数は非常に単純なので、わらわみたいなアホにとってはありがたいのじゃ。
 処理が単純で最近ではもっぱら使用されているらしいのじゃ。(ただし、単純すぎるため派生版が使用されているらしいのじゃ。)

2.5.1 Relu関数の式

f(x)\quad =\quad \left\{
\begin{array}{ll}
x & (x \geq 0) \\
0 & (x \lt 0)
\end{array}
\right.

2.5.2 Relu関数の図

relu.png

 上図がRelu関数の図なのじゃ。
 シグモイド関数に比べてシンプルな感じがするのじゃ。

2.5.3 Relu関数の特徴

 Relu関数の特徴としては

  • 処理がシンプル
  • 0の部分があり、後に記述する学習に関して収束が早い
  • x>0において、勾配(微分のこと)が1であり、勾配消失(後の章で記述)が起き辛い

 などがあるのじゃ。
 とても便利なのじゃ!

2.5.4 Relu関数のソースコード

 ソースコードは以下のようになるのじゃ!

import numpy as np
import matplotlib.pyplot as plt

def relu(x):
    return np.maximum(x, 0)

x = np.arange(-5, 5, 0.1)
y = relu(x)
plt.plot(x, y)
plt.show()

3. ニューラルネットワークにおける計算

 ニューラルネットワークは、多くの層で構成されていて、それぞれのニューロンが次の層のすべてのニューロンにつながっているため計算量が多いのじゃ。
 そこでなのじゃ!
 Pythonのライブラリであるnumpyを使用することで比較的ラクに計算を行えることが出来るのじゃあ!

3.1 numpyによる行列計算

 わらわは線形代数が苦手なため、あまり行列にいい思い出がないのじゃが頑張って記述するのじゃあ・・・
 numpyは行列の計算もカバーしていて、dot関数を使用することで自動で最適化を行って計算を行ってくれるのじゃ!
 別にfor文を使用しても計算出来るのじゃが、一度ndarray型からarray型に変換する必要があったり、次元数が増えてくるとforのネスト構造がきつくなってくるからあまりやらないほうがいいのじゃ。
 では早速ソースコードと照らし合わせて見ていこうと思うのじゃ。

 

import numpy as np

#行列の宣言
A = np.array([[1, 2, 3], [4, 5, 6]])
B = np.array([[3,10], [-2, 3], [3, 0]])

A.shape #(2,3)
B.shape #(3,2)

C = np.dot(A, B) #(2,3) * (3,2)
C.shape #(2,2)

 上のソースコードでは

  1. (2,3)の行列Aの宣言
  2. (3,2)の行列Bの宣言
  3. AとBの行列の計算
  4. 結果の行列(2,2)をCに格納

 という処理を行っているのじゃ!
 詳しくは他のサイト様を当たって欲しいなのじゃ!

numpy.png

3.2 ニューラルネットワークにおける行列計算

 
 numpyでの行列を少しだけ復習したので、今度は、ニューラルネットワークではどんな行列計算が行われているのか見ていこうと思うのじゃ。

3.2.1 重みの行列計算

行列イメージ.png

 上の図を見てほしいのじゃ。
 上の図は2つの層で構成されていて、入力x1, x2に重みをかけて3つの出力値を計算しているのじゃ。
 前の層のニューロンは2つあって、後の層のニューロンは3つあるのじゃ。
 そのため、前の層と後の層の間にある重みWは2*3で6つの要素を持つのじゃ。前の層のニューロンの数と後の層のニューロンの数の積が、重みWの要素数になるのじゃな。
 また、Wの行列に注目してみると、行の数は2、列の数は3になっているのじゃ。つまり、2つの層の重みは、行数が前の層のニューロンの個数、列数が後の層のニューロンの個数になるわけじゃな。
 ・・・説明しづらいのじゃが、重みは行ごとに見ていくとわかりやすいと思うのじゃ。前の層のニューロン一つから次の層のニューロンへ向かう矢印(重み)が、重み行列Wの一行を表していると考えると、妾はわかりやすかったのじゃ。

3.2.2 重みの行列計算のメリット

 ニューラルネットワークの重みの計算は行列を使用すると非常にメリットが大きいのじゃ。
 メリットの一つを上げるのじゃ。3.2.1の図に記入されておるのじゃが、後ほどデータをニューラルネットワークに流すとき、その際に流すデータの個数にかかわらず計算をすることが出来るのじゃ。

 具体例をあげるのじゃ。
 画像をニューラルネットワークに流すとするのじゃ。画像の大きさは20*20とすると入力層のニューロンの数は400個になるのじゃ。
 そうすると入力するデータの画像をn枚とすると、入力する際の行列は(n, 400)として表されるのじゃ。
 次の層のニューロンの個数が200個だとすると、重みが(400,200)になるのじゃ。
 ここで行列計算を行ってみると、出力される行列は(n, 200)になるのじゃ。
・・・ここで出力される行列の行数nが大事なのじゃ!
 いくらこの後、中間層を増やして行列計算をしても出力値の行数は必ずnになるのじゃ。理屈はよくわからんのじゃ!
 出力の行数が必ずnであるため、データの個数の認識が変わらず、常に同じ行列計算を行えるのじゃ。
 どんな値を入れても同じ計算を行えるのは非常にありがたいことなのじゃな。
 ・・・説明が分かりずらかったら申し訳ないのじゃ。

3.3 出力層における計算

 出力層以外の層では、今のところは一貫して「重みの行列計算→活性化関数」を何度も繰り返して連続して行うのじゃ。
 しかし、出力層においては異なる計算をすることに注意せねばならないのじゃ。
 異なる計算をする理由としては、出力する際は、適切な値にしてやらんと、よくわからん値のまま出てしまうからなのじゃ。
 早速、どんな計算を出力層で行うのか見ていこうと思うのじゃ。

3.3.1 恒等関数

  回帰問題で使用するのが恒等関数じゃな。
 といっても、恒等関数は何かするのかといったら……特になにもしないのじゃ。
 受け取った値をそのまま出力するだけなのじゃ。
 3.3.2で記述するソフトマックス関数に合わせて、回帰問題だけ出力層で何も計算をしないのはバランスが悪いだろ! みたいなことなのだと思うのじゃ。

3.3.2 ソフトマックス関数

 分類問題で使用されるのがソフトマックス関数なのじゃ。
 計算式は以下の式で表されるのじゃ。

y_k =\frac{exp(a_k)}{\sum_{i=1}^{n}exp(a_i)}

 上の式では

  • 出力層のニューロンの個数はn個
  • ykは、出力層のk番目の出力を表す
  • aiは、出力層の前の層からの重みをかけた入力信号の値
  • 分母は、前の層からの入力信号を指数関数で変換したものの総和
  • 分子は、出力層のk番目のニューロンに入ってくる入力信号を指数関数で変換したもの

 を表すのじゃ。
 ・・・・・・よくわからんのじゃ!あまり詳しく知らなくていいと思うのじゃ!

 大事なのはソフトマックス関数の出力値が何を表すのかということなのじゃ!

 実はソフトマックス関数の出力値は0から1の実数になるのじゃ。(やってることは、面倒な指数関数を抜かして考えれば、全体の合計分の注目値じゃからの)
 ・・・・・・全体の合計分の注目値のじゃ?
 ・・・実はソフトマックス関数の出力値は確率としてみることができるのじゃ。妾も高校生で確率を習ったときは、全体試行の合計回数分の求めたい試行の回数と習った記憶があるのじゃ!

 よって、ソフトマックス関数を利用すると
 出力値y[0]が0.2より0番目の起こる確率は20%
 出力値y[1]が0.3より1番目の起こる確率は30%
 出力値y[2]が0.02より2番目の起こる確率は2%
 出力値y[3]が0.48より3番目の起こる確率は48%
 ゆえに、y[3]の要素が一番確率が高いため、現段階でもっとも考えられる分類は3番目のクラスの要素だ!
 のように、確率を利用して、分類を行うことが出来るのじゃ。
 ソフトマックス関数様バンザイじゃな。

4 バッチ処理

 3の行列計算で少し触れたのじゃが、ニューラルネットワークで学習を行うときはデータを入力する必要があるのじゃ。
 その際には、一つ一つデータを入力するのではなく、複数のデータをまとめてぶちこむためのバッチを作成してから、バッチごとニューラルネットワークにぶち込んだほうが良いのじゃ。
 バッチを使用するほうが良い理由としては、一重に処理効率の問題なのじゃ。numpyなどの計算ライブラリは行列計算を最適化して効率よく行っているため、バッチなどの塊にしてデータをぶち込んだほうが大幅に時間が短縮できるというわけじゃな。

5 第三章振り返り

 第三章では、ニューラルネットワークについて見てきたのじゃ。
 ニューラルネットワークは、たくさんのパーセプトロンが何層も重なってできているんじゃったな。
 入力層・中間層では、重みの計算は行列計算で行い、行列計算した値は活性化関数で表現豊かにするんじゃったな。
 出力層では、回帰問題ではそのまま出力。分類問題ではソフトマックス関数を利用して、確率として出力値を捉えて、どの分類が一番確率的に考えるのかがだいじじゃったな。
 ニューラルネットワークの学習を行うためにデータを入力する際は、処理効率の問題から、バッチとしてデータをまとめてぶち込むことが大切じゃったな。

 ・・・非常に難しい内容なのじゃ。
 頑張って理解していこうと思うのじゃ。
 また、ニューラルネットワークの全体の実装に関しては今回は省略したのじゃ。
 理由としては、将来的にChainerなどのライブラリを使用する際は、あまり重みの行列の次元数を意識する必要がないからなのじゃ。一回このゼロから学ぶDeepLearnigのソースコードを書いた後、Chainerを使用したら、あんなに苦労した実装がクソ雑魚簡単じゃったのじゃ・・・
 申し訳ないのじゃが、第三章の実装を見たい方は本を買っていただきたいのじゃ(番宣)。第四章は自分なりにもっと実装を増やしていこうと思うのじゃ。

6 それぞれの章へのリンク

自分流まとめホーム
第二章 パーセプトロン
第三章 ニューラルネットワークの学習
第四章 ニューラルネットワークの学習
第五章 誤差逆伝播法
第六章 学習においてのテクニック
第七章 畳み込みネットワーク
第八章 DeepLearning

7 参考文献

書籍 ゼロから作るDeepLearning オライリー・ジャパン
マークダウン記法
https://qiita.com/hiroyuki_hon/items/f2a779bb295fd12646ab
Deep Learningでラブライブ!キャラを識別する http://christina.hatenablog.com/entry/2015/01/23/212541
Qiitaの数式チートシート
https://qiita.com/PlanetMeron/items/63ac58898541cbe81ada

9
6
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
9
6