Learning』のコメントで、パラメータの勾配を求めるのに数値微分の方法が紹介され、ソースコードも載っている。(112ページ〜)とても簡単な2層のニューラルネットワークを作って試そうという訳である。学習に使うデータは、手書き数字のデータとして有名なMNISTデータセットを利用する。print("{0:d}\t{1:f}\t{2:f}\t{3:f}".format(i,te,train_acc,test_acc))この中の勾配の計算の部分の前後で時間を計測し、勾配の計算時間を求める。結果の表示は、1エポック(データ全体を1回学習に使用すると1エポック)毎に表示している。テスト精度になっている。117ページのヒント「鳥の絵」には、数値微分はとても遅いので、数値微分ではなくBackpropagation(誤差逆伝搬法)のプログラムも用意しているので、そちらを使って実験するようにと書かれていた。コード中には、2つの勾配計算方法の呼び出しが併記されていた。―――となると、つい、どのくらいの速度差が出るのか試してみたくなって、やってみた。train_nueralnet.py039.7118620.0987170.098000140.8839880.0987170.098000242.2747810.0987170.098000340.6178680.0987170.098000440.4994710.0987170.098000540.5574890.0987170.098000641.6224600.1123670.113500740.8265190.1164500.118000840.5555520.1123670.113500940.5555570.1123670.113500これを見ると、前半の誤差逆伝搬(高速)版では、1エポックが約1ミリ秒に対し、後半の数値微分(低速)版では40秒程度になっている。約40,000倍速度向上が実現できている。確かに、これは画期的である。誤差逆伝搬法の説明は長くなるので、ここでは行わない。この本では直感的でわかりやすい計算グラフを使って説明している。"Small";という風に三項演算子が使えて便利だった。str'Big'と書くのは面倒だ。説明はこの4行タイプばかりである。実は、これを1行で書くことが可能なのだ。str'Small'もちろん、代入文にせず、式だけでも書ける。'Small''Small'条件式の書式を書くと、次のようになる。〈式f〉この書き方は、使いこなせれば便利なことは多い。以下は、良い子は読まない方が良いと思うが書いておく。実は、これ以外にも1行で書く方法がある。いっても、かなりアレな方法である。['Small','Big'][num>10]'Small'この書式は次のようになっている。条件式がTrueのときに1,Falseのときに0として扱われるので、この書き方が成立する。この書き方でコンパクトになるが、非推奨である。TweetPythonで円周率100万桁の計算をしてきたが、ちょっとだけ誤差がでてしまった。計算の桁数を十分に余裕を持って100万100桁まで計算して100万桁だけ採用すれば、きっと正しい値になるだろう。余分な桁数まで精度をあげることなく、つまり無駄なく計算をしたいものである。いう風にやるのが良いだろうか。各項を項番号nとしたとき、nの式で表した。n=0,1,2,3,....とやって、項が想定していた誤差epsより小さくなるまで足してきた。このやり方は、とても「マズイ」。超高精度計算ではやってはいけない方法だ。これをちょっとだけ説明しておこう。こんな実験をやってみた。lamda関数をつい使ってみたが、lambda関数の説明は今回は省略する。便利なものだということだけ覚えておいてほしい。3.1417658730158724term(n)という関数を作って、初項を計算してみたが、すでに3.14...とかなり円周率に近い値になっている。足し合わせた合計は、ますます円周率に近づくはずである。各項は、どんどん小さくなっていく。今のプログラムは横着をして、どの項数も同じ精度、有効数字で計算しているのだが、総和は3.14....で、足す数は非常に小さい数である。足す数の有効数字が100万桁あっても、足された結果は3.14...としたときの有効桁数100万桁になるから、足す数は有効桁数が100万桁でも、桁合わせして足されるため、実際に足した後に反映される桁は一部である。nが大きくなるにしたがって、実際の有効桁数はどんどん減ってしまう。これが積もっていくと、誤差が何桁にもなってしまう。いうことで、足し方を変えよう。前から足してダメなら、後ろから順番に足してみよう。以下がそのプログラムである。code="">最初に、何項になったらepsより小さくなるかを求めて、そこから初項まで逆順に加えている。これで実行した結果を示す。'56787961303311646283996346460422090106105779458151'今回は、項の計算を2回行っているのだが、全体の計算時間は1回しかやらなかった前回よりも短くなっている。いうところにも、後ろから足した効果が出ている。100万桁の値とちゃんと一致している。この計算、もっと桁数をサボりながら100万桁計算することができるが、それくらいは各自でやってみよう。桁数をどんどん増やしたいなら、はやりPythonでは限界がある。いう場合は、C言語とかで頑張って欲しい。その場合でも、今回使った円周率の次の公式は役立つはずだ。今から40年近く前、8ビットパソコン(マイコン)で1万桁を求めるのが流行ったりしたが、コンピュータの性能はどんどん上昇し、いまや個人でも1兆桁に挑戦できるくらいコンピュータの性能が向上している。いうことで、円周率の話はここで終わりとする。発行688ページ、5400円(本体)オライリー・ジャパンISBN978-4-87311-777-5副題にPythonとあるので、Pythonで行列の計算処理をしっかりやるための本と受け取るのが普通と思うが、本書はそういう本ではない。Pythonプログラミングの本というより、数学書に相当近い。行列といえば、当然NumPyを使い倒すPythonプログラマ養成本と考えてしまうのだが、本書ではNumPyについては書かれていない。数学書といったように、コードは含まれているのだが、それよりも数学、行列をしっかり教える本で、通常の行列計算以外にも、行列はいろりろ使い道があるなどの話題が多い。逆に、普通のPythonの本ではあまり説明の無い内包についてはしつこく出てくる。普通だったら、for文を使って、その後インデントしてという感じになるようなことを、内包を使って、ちょろっとコーディングしてしまおうという方針のようだ。内包というのは、数学の表記と同じなので、とてもなじみやすいと書いてある。いっても、それは数学者にとって、日常的な書き方がそのままPythonにも使えて便利ということで、普通の数学が苦手なプログラマには逆効果かも知れない。本書の課題では、内包を使ってプログラムせよというのが多い。これをやっていると、次第に、def、:(コロン)、字下げなどが無いプログラムを書くようになり、Pythonらしくなくなる。lambda関数も詳しく説明しているかと思ったら、こちらは入っていなかった。内包とlambda関数を使い倒すと面白いと思うのだが。いうことで、本書は、かなり毛色の変わったPythonの本で、線形代数学にプログラミングが付加された本である。準備としてPythonの本を読もうと言う場合は、絶対に他書を読むべし。―――と書いたが、まだ4割くらいしか読んでいない。Tweetせっかく早く収束する円周率の公式を使って計算をはじめたのだが、永久ループに入ってしまったようだ。永久ループから抜ける判断をしているのは、次の個所だけである。breakこれから考えられるのは、この条件式がいつまで経っても成立しないことだ。tは高精度な計算をしているので、たぶん問題ないだろう。限界を決めるのに、10のべき乗を利用しているのだが、もしかしてこれが問題だろうか。それで、こんな実験をしてみた。False10**(-400)は、0.0と等しくなってしまったようだ。abs(t)<0.0:という絶対に成立しないことをしていたようだ。高精度の計算を行うには、もっと微小な値をちゃんと計算し、比較しないといけない。すればよいだろうか?ということで、微小な下限値を、tと同様に、まず式で求め、evalfで桁数を指定して評価するように変更してみた。sigma.evalf(len)epsの値だが、余裕をもって2桁小さくした。これで、1001桁で実行してみた。'18577805321712268066130019278766111959092164201989'大丈夫なようだ。時間計測を含めて、ちょっと100万桁求めてみた。'56787961303311646283996346460422090106105779458151'43364秒かかった。最後の桁が3だけ違った。