はじめに
本記事はライブラリを一切使わず、ニューラルネットワークを組む方法について数学的な説明と共に解説する記事となっています。説明はC言語で書きますが、他言語を使う人でも参考になると思います。
ニューラルネットワークをNNと略している部分があります。
第一回目のテーマは「ニューラルネットワークを理解したい!」です。それでは本編どうぞ。
NNを「神経のシミュレーション」と考えない!
ニューラルネットワークと調べると、よくこんな説明を目にします。
ニューラルネットワークは神経のシナプスを模した物です。一つ一つのシナプスは受け取った幾つかの入力の総和を、活性化関数を介して出力します。
こういう感じの説明を見ると「なるほど、ニューラルネットワークは神経のシミュレーションをしているんだ」というようなイメージを持ってしまいがちです。しかしそれは間違い、とは言えませんが理解しづらくなってしまうと僕は考えます。
ニューラルネットワークを数学的に理解したいなら、「ニューラルネットワークはパラメータを調節可能な関数である」と捉える方がいいと思うのです。
パラメータ調整可能な関数↓
$$
Output=f(Input, Parameter)
$$
その一例。ここでは入力と出力が共に単一の数字↓
$$
f(x, P)=P_0 \times x + P_1
$$
ただの一次関数$y=ax+b$、これも立派な「パラメータを調節可能な関数」ですよね。
損失関数
ニューラルネットワークの中でも所謂「教師あり学習」をさせる時は「入力値」と「正しい出力値」が分かっています。これを先ほどの一次関数$f(x, P)=P_0 \times x + P_1$を例にとって説明します。
例えば入力xとその時の出力yが次のように与えられているとしましょう。
x(input) | 0 | 1 | 2 |
---|---|---|---|
y(output) | -2 | 1 | 4 |
さて、ここからどうやっていいパラメータを知りましょうか。
あ、連立方程式を解いたりするのは無しで。
「それなら、取りあえず適当な数字を当てはめてみたら?」
横暴に聞こえますが、実はNNもこういう事をしています。NNはランダムなパラメータで初期化します。
例えば$P_0=1 ; P_1=1$と考えてみましょう。そして$x=0$を代入すると$f(x,P)=1$となります。与えられた答えである$y=-2$よりも大きすぎますね。
ここで「○○になってほしいのに、××が出てきた。全然良くない」と言う時の「良くない度合い」を数値化しましょう。今回ですと単一の数字ですので「良くない度合いは$1-(-2)=3$」と言えそうですが、実際には複数のOutputがある場合がほとんどですので、良くない度合いは二乗して合計(平均)する事が多いです。今回ですと9ですかね。
この良くない度合いは損失関数(Loss Function)と言います。また、差を二乗して平均する事を平均二乗誤差(MSE)と言います。「損失関数はMSEを用いました」などと使えます。
損失関数とは出力と答えを比較した時の「良くない度合い」
MSEとは損失関数の一種で、「出力と答えの差の二乗の平均」
パラメータ調節の問題
さて、ここまで「$P_0=1 ; P_1=1$として$x=0$を代入すると$f(x,P)=1$となり、えられた答えである$y=-2$よりも大き過ぎる。この時の損失(MSE)は9」という話をしてきました。次はパラメータの調節方法についての話です。
さて、この損失を減らすにはどうすればいいでしょうか? どうすれば$f(0,P)$を-2に近づける事が出来るでしょうか?
「パラメータが大きすぎたのでは? $P_0$と$P_1$の値を減らしてみたら?」
と考えてしまってはいけません。例えば$P_0$の値を減らして$0$や$-1$にしたとしましょう。$f(x)$の値はどうなりますか? そうです、変わらないですよね。
このように「パラメータの中には損失に影響しない物がある」のです。
パラメータの中には損失に(あまり)影響しない物もある
ではどうやって「このパラメータは関係しない」「このパラメータを増やせばいい」「このパラメータは減らせばいい」などを判断すればいいのでしょうか? それを次の項で考えます。
視点を変える
ここまで「ニューラルネットワークはパラメータを調節可能な関数である」と話してきました。ただ、ちょっとだけ、ちょっとだけ視点を変えさせてください。
先ほどからくどいように「損失(Loss)を減らしたい!」と言っているので、Lossを左辺に持ってきた数式を書いてみました。
$$
Loss=(f(x,P)-y)^2
$$
今、教師データとして「$x=0$の時$y=-2$である」と分かっているので、このようにも書けます。
$$
Loss=(f(0,P)-(-2))^2
$$
これを展開するとこのようになります。
$$
Loss=((P_0 \times 0 + P_1)-(-2))^2=P_1^2+4P_1+4
$$
いかがでしょうか。このようにすると、Lossが$P_1$の関数であり、$P_0$は無関係であると一目で分かるのではないでしょうか?
「で、$P_1$は減らすの? 増やすの? どっちなの?」
まあ今回はパラメータが一つ(多くても二つ)なので、$P_1$の最適値を出せますが、本物のニューラルネットワークを想定して話を進めましょう。つまり、$P_1=1$から増やすか減らすかどっちがいいか皆目見当がつかないとしましょう。
解決法の一つとして「取りあえず0.001だけ増やして(減らして)みる」という方法があります。$P_1=1.001$にすると$Loss=9.006001$となりLossが増えてしまいました。という事で減らすのが正解みたいです。
とは言え、「0.001だけ増やす(減らす)」って不格好ですよね。もっとスマートな方法はないでしょうか? そう、ここで微分を使います。
微分の復習
微分を忘れている人の為にちょー簡単に説明すると微分した値とは「物凄く小さい値増やす(減らす)とどうなるか」を示す値です。まさに今回知りたい事です。
例えば$P_1$を1から0.001だけ増やすと$Loss$が約0.006増加しましたよね? 0.001の6倍です。$Loss$の増加量(ここでは0.006)を$dLoss$、$P_1$の増加量(ここでは0.001)を$dP_1$と書くと、次のように書くことができます。
$$
\frac{dLoss}{dP_1}=2P_1+4
$$
この$2P_1+4$こそが導関数(微分の式)なのです。
これ以上の事は他の数学の専門サイトにお任せして、今回は以下の事だけ知っておきましょう。
ある入力に対する損失はパラメータの関数として現せる
あるパラメータを増やすか減らすかは微分を使って求める。
第一回目はここまで。第二回「ニューラルネットワークを作りたい! Part1」に続きます。
第二回:ニューラルネットワークを作りたい! Part1
第三回:ニューラルネットワークを作りたい! Part2