アプリでまなぶNN：正則化をテンソルフロープレイグラウンドで試してみた

# プレイグラウンド入門

ニューラルネットワークの学習は初めて学ぶ人にとってはハードルがかなり高いばかりではなく、進歩のスピードもけた違いなのでひたすら圧倒されて終わってしまいます。本を開いても、ネットを検索しても難しい専門用語で満ち溢れています。かつ、プログラミングの経験のないものにとってはなおさらです。ニューラルネットワークを少し理解し始めて自分の考えや理解を試してみたくてもプログラムができなければ、どうすることもできません。これはIT以外の専門家が自分の専門分野の問題をニューラルネットワークで試してみたいなどというときにも起こります。そんなときに初学者が自分の理解を簡単に試せるアプリがあります。それがテンソルフロープレイグラウンドです。すでにたくさんの解説がネット上で公開されています。

[TensorFlow Playgroundの仕組み](https://hinaser.github.io/Machine-Learning/index.html)

[誰でもわかるニューラルネットワーク：テンソルフロープレイグラウンド ](https://qiita.com/innovation1005/items/e269d8bac3032e34fd15)

などがあります。


まず、[テンソルフロープレイグラウンド](https://playground.tensorflow.org/)をクリックするとA Neural Network Playgroundが立ち上がります。

![playground.jpg](https://qiita-image-store.s3.amazonaws.com/0/267055/f5b822c3-9af5-5c42-5e72-ce6c9bae751c.jpeg)


左端の４つのボックスから出力の画像を選びます。今回は正規分布といわれる青の点が第一象限に赤の点が第三象限にあるものを選びます。

![data3.jpg](https://qiita-image-store.s3.amazonaws.com/0/267055/5d615467-ae89-bc9e-dcee-642bc8bc1286.jpeg)

この赤と青を分離するためには単純パーセプトロンで十分です。単純パーセプトロンは一般には入力が２つで隠れ層の数が１つ、ユニットの数も１つです。したがって入力には

![features.jpg](https://qiita-image-store.s3.amazonaws.com/0/267055/fa976005-f245-9668-3c5a-ade84a9abd7c.jpeg)

の中から$X_1$と$X_2$を選びます。そうしてつぎのようなニューラルネットワークを作ります。

![s_perceptron.png](https://qiita-image-store.s3.amazonaws.com/0/267055/364dfa2d-d6e6-07ce-95a9-9b119014f8e4.png)

実行ボタンを押して少し経つと画面が動いて、2つの赤と青の点が分離されます。
![classification6.jpg](https://qiita-image-store.s3.amazonaws.com/0/267055/cb9bcff3-9808-0113-c42e-d8536c6ced11.jpeg)

カーソルをニューロンを結ぶ線の上に持って行ってみてください。重みが現れます。ニューロンの左下の黒いボッチに持って行ってみてください。バイアスが現れます。これらの重みとバイアスは青と赤の点を分離する境界線を表現します。式で表してみましょう。
![perceptron110.jpg](https://qiita-image-store.s3.amazonaws.com/0/267055/5a49531c-a8d4-645a-b1c0-cc7dfc873916.jpeg)

# 正則化を試す

ディープラーニングでは層を増やしたり、ユニットの数を増やしたりして、複雑なパターンに対応できるモデルを構築します。そのために、自由度が高くなりすぎて、過学習が起きやすくなります。したがって、この過学習を抑制する技術が必要です。

過学習に陥る原因として

- パラメータの数が多すぎる
- 訓練データの数が十分ではない
- データにノイズが含まれている

の3つが主に考えられます。これらの過学習を抑える方法として正則化という方法が考えられています。これはある特定の重みが大きくなることで起きてしまう過学習を防ごうという考え方です。重みの最適化では損失関数の値を最小にします。そこで、重みが大きくなりすぎることを避けるために、損失関数の中に重みの関数を加えて、重みが大きくなることを防ぐのです。その方法には２つあり、

## L1正則化：

ペナルティーとして損失関数に

$\sum ||w_i||$
 
を加える。
## L2正則化(荷重減衰)：

ペナルティーとして損失関数に

 $\sum ||w_i||^2$

を加える。



つぎに入力にすべての入力データを選択し、隠れ層もニューロンもめいっぱい増やしましょう。
![L1_0.png](https://qiita-image-store.s3.amazonaws.com/0/267055/6b23f84f-b181-7e8b-7246-6548188ff72d.png)

これを実行するととりあえずはうまく分離ができますが、すこしひん曲がってしまいます。
![L1_3.jpg](https://qiita-image-store.s3.amazonaws.com/0/267055/5454b2a0-dcef-7cd8-3376-2ad0ebb5e854.jpeg)
どうでしょうか？これにもっとノイズを加えてください。分離はぐちゃぐちゃになってしまいます。それぞれのニューロンとニューロンをつなぐ線を見てみるとばらばらに配分されていることが分かります。

そこで活躍するのが正則化の技術です。まずはRegularizationをL1に変更し、rateを0.03にします。結果は以下の通りです。
![L1.jpg](https://qiita-image-store.s3.amazonaws.com/0/267055/7b692774-8a96-cd45-eacb-3288dc1aeedc.jpeg)
なんと入力のデータが$X_1$と$X_2$に限定されました。そして隠れそうですが、ニューロンの数が１つに限定され、ボックスのなかの模様を見るとどれも同じような直線になっているので、機能を限定しているのが分かります。

つぎにL2正則化を使ってみましょう。RegularizationをL2に変更し、rateを同じく0.03に設定します。
![L2.png](https://qiita-image-store.s3.amazonaws.com/0/267055/b3cfa8ce-1283-91ec-5b77-41d887c86ac2.png)

L1ほどではないにしても効果はありそうです。それぞれのニューロンを結ぶ線とボックスの中の模様を見てみてください。L1正則化とは全く違う形で機能しているのが分かります。

一般にL1正則化は重要なものを選択する機能があって、L2正則化は均等に配分する性質があることが分かります。同じ正則化でも用途によって使い分けをしないと、うまく機能しないことがこんな簡単なテストからわかります。

# 熱ゆらぎと量子ゆらぎ


ニューラルネットワークの重みを更新する際にノイズを加える方法があります。焼きなまし法と呼ばれます。この方法は勾配法に熱ゆらぎを加えていることになります。また、正則化はこの点からするの量子ゆらぎを加えていることになります。[量子コンピュータが人工知能を加速する。参照](http://www.kurims.kyoto-u.ac.jp/~kyodo/kokyuroku/contents/pdf/2059-02.pdf)


参考：

「脳・心・人工知能 数理で脳を解き明かす」(ブルーバックス)
[「圧縮センシングにもとづくスパースモデリングへのアプローチ」](http://mns.k.u-tokyo.ac.jp/~sparse2017/pdf/7.pdf)