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

計算機基礎A - Maxima 入門 (1)

計算機基礎A - Maxima 入門 (2)

本格的に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と戯れていたら、こんな衝撃的な記事を見つけたぞ。

Emacsは衰退しました

桑原、くわばら。

去年のあれから

NetBSDの標準コマンドの処理をgdbでざっくりと把握してみる

Emacsをワンライナーとして使う

逆転ポインタ法によるガーベジコレクションの実装とスタック無し再帰

お気楽 ISLisp プログラミング超入門

PythonデバッグTips

Rと競馬データで学ぶ統計学 番外編 Rで有馬記念を当てましょう2016

投資競馬 Advent Calendar 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