以下のやってみた日記は、機械学習初心者が書いているため、間違っている内容が含まれている可能性があります。 間違いがあれば、ご指摘頂ければうれしいです。
CNTKのリファレンスとして、チュートリアルをたくさんやってきたが、まだCNTKを理解できているとは言い難い。 まだ、自分でネットワークを構成してみろと言われても、出来る気がしない。なかなかCNTKのネットワーク構築は複雑だ。
自分の理解を深めるための演習問題として、「多項式のフィッティング」をCNTKで実装するにはどうしたらいいんだろう、ということを調査した。 ちなみに、TensorFlowで多項式のフィッティングに挑戦したのは以下だ。
そもそも多項式のフィッティングを機械学習で実装するには
大量のデータを読み込ませ、ここから最適なパラメータを抽出し、そのパラメータに適した値を出力できるようになる。これが多項式フィッティングの基本だ。 機械学習の書籍を読んでみると、このアルゴリズムは一般的に「回帰(regression)」と言われる。
- 作者: 岡谷貴之
- 出版社/メーカー: 講談社
- 発売日: 2015/04/08
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (7件) を見る
上記の本には、深層学習の基本として3つの機械学習の問題を示している
- 回帰(regression) : 出力に連続値を取る関数を対象に、訓練データをよく再現するような関数を定める
- 二値分類 : 入力の内容に応じて2種類に区別する問題
- 男女の分類など。CNTKではSimple2dが相当する
- 多クラス分類 : 入力の内容に応じて有限個のクラスに分類する
- 文字認識など。CNTKではMNISTが相当する
問題の種別 | 出力層の活性化関数 | 誤差関数 |
---|---|---|
回帰 | 恒等写像 | 二乗誤差 |
二値分類 | ロジスティック関数 | 式 |
多クラス分類 | ソフトマックス関数 | 交差エントロピー式 |
今回は、回帰に挑戦してみよう。つまり、目的はこうだ。
- 目的 : 入力データ(x,y値のペア)から、関数の形状を学習する
- 手段 : 大量の訓練データを利用して、深層ネットのパラメータを最適化する。最後にテストデータを渡して、どの程度近似されたかをチェックする
CNTKでフィッティングを実現するには
これまでのチュートリアルはラベリング(二値分離、多クラス分類)である
ラベリングは、CNTKのチュートリアルでもさんざん出てきた。では、回帰はどのように実現すれば良いのだろう? ラベリングは、入力データに対して、複数の出力ノードが存在し、「どのノードに出力される確率が最も高いか?」を学習し、ネットワーク内のパラメータを調整する。 一方で、回帰は、出力値と理想データが同一になるようにパラメータを調整する。このあたりのディープネットの初心者のためよく分かっていないが、こんな感じだろうか?
まずは訓練データを用意する
こんなデータを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 ...
実際には、以下のような関数から生成したモデルである。
これを学習して、この関数を再現するためのパラメータを作っていこう。
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でプロットしてみよう。
お、形状は似ているね!しかし、オフセットが合っていない。また、結局どのようなパラメータになったのか、検証ができていない。ここらへんはまだ調査をする必要があるな。