俵言スマートフォン用の表示で見る俵言しがない社会人が書く、勉強とかのこと。第2回:3章(その1)パーセプトロンとニューラルネットワークの違いはじめに第1回を上げてから四日ぐらいで早くも第2回を上げられるのを嬉しく思います。3章を分割することに決めたから早く上げれたってだけなのですが..やっぱり「ある程度まとまった量で上げたい」とか考えるとズルズルとずれていって結局闇に飲まれていくと思うんですよね(下書きで残っている記事たちを見つつ..)。章を一気にとかじゃなくてある程度切りのいい所で記事を書く形にしようと思います。Learning」を勉強していきます。ニューラルネットワーク2章にはパーセプトロンのことが載っていましたが、3章はニューラルネットワークのお話です。個人的には「パーセプトロンの方が単純らしい」ぐらいの印象を持ってたんですが、よくよく考えると両者がどう違うのかは知りませんでした。(広義にはパーセプトロンもニューラルネットワークに含まれそうですが。)この章ではその話が出てきます。3章は「まとめ」を合わせて7節あるのですが、大体以下のような流れです。実装したニューラルネットワークを試してみるというわけで、今回はその1の活性化関数のお話です。大げさに言えば「遂に明らかになる、パーセプトロンとニューラルネットワークの違い!」って感じでしょうか。因みに前回の終わりで言っていた様に、3章ではNN(※めんどくさいので以降略記します)の学習方法の話が出てきません。3章でNNの動作の仕方を学んだ後、4章で学習方法を学ぶとのことです。(その1)パーセプトロンとNNの違い2章ではパーセプトロンの層を増やすと表現力が増していくことを述べた。そのためには、人間が適切な重みを選ばなければならなかった...。NNはこの問題を解決できる。データから適切な重みを学習できるという重要な性質を持っているのだ..みたいなこと(※表現はこの通りではありません)が3章の冒頭に書かれているのですが、3章では学習の話が出てきません。この章では、パーセプトロンとNNの大きな違いとして活性化関数について述べられています。これがどうやら学習に関わってくるらしいのですが、それは4章までのお楽しみみたいですね。活性化関数とは?ここまで何度も名前だけ出てきた活性化関数ですが、入力の(重みつき)総和を出力に変換する関数のことを言うそうです。wikipediaさん曰く伝達関数とも呼ばれるとか。入力信号に対してニューロンがどう活性化するか(発火する)かの度合いを表す関数ともいえます。なる)か決めていました。この機能を式で書くと、となります。パーセプトロンの活性化関数です。ちなみにこの関数は、閾値(ここでは0)で出力が切り替わることからステップ関数とか階段関数と呼ばれます。これを用いると、一番最初の式がと簡単に書けます。置けば、と更にシンプルになります。(「何でわざわざ置いたの?」って話ですが、詳しくは次回で。)パーセプトロンとNNの違いは何なのか活性化関数を説明したところで、本題であるパーセプトロンとNNの違いの話に入ります。実のところ、両者の大きな違いは活性化関数の違いだけだそうです。意外だったのですが、つまるところノード(ニューロン)のつながり方や入力信号の伝わり方にほとんど違いはなくて、入力に対してどう出力(発火)するかだけが違いらしい。非常にシンプルですね。いうわけで、この後は両者の違いをもたらしている活性化関数の違いを見ていきます。うん、これだけ見てもよくわかりません。いうわけで実際に実装してプロットしてみます。ステップ関数、シグモイド関数の実装は以下の通りです。ベクトル(numpy.ndarrayで表現)だということ。スカラー値の様に思えます。いやーpython最高ですね!本でもこの点を強調していました。ちなみに、>や+などの二項演算子、よく使うexpやsqrt,logなどの関数はnumpy.ndarrayに対して定義されているため、上の実装のようにかなり直感的に使うことができます。「自作のややこしい関数を各要素に対して適用したい!」なんてときはどうするんでしょうか..?この疑問は一旦置いておいて、とりあえずプロットをします。保存fig.savefig("step_sigmoid.png")これでもいいんですが、違いを際立たせるために重ねて図示してみます。保存fig.savefig("step_sigmoid_overwrap.png")ぱっと見ると、「ステップ関数をとても滑らかにしたものがシグモイド関数」みたいな印象を受けます。実際両者の大きな違いは、ステップ関数は連続関数でない(閾値を境に0から1に変化)がシグモイド関数は連続に変化するところです。これが学習に大きく関わってくるらしい..。逆関数でも作るんですかね?まあ4章を楽しみにしておきましょう。連続性が大きな違いの両者ですが、見た目からもわかるように結構似ています。共通点としてどちらも入力が小さければ値が0に、大きければ値が1になるステップ関数(繋がっていない折れ線)もシグモイド関数(曲線)も非線形な関数であるが上げられます。この非線形性がめっちゃ重要だってことが本の中で語られてます。非線形性の重要性なぜ活性化関数が非線形なことが重要なのか?それは、もし活性化関数が線形関数だった場合、NNを多層にする意味が無くなってしまうからです。例として、仮に活性化関数がのような線形関数であった場合を考えます。問題を単純にするために一層あたりのノードを一つとして層を三つ通ったときを考えると、出力は活性化関数を三回重ねがけしたとなります。とおくとと書けてしまう。三回重ねがけしても関数の形が一回の場合とまったく同じなので、多層にする(隠れ層を用意する)意味が無くなっちゃうんですね。)を変えちゃえば一層で表現できるってことですし。これにはなるほどなあーと思いました。この記事でもっとも大事なとこ上げろって言われたら間違いなくここだと思います。ReLU関数この章では、NNでよく使う活性化関数はシグモイド関数だという話が出ました。シグモイド関数は古くからNNで用いられてきたそうです。Unit)関数(日本語で正規化線形関数)がよく用いられるそうです。そのまま返す関数です。こいつが使われる理由も多分後々語られる..はず..。ステップ関数、シグモイド関数、ReLU関数を図示してみましょう。各要素に対して作用しています。三者をプロットしましょう。図を保存fig.savefig("step_sigmoid_ReLU.png")思ったより見にくくなってしまった..。わかるのは、ReLUだけ値がどんどん大きくなるってことですね。これが多分よい効果をもたらすから使われていると思いますが、それについてはどこかで説明があるでしょう。今回のまとめこんなところで3章(その1)は終了です。活性化関数が非線形だからこそ、NNを多層にする意味があるといったところ。途中でも言いましたが、最後の話はいわれたらわかる話ですけどとっても重要だと思ってます。次回は多層NNを実際に実装してみるお話です。python(numpy)の便利さが遺憾なく発揮される回になると思います。コードの占める量も増えそう笑いつになるかはわかりませんが、ペース落としたくないので出来るだけ今週中に上げるつもりで頑張ろうと思います。おまけステップ関数とかの実装のときに「自作の関数をベクトルの各要素に適用したいときにどうすればいいの?」って話をしたんですが、調べたらやっぱり同じ要望を持つ人はいるみたいです。stackoverflow.comこの記事の中では「結局順番に関数適用するしかないけど、どの方法が一番コスト(時間など)が低いのか」って話してました。方法としては単純にfor文でnumpy.ndarrayから要素を順番に取り出して関数適用numpy.fromiterを用いるnumpy.factorizedを用いるの3つが上げられていました。「データ量によって効率性が違う」とか「この方法が一番いい」とか意見がいくつかあって、結局どれ使っていいのかはいまいちわかんないですが。それと、if-elseを組み込まないといけない関数はnumpy.whereを使うとよいとの話がありました。yこのように書けます。関数をモジュール化して見やすくしたいならfromiterのようなものを使うのはありですね、関数が複雑すぎる場合は特に。whereもかなり便利だと思います。今回は一次元の配列(ベクトル)に対して関数を適用することを考えたんですが、行列も似たような要望があると思います。そのうち調べようかな。俵言は、Amazon.co.jpを宣伝しリンクすることによってサイトが紹介料を獲得できる手段を提供することを目的に設定されたアフィリエイト宣伝プログラムである、Amazonアソシエイト・プログラムの参加者です。はてなブログをはじめよう!Tawaraさんは、はてなブログを使っています。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。