Deep Learning 4.2 ステップ関数

4.2.1 ステップ関数の実装

ステップ関数は、次式で表される。

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

単純に実装すれば、

となるが、xにNumPy配列を使用したいため、下記に変更する。

y = x > 0は見慣れないコードかもしれないが,
xが0より大きいならば真(TRUE)を
xが0より小さいならば偽(FALSE)を返す論理式である。
返った真偽値をyに代入する。

astype()関数は()内の型に型変換(キャスト)する。
int型は整数型なので
y = x > 0の結果が、つまりyの値が
TRUEならば1にFALSEならば0に変換される。

実装を下図に示す。

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企業がヤバイのは、ハッキングやウィルス、情報漏洩に加え、こういう問題に神経を削らなければいけないからである。