ゼロDee --がんばってます
さて。
誤差逆伝播法も理解したいのだが、それ以前に機械学習のもう少し基本的部分を知っておきたい。そもそも、誤差逆伝播法は、関数の勾配を求める手段だ。勾配がわからなければ次に進めないのはわかっているが、まずは基本的な形で最後まで行ってみない。勾配の求め方ばかりやっていてもつまらない、ということだ。
なにより、「エクセルでわかる機械学習 超入門」では、エクセルの機能であるソルバーでやっていたことを、python だとどうなるのかが知りたい。
ということで、勉強だが、「ゼロから作るDeep Learning」を買って、読み解こうと頑張っている。がんばってはいるが、難しい。一度や二度、目を通したぐらいでは、全くわからない。
わからないはずだ。本に載っているコードだけで完結していると思ってた。違う。それなりの分量のコードが、Githubに置いてあった。もっと早く見るべきだった。
しかし、そのコードを見ても、すぐにはわからない。ゆっくりゆっくりだけど、解読中。
誤差逆伝播法
さて、勉強がなかなか進まない。アリさんのケーキ探しのやり方は、誤差逆伝播法だという。なにがどう誤差逆伝播法なのかよくわからない。そもそも誤差逆伝播法とはなんぞや。調べてみると、連鎖率なるものを使うらしい。なんだそりゃ? これを調べると、多変数関数の合成関数の微分だとか。はあ、そんなもの使うんですか。
数十年前、高校生だった時、微分なるものを勉強した覚えがある。微分積分が出てきた段階で数学をあきらめた、というほどではないが、なんせ文系、基本的な事しか習ってない。
連鎖率、合成関数どころか、偏微分も名前しか知らない。しょうがない。50代半ばの手習いだ。
といって、ネットで微分について調べると、偏微分どころか、一変数の微分でも、サインの微分とか、対数の微分とかばっかり出てくる。えええ、これって、微分の中でもかなり高度なやつじゃない?まあいい。対数を微分すると、どうしてこうなるのかはわからなくても、とにかくこうなる、という方向で進んでみよう。
(ところで、誤差逆伝播法は、英語でbackpropというらしい。私は最初見た時、backdropと読んでしまい、以降、しばらくプロレス技ばかり頭に浮かんでいた。違うんですね。)
アリさんのケーキ探し ―― よくわからん
「Excelでわかる機械学習超入門」でのDQN。よくわからん。なんだか、既に正解がわかっているものに、いかに合わせるか、というもののように見えてしまうが、何か違うのだろう。ブツブツ。
しかし、超初心者向けだからVBAを使わない、というのも、どうだろう。シートはかなり複雑な構造になるし、DQNでは配列数式{}なんてものまで出てくる。これって、エクセルではかなり上級ではないだろうか。少なくとも、VBAの入門編より高度な技術のような気がする。どうせソルバーとか、中でなにやってるのかわからない機能をつかうんだから、VBAの初歩を使ってもいいんじゃないだろうか。まるで、中学入試の時に、方程式は中学で習うものだから使っちゃいけません、と言われ、方程式が使えたら簡単なのに、と思いつつ、ツルカメ算とか仕事算とか植木算とかを応用したマニアックとしか言いようのない解法を駆使して解いているみたい、な気がする。
いや、ブツブツいってますけど、この本は私にとってはとてもありがたい、いい本です。
アリさんのケーキ探し―― 大きい版2
拡張してみた。考え方は同じはずなのに、修正すべき個所は意外と多かった。たかがこれだけのコードで、ちょっと変えただけなのに。何度試しても修正し忘れとか、いつの間にか変わっていたりとか、なかなかうまく行かない。
例えばこれ。なんでまた各Q値がマイナスになる?とわけわからずあちこち確認、さらに各ステップの記録をひとつひとつ見ていったが、やっぱり初歩的な、しかし致命的な間違い。D37がなぜか-1になっているのはいいとして、i37が空欄になっている。j37もない。それではダメだ。各状態で、次の部屋の魅力度を示すのがQ値だが、新たなQ値は、現状のQ値を使う。それが無ければ、即時報酬の-1ばかりで新たなQ値を算出することになる。当然だめだ。
このほか、いくつも修正をして、やっと形になったかな、という結果がこれ。一応、最短ルートの一つを出している。
エピソードが50回でこれだが、100回でもあんまり変わらなかった。最初の一歩は、下より右である。でも、下でも同じ回数でケーキに到達できるはずだが。
初期値を変えてみるとどうなるか、試してみよう。
アリさんのケーキ探し -- 大きい版
ちょっと拡張して遊んでみる。
これまでは3X3の世界だったが、4X4ではどうだろうか。
すこし広くなるだけで、計算量は膨大に増えるだろうが、それでも同じ理屈でできるはず。
とりあえず、シートを作ってみた。
どんなことになるかな。
アリさんのケーキ探し ―― コード
作ったコードは以下のようなもの。
3つの部分に分けた。
シートのセルを変数にしたし、繰り返しもfor-nextではなく、while-Loopにしたので、ほとんどDimは使わなかった。
この方がすっきりしている。
Sub step1() Dim Gran, Gran2 Range("b17") = Range("b20") Range("b18") = Range("b21") Gran = Rnd() Range("d6") = Gran ' Greedy で行くか、冒険で行くか、その結果、どの方向に行くかを決める ' 行く方向はf6に表示 If Gran >= Range("b13") Then Range("f6") = "Greedy" Range("b14") = Range("c12").Offset(Range("b16"), 6) Else Range("f6") = "冒険" ' 現在の状態で、移動可能な方向の数 Range("g6") = Range("q1").Offset(Range("b16"), 4) ' 乱数を使い、何番目の方向に行くかを決定 Range("h5") = Rnd() Range("h6") = Int(Range("h5") * Range("g6") + 1) Range("b14") = Range("q1").Offset(Range("b16"), Range("h6")) End If ' 行く方向によって、次状態の行、列を更新 If Range("b14") = 1 Then Range("b21") = Range("b18") + 1 ElseIf Range("b14") = 2 Then Range("b20") = Range("b17") - 1 ElseIf Range("b14") = 3 Then Range("b21") = Range("b18") - 1 ElseIf Range("b14") = 4 Then Range("b20") = Range("b17") + 1 End If ' 行った方向によってQ値を修正 ' 次の状態の報酬 Range("k13") = Range("f1").Offset(Range("b20"), Range("b21")) ' 次の状態の魅力度(割引、学習前) Range("k15") = Range("b9") * Range("c12").Offset(Range("b19"), 5) + Range("k13") ' 現状態のQ値 Range("k17") = Range("c12").Offset(Range("b16"), Range("b14")) ' 現状態から次状態への新Q 値 Range("k19") = Range("k17") + Range("b10") * (Range("k15") - Range("k17")) ' 新Q値をQ値表へ Range("c12").Offset(Range("b16"), Range("b14")) = Range("k19") Range("a12:k21").Copy Cells(Range("e8"), Range("e10")) Range("e10") = Range("e10") + 14 End Sub Sub episode1() Range("l2:o10").Copy Range("d13:g21") Range("b15") = 1 Range("b20") = 1 Range("b21") = 1 Range("e10") = 14 Do While Range("b15") < 25 step1 If Range("b19") = 9 Then Range("a12:k21").Copy Cells(Range("e8"), 1) Range("d13:g21").Copy Range("l2:o10") Exit Do End If Range("b15") = Range("b15") + 1 Loop End Sub Sub ant() Range("e8") = 24 Range("b13") = 1 Range("b12") = 1 Do While Range("b12") < 51 episode1 Range("e10") = Range("e10") + 1 Range("b13") = Range("b13") - 0.02 Range("e8") = Range("e8") + 12 Range("b12") = Range("b12") + 1 Loop End Sub
初期のQ値は乱数で置いたけど、これを別の乱数にしてもほぼ同じ結果が得られた。次に進む前に、もう少し遊んでみたい。