FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

CNTKを使って関数フィッティングに挑戦(CNTKの構造を理解する)

以下のやってみた日記は、機械学習初心者が書いているため、間違っている内容が含まれている可能性があります。 間違いがあれば、ご指摘頂ければうれしいです。

CNTKのリファレンスとして、チュートリアルをたくさんやってきたが、まだCNTKを理解できているとは言い難い。 まだ、自分でネットワークを構成してみろと言われても、出来る気がしない。なかなかCNTKのネットワーク構築は複雑だ。

自分の理解を深めるための演習問題として、「多項式のフィッティング」をCNTKで実装するにはどうしたらいいんだろう、ということを調査した。 ちなみに、TensorFlowで多項式のフィッティングに挑戦したのは以下だ。

msyksphinz.hatenablog.com

そもそも多項式のフィッティングを機械学習で実装するには

大量のデータを読み込ませ、ここから最適なパラメータを抽出し、そのパラメータに適した値を出力できるようになる。これが多項式フィッティングの基本だ。 機械学習の書籍を読んでみると、このアルゴリズムは一般的に「回帰(regression)」と言われる。

深層学習 (機械学習プロフェッショナルシリーズ)

深層学習 (機械学習プロフェッショナルシリーズ)

上記の本には、深層学習の基本として3つの機械学習の問題を示している

  • 回帰(regression) : 出力に連続値を取る関数を対象に、訓練データをよく再現するような関数を定める
  • 二値分類 : 入力の内容に応じて2種類に区別する問題
    • 男女の分類など。CNTKではSimple2dが相当する
  • 多クラス分類 : 入力の内容に応じて有限個のクラスに分類する
    • 文字認識など。CNTKではMNISTが相当する
問題の種別 出力層の活性化関数 誤差関数
回帰 恒等写像 二乗誤差
二値分類 ロジスティック関数
多クラス分類 ソフトマックス関数 交差エントロピー

今回は、回帰に挑戦してみよう。つまり、目的はこうだ。

  • 目的 : 入力データ(x,y値のペア)から、関数の形状を学習する
  • 手段 : 大量の訓練データを利用して、深層ネットのパラメータを最適化する。最後にテストデータを渡して、どの程度近似されたかをチェックする

CNTKでフィッティングを実現するには

これまでのチュートリアルはラベリング(二値分離、多クラス分類)である

ラベリングは、CNTKのチュートリアルでもさんざん出てきた。では、回帰はどのように実現すれば良いのだろう? ラベリングは、入力データに対して、複数の出力ノードが存在し、「どのノードに出力される確率が最も高いか?」を学習し、ネットワーク内のパラメータを調整する。 一方で、回帰は、出力値と理想データが同一になるようにパラメータを調整する。このあたりのディープネットの初心者のためよく分かっていないが、こんな感じだろうか?

f:id:msyksphinz:20160203022737p:plain

まずは訓練データを用意する

こんなデータを100000点ほど用意した。1列目がxで、2列目がyである。

-0.225621 0.523711
-0.380225 0.671129
0.096487 0.203663
0.191154 0.110008
1.097372 -0.590012
...

実際には、以下のような関数から生成したモデルである。

f:id:msyksphinz:20160203023007p:plain

これを学習して、この関数を再現するためのパラメータを作っていこう。

CNTKでRegressionのラベルを用意するためには

Simple2dとMNISTはクラス分類のため、各出力ノードはラベルと一致しているが、回帰はそうではない。ノードの出力はxと同一の浮動小数点で、ラベルのように有限値を取らない。 このため、CNTKのlabelクラスに、Regressionタイプを追加する。

        labels = [
            type=real
            labelType= Regression
            dim = 1        # One label dimension
            start = 1      # Skip two elements
            labelDim = 1   # labels possible
            labelMappingFile = "$DataDir$/mapping.txt"
        ]

一応、ラベルは1個定義しているが、これにあまり意味はない。あくまでラベルは回帰用に定義されている。

CNTK/Configuration Files.md at master · Microsoft/CNTK · GitHub

labelType – [{Category},Regression,None] the type of label

回帰用にSGDのパラメータを用意する

ネットワークのパラメータを、二乗誤差に設定する。

    SimpleNetworkBuilder = [
        # 2 input, 2 50-element hidden, 2 output
        layerSizes = 1:50*2:1
        trainingCriterion = "SquareError"
        evalCriterion = "ErrorPrediction"
        layerTypes = "Sigmoid"
        initValueScale = 1.0
        applyMeanVarNorm = true
        uniformInit = true
        needPrior = true
    ]

ちなみに、

        layerSizes = 1:50*2:1

なので、

  • 1入力
  • 50段2列
  • 1出力

のディープネットだ。しょっぼ!!

作成したCNTK訓練ファイル

#######################################
#  TRAINING CONFIG                    #
#######################################

Simple_Demo_Train = [
    action = "train"

    # Notation xxx:yyy*n:zzz is equivalent to xxx, then yyy repeated n times, then zzz
    # Example: 10:20*3:5 is equivalent to 10:20:20:20:5
    SimpleNetworkBuilder = [
        # 2 input, 2 50-element hidden, 2 output
        layerSizes = 1:50*2:1
        trainingCriterion = "SquareError"
        evalCriterion = "ErrorPrediction"
        layerTypes = "Sigmoid"
        initValueScale = 1.0
        applyMeanVarNorm = true
        uniformInit = true
        needPrior = true
    ]

    SGD = [
            # epochSize = 0 means epochSize is the size of the training set
        epochSize = 0
        minibatchSize = 25
        randomizeRange = 5
        learningRatesPerMB = 0.5:0.2*20:0.1
        momentumPerMB = 0.9
        dropoutRate = 0.0
        maxEpochs = 10
    ]

    # Parameter values for the reader
    reader = [
        type=real
        readerType = "UCIFastReader"
        file = "$DataDir$/input.txt"
        miniBatchMode = "partial"
        verbosity = 1

        features = [
            dim = 1        # two-dimensional input data
            start = 0      # Start with first element on line
        ]

        labels = [
            type=real
            labelType= Regression
            dim = 1        # One label dimension
            start = 1      # Skip two elements
             labelDim = 1   # Two labels possible
            labelMappingFile = "$DataDir$/mapping.txt"
        ]
    ]
]

学習させ、テストする

テストデータとして、1000点のテストデータを作成する。フォーマットは同じで、yの値は本来は必要ないのだが、yの値をもっているとおそらく誤差の計算ができる。

1.563948 -0.699977
-1.720566 1.288805
0.988823 -0.535380
...

テスト用のシナリオは、訓練用のシナリオと殆ど同一である。あとは、出力ノードの値をファイルに出すようにoutputPathを設定する。

Simple_Demo_Output=[
    action = "write"

    # Parameter values for the reader
    reader = [
        readerType = "UCIFastReader"
        file = "$DataDir$/test.txt"
        randomize = "none"

        features = [
            dim = 1
            start = 0
        ]

        labels = [
            type=real
            labelType= Regression
            dim = 1        # One label dimension
            start = 1      # Skip two elements
            labelDim = 0   # Two labels possible
            labelMappingFile = "$DataDir$/mapping.txt"
        ]
    ]

    outputPath = "$OutputDir$/SimpleOutput"    # Dump output as text
]

学習・テスト実行

以下のようにして、cntkを実行する。

$ cntk configFile=Simple.cntk
...
Validating --> B2 = LearnableParameter -> [1 x 1]
Validating --> HLast = Plus(W2*H1[1 x *], B2[1 x 1]) -> [1 x 1 x *]
Validating --> SquareError = SquareError(labels[1 x *], HLast[1 x 1 x *]) -> [1]

9 out of 20 nodes do not share the minibatch layout with the input data.

Post-processing network complete.


Allocating matrices for forward and/or backward propagation.
UCIFastReader: Starting at epoch 0, counting lines to determine record count...
 1000 records found.
starting epoch 0 at record count 0, and file position 0
already there from last epoch
Minibatch[1]: ActualMBSize = 1000
Total Samples Evaluated = 1000
COMPLETED

学習は完了したらしい。../Output/に学習結果のノード値が出力されているので、入力データとペアにして、プロットしてみよう。

学習・テスト結果の確認

../Output/SimpleOutput.ScaledLogLikelihood の内容を入力データと一緒にExcelでプロットしてみよう。

f:id:msyksphinz:20160203024251p:plain

お、形状は似ているね!しかし、オフセットが合っていない。また、結局どのようなパラメータになったのか、検証ができていない。ここらへんはまだ調査をする必要があるな。

過去の記事

msyksphinz.hatenablog.com

msyksphinz.hatenablog.com

msyksphinz.hatenablog.com