以前に、
という記事を書いて、次回はback propagationと勾配降下法について説明しますねって書いてから2年以上経ちました。。

これはめんどくさくなってしまったからですね。。
そもそもニューラルネットワークを自分で実装したのは2020年3月の大学2年生の春休みに時間が余って暇だったからで、その記事を書いた2020年10月には7か月も経ってていろいろ忘れてしまっていたんですよね。

そこで久しぶりに復習をしようということでざっくり思い出して書こうと思います。

ニューラルネットワークは入力層、中間層、出力層の3つがある。
入力層の値に重みという係数をかけて、入力層の数だけそれらを足し合わせて、活性化関数に入れて中間層に入れると。

そしてまた重みかけて足し合わせて活性化関数に入れて出力層として出力すると。

この出力の値が正しい値に近づくように学習させるのが今回のback propagationと勾配降下法です。

自分で実装した時は、教師あり学習として適当な関数を用意して、xを入力してyがその用意した関数とどのくらい誤差があるかを計算して、その後差が小さくなるように重みを調整していきました。

またその後は教師なし学習として、シューティングゲームで敵と味方、弾の座標を入力値として、その座標にQ学習によって得点を付けることでシューティングゲームのAIを作ろうとしました。
めちゃ弱かったのですが、なんか弾を避けようとする意志を感じ取れるくらいには学習させることができたので、ライブラリを使わず自力で実装した結果としてはまあまあだったのではないかと自分では思っています。

あとQ学習とモンテカルロ法で五目並べとオセロのAIを作りました。
全然強くはなりませんでしたが、なんかこう自分で作ったAIが弱い手を打ってても愛着がわいてきて楽しかった記憶があります。

今回は関数近似について少し説明します。

勾配降下法

勾配降下法は関数の傾きから最小値を探す方法です。
出力層の値と近似したい関数のyの値の差を二乗することで二次関数となり、誤差を放物線で表せるようになります。
その誤差の二次関数を誤差関数と言い、その微分を求めて傾きを出し、傾きが0に近いほど誤差が小さいと判断できるわけです。

誤差関数が小さくなるように重みwの値を調整していくのがback propagationです。

誤差逆伝播法(back propagation)

どのように重みの値を調整していくか。
まずは誤差関数を微分して傾きを求めます。
放物線なので、最小値よりもxが大きいところで微分すれば傾きは正になります。
このとき最小値に近づけるにはxを負の方向に動かす、すなわち傾きの符号と逆方向にxを動かせば誤差が小さくなってきます。

そしてこの誤差関数は、入力層とその重み、入力層の活性化関数、中間層とその重みを足してできているため、これらの重みを使って誤差関数を表すことができます。

すなわち、誤差関数を重みで偏微分することで重みの傾きが分かり、その傾きの符号と逆方向に値を調整すればよいことが分かります。

このとき重みをどのくらい調整するか(足し引き)するかを学習率と言います。
この誤差関数を重みで偏微分するのが一番理解するのが難しいところですよね。

でも頑張って紙に書いて計算してください。。
今の自分にはめんどくさくて無理です。
これは活性化関数によって微分の式が異なるため、活性化関数の個数だけ自分で実装して非常にめんどくさかったです。


実は私はニューラルネットワークをkuinというゲームの作成に向いているプログラミング言語で実装したんですが、今はkuinが更新されて、dbg@printとか:$(スワップ演算子)とかが使えなくなったんですよね。
なのでプログラムを修正するのがめんどくさくて昔のkuinをgithubからわざわざダウンロードして今は動かして自分が作ったプログラムがどんな感じだったか見てます。

口で簡単に説明できるくらいには思い出せたと思うのでここにまとめられてよかったです。

活性化関数:sigmoid
活性化関数:ReLU
活性化関数:step

活性化関数が変わると近似の仕方が大きく変わってくるので面白いですよね。