Coding Memos

try {coding} catch {questions}

ニューラルネットワークの活性化関数【ゼロ作DL_9】

本稿ではニューラルネットワークの定式化についての学習記録です。 「ゼロから作るDeep Learning」の内容に沿っていますが、今回は割と内容について、自身で考えたことを書きます。

f:id:codingmemos:20170304185553g:plain

村上・泉田研究室 ニューラルネットワーク から画像引用

パーセプトロンでいいのか?

これまでにパーセプトロンアルゴリズムを定式化して来ました。 {
y = b + w_1x_1 + w_2x_2
}

と、このブログでは見慣れた形式です。

これは、

{\displaystyle
y = 
   \left\{
    \begin{array}{l}
      0 \ \ (b + w_1x_1 + w_2x_2 \leqq 0)\\
      1 \ \ (b + w_1x_1 + w_2x_2 \gt 0)
    \end{array}
  \right.
}

というふうに場合分けした形で、出力値を得ていましたね。

これをグラフにプロットすると、こんな感じ。

f:id:codingmemos:20170304185915p:plain

import numpy as np
import matplotlib.pyplot as plt

def step_func(x):
  return np.array(x > 0, dtype=np.int)
  # x > 0の条件をみたしていれば、普通はTrueが返るが、int型で返すようにしている。すなわち、Trueの場合は1が返る。
x = np.arange(-5.0, 5.0, 0.1)
y = step_func(x)
plt.plot(x,y)
plt.ylim(-.1, 1.1)
plt.show()

確かに閾値をまたいだ時に、0から1に急激にジャンプしてますが、自然界でこのような特異的なジャンプを見せるというのは 考えにくいんじゃないかと思います。

ニューロンで言えば、ある一定の入力があれば出力される全か無かの法則ではありますが、ここまで厳密に隔てられているわけではありません。(実態はニューロン内外の電位差による脱分極により、発火が起こるわけですから。)

そこで、このステップ関数をより滑らかにしたシグモイド関数を使ってみようとなるわけですね。

シグモイド関数の導入

f:id:codingmemos:20170304190613p:plain

シグモイド曲線は上記のような曲線で、さっきのパーセプトロンをなめらなか曲線で描いた感じですね。 こちらの場合は、先ほどのステップ関数よりも、より柔軟です。

ステップ関数では、入力信号が、少しでも閾値をこえれば、出力するようなジャンプを見せますが、 シグモイドでは、そのようなジャンプをせず、閾値付近で微々たる出力、というものを許容します。

一般的なシグモイド関数の数式は以下のようになります。

{\displaystyle
y=\frac{1}{1+\exp(-x)}
}

より一般的には、ロジスティック関数を入れたほうがいいでしょうが、モデルとしては、ゲインを1とした時の標準シグモイド関数で十分事足りるはずです(よね?)

シグモイド関数 - Wikipedia

ロジスティック関数は、人口増加モデルや、例えば生物学的に言えば、細胞増殖のモデルなどがこれに当てはまりますね。 自然界でもよく「採用」されるモデルです。

話が逸れましたが、ステップ関数をより現実的に近づいたシグモイド関数を採用してみようということですね。

活性化関数

さて、ここまでに、

と「閾値を超えるか否かの加工をしてくれる関数」が二つ出て来ました。

{x(input) \to h(x) (process) \to y(output)}

というイメージをしてみると、hという関数でゴニョゴニョとやって、その値によって出力が0 or 1 となるわけです。

業界的には、この hという関数を「活性化関数」というみたいです。

なので、いままでに、この活性化関数の選択肢として、ステップ関数やシグモイド関数が出て来たということになります。

今までに出て来たのはこの二つですけど、自然界を観察することで、これよりも適した活性化関数があるかもしれません。 なぜ、シグモイドか、なぜステップかということではなく、わかりやすいモデルの一例としてこの二つということになるでしょうね。

自然科学においては、観察結果を厳密に表す数式を作ったところで、他の観察結果に適用できなかったり、数式のパラメータが多すぎて扱えないということだったり、人間が科学的に自然を扱うには様々な制約があります。

そこで、パラメータを少なくしつつ、現実的な観察結果にも適用できるモデルで近似するわけですね。

シグモイド関数の実装

NumPyのおかげで、簡単に実装できますね。 さっきのコードに追記しています。

import numpy as np
import matplotlib.pyplot as plt

def step_func(x):
  return np.array(x > 0, dtype=np.int)
  # x > 0の条件をみたしていれば、普通はTrueが返るが、int型で返すようにしている。すなわち、Trueの場合は1が返る。

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

x = np.arange(-5.0, 5.0, 0.1)
y1 = step_func(x)
y2 = sigmoid(x)
plt.plot(x,y1, label="step")
plt.plot(x, y2,linestyle="--", label="sigmoid")
plt.ylim(-.1, 1.1)
plt.legend()
plt.show()

これによって、プロットすると(さっきのステップと一緒に描画すると)下図のようになります。

f:id:codingmemos:20170304193737p:plain

グラフ中、-4 から -2 に2増加するのと、 -2から0へ2増加するのでは、y値の変化量が変わっていますね。 このような急激な変化を見せるのが、「全か無かの法則」に適した関数と言えそうです。

本稿では、活性化関数と、これに採用できる一つの例としてシグモイド関数があるということを学びました。 さらに進むと、活性化関数として他のものが採用されるようですので、それも楽しみですね。