Deep Learning 4.1 シグモイド関数

ニューラルネットワークに使われる活性化関数h()は閾値を境にして、
出力が切り替わる関数で、ニューラルネットワークの元となるパーセプトロン
は活性化関数として、ステップ関数(後述)を使用しているが、
ニューラルネットワークではシグモイド関数やReLU関数(後述)を使用する。

5.1 シグモイド関数

ニューラルネットワークで最もよく用いられる活性化関数の一つはシグモイド関数であり、

\[ h(x) =  \frac{1}{1+exp(-x)} \tag{1.6}\]

ここでexp(-x)は

\[exp(-x) = e^{-x}\]

を意味する。eはネイピア数と呼ばれるものであり、e=2.7182….の実数を表す。

円周率πと大して変わらない。eの登場で高等数学が訳が分からなくなるのには
理由がある。eの定義、導出について、数学のえっきす(x)と発音しがちな数学教師が、
これは こうだ! と言って、得意げに、数式を書き、説明を終了するからである。

eの導出についてはこちらが親切です。

思考停止して、ああそうなんだ。といって暗記する人は先に進めるが、なぜだ!といって止まる人は、

\[(e^{x})’ = e^{x}\]

\[log(x)’ = \frac{1}{x}\]

という性質に至るまでに、何故なんだ……

そもそも

\[\displaystyle \lim_{h \to 0} f(h) \]

とは? 0に極限に近づくことがありうるのか?ゲシュタルト崩壊。

1+1=2というのは本当か? 最初にある純水1ℓとt秒後に純水1ℓを注いだものがはたして2ℓといえるのか?

なんでまさお君はりんごとバナナを買いに行かされたんだ? (もっと必要なものがあるだろうに…!?)

なんでまさおなんだ? ただしい おとこ・・・ 正しいとは?

やがて、発狂。

©藤子・F・不二雄

という事態を防ぐため、えっきす先生は配慮してくださったのです。(ありがたい)

そして、ここで数学が嫌いになる人が多いでしょうが、
プログラミングはありがたいことに、(突き詰めれば)偉い先人たちの考え出した公式のみが必要であり、数学者でない限り、論理的な数式展開は全く必要ありません。
例えばPythonではシグモイド関数をh(x)と定義した場合、
≫ h(1.0)
≫ 0.731…
のように、計算結果が返るだけです。

Deep Learning 4 活性化関数

\[y = h(b + w_1x_1 + w_2x_2 ) \tag{1.2}\]

上式をさらに置き換えると、

\[a = b + w_1x_1 + w_2x_2  \tag{1.4}\]

\[y = h(a) \tag{1.5}\]

式(1.4)では、重み付き入力信号(wi*xi)とバイアス(b)の総和を計算し、それを
aとする。

式(1.5)において、aがh()で変換されyが出力される。h()を活性化関数といい,出力yで表記。

ニューロンは一つの〇で図示してきたが、下図を、式(1.4)と(1.5)を明示的に示す。

 

Deep Learning 3 ニューラルネットワーク

1.パーセプトロンからニューラルネットワークへ

ニューラルネットワークは脳機能をコンピュータ表現したものらしい。脳の機能については、あまり興味がないので、ここでは、ニューロンの脳科学的説明は省略させていただく。

1.1ニューラルネットワークの例

左の列を入力層、一番右の列を出力層、中間の列を中間層と呼ぶ。中間層は隠れ層とよぶこともあるらしい。中間層は人の目には見えないためらしい。

Pythonで実装するため、便宜的に入力層を第0層、中間層を第1層、出力層を第2層と呼ぶ。上図のネットワークは全部で3層から構成されているが、重みを持つ層は2層であるため、「2層ネットワーク」と呼ぶことにする。

yellow sweets という入力に対して、中間層の処理を通して、バナナ、チンコという出力をする。AIが複数の出力を返すのに、不思議に思うかもしれない。

エヴァンゲリオンでスパコンMAGIが賛成77% 反対22% 条件付き賛成が1%などというの(正確には違うセリフだと思う)を思い出してほしい。

出力層のうち、たとえばバナナの数値が0.9でチンコの数値が0.1の場合AIはバナナを返すし、逆ならば、チンコを返す。これはアラビア数字(0~9)一けたの不鮮明な画像イメージを入力として、出力層のうち、最も適応度が高い数値の数字(例えば2)を返すのをイメージしてほしい。

1.2パーセプトロンの復習

上図のネットワークにはバイアスbが図示されていないが、バイアスを明示するならば
描きのようになる。バイアスの入力信号は常に1であるため、図では、灰色で塗りつぶし、他のニューロンと区別することにする。

 

\begin{eqnarray} y= \begin{cases}
0 & (b + w_1x_1 + w_2x_2 ) \leqq 0 \\
1 & (b + w_1x_1 + w_2x_2 ) > 0 \tag{1.2}
\end{cases}
\end{eqnarray}

前回説明した上記のパーセプトロンの式(1.2)を式(1.3)に書き換えると、

\[y = h(b + w_1x_1 + w_2x_2 ) \tag{1.3}\]

\begin{eqnarray} h(x)= \begin{cases}
0 & x \leqq 0 \\
1 & x > 0 \tag{1.4}
\end{cases}
\end{eqnarray}

式(1.4)は、入力信号の総和がh(x)という関数によって、変換され、
その変換された値が出力yになるということを表している。
式(1.4)で表されるh(x)関数は入力が0を超えたら、1を返し、そうでなければ0を返す。

式(1.2)と式(1.3),(1.4)は同じことを言っている。

Deep Learning 3 パーセプトロンのpythonでの実装

pythonには現実、神話とわず大蛇の意味がある。
プログラミング言語Pythonを作った人は、空飛ぶモンティパイソンというコメディTVからとったと言っている。(空飛ぶモンティパイソンについて、調べてみたが、何回読んでも意味不明である。変態の考えることはいつも理解されない(不幸なことだ)。コルトパイソンのパイソンの由来は「ただ、カッコイイから」らしい。こちらのほうがまだわかる。)

バイアスの導入

\begin{eqnarray} y= \begin{cases}
0 & (w_1x_1 + w_2x_2 ) \leqq \theta \\
1 & (w_1x_1 + w_2x_2 ) > \theta \tag{1.1}
\end{cases}
\end{eqnarray}

前回説明した上式においてθ=-bとすると、

\begin{eqnarray} y= \begin{cases}
0 & (b + w_1x_1 + w_2x_2 ) \leqq 0 \\
1 & (b + w_1x_1 + w_2x_2 ) > 0 \tag{1.2}
\end{cases}
\end{eqnarray}

と変形できる。

ここでbをバイアス(bias:偏り,ゲタばき)と呼ぶ。w1,w2は前回説明したように重みである。

この実装を下に示す。

x = np.array([0,1])では 普通の言語で言うところの x[] = {0,1};である。すなわち、
x[0] = 0; x[1] = 1;である。
同様に、w = np.array([0.5,0.5]);  w[] = {0.5,0.5};であり、すなわち、
w[0] = 0.5; w[1] = 0.5;

NumPy配列(Python実装の配列)の乗算では、2つの配列の要素数が同じ場合、その要素どうしが乗算される。(C言語などでは、x[0] * w[0]; x[1] * w[1]; としなければならない。)

np.sum(w*x)については、wの配列とxの配列の乗算の和である。

\begin{equation}
f(x) = \sum_{i=0}^1 x_iw_i = x_0 \times w_0 + x_1 \times w_1\\
= 0 \times 0.5 + 1 \times 0.5 = 0 + 0.5 = 0.5
\end{equation}
とあらわされ、
すなわち、w * x = [0,  1] * [0.5,  0.5] = [0 * 0.5 , 1 *0.5] => [0,  0.5]であり、

np.sum(w*x) = 0+0.5 = 0.5;であり、各要素の総和が計算される。この総和は重み付き和とよばれ、これにバイアスを加算すれば、式(1.2)の計算は終了する。

ここで b= -0.7であり、np.sum(w*x)= 0.5であるのに、なぜ出力結果が-0.2とならず、
-0.199999…という奇妙な浮動小数点数になっているか、不思議に思うだろうが、これは演算誤差とよばれるもので、こちらを参照されたし。

オーバーフローとアンダーフローについてはこちらを参照されたし。

これはテストプログラムなので、修正を省略するが、金融系の例えばATMのプログラムでこのようなことがおきたら、どうなるか想像するだけで恐ろしいであろう。

金融系のIT企業がヤバイのは、ハッキングやウィルス、情報漏洩に加え、こういう問題に神経を削らなければいけないからである。

Deep Learning 2 パーセプトロン

パーセプトロン(あるいは、人工ニューロンや単純パーセプトロンというらしい)、は、ニューラルネットワーク(ディープラーニング)、人工知能が”学習”するのに必要な概念である(らしい)ので、ここで記述しておく。

パーセプトロンは、複数の信号として受け取り、ひとつの信号を出力する。
ここで言う「信号」とは電流や川のような「流れ」を持つイメージである。
電流が導線を流れ、電子eを先に送り出すように、パーセプトロンの信号も流れを作り、情報を先へと伝達していく。ただし、実際の電流とは違い、パーセプトロンの信号は「流す/流さない(1か0)」の二値の値。0を信号を流さない。1を信号を流すとする。

記法や概念は有限オートマトンに似ている。忌まわしいオブジェクト指向のモデリング言語(UML)の、なんかのクラス図や図形にも似ている。クラス図やオブジェクト図、ユースケース図など、あの複雑怪奇な記法を知っていたからと言って、何の役にも立たない(クラス図の表記の専門家しか精確に多重度などは描けないし、そもそも新人の技術者や組み込み系専門の技術者は読めない。さらに悪いことには、ある程度の専門家でも、描く人によって、図形が違う。)狂人のつぶやき、”図画工作の僕のおとうさん”のような物と違って、パーセプトロンは単純で明快である。

\[ x_1, x_2 は入力信号、yは出力信号、w_1,w_2は重みを表す。(wはweightの頭文字)\]

図の〇は「ニューロン」や「ノード」と呼ばれる、(脳細胞の一つと考えるとわかりやすい。)
入力信号は、ニューロンに送られる際に、それぞれに固有の重みが乗算される。
\[(w_1x_1,w_2x_2)\]
ニューロンでは、送られてきた信号の総和が加算され、その総和が限界値を超えたときのみ1を出力する。これをニューロンが発火すると表現することもある。(入力信号がストレスで、限界値を超えるとキレる(1を出力する,または発火する)と考えるとわかりやすいかもしれない。)

ここではその限界値を閾値(しきいち)と呼び、θという記号であらわす。

パーセプトロンの動作原理はこれだけである。以上のことを数式で表すと下のようになる。

 

\begin{eqnarray} y= \begin{cases}
0 & (w_1x_1 + w_2x_2 ) \leqq \theta \\
1 & (w_1x_1 + w_2x_2 ) > \theta \tag{1.1}
\end{cases}
\end{eqnarray}

パーセプトロンは、複数ある入力信号のそれぞれに固有の重み(ex.w1,w2)を持つ。そして、その重みは、各信号の重要性をコントロールする要素として働く。重みが大きければ大きいほど、その重みに対応する信号の重要性が高くなる。

人がストレスでキレる例を挙げれば、家庭のストレス、通勤のストレス、上司のストレスなど様々なストレスがあるが、ある人が、通勤、家族のストレスはあまり感じないが、上司のストレスを大きく感じる場合、通勤、家族(のストレス)の重みは小さく、上司(のストレス)の重みは大きい。