読者です 読者をやめる 読者になる 読者になる

takeda_san’s blog

JavaFXとDeeplearning4jを頑張る方向。

サンプルプログラムをいじろう その1

機械学習 Deeplearning4j Java

前回のあらすじ

多層パーセプトロンプログラムを読んだ。

takeda-san.hatenablog.com

やったこと

今回からサンプルプログラムを少しいじって、何かデータを解析してみる。
どうせやるなら心躍る題材をということで、株価をデータとして扱います。

2015年の株価のデータで学習して2016年のデータで答え合わせをします。
日付を入力して株価(その日の終値)を出力するようなものを想定。

株価のデータは、ここから拝借しました。
何と便利な世の中か。

株価データ・株主優待情報・先物データ・ランキングデータ・CSVダウンロード無料 | 株式投資メモ・株価データベース

早速、csvを読み込んで…と行きたいが、こういうのは、まず小さく動作が確認できる機能を作ってそこから大きくしたほうがよいだろう。
数日分のデータを読んで、数日分の株価を出力するプログラムを書こう。

というわけでデータセットだけを挿げ替えたプログラム。

   public static void main(String[] args) throws Exception
    {
        // 変数定義
        int seed        = 123;          // 乱数シード
        int iterations  = 2000;         // 学習の試行回数
        int inputNum    = 1;            // 入力数
        int middleNum   = 10;           // 隠れ層のニューロン数
        int outputNum   = 1;            // 出力数

        INDArray    tIn     = Nd4j.create( new float[]{ 20150105 ,             // 入力1
                                                          20150106 ,             // 入力2
                                                          20150107 ,             // 入力3
                                                          20150108  },           // 入力4
                                           new int[]{ 4 , 1 } );            // サイズ
        INDArray    tOut    = Nd4j.create( new float[]{ 2512 , 2467 , 2469 , 2502} ,    // 出力1~4
                                           new int[]{ 4 , 1 } );            // サイズ
        DataSet     train   = new DataSet( tIn , tOut );                    // 入出力を対応付けたデータセット
        System.out.println( train );

        // ニューラルネットワークを定義
        MultiLayerConfiguration.Builder builder = new NeuralNetConfiguration.Builder()
                .seed(seed)
                .iterations(iterations)
                .learningRate(0.01)
                .weightInit(WeightInit.SIZE)
                .optimizationAlgo(OptimizationAlgorithm.STOCHASTIC_GRADIENT_DESCENT)
                .updater( Updater.NONE )
                .list()
                .layer(0, new DenseLayer.Builder()
                        .nIn(inputNum)
                        .nOut(middleNum)
                        .activation("sigmoid").build())
                .layer(1, new OutputLayer.Builder( LossFunctions.LossFunction.MSE )
                        .nIn(middleNum)
                        .nOut(outputNum)
                        .activation("sigmoid")
                        .build())
                .backprop(true).pretrain(false);

        // ニューラルネットワークを作成
        MultiLayerConfiguration conf        = builder.build();
        MultiLayerNetwork       perceptron  = new MultiLayerNetwork(conf);
        perceptron.init();

        // 確認用のリスナーを追加
        perceptron.setListeners( new ScoreIterationListener(1) );

        // 学習(fit)
        perceptron.fit( train );

        // パーセプトロンの使用
        for( int i=0 ; i<train.numExamples() ; i++ )
        {
            // i個目のサンプルについて、
            INDArray    input  = train.get(i).getFeatureMatrix();
            INDArray    answer = train.get(i).getLabels();
            INDArray    output = perceptron.output( input , false );
            System.out.println( "result" + i );
            System.out.println( " input  : " + input );
            System.out.println( " output : " + output );
            System.out.println( " answer : " + answer );
            System.out.flush();

        }

    }

動作結果

result0
 input  : 20,150,104.00
 output : 1.00
 answer : 2,512.00
result1
 input  : 20,150,106.00
 output : 1.00
 answer : 2,467.00
result2
 input  : 20,150,108.00
 output : 1.00
 answer : 2,469.00
result3
 input  : 20,150,108.00
 output : 1.00
 answer : 2,502.00

出力すべて1。
なんかそんな気はしてた。
楽して億万長者には、なれないのだ。

検討はまた次回。

次回の予定

・サンプルプログラムをいじる
・courseraの動画を見る
・Deep Learning Javaプログラミングを読む
・プログラミングのための線形代数を読む
Mavenのpomの読み方

多層パーセプトロンプログラムの理解

機械学習 Deeplearning4j Java

前回のあらすじ

パーセプトロンプログラムを最後まで読んだ。

takeda-san.hatenablog.com

やったこと

今回からは多層パーセプトロンプログラムを読んでいく。
courseraの機械学習動画や各種技術書で基礎をじっくりと…
と思っていたが結局プログラムを実際に動かした方が理解が早い。

Java DeepLearning4j 多層パーセプトロンの構築|軽Lab

早速プログラムを見ていく。

        INDArray    tIn     = Nd4j.create( new float[]{ 1 , 1 ,             // 入力1
                                                        1 , 0 ,             // 入力2
                                                        0 , 1 ,             // 入力3
                                                        0 , 0 },            // 入力4
                                           new int[]{ 4 , 2 } );            // サイズ
        INDArray    tOut    = Nd4j.create( new float[]{ 0 , 1 , 1 , 0} ,    // 出力1~4
                                           new int[]{ 4 , 1 } );            // サイズ
        DataSet     train   = new DataSet( tIn , tOut );                    // 入出力を対応付けたデータセット
        System.out.println( train );

このあたりは、パーセプトロンプログラムと同じ。
入力と出力のデータセットを生成している。

        // ニューラルネットワークを定義
        MultiLayerConfiguration.Builder builder = new NeuralNetConfiguration.Builder()
                .seed(seed)
                .iterations(iterations)
                .learningRate(0.01)
                .weightInit(WeightInit.SIZE)
                .optimizationAlgo(OptimizationAlgorithm.STOCHASTIC_GRADIENT_DESCENT)
                .updater( Updater.NONE )
                .list()
                .layer(0, new DenseLayer.Builder()
                        .nIn(inputNum)
                        .nOut(middleNum)
                        .activation("sigmoid").build())
                .layer(1, new OutputLayer.Builder( LossFunctions.LossFunction.MSE )
                        .nIn(middleNum)
                        .nOut(outputNum)
                        .activation("sigmoid")
                        .build())
                .backprop(true).pretrain(false);

次はニューラルネットワークの定義部分。
seed … 乱数生成 iteraions … 繰り返し回数 learningRate … 学習率   までは同じ。
waightInitだが、今回はWeightInit.SIZEが指定されている。

WeightInit.SIZEとは「最小および最大のシェイプを使用して、一定の一様分布からの得るサンプルウェイト」とあるが、シェイプとは?
グラフの形のことを言ってんのかな…?
この辺りはページに書いていることを、そういうもんだということで、とりあえず納得しておこう。

optimizationAlgo … 誤差関数には確率的勾配降下法を使う
updater … なし list … 層の数だが…これ、今回入力層含め3層だから引数に3を入れるべきでは?
と思ったが、手元の技術書のサンプルプログラムから仕様が変わったようだ。
何層でも引数なしが正しい。
layer … 各レイヤの定義。DenseLayerとは前のレイヤーと全接続するレイヤーのこと。
backprop … 誤差逆伝搬の有無を指定する。
pretrain … 事前学習の有無を指定する。

以降、まったく同じなので省略。

いくつかパラメータが変わっているが基本的にパーセプトロンと同じ。
ありがたいことに多層パーセプトロンプログラムの構造まで解説されているので、プログラムも難なく読むことができた。

次回の予定

・courseraの動画を見る
・Deep Learning Javaプログラミングを読む
・不明点の確認(乱数を指定する意味、確率的勾配降下法とは)
・プログラミングのための線形代数を読む
Mavenのpomの読み方

パーセプトロンプログラムの理解 その4

機械学習 Deeplearning4j Java

前回のあらすじ

学習率と重みについて、少し深堀り。

takeda-san.hatenablog.com

やったこと

学習の実行と結果表示部分のプログラムを読む。

        // 確認用のリスナーを追加
        perceptron.setListeners( new ScoreIterationListener(1) );
         
        // 学習(fit)
        perceptron.fit( train );
         
        // パーセプトロンの使用
        for( int i=0 ; i<train.numExamples() ; i++ )
        {
            // i個目のサンプルについて、
            INDArray    input  = train.get(i).getFeatureMatrix();
            INDArray    answer = train.get(i).getLabels();
            INDArray    output = perceptron.output( input , false );
            System.out.println( "result" + i );
            System.out.println( " input  : " + input );
            System.out.println( " output : " + output );
            System.out.println( " answer : " + answer );
            System.out.flush();
             
        }

perceptron.setListeners( new ScoreIterationListener(1) );
リスナを登録して、定期的にログを出力するようにするコード。
setListenersメソッドの引数で指定する。
ScoreIterationListener(1)で学習一回につきログを1回出力するようだ。

perceptron.fit( train );
学習を実行する。

train.numExamples()でデータセット内のサンプル数が取得できる。
INDArray input = train.get(i).getFeatureMatrix();、で入力値を取得できる。
INDArray answer = train.get(i).getLabels();、で入力値につけたラベル(回答)を取得できる。
INDArray output = perceptron.output( input , false );、で学習させたパーセプトロンに入力値を与えて出力を得る。
次の行からは学習データの答えと出力値をコンソール出力して確認している。

ようやく最後まで読み切った。
プログラムの内容自体はJavaDocソースコードをよーーーーく読めば何とか理解できるレベルだが、そもそもの機械学習ディープラーニングの知識が明らかに不足しているので、その寄り道に時間が恐ろしくかかってしまった。
一旦、Deeplearning4jのコードから離れて、基礎知識をかためていこうと思う。

その道の方には有名なこのサイトをとりあえず見ていこうと思う。
最初のほうだけちらっと見たが、これも無料でやってもらって申し訳ないという気持ちになるすばらしいコンテンツだ。
本編のほうは日本語字幕がついていて、感謝の気持ちしかない。

https://www.coursera.org/learn/machine-learning

あとは、挫折していたDeep Learning Javaプログラミングをもう一度読んでいく。
すこし賢くなったので、前よりは読み進められるだろう。

次回の予定

・courseraの動画を見る
・Deep Learning Javaプログラミングを読む
・不明点の確認(乱数を指定する意味、確率的勾配降下法とは)
・プログラミングのための線形代数を読む
Mavenのpomの読み方

学習率、重みってなんだ?

機械学習

前回のあらすじ

ニューラルネットワークの定義、生成部分のコードを読んだ。

takeda-san.hatenablog.com

やったこと

重みってなんだ?

前回のニューラルネットワークの定義の中で重みというパラメータが登場した。
この重みは、以前にやった下記の数式におけるvの値のこと。
重みを適切に調整し、欲しい出力を得る。


\displaystyle f(x) = f( \sum_{i=0}^{N} v_i x_i - \theta )

takeda-san.hatenablog.com

プログラム内に登場したパラメータとしての重みは、各入力に対する重みの初期値を設定しているっぽい。
なぜ初期化が必要かというと、学習の進むスピードが変わるらしい。

kaeken.hatenablog.com

多層パーセプトロンにおいて、学習時の勾配消失が問題になっていたが、そのあたりと関係がありそう・・・?
初期値を設定する意味は分かったし、話がさらに深くなりそうなので、いったんこの辺で打ち切り。

学習率ってなんだ?

これまた、ニューラルネットワークの定義の中で登場した学習率。
この学習率とは、重みのパラメータを学習していく中で更新していくワケですが、その更新の幅を指しているようです。
1より小さくするのが普通らしい。
この値を小さくすればするほど更新幅が小さいから正確に学習できるが、計算回数が多くなる?
幅大きいと学習によるパラメータ調整が行ったり来たりで収束しない?
値を何を基準にすればよいのかは、また別途。

次回の予定

・不明点の確認(乱数を指定する意味、確率的勾配降下法とは) ・プログラミングのための線形代数を読む ・サンプルプログラム(Perceptron/LenetMnistExample)を読む ・Mavenのpomの読み方

パーセプトロンプログラムの理解 その3

機械学習 Deeplearning4j Java

前回のあらすじ

学習データの生成方法部分を読んだ。

takeda-san.hatenablog.com

やったこと

なんとも本丸感がある、このワンライナー。 落ち着いてひとずつ確認していきます。

        // ニューラルネットワークを定義
        MultiLayerConfiguration.Builder builder = new NeuralNetConfiguration.Builder()
                .seed(seed)
                .iterations(iterations)
                .learningRate(0.01)
                .weightInit(WeightInit.XAVIER)
                .optimizationAlgo(OptimizationAlgorithm.STOCHASTIC_GRADIENT_DESCENT)
                .updater( Updater.NONE )
                .list()
                .layer(0, new OutputLayer.Builder( LossFunctions.LossFunction.MSE )
                        .nIn(inputNum)
                        .nOut(outputNum)
                        .activation("sigmoid")
                        .build())
                .backprop(true).pretrain(false);

        // ニューラルネットワークを作成
        MultiLayerConfiguration conf        = builder.build();
        MultiLayerNetwork       perceptron  = new MultiLayerNetwork(conf);
        perceptron.init();

大きな流れとしては以下のようになっているようだ。

  1. NeuralNetConfiguration.Builder()でニューラルネットワークの設定し、buildメソッドで設定オブジェクトを生成
  2. 1.で作った設定を使用してモデルのインスタンスを生成
  3. 2.で作ったモデルを初期化する

MultiLayerConfiguration.Builderは、モデルの全体的な構造を定義するビルダークラス。
NeuralNetConfiguration.Builder()は、ニューラルネットワークのビルダーメソッド。
seed()は、乱数の種を指定するメソッド。
んー、なぜ乱数を生成する必要があるんだろうか…
別途調べよう。

深層学習(ディープラーニング)は自然現象であると考えると捉えやすい - WirelessWire News(ワイヤレスワイヤーニュース)

iterations()は、繰り返し回数を指定するメソッド。今回は1000回学習する。
learningRate()は、学習率を指定するメソッド。今回の学習率は0.01。
学習率とはモデルのパラメータを更新する幅らしい。
これも別途調べる。

weightInit()は、重みを指定するメソッド。
重みとは個々の神経細胞同士の繋がりの強さ(伝達物質の伝導しやすさ)を示す。らしい
これも…別途調べる。

optimizationAlgo()は、学習アルゴリズムを指定するメソッド。
確率的勾配降下法を使用する。
これも…・・・別途調べる。

updater()は、学習率の最適化など学習アルゴリズムの更新に使う。今回はNONEなので特に更新なし。
list()は、ニューラルネットワークの層の数を指定する。今回は1層なので指定なし。
 →入力層は数えない
layer()は、ニューラルネットワークのレイヤーを指定する。
 →活性化関数にシグモイド関数、誤差関数にMSE、入力が2つ、出力1つ(ORなので)
backprop()は、誤差逆伝搬の有無を指定するメソッド。
pretrain()は、事前学習の有無を指定するメソッド。

一通り技術書&JavaDocとにらめっこして調べてましたけど、下記記事に全部乗ってましたね。
ま、まぁ自分で調べることに意味があるから…

Java DeepLearning4j パラメータの設定|軽Lab

次回の予定

・不明点の確認(乱数を指定する意味、学習率とは、重みとは、確率的勾配降下法とは)
・プログラミングのための線形代数を読む
・サンプルプログラム(Perceptron/LenetMnistExample)を読む
Mavenのpomの読み方

パーセプトロンプログラムの理解 その2

機械学習 Deeplearning4j Java

前回のあらすじ

活性化関数として使われる、シグモイド関数
誤差関数として使われるMSEについてそれとなくわかった気になる。

takeda-san.hatenablog.com

やったこと

実際にプログラムを読んでいく。

INDArray    tIn     = Nd4j.create( new float[]{ 1 , 1 ,         // 入力1
                                                        1 , 0 ,         // 入力2
                                                        0 , 1 ,         // 入力3
                                                        0 , 0 },        // 入力4
                                           new int[]{ 4 , 2 } );        // サイズ

INDArrayとは、Deeplearning4jに含まれるND4j内に定義された行列を格納する型。
Nd4jのファクトリクラスで生成されたオブジェクトを格納する。
Nd4j.createメソッドの第一引数にfloatの配列、第二引数にintの配列を渡している。
JavaDocを読むと第一引数は「N次元配列」をメモリに連続して格納するために一つの配列にデータを格納したもの。
第二引数は行列の行, 列をしていするものらしい。
大量にあるテストデータで、いちいち多次元配列を作っていたのではメモリ効率が悪いというのは理解できる。

http://nd4j.org/doc/org/nd4j/linalg/factory/Nd4j.html#create-float:A-int:A-

つまり、ここは4行、2列の行列([[1,1],[1,0],[0,1],[0,0])のデータを作りますということ。

次の出力テストデータの生成も同様に4行1列のデータを作りますということ。

INDArray    tOut    = Nd4j.create( new float[]{ 1 , 1 , 1 , 0} ,
                                           new int[]{ 4 , 1 } );        // サイズ

次の行はコメント通り、入出力をワンセットとして扱うためのデータセットとして入力データ、出力データを格納している。

DataSet     train   = new DataSet( tIn , tOut );         // 入出力を対応付けたデータセット

しかしまぁ、Eclipseデフォルトのフォーマッタだとインデントをせっかくそろえても崩れて悲しい気持ちになる。 ちょっとカスタマイズしようか…

次回の予定

・プログラミングのための線形代数を読む
・サンプルプログラム(Perceptron/LenetMnistExample)を読む
Mavenのpomの読み方

パーセプトロンプログラムの理解 その1

機械学習 Deeplearning4j Java

前回のあらすじ

なぜ4層以上がDeep Learningなのかをふわっと理解。

takeda-san.hatenablog.com

やったこと

パーセプトロンの実装例のプログラムを読む

ここのパーセプトロンの実装プログラム(Perceptron.java)を読んでいきます。

Java DeepLearning4j 基本的な利用方法|軽Lab

入力と出力から見るにOR演算のプログラムらしい。
活性化関数にシグモイド関数を…、ん、「シグモイド関数」ってなんだ。

シグモイド関数

次のような関数をシグモイド関数と呼ぶらしい。


\displaystyle σ(x) = \frac{1}{1 - e ^ -x}

え、高校数学の範囲なの…?

シグモイド関数の意味と簡単な性質 | 高校数学の美しい物語

eってなんだっけ…(自然対数久しぶりに思い出しました)
気をとりなおして…
シグモイド関数とは、任意の実数を0~1にする関数。

誤差関数MSEとは

誤差関数には 
\displaystyle MSE( \sum (t-o) ^ 2 )
を使う…?
MSE(mean square error)は平均二乗誤差を意味するらしい。
平均二乗誤差、昔に勉強したような…

助けてgoogle先生
いくつか、見てみましたがこの説明が一番ピンときました。
そもそも、誤差ってなんだっけからわかりやすく説明されていました。

http://012.o.oo7.jp/2016hyoujyunhensa_heikinjijyougosa.pdf

測定値と真値の差を二乗することで、その測定値の正確さを示す指標を求めるということなのだろうか。
とすると誤差関数としては適当に思える。
まだ、少しもやもやするが、このあたりは別途調べるとしよう。

いろいろと過去の不勉強が一度に襲い掛かってきている。 が、プログラム全体の理解までもう少し。

今後の予定

・プログラミングのための線形代数を読む
・サンプルプログラム(Perceptron/LenetMnistExample)を読む
Mavenのpomの読み方