このtiny-dnnですが、C++11のテンプレート機能をゴリゴリ使っているためコンパイラがかなり最近のものに限定されます。
- C++ Builder XE3 … 少し古いためC++11が部分対応なのでコンパイル不可
- Visual C++ 2017 … コンパイラのテンプレート展開のバグらしく、不可解なエラーが出てコンパイル不可
- Visual C++ 2015 … 正式に対応が謳われているため問題なし
どんなニューラルネットを作るか?
以下のような単純な4次元の入力データを4つ用意し、それぞれクラス0,1に分類するだけの超簡単なクラス判別NNを作成してみます。
S1 = [1,0,1,0] ; クラス0
S2 = [0,1,0,1] ; クラス0
S3 = [1,1,0,0] ; クラス1
S4 = [0,0,1,1] ; クラス1
入力データが4次元なので入力層は4点、 クラスが2つなので出力層は最低2点あれば良いことになります。
また、一層のパーセプトロンでは線形判別できないので、中間層は32点結合の3層としました。
#define _SCL_SECURE_NO_WARNINGS
#include <tiny_dnn/tiny_dnn.h>
using namespace tiny_dnn;
using namespace tiny_dnn::layers;
void main(int argc,...)
{
//-------------------------------------------------------------
// ニューラルネットの構造を定義
//-------------------------------------------------------------
network<sequential> net;
net << fc(4, 32) << activation::tanh()
<< fc(32, 32) << activation::tanh()
<< fc(32, 32) << activation::tanh()
<< fc(32, 3) << activation::softmax();
//-------------------------------------------------------------
// 学習データ(ベクトルの次元 = 入力層の点数)
//-------------------------------------------------------------
vec_t sample1;
vec_t sample2;
vec_t sample3;
vec_t sample4;
sample1.assign(4, 0);
sample1[0] = 1;
sample1[2] = 1;
sample2.assign(4, 0);
sample2[1] = 1;
sample2[3] = 1;
sample3.assign(4, 0);
sample3[0] = 1;
sample3[1] = 1;
sample4.assign(4, 0);
sample4[2] = 1;
sample4[3] = 1;
std::vector<vec_t > trainData;
std::vector<label_t> trainLabels;
trainData.assign(4, vec_t()); // クラス分類数
trainData[0] = sample1;
trainData[1] = sample2;
trainData[2] = sample3;
trainData[3] = sample4;
// 教師データ
// 学習サンプルがどのクラスに属するかを教示するデータ。
// クラス番号は 0 to 出力層の点数M-1 の範囲。
trainLabels.assign(4, 0);
trainLabels[0] = 0;
trainLabels[1] = 0;
trainLabels[2] = 1;
trainLabels[3] = 1;
//-------------------------------------------------------------
// 学習実行
//-------------------------------------------------------------
adagrad optimizer;
if (!net.train<mse>(optimizer, trainData, trainLabels, 1, 200))
{
printf("train - error");
return;
}
//-------------------------------------------------------------
// 未知データを判定
//-------------------------------------------------------------
for(int i=0;i<trainData.size();++i)
{
printf("predict #%d\n", i+1);
tensor_t result;
std::vector<vec_t> unknownData;
unknownData.assign(1, vec_t());
unknownData[0] = trainData[i]; // 学習に使ったデータを判定してみる
result = net.predict(unknownData);
vec_t vec = result[0];
for (int i = 0; i < vec.size(); ++i)
printf("Class%d : %0.2f\n", i, vec[i]);
printf("\n");
}