octaveで深層学習 (2)
『コンピュータが小説を書く日』(日本経済新聞出版社)なんて本を読んだ。
名古屋大学の 作家ですのよグループ が、コンピュータに小説を書かせたと話題になったののまとめ本。
コンピュータが小説を書く日で、 試せるみたい。Ruby語で書いたとか。日本語には日本で開発された言語が良く合う。 外国製のPythonじゃ、やりにくくてかなわんだろう。
ここに出て来る数列。フィボナッチと素数列は、すぐに分かったけど、もう一つは ハーシャッド数と言うものらしい。こういうのなら無限に続くから コンピュータは飽きずに計算するよな。そこはかとなく、高尚。
日経が主催してる、星新一賞に応募したショートストーリーが、同本にも袋とじで 掲載されてて、ドキドキしたぞ。思わず昔の アムネスラムちゃんを思い出しちゃったのは おじさんの秘密だ。
そういう人は、こちらも見ておけ。 官能小説自動生成ソフト七度文庫
移植
前回は、Neural Network for Character Recognitionをやる、jh1505.m を試してみて、 最後は、グラフ書きの部分を追い出してみた。GUIが嫌いなんでAVは必要無いって寸法。
身軽になった所で、昨年の暮にnodeで試した血圧データから、それが朝測ったものか 寝る前に測ったものかを当てるやつを、Octaveに移植してみる。
移植と言っても、入力部分を変更するだけと高を括っていたら、確率50%でしか当たらない ものが出来てしまったぞ。
でもエラーデータを見ると1つおきになっている。例によって考えるのを拒否してる 症状が出てる。この人工知能って、こういう事には向かない設計になってるの? いまいち、心臓部を理解していないので、こんな不安が頭をもたげてくる。
octave> [0] Training error=20.402071, Test error=15.301816 [100] Training error=20.011006, Test error=15.008254 [200] Training error=20.004843, Test error=15.003632 [300] Training error=20.010957, Test error=15.008213 [400] Training error=20.001726, Test error=15.001295 Error in Train:1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 Error/TRAINED = 20/40 = 0.500 Error in Test:1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 Error/TEST = 15/30 = 0.500 Elapsed time is 3.01444 seconds.
で、元になった画像を扱うやつは、白黒の諧調を0.0から1.0の間の数値で表していたな。 それに対して、オイラーの移植したのは、血圧や脈拍をそのままの形で与えていた。
これが原因で、脳味噌が沸騰と言うか飽和してるんじゃなかろうか。どんなに血圧が高くても 低くても、1.0-0.0の間に入るように正規化しちゃえ。これで、どうだ。
どうやら動き出したようだ。
octave> [0] Training error=20.222105, Test error=15.157384 [100] Training error=7.920089, Test error=5.110528 [200] Training error=7.495912, Test error=4.642662 [300] Training error=6.807975, Test error=3.932901 [400] Training error=6.258664, Test error=3.367179 Error in Train:2 13 22 26 Error/TRAINED = 4/40 = 0.100 Error in Test:24 30 Error/TEST = 2/30 = 0.067 Elapsed time is 3.20837 seconds.
下記は、移植の主要部分。土台で定義されてた順番を都合で一部移動させてる。 エンジンや判定と言った主要部分は、そのまま流用。
### bld for octave tic(); clear; close all; %%%%%%%%%%%%%% Neural Network %%%%%%%%%%%%%%%%%%% M=3; %%%%% Input units H=6; %%%%% Hidden units >=4 N=2; %%%%% Output units CYCLE=500; %%%%% Training Cycle A=csvread('old.csv'); ## Training data n=size(A,1); B=csvread('2016.csv'); ## Test data ntest=size(B,1); %%%%%%%%%%%%%% input, hidden, output %%%%%%%%%%%%%% x=zeros(M,1); h=zeros(H,1); o=zeros(N,1); xdata=zeros(M,n); %%%%%% data ydata=zeros(N,n); %%%%%% exp xtest=zeros(M,n); ytest=zeros(N,n); #### convert data between 1-0 #### function out = b10(in) n = size(in,2); out = zeros(3,n); ct = zeros(3,2); ##keyboard() for c = 1:3 ct(c,1) = min(in(:,c)); ct(c,2) = range(in(:,c)); end for c = 1:3 for i = 1:n out(c,i) = (in(c,i) - ct(c,1)) / ct(c,2); end end end %%%%%%%%%%%%%%%%%%%% Training Data xdata=A'; xdata=b10(xdata(2:4, :)); for i=1:1:n if(mod(A(i,1), 100) < 12) ydata(:,i)=[1;0]; ## at wakeup else ydata(:,i)=[0;1]; ## at night end end %%%%%%%%%%%%%%%%%%%%%%% Test data xtest=B'; xtest=b10(xtest(2:4, :)); for i=1:1:ntest if(mod(B(i,1), 100) < 12) ytest(:,i)=[1;0]; else ytest(:,i)=[0;1]; end end %%%%%%%%%%%%%%%%% RIDGE and LASSO %%%%%%%%%%%%%%%%%%% :
続いて本番データでやってみる。教師データを1000個、テストデータを500個に設定。
何の補正も無し。
octave> [0] Training error=462.912541, Test error=285.215340 [100] Training error=108.920808, Test error=40.341075 [200] Training error=109.708743, Test error=39.300573 [300] Training error=109.451957, Test error=39.143646 [400] Training error=109.086866, Test error=39.282390 Error in Train: Error/TRAINED = 74/1000 = 0.074 Error in Test: Error/TEST = 25/500 = 0.050 Elapsed time is 77.1049 seconds.
RIDGE on
octave> [0] Training error=486.197784, Test error=296.680964 [100] Training error=149.785996, Test error=46.885967 [200] Training error=145.230917, Test error=49.001500 [300] Training error=145.363530, Test error=52.175482 [400] Training error=148.101795, Test error=55.858411 Error in Train: Error/TRAINED = 89/1000 = 0.089 Error in Test: Error/TEST = 22/500 = 0.044 Elapsed time is 77.3616 seconds.
LASSO on
octave> [0] Training error=485.570889, Test error=295.654301 [100] Training error=108.716006, Test error=43.215841 [200] Training error=109.147088, Test error=42.974224 [300] Training error=109.569210, Test error=43.690219 [400] Training error=110.002439, Test error=44.398060 Error in Train: Error/TRAINED = 75/1000 = 0.075 Error in Test: Error/TEST = 28/500 = 0.056 Elapsed time is 82.6531 seconds.
教師データに使った、最高血圧の統計データ。octaveって簡易なRみたい。
octave> statistics( A(:, 2) ) ans = 89.00000 108.00000 116.00000 123.00000 137.00000 115.35500 9.75562 -0.14837 2.36525
Backpropagation Learning
今回のコードの肝は、Backpropagation Learningに尽きる。これが分からないと 理解した事にならない。
幸いな事に、 高卒でもわかる機械学習 (5) 誤差逆伝播法 その1 とか 高校生でも分かるように誤差逆伝播法を解説してみる が公開されているので、じっくりと読んでおこう。
octave> dbstop('bld.m', 113) ans = 115 octave> bld stopped in /home/sakae/bld/bld.m at line 115 115: if(mod(cycle,MODCYC)==0) debug> ii ii = 100 debug> delta1 delta1 = 0.13678 -0.13678 debug> delta2 delta2 = 4.0110e-03 4.5696e-03 1.9618e-03 8.6266e-04 -1.2991e-03 5.5217e-04
こんな具合にdebuggerで止めて、その時の変数の値を簡単に確認出来る。けど、こんな 値を見せられた所で、コンピュータは何を考えているか、さっぱり理解出来ないよ。
次は、 ニューラルネットを使ってみようだな。計算重そう。
微分 積分をOctaveで
例のシグモナイド関数をmaximaで記号微分したら、下記のようになった
[sakae@fedora ~]$ maxima Maxima 5.38.0 http://maxima.sourceforge.net using Lisp SBCL 1.3.4-1.fc24 Distributed under the GNU Public License. See the file COPYING. Dedicated to the memory of William Schelter. The function bug_report() provides bug reporting information. (%i1) diff(1/(1+exp(-x)),x); - x %e (%o1) ------------ - x 2 (%e + 1)
上で解説されてたような、巧みな簡約は、ちょっと無理っぽい。
所で、この微分してくれる関数 diffには、もう一つ引数が有って、何回微分するかってのが 指定出来るようになってる。一番使うのは、1回微分する事だろうから、省略時は1が使われる。
この何回ってのを、数学界では気取って、階と言ってる。2階微分とかね。2回と素直に 言えばかわいいのにね。 数学界は、やたら階のつく語句が多いな。思いつく所で、1階微分方程式、階乗、階差数列、高階関数とかね。
数学の、「にかいびぶん」というのは、2回微分、2階微分、のどちらでしょうか? そういう事 なのか。マンションで高階に住む人には高い税金を掛けましょうって、住む世界が違う人達 だから、許されるのだな。
(%i2) diff(x^3,x); 2 (%o2) 3 x (%i3) diff(3*x^2,x); (%o3) 6 x (%i4) diff(x^3,x,2); (%o4) 6 x
本格的にmaximaやるなら、fedoraに入っている、wxmaximaがそれっぽくていいぞ。
思わず隠れlispに触れてしまったけど、octaveに話を戻しましょ。octaveで微分や積分って 出来るの? ちょいと調べてみたぞ。
常微分方程式(Ordinary Differential Equation ODE)の解法とその応用
Octaveで遊ぶ数値解析入門(付録に、微積分が出て来る)
微分の例。1/(1+t^2) を、初期値1で、0から5の範囲で求める。結果は、plot(t,x)として 眺めるのが普通。
t = linspace(0, 5, 51); function dx = f(x,t) dx(1) = 1 / (1 + t^2) ; end x = lsode(@f, 1, t);
数値積分の例。f = 2*x を、0から1まで積分。
octave:11> f = @(x) 2 * x f = @(x) 2 * x octave:12> quad(f, 0, 1) ans = 1
emacs
今まで、widen-window.elってのを使っていて、上下に分割したwindowsでカーソルのある 方が広くなるようにしてた。この間、FreeBSDのパッケージをアップデートしたら、25.1に なり、エラーを出すようになった。原因は今まで有った関数が無くなってしまった為。 全くemacsの開発者は、勝手な事を平気でするので困るぞ。
もう、平凡な関数だけを使って同等機能を実現するしかないな。
;;; split window and resize windows (defun other-window-or-split () (interactive) (if (one-window-p) (progn (split-window-vertically) (shrink-window 9)) (progn (other-window 1) (balance-windows) (enlarge-window 9)))) (global-set-key (kbd "C-z") 'other-window-or-split)
C-z すると、画面が分割されていなかったら2つに分割。今居る画面を狭める。 もう一度、C-zすると、今度は分割されてるので、反対側に移り等分にする。 それから、画面を広げる。これで C-x o という画面間のカーソル移動を忘れても大丈夫。
上でwindowの高さを変えるのに、3種類の関数を使ったけど、whenと(shrink-window-if-larger-than-buffer)一本槍の方が楽かも。
とか言いながらemacsと戯れていたら、こんな衝撃的な記事を見つけたぞ。
桑原、くわばら。
去年のあれから
NetBSDの標準コマンドの処理をgdbでざっくりと把握してみる
逆転ポインタ法によるガーベジコレクションの実装とスタック無し再帰
Rと競馬データで学ぶ統計学 番外編 Rで有馬記念を当てましょう2016
easy_way
教授の書かれた物価高のコードを見ていたら、面白いのを見つけた。
AAA=xlsread('estat2.csv'); [ALL,SHURUI]=size(AAA); MAXMAX=max(max(AAA)); MINMIN=min(min(AAA)); AAA=0.01+0.98*(AAA-MINMIN)/(MAXMAX-MINMIN); %%%%%%%%%%%%%%%%%%%%%%%%%%% 値を [0,1]に正規化 %%%%%%%%%%%%%%%%%% bukkadata=AAA';%%% bukkadata は 118種目×(44年・12月=528)
俄かに理解出来なかったのでhelpしてみた。
For a vector argument, return the maximum value. For a matrix argument, return the maximum value from each column, as a row vector, or over the dimension DIM if defined, in which case Y should be set to the empty matrix (it's ignored otherwise). For two matrices (or a matrix and scalar), return the pair-wise maximum. Thus, max (max (X)) returns the largest element of the matrix X,
対象データが全ての列で物価なんで、上のような方法を取れる。オイラーが書いた 正規化コードで同じ事をやって出来ない事はないけど、列毎(最高血圧、最低血圧、脈拍)に やるのが正解だろう。
疑似コードは下記になるかな。
octave:18> z=zeros(size(AAA)); octave:19> range(AAA) ans = 38 25 22 octave:20> min(AAA) ans = 103 62 53 octave:21> z(:,1) = (AAA(:,1) - 103) / 38; octave:22> z(:,2) = (AAA(:,2) - 62) / 25; z = 0.50000 0.60000 0.00000 0.05263 0.16000 0.00000 0.44737 0.68000 0.00000 :
後、こんな事も出来るとな。実際のコードで使われていた。深層学習用にぴったり。
If called with one input and two output arguments, 'max' also returns the first index of the maximum value(s). Thus, [x, ix] = max ([1, 3, 5, 2, 5]) => x = 5 ix = 3