caffe 識別篇

# caffe 識別篇

## 始めに

+ http://qiita.com/knknkn1162/items/646d28fc9885334ea64d の続きです。

+ 設定は前回大体同じで、今度は、実際に学習させたい少々難しい画像(30*30の正常or欠陥画像)の2クラス判別をcaffe使って、行います。

+ caffe.exeを使ったコマンドベースで識別方法と、pycaffeを用いた識別方法を紹介します。webではどちらか一方しか紹介されていない（ような気がするので、）対応を心がけました。


## 動作環境

Windows 7 64bit + RAM 16GB + Cygwin(cpuモードで)

## ディレクトリ配置

```text
caffe-windows/
　├ data/
　│　　└ mytest/
　│　　   ├ train.txt #学習時のdbの紐づけで使用
　│　　   ├ eval.txt #.識別時に使用(caffe testコマンド => deploy_leveldb作成時に使用, pycaffe(python) => classifier.pyの答え合わせで使用)
　│　　   ├ mean.binaryproto #学習時に作成(平均画像 : compute_image_mean.exeで作成)
　│　　   ├ mytest_train_leveldb/ #学習時に作成(convert_imageset.exeで作成)
　│　　   ├ mytest_deploy_leveldb/ #識別時に作成(caffe testコマンドの時に使用)
　│　　   ├ src/
　│　　 　│　└ 0000001.bmp
　│　 　　│　└ 0000002.bmp
　│　 　　│　└ 0060000.bmp 
　│　 　　│　└ (以下省略。学習用：train data=>50000枚)
　│ 　　　│　
　│　　   ├ check/ (pycaffeで画像識別時に使用)
　│　　　　　└ 0060001.bmp 
　│　　　　　└ 0060002.bmp 
　│　　　　　└ (以下省略。  識別用:eval data => 11871枚作成)
　│
　├ example/
　│　　├ eval.sh #識別時に使用
　│　　├ train.sh #学習時に使用
　│　　└ mytest/
　│　　　　　└ solver.prototxt #学習時に使用
　│　　　　　└ train_test.prototxt #学習時、caffe testコマンド(識別時)に使用
　│　　　　　└ mytest_iter_100000.caffemodel #.学習後に生成される
　│　　　　　└ deploy.prototxt #識別時に使用(pycaffe のnet_path変数 として用意)
　├ Build/
　│　└ x64/
　│　　　└ Release/ #パスを通しておく。
　├ classifier.py (識別時に使用)
```

## 学習

### 学習の準備

+ 画像データ(30px四方)を用意しておく。今回は、テストのため、わかりやすいように、異常物をランダムにくっつけ、人工的に作成。画像を(正常):(異常) = 1:1.1位の割合で用意した。グレー画像。

+ train.txt, answer.txtは前とおんなじように用意。(データ数のみ異なる)

+ solver.prototxtは以下のように記述(100000回最大でイテレーションを回すので、それに合わせて、snapshotとかを大きくしてます)：

```text:solver.prototxt
net: "examples/mytest/lenet/train_test.prototxt"
test_iter: 100
test_interval: 500
base_lr: 0.005 # ここもちょっと変えているかな？
momentum: 0.9
weight_decay: 0.0005
# The learning rate policy
lr_policy: "inv"
gamma: 0.0001
power: 0.75
# Display every 100 iterations
display: 500
# The maximum number of iterations
max_iter: 100000
# snapshot intermediate results
snapshot: 10000
snapshot_prefix: "examples/mytest/lenet/mytest"
# solver mode: CPU or GPU
solver_mode: CPU
```

+ train_test.prototxtは以下のように記述[^train-test] (学習時、識別時ともにこのファイルを使用します。)：

[^train-test]: 前とほとんど変わっていないです。バッチサイズのみ変更しています。


```ruby:train_test.prototxt
name: "LeNet"
layer {
  name: "data"
  type: "Data"
  top: "data"
  top: "label"
  include {
    phase: TRAIN
  }
  transform_param {
    scale: 0.00390625 #raw_scale is 255, so, 1/255 scaling
	mean_file: "data/mean.binaryproto"
  }
  data_param {
    source: "data/mytest_train_leveldb"
    batch_size: 100
    backend: LEVELDB
  }
}
layer {
  name: "data"
  type: "Data"
  top: "data"
  top: "label"
  include {
    phase: TEST
  }
  transform_param {
    scale: 0.00390625
	mean_file: "data/mean.binaryproto"
  }
  data_param {
    source: "data/mytest_deploy_leveldb"
    batch_size: 1
    backend: LEVELDB
  }
}
layer {
  name: "conv1"
  type: "Convolution"
  bottom: "data"
  top: "conv1"
  param {
    lr_mult: 1
  }
  param {
    lr_mult: 2
  }
  convolution_param {
    num_output: 20
    kernel_size: 5
    stride: 1
    weight_filler {
      type: "xavier"
    }
    bias_filler {
      type: "constant"
    }
  }
}
layer {
  name: "pool1"
  type: "Pooling"
  bottom: "conv1"
  top: "pool1"
  pooling_param {
    pool: MAX
    kernel_size: 2
    stride: 2
  }
}
layer {
  name: "conv2"
  type: "Convolution"
  bottom: "pool1"
  top: "conv2"
  param {
    lr_mult: 1
  }
  param {
    lr_mult: 2
  }
  convolution_param {
    num_output: 50
    kernel_size: 5
    stride: 1
    weight_filler {
      type: "xavier"
    }
    bias_filler {
      type: "constant"
    }
  }
}
layer {
  name: "pool2"
  type: "Pooling"
  bottom: "conv2"
  top: "pool2"
  pooling_param {
    pool: MAX
    kernel_size: 2
    stride: 2
  }
}
layer {
  name: "ip1"
  type: "InnerProduct"
  bottom: "pool2"
  top: "ip1"
  param {
    lr_mult: 1
  }
  param {
    lr_mult: 2
  }
  inner_product_param {
    num_output: 500
    weight_filler {
      type: "xavier"
    }
    bias_filler {
      type: "constant"
    }
  }
}
layer {
  name: "relu1"
  type: "ReLU"
  bottom: "ip1"
  top: "ip1"
}
layer {
  name: "ip2"
  type: "InnerProduct"
  bottom: "ip1"
  top: "ip2"
  param {
    lr_mult: 1
  }
  param {
    lr_mult: 2
  }
  inner_product_param {
    num_output: 2 #NOTE that we try 2 classification(true or false), so we change num_output para from 1000 to 2
    weight_filler {
      type: "xavier"
    }
    bias_filler {
      type: "constant"
    }
  }
}
layer {
  name: "accuracy"
  type: "Accuracy"
  bottom: "ip2"
  bottom: "label"
  top: "accuracy"
  include {
    phase: TEST
  }
}
layer {
  name: "loss"
  type: "SoftmaxWithLoss"
  bottom: "ip2"
  bottom: "label"
  top: "loss"
}
```

lenetネットワークの構成については、
http://www.slideshare.net/rezoolab/caffe のp.6 とかを見ればよいと思います。

後は、

```ruby
  include {
    phase: TEST
  }
```
と書くと、識別時にのみlayerが取り込まれるという意味です。(ずっと誤解していました)

### 学習結果

約88%で収束したので、打ち切りました。

```text
学習データ(50000枚:100000iter)
[内訳]
正常画像：26183
異常を含む画像：23817
10/24 17:00 -> 10/25 10:00(所要時間　18h)

# <... 中略>
I1026 02:01:15.841161 375892 solver.cpp:337] Iteration 100000, Testing net (#0)
I1026 02:01:29.253844 375892 solver.cpp:404]     Test net output #0: accuracy = 0.8796
I1026 02:01:29.253844 375892 solver.cpp:404]     Test net output #1: loss = 0.420841 (* 1 = 0.420841 loss)
I1026 02:01:29.363865 375892 solver.cpp:228] Iteration 100000, loss = 0.0469159
I1026 02:01:29.363865 375892 solver.cpp:244]     Train net output #0: loss = 0.0469161 (* 1 = 0.0469161 loss)
I1026 02:01:29.363865 375892 sgd_solver.cpp:106] Iteration 100000, lr = 0.0008278
```

訓練が終わった後は、caffemodelとsolverstateが出力されます。識別では、この作成されたcaffemodel(mytest_iter_100000.caffemodel)を使用します。

## 識別
識別データ(11181枚 : 30*30四方, grayscale:255 階調)を用いて識別

### caffe.exeのtestコマンドを用いて識別

簡易識別をしたいときに用います。

```bash:cygwin
$ caffe.exe --help
caffe.exe: command line brew
usage: caffe <command> <args>

commands:
  train           train or finetune a model
  test            score a model
  device_query    show GPU diagnostic information
  time            benchmark model execution time
# <省略>
```

ということで、train_test.prototxtを用意して、

```bash:eval.sh
#!/usr/bin/env sh
# This script converts the mytest data into lmdb/leveldb format,
# depending on the value assigned to $BACKEND.

EXAMPLE=examples/mytest
DATA=data/mytest
BUILD=Build/x64/Release

BACKEND="leveldb"

echo "Creating ${BACKEND}..."
rm -rf $DATA/mytest_deploy_${BACKEND}


convert_imageset.exe $DATA/src/ \
  $DATA/eval.txt $DATA/mytest_deploy_${BACKEND} --backend=${BACKEND} --gray

caffe test -model $EXAMPLE/lenet/train_test.prototxt --weights $1 --iterations $2
```

```bash:cygwin
$ date; ./examples/mytest/eval.sh ./examples/mytest/lenet/mytest_iter_100000.caffemodel 10000; wait; date;
# <省略>
I1102 07:59:55.009570  4556 caffe.cpp:276] Batch 0, accuracy = 1
I1102 07:59:55.009570  4556 caffe.cpp:276] Batch 0, loss = 0.00207879
I1102 07:59:55.010571  4556 caffe.cpp:276] Batch 1, accuracy = 1
I1102 07:59:55.010571  4556 caffe.cpp:276] Batch 1, loss = 0.140107
I1102 07:59:55.041574  4556 caffe.cpp:276] Batch 2, accuracy = 1
I1102 07:59:55.041574  4556 caffe.cpp:276] Batch 2, loss = 0.0174714
I1102 07:59:55.076577  4556 caffe.cpp:276] Batch 3, accuracy = 1
I1102 07:59:55.076577  4556 caffe.cpp:276] Batch 3, loss = 5.96047e-007
I1102 07:59:55.084578  4556 caffe.cpp:276] Batch 4, accuracy = 1
I1102 07:59:55.084578  4556 caffe.cpp:276] Batch 4, loss = 0
I1102 07:59:55.085578  4556 caffe.cpp:276] Batch 5, accuracy = 1
I1102 07:59:55.085578  4556 caffe.cpp:276] Batch 5, loss = 0
I1102 07:59:55.090579  4556 caffe.cpp:276] Batch 6, accuracy = 1
I1102 07:59:55.090579  4556 caffe.cpp:276] Batch 6, loss = 0
I1102 07:59:55.091579  4556 caffe.cpp:276] Batch 7, accuracy = 1
I1102 07:59:55.091579  4556 caffe.cpp:276] Batch 7, loss = 0
I1102 07:59:55.092579  4556 caffe.cpp:276] Batch 8, accuracy = 1
I1102 07:59:55.092579  4556 caffe.cpp:276] Batch 8, loss = 0
I1102 07:59:55.093580  4556 caffe.cpp:276] Batch 9, accuracy = 1
I1102 07:59:55.093580  4556 caffe.cpp:276] Batch 9, loss = 0
I1102 07:59:55.094579  4556 caffe.cpp:276] Batch 10, accuracy = 1
I1102 07:59:55.094579  4556 caffe.cpp:276] Batch 10, loss = 0
I1102 07:59:55.095579  4556 caffe.cpp:276] Batch 11, accuracy = 1
I1102 07:59:55.095579  4556 caffe.cpp:276] Batch 11, loss = 0.00314443
I1102 07:59:55.095579  4556 caffe.cpp:276] Batch 12, accuracy = 1
I1102 07:59:55.096580  4556 caffe.cpp:276] Batch 12, loss = 0.00517411
I1102 07:59:55.096580  4556 caffe.cpp:276] Batch 13, accuracy = 1
I1102 07:59:55.096580  4556 caffe.cpp:276] Batch 13, loss = 0.00372884
I1102 07:59:55.097579  4556 caffe.cpp:276] Batch 14, accuracy = 1
I1102 07:59:55.097579  4556 caffe.cpp:276] Batch 14, loss = 0.00436105
I1102 07:59:55.098579  4556 caffe.cpp:276] Batch 15, accuracy = 1
I1102 07:59:55.098579  4556 caffe.cpp:276] Batch 15, loss = 0.00345169
I1102 07:59:55.099580  4556 caffe.cpp:276] Batch 16, accuracy = 1
I1102 07:59:55.099580  4556 caffe.cpp:276] Batch 16, loss = 0.176153
I1102 07:59:55.100580  4556 caffe.cpp:276] Batch 17, accuracy = 1
I1102 07:59:55.100580  4556 caffe.cpp:276] Batch 17, loss = 0.00777385
I1102 07:59:55.101580  4556 caffe.cpp:276] Batch 18, accuracy = 1
I1102 07:59:55.101580  4556 caffe.cpp:276] Batch 18, loss = 0.0316679
I1102 07:59:55.102581  4556 caffe.cpp:276] Batch 19, accuracy = 1
I1102 07:59:55.102581  4556 caffe.cpp:276] Batch 19, loss = 0.00257896
I1102 07:59:55.103580  4556 caffe.cpp:276] Batch 20, accuracy = 1
I1102 07:59:55.103580  4556 caffe.cpp:276] Batch 20, loss = 1.19209e-007
I1102 07:59:55.104580  4556 caffe.cpp:276] Batch 21, accuracy = 1
I1102 07:59:55.104580  4556 caffe.cpp:276] Batch 21, loss = 0
I1102 07:59:55.105581  4556 caffe.cpp:276] Batch 22, accuracy = 1
I1102 07:59:55.105581  4556 caffe.cpp:276] Batch 22, loss = 0
I1102 07:59:55.106580  4556 caffe.cpp:276] Batch 23, accuracy = 1
I1102 07:59:55.106580  4556 caffe.cpp:276] Batch 23, loss = 0
I1102 07:59:55.107580  4556 caffe.cpp:276] Batch 24, accuracy = 1
I1102 07:59:55.107580  4556 caffe.cpp:276] Batch 24, loss = 0
I1102 07:59:55.108580  4556 caffe.cpp:276] Batch 25, accuracy = 1
I1102 07:59:55.108580  4556 caffe.cpp:276] Batch 25, loss = 0
I1102 07:59:55.109580  4556 caffe.cpp:276] Batch 26, accuracy = 1
I1102 07:59:55.109580  4556 caffe.cpp:276] Batch 26, loss = 0
I1102 07:59:55.110581  4556 caffe.cpp:276] Batch 27, accuracy = 1
I1102 07:59:55.110581  4556 caffe.cpp:276] Batch 27, loss = 0
I1102 07:59:55.111582  4556 caffe.cpp:276] Batch 28, accuracy = 1
I1102 07:59:55.111582  4556 caffe.cpp:276] Batch 28, loss = 0.00151803
I1102 07:59:55.113581  4556 caffe.cpp:276] Batch 29, accuracy = 1
I1102 07:59:55.113581  4556 caffe.cpp:276] Batch 29, loss = 0.000643878
I1102 07:59:55.114581  4556 caffe.cpp:276] Batch 30, accuracy = 1
I1102 07:59:55.114581  4556 caffe.cpp:276] Batch 30, loss = 0.00320303
I1102 07:59:55.115581  4556 caffe.cpp:276] Batch 31, accuracy = 1
I1102 07:59:55.115581  4556 caffe.cpp:276] Batch 31, loss = 0.0053963
I1102 07:59:55.116581  4556 caffe.cpp:276] Batch 32, accuracy = 1
I1102 07:59:55.116581  4556 caffe.cpp:276] Batch 32, loss = 0.00134141
I1102 07:59:55.117581  4556 caffe.cpp:276] Batch 33, accuracy = 1
I1102 07:59:55.117581  4556 caffe.cpp:276] Batch 33, loss = 0.0414601
I1102 07:59:55.118582  4556 caffe.cpp:276] Batch 34, accuracy = 1
I1102 07:59:55.118582  4556 caffe.cpp:276] Batch 34, loss = 0.0304497
I1102 07:59:55.119581  4556 caffe.cpp:276] Batch 35, accuracy = 1
I1102 07:59:55.119581  4556 caffe.cpp:276] Batch 35, loss = 0.0105491
I1102 07:59:55.120582  4556 caffe.cpp:276] Batch 36, accuracy = 1
I1102 07:59:55.120582  4556 caffe.cpp:276] Batch 36, loss = 2.38419e-007
I1102 07:59:55.135583  4556 caffe.cpp:276] Batch 37, accuracy = 1
I1102 07:59:55.135583  4556 caffe.cpp:276] Batch 37, loss = 0
I1102 07:59:55.136584  4556 caffe.cpp:276] Batch 38, accuracy = 1
I1102 07:59:55.136584  4556 caffe.cpp:276] Batch 38, loss = 0
I1102 07:59:55.138583  4556 caffe.cpp:276] Batch 39, accuracy = 1
I1102 07:59:55.138583  4556 caffe.cpp:276] Batch 39, loss = 0
I1102 07:59:55.139583  4556 caffe.cpp:276] Batch 40, accuracy = 1
I1102 07:59:55.139583  4556 caffe.cpp:276] Batch 40, loss = 0
I1102 07:59:55.140584  4556 caffe.cpp:276] Batch 41, accuracy = 1
I1102 07:59:55.140584  4556 caffe.cpp:276] Batch 41, loss = 0
I1102 07:59:55.141584  4556 caffe.cpp:276] Batch 42, accuracy = 1
I1102 07:59:55.141584  4556 caffe.cpp:276] Batch 42, loss = 0
I1102 07:59:55.153585  4556 caffe.cpp:276] Batch 43, accuracy = 1
I1102 07:59:55.153585  4556 caffe.cpp:276] Batch 43, loss = 1.19209e-007
I1102 07:59:55.155586  4556 caffe.cpp:276] Batch 44, accuracy = 1
I1102 07:59:55.155586  4556 caffe.cpp:276] Batch 44, loss = 0.00371561
I1102 07:59:55.156585  4556 caffe.cpp:276] Batch 45, accuracy = 1
I1102 07:59:55.156585  4556 caffe.cpp:276] Batch 45, loss = 0.000123628
I1102 07:59:55.157585  4556 caffe.cpp:276] Batch 46, accuracy = 1
I1102 07:59:55.157585  4556 caffe.cpp:276] Batch 46, loss = 0.00122151
I1102 07:59:55.157585  4556 caffe.cpp:276] Batch 47, accuracy = 1
I1102 07:59:55.158586  4556 caffe.cpp:276] Batch 47, loss = 0.00462845
I1102 07:59:55.158586  4556 caffe.cpp:276] Batch 48, accuracy = 1
I1102 07:59:55.159585  4556 caffe.cpp:276] Batch 48, loss = 0.00516471
I1102 07:59:55.160586  4556 caffe.cpp:276] Batch 49, accuracy = 1
I1102 07:59:55.160586  4556 caffe.cpp:276] Batch 49, loss = 0.0118847
I1102 07:59:55.161586  4556 caffe.cpp:276] Batch 50, accuracy = 1
I1102 07:59:55.161586  4556 caffe.cpp:276] Batch 50, loss = 0.00601578
I1102 07:59:55.162586  4556 caffe.cpp:276] Batch 51, accuracy = 1
I1102 07:59:55.162586  4556 caffe.cpp:276] Batch 51, loss = 0.00351964
I1102 07:59:55.163586  4556 caffe.cpp:276] Batch 52, accuracy = 1
I1102 07:59:55.163586  4556 caffe.cpp:276] Batch 52, loss = 0.00372381
I1102 07:59:55.164587  4556 caffe.cpp:276] Batch 53, accuracy = 1
I1102 07:59:55.164587  4556 caffe.cpp:276] Batch 53, loss = 5.96047e-007
I1102 07:59:55.166586  4556 caffe.cpp:276] Batch 54, accuracy = 1
I1102 07:59:55.166586  4556 caffe.cpp:276] Batch 54, loss = 0
I1102 07:59:55.167587  4556 caffe.cpp:276] Batch 55, accuracy = 1
I1102 07:59:55.167587  4556 caffe.cpp:276] Batch 55, loss = 0
I1102 07:59:55.168586  4556 caffe.cpp:276] Batch 56, accuracy = 1
I1102 07:59:55.168586  4556 caffe.cpp:276] Batch 56, loss = 0
I1102 07:59:55.169586  4556 caffe.cpp:276] Batch 57, accuracy = 1
I1102 07:59:55.169586  4556 caffe.cpp:276] Batch 57, loss = 0
I1102 07:59:55.170588  4556 caffe.cpp:276] Batch 58, accuracy = 1
I1102 07:59:55.170588  4556 caffe.cpp:276] Batch 58, loss = 0
I1102 07:59:55.171587  4556 caffe.cpp:276] Batch 59, accuracy = 1
I1102 07:59:55.171587  4556 caffe.cpp:276] Batch 59, loss = 0
I1102 07:59:55.172587  4556 caffe.cpp:276] Batch 60, accuracy = 1
I1102 07:59:55.172587  4556 caffe.cpp:276] Batch 60, loss = 0
I1102 07:59:55.173588  4556 caffe.cpp:276] Batch 61, accuracy = 1
I1102 07:59:55.173588  4556 caffe.cpp:276] Batch 61, loss = 0.00573326
I1102 07:59:55.174587  4556 caffe.cpp:276] Batch 62, accuracy = 1
I1102 07:59:55.174587  4556 caffe.cpp:276] Batch 62, loss = 0.00347143
I1102 07:59:55.175587  4556 caffe.cpp:276] Batch 63, accuracy = 1
I1102 07:59:55.175587  4556 caffe.cpp:276] Batch 63, loss = 0.00199535
I1102 07:59:55.176587  4556 caffe.cpp:276] Batch 64, accuracy = 1
I1102 07:59:55.176587  4556 caffe.cpp:276] Batch 64, loss = 0.00278288
I1102 07:59:55.177587  4556 caffe.cpp:276] Batch 65, accuracy = 1
I1102 07:59:55.177587  4556 caffe.cpp:276] Batch 65, loss = 0.0025841
I1102 07:59:55.178587  4556 caffe.cpp:276] Batch 66, accuracy = 1
I1102 07:59:55.178587  4556 caffe.cpp:276] Batch 66, loss = 0.00708935
I1102 07:59:55.178587  4556 caffe.cpp:276] Batch 67, accuracy = 1
I1102 07:59:55.178587  4556 caffe.cpp:276] Batch 67, loss = 0.00605667
I1102 07:59:55.179587  4556 caffe.cpp:276] Batch 68, accuracy = 1
I1102 07:59:55.179587  4556 caffe.cpp:276] Batch 68, loss = 0.00665238
I1102 07:59:55.180588  4556 caffe.cpp:276] Batch 69, accuracy = 1
I1102 07:59:55.180588  4556 caffe.cpp:276] Batch 69, loss = 0.00212681
I1102 07:59:55.181588  4556 caffe.cpp:276] Batch 70, accuracy = 1
I1102 07:59:55.181588  4556 caffe.cpp:276] Batch 70, loss = 0.0304509
I1102 07:59:55.182588  4556 caffe.cpp:276] Batch 71, accuracy = 1
I1102 07:59:55.182588  4556 caffe.cpp:276] Batch 71, loss = 7.27179e-006
I1102 07:59:55.183588  4556 caffe.cpp:276] Batch 72, accuracy = 1
I1102 07:59:55.183588  4556 caffe.cpp:276] Batch 72, loss = 0
I1102 07:59:55.184588  4556 caffe.cpp:276] Batch 73, accuracy = 1
I1102 07:59:55.184588  4556 caffe.cpp:276] Batch 73, loss = 0
I1102 07:59:55.185588  4556 caffe.cpp:276] Batch 74, accuracy = 1
I1102 07:59:55.185588  4556 caffe.cpp:276] Batch 74, loss = 0
I1102 07:59:55.185588  4556 caffe.cpp:276] Batch 75, accuracy = 1
I1102 07:59:55.185588  4556 caffe.cpp:276] Batch 75, loss = 0
I1102 07:59:55.186589  4556 caffe.cpp:276] Batch 76, accuracy = 1
I1102 07:59:55.186589  4556 caffe.cpp:276] Batch 76, loss = 0
I1102 07:59:55.187588  4556 caffe.cpp:276] Batch 77, accuracy = 1
I1102 07:59:55.187588  4556 caffe.cpp:276] Batch 77, loss = 0.00324118
I1102 07:59:55.188588  4556 caffe.cpp:276] Batch 78, accuracy = 1
I1102 07:59:55.188588  4556 caffe.cpp:276] Batch 78, loss = 0.00699073
I1102 07:59:55.189589  4556 caffe.cpp:276] Batch 79, accuracy = 1
I1102 07:59:55.189589  4556 caffe.cpp:276] Batch 79, loss = 0.00333453
I1102 07:59:55.190589  4556 caffe.cpp:276] Batch 80, accuracy = 1
I1102 07:59:55.190589  4556 caffe.cpp:276] Batch 80, loss = 0.00858627
I1102 07:59:55.191589  4556 caffe.cpp:276] Batch 81, accuracy = 1
I1102 07:59:55.191589  4556 caffe.cpp:276] Batch 81, loss = 0.012485
I1102 07:59:55.192589  4556 caffe.cpp:276] Batch 82, accuracy = 1
I1102 07:59:55.192589  4556 caffe.cpp:276] Batch 82, loss = 0.00126018
I1102 07:59:55.196589  4556 caffe.cpp:276] Batch 83, accuracy = 1
I1102 07:59:55.196589  4556 caffe.cpp:276] Batch 83, loss = 0.00604102
I1102 07:59:55.197589  4556 caffe.cpp:276] Batch 84, accuracy = 1
I1102 07:59:55.197589  4556 caffe.cpp:276] Batch 84, loss = 0.00597452
I1102 07:59:55.197589  4556 caffe.cpp:276] Batch 85, accuracy = 1
I1102 07:59:55.197589  4556 caffe.cpp:276] Batch 85, loss = 0.00348387
I1102 07:59:55.198590  4556 caffe.cpp:276] Batch 86, accuracy = 1
I1102 07:59:55.198590  4556 caffe.cpp:276] Batch 86, loss = 0.0011795
I1102 07:59:55.199589  4556 caffe.cpp:276] Batch 87, accuracy = 1
I1102 07:59:55.199589  4556 caffe.cpp:276] Batch 87, loss = 0.0960982
I1102 07:59:55.201591  4556 caffe.cpp:276] Batch 88, accuracy = 1
I1102 07:59:55.201591  4556 caffe.cpp:276] Batch 88, loss = 0.0198378
I1102 07:59:55.201591  4556 caffe.cpp:276] Batch 89, accuracy = 1
I1102 07:59:55.201591  4556 caffe.cpp:276] Batch 89, loss = 0.0390513
I1102 07:59:55.202590  4556 caffe.cpp:276] Batch 90, accuracy = 1
I1102 07:59:55.202590  4556 caffe.cpp:276] Batch 90, loss = 0.00671676
I1102 07:59:55.203590  4556 caffe.cpp:276] Batch 91, accuracy = 0
I1102 07:59:55.203590  4556 caffe.cpp:276] Batch 91, loss = 0.734476
I1102 07:59:55.204591  4556 caffe.cpp:276] Batch 92, accuracy = 1
I1102 07:59:55.204591  4556 caffe.cpp:276] Batch 92, loss = 0.329517
I1102 07:59:55.205590  4556 caffe.cpp:276] Batch 93, accuracy = 0
I1102 07:59:55.205590  4556 caffe.cpp:276] Batch 93, loss = 3.2879
I1102 07:59:55.206590  4556 caffe.cpp:276] Batch 94, accuracy = 1
I1102 07:59:55.206590  4556 caffe.cpp:276] Batch 94, loss = 0.00880476
I1102 07:59:55.207590  4556 caffe.cpp:276] Batch 95, accuracy = 1
I1102 07:59:55.207590  4556 caffe.cpp:276] Batch 95, loss = 0.00612492
I1102 07:59:55.208590  4556 caffe.cpp:276] Batch 96, accuracy = 1
I1102 07:59:55.208590  4556 caffe.cpp:276] Batch 96, loss = 0.00298934
I1102 07:59:55.209590  4556 caffe.cpp:276] Batch 97, accuracy = 1
I1102 07:59:55.209590  4556 caffe.cpp:276] Batch 97, loss = 0.00931252
I1102 07:59:55.211591  4556 caffe.cpp:276] Batch 98, accuracy = 1
I1102 07:59:55.211591  4556 caffe.cpp:276] Batch 98, loss = 0.0195644
I1102 07:59:55.212591  4556 caffe.cpp:276] Batch 99, accuracy = 1
I1102 07:59:55.212591  4556 caffe.cpp:276] Batch 99, loss = 0.00813458
I1102 07:59:55.214591  4556 caffe.cpp:276] Batch 100, accuracy = 1
I1102 07:59:55.214591  4556 caffe.cpp:276] Batch 100, loss = 0.0215285
# <省略>
```
で、結果的に正答率は0.900546でした。


### pycaffeを用いて識別

 http://kivantium.hateblo.jp/entry/2015/09/08/012921
 と
 http://nbviewer.jupyter.org/github/BVLC/caffe/blob/master/examples/00-classification.ipynb
を参考にしました。

開発環境は、メインで、Visutal studio 2015 community PTVS: anaconda2をInterpreterに使用しました。
また、デバッグ、問題点の洗い出しについてはJupyterを用いました。

VS2015のanaconda2導入設定については、
1. ツールタブ >> Python tools >> Python environments >> anaconda2 のデータベースアイコンクリック. refreshされ、IDEないでintellisenseが働きます

2.プロジェクトタブ >> ${project_name}のプロパティ >> Generalタブ >> Interpreterにanaconda2を指定
で大丈夫だったはずです[^vs2013]。

注意）
import caffeを含むコードをビルドすると、以下の例外が出るが、
![image](http://i.stack.imgur.com/Jrz33.png) Exception settingsのチェックを外すと、問題なく動作します。

[^vs2013]: ちなみに、VS2013では自分の環境ではデータベースrefreshすると、"Python Tools for Visual Studio background analyzerは動作を停止しました"的なことが出て、詰みました（Webで調べてもよくわからず...)

prototxtから見ていきます。頭のlayerのtypeがInputとなっていることに注意して、

```ruby:deploy.prototxt
name: "LeNet"
layer {
  name: "data"
  type: "Input"
  top: "data" # net.inputs[0]に対応
  # [バッチ数、channel(今回はgrayscaleなので、1), height, width]の順に記載する.
  # 以下、バッチ数 => K, width => W, height => Hと表記.なので、[K, 1, H, W] (channelを外に出して、[K, H, W]
  input_param { shape: { dim: 1 dim: 1 dim: 30 dim: 30 } }
}
layer {
  name: "conv1"
  type: "Convolution"
  bottom: "data"
  top: "conv1"
  param {
    lr_mult: 1
  }
  param {
    lr_mult: 2
  }
  convolution_param {
    num_output: 20
    kernel_size: 5
    stride: 1
    weight_filler {
      type: "xavier"
    }
    bias_filler {
      type: "constant"
    }
  }
}
layer {
  name: "pool1"
  type: "Pooling"
  bottom: "conv1"
  top: "pool1"
  pooling_param {
    pool: MAX
    kernel_size: 2
    stride: 2
  }
}
layer {
  name: "conv2"
  type: "Convolution"
  bottom: "pool1"
  top: "conv2"
  param {
    lr_mult: 1
  }
  param {
    lr_mult: 2
  }
  convolution_param {
    num_output: 50
    kernel_size: 5
    stride: 1
    weight_filler {
      type: "xavier"
    }
    bias_filler {
      type: "constant"
    }
  }
}
layer {
  name: "pool2"
  type: "Pooling"
  bottom: "conv2"
  top: "pool2"
  pooling_param {
    pool: MAX
    kernel_size: 2
    stride: 2
  }
}
layer {
  name: "ip1"
  type: "InnerProduct"
  bottom: "pool2"
  top: "ip1"
  param {
    lr_mult: 1
  }
  param {
    lr_mult: 2
  }
  inner_product_param {
    num_output: 500
    weight_filler {
      type: "xavier"
    }
    bias_filler {
      type: "constant"
    }
  }
}
layer {
  name: "relu1"
  type: "ReLU"
  bottom: "ip1"
  top: "ip1"
}
layer {
  name: "ip2"
  type: "InnerProduct"
  bottom: "ip1"
  top: "ip2"
  param {
    lr_mult: 1
  }
  param {
    lr_mult: 2
  }
  inner_product_param {
    num_output: 2
    weight_filler {
      type: "xavier"
    }
    bias_filler {
      type: "constant"
    }
  }
}

# http://seiya-kumada.blogspot.jp/2015/07/caffe.html
 layer {
   name: "prob"
   type: "Softmax"
   bottom: "ip2"
   top: "prob"  # net.outputs[0]に対応
}
```

頭とお尻の部分でeval.prototxtと変更になっています。

次にpycaffeを用いて識別したいので、かきかきします。
実は、caffe.exeの時の評価と結果のずれがあり、transformerにinput_scaleの値を指定する必要があるということに気づくまで一日くらい費やしてしまったのですが、
http://files.sig2d.org/sig2d14.pdf のp.10に解決の糸口を見つけたので一部抜粋しておきます：

>input_scale,raw_scale
>入力データに対して掛けるスケール値．教師データの作成時に行なった正規化と，今から判別器に入力するデータの正規化が異なる場合，この値を設定する必要がある．この設定による各画素値は，生の画素値をraw,補正後の画素値をinputとして以下の計算式で与えられる．
input=(raw×raw_scale-mean)×input_scale

```py:classifier.py

import caffe
from caffe.proto import caffe_pb2
from caffe.io import blobproto_to_array
import numpy as np # for array
import glob
import os.path

# directory = "C:/dev/caffe/caffe-windows"
net_path = "./examples/mytest/lenet/deploy.prototxt"
model_path = "./examples/mytest/mytest_iter_100000.caffemodel"
mean_path = "./data/mytest/mean.binaryproto"
eval_path = "./data/mytest/eval.txt"

# -- 
#net_path : deploy.prototxt, model_path : caffemodel. 識別なので、Caffe.TESTと記載
net = caffe.Net(net_path, model_path,caffe.TEST)
# --

# for preprocess
transformer = caffe.io.Transformer({'data':net.blobs['data'].data.shape})
# channel_swapはRGBをσ(RGB) = BGRにしたいときに用いる。
# 対して、set_transposeは、[H, W, K] => [K, H, W]としたいときとかに用いる。
transformer.set_transpose('data', (2,0,1)) 

mean_blob = caffe_pb2.BlobProto()
with open(mean_path, "rb") as f:
    mean_blob.ParseFromString(f.read())
mean_array = blobproto_to_array(mean_blob)
mean_array = np.asarray(mean_blob.data).reshape((mean_blob.channels, mean_blob.height, mean_blob.width))
transformer.set_mean('data', mean_array)

#上記の説明参照
transformer.set_raw_scale('data', 255)
# scaling to 1/255 = 0.003..
transformer.set_input_scale('data', 0.00390625)

# sample test for 11181 images
cnt = 0 #number of the collect answer
num = 11181

numbers = [str(i+60000).zfill(7) for i in range(1,num+1)]
filename = [s + ".bmp" for s in numbers]
images = "data/mytest/check"


import csv
reader = csv.reader(open(eval_path), lineterminator = ' ')
ansList = []
for row in reader:
    i = 0
    (fl, i) = row[0].split(' ')
    ansList.append((int(i)))


for i, fname in enumerate(filename):

    fn = images + "/" + fname
    
    image = caffe.io.load_image(fn, color = False)
    # image : (H×W×K) ndarray  => set_transposeが効いて、outputは(K×W×H) ndarray型になる。
    proc = transformer.preprocess('data', image)
   # (K×W×H) ndarray のinputデータ : proc
   # net.inputs[0]はdeploy.prototxtのdataレイヤーに記載の'data'(topプロパティ)
    out = net.forward_all(**{net.inputs[0]:proc})
    # net.outputs[0]はdeploy.prototxtのdataレイヤーに記載の'prob'(topプロパティ)
    predictions = out[net.outputs[0]]
    answer = np.argmax(predictions)

    print predictions,  "<= prob"
    print net.blobs['ip2'].data ," <= ip2"

    print fn, i,", true answer =>", ansList[i],", eval =>", answer, ansList[i] == answer
    cnt = cnt + 1 if (ansList[i] == answer) else cnt
print cnt, "/", num

```

長いですが、大したことはやっていなくって、

```py
# deploy(ネットワーク設定)とcaffemodel(学習出力パラメータ群)の読み込み
#net_path <- deploy.prototxt, model_path <- caffemodel
net = caffe.Net(net_path, model_path,caffe.TEST)
# transformerの設定(for using preprocess phase only)
transformer = caffe.io.Transformer({'data':net.blobs['data'].data.shape})
# filename -> ネットワークに沿って演算されて、出力ベクトル (1*2 ndarray)が得られる。
out = net.forward_all(**{net.inputs[0]:transformer.preprocess('data', caffe.io.load_image(fn, color = False))})
# show most probable class
answer = np.argmax(out[net.outputs[0]])
```
で識別で予測されたanswerと本当の答えが記載されているanswer.txtとを比較してチェックしているだけです。

出力結果は以下のような感じになりました。

```bat:cmd.exe
[[ 0.99750298  0.00249705]] <= prob
[[ 2.98188448 -3.00825882]]  <= ip2
data/check/0060001.bmp 0 , true answer => 0 , eval => 0 True
[[ 0.84466338  0.15533663]] <= prob
[[ 0.88548481 -0.80785882]]  <= ip2
data/check/0060002.bmp 1 , true answer => 0 , eval => 0 True
[[ 0.97809428  0.0219057 ]] <= prob
[[ 1.93141639 -1.86744297]]  <= ip2
data/check/0060003.bmp 2 , true answer => 0 , eval => 0 True
[[  8.44261933e-07   9.99999166e-01]] <= prob
[[-7.0260458   6.95875645]]  <= ip2
data/check/0060004.bmp 3 , true answer => 1 , eval => 1 True
[[  5.23068120e-14   1.00000000e+00]] <= prob
[[-15.21660709  15.36504269]]  <= ip2
data/check/0060005.bmp 4 , true answer => 1 , eval => 1 True
[[  2.16108363e-17   1.00000000e+00]] <= prob
[[-19.06203842  19.31130028]]  <= ip2
data/check/0060006.bmp 5 , true answer => 1 , eval => 1 True
[[  3.03096744e-17   1.00000000e+00]] <= prob
[[-18.61361885  19.42144585]]  <= ip2
data/check/0060007.bmp 6 , true answer => 1 , eval => 1 True
[[  2.20863166e-16   1.00000000e+00]] <= prob
[[-17.62698936  18.42199898]]  <= ip2
data/check/0060008.bmp 7 , true answer => 1 , eval => 1 True
[[  2.60469958e-15   1.00000000e+00]] <= prob
[[-16.56490326  17.01655579]]  <= ip2
data/check/0060009.bmp 8 , true answer => 1 , eval => 1 True
[[  7.49017981e-13   1.00000000e+00]] <= prob
[[-13.91413593  14.00587749]]  <= ip2
data/check/0060010.bmp 9 , true answer => 1 , eval => 1 True
[[  2.98124263e-08   1.00000000e+00]] <= prob
[[-8.61068058  8.71765995]]  <= ip2
data/check/0060011.bmp 10 , true answer => 1 , eval => 1 True
[[ 0.99622607  0.00377389]] <= prob
[[ 2.80986714 -2.76599956]]  <= ip2
data/check/0060012.bmp 11 , true answer => 0 , eval => 0 True
[[ 0.99383426  0.00616576]] <= prob
[[ 2.55797553 -2.52458334]]  <= ip2
data/check/0060013.bmp 12 , true answer => 0 , eval => 0 True
[[ 0.99590862  0.00409134]] <= prob
[[ 2.75059795 -2.74418426]]  <= ip2
data/check/0060014.bmp 13 , true answer => 0 , eval => 0 True
[[ 0.99530667  0.00469327]] <= prob
[[ 2.69898725 -2.65793467]]  <= ip2
data/check/0060015.bmp 14 , true answer => 0 , eval => 0 True
[[ 0.99600548  0.00399459]] <= prob
[[ 2.80181313 -2.71699834]]  <= ip2
data/check/0060016.bmp 15 , true answer => 0 , eval => 0 True
[[ 0.83415365  0.16584632]] <= prob
[[ 0.847      -0.76835608]]  <= ip2
data/check/0060017.bmp 16 , true answer => 0 , eval => 0 True
[[ 0.9907499   0.00925016]] <= prob
[[ 2.36697435 -2.30684662]]  <= ip2
data/check/0060018.bmp 17 , true answer => 0 , eval => 0 True
[[ 0.96608049  0.03391952]] <= prob
[[ 1.7060734  -1.64318299]]  <= ip2
data/check/0060019.bmp 18 , true answer => 0 , eval => 0 True
[[ 0.99683195  0.00316807]] <= prob
[[ 2.90177608 -2.84968448]]  <= ip2
data/check/0060020.bmp 19 , true answer => 0 , eval => 0 True
[[  1.18890746e-07   9.99999881e-01]] <= prob
[[-7.89830256  8.04675865]]  <= ip2
data/check/0060021.bmp 20 , true answer => 1 , eval => 1 True
[[  2.60205052e-13   1.00000000e+00]] <= prob
[[-14.19086933  14.78643799]]  <= ip2
data/check/0060022.bmp 21 , true answer => 1 , eval => 1 True
[[  1.05305694e-14   1.00000000e+00]] <= prob
[[-15.77843571  16.40605736]]  <= ip2
data/check/0060023.bmp 22 , true answer => 1 , eval => 1 True
[[  1.67895694e-16   1.00000000e+00]] <= prob
[[-17.80656433  18.51662636]]  <= ip2
data/check/0060024.bmp 23 , true answer => 1 , eval => 1 True
[[  4.60003907e-17   1.00000000e+00]] <= prob
[[-18.51346588  19.1044178 ]]  <= ip2
data/check/0060025.bmp 24 , true answer => 1 , eval => 1 True
[[  4.48662797e-17   1.00000000e+00]] <= prob
[[-18.31805801  19.32478905]]  <= ip2
data/check/0060026.bmp 25 , true answer => 1 , eval => 1 True
[[  3.96798446e-14   1.00000000e+00]] <= prob
[[-15.41134453  15.44658756]]  <= ip2
data/check/0060027.bmp 26 , true answer => 1 , eval => 1 True
[[  2.74925345e-08   1.00000000e+00]] <= prob
[[-8.72124386  8.68810844]]  <= ip2
data/check/0060028.bmp 27 , true answer => 1 , eval => 1 True
[[ 0.998142    0.00185796]] <= prob
[[ 3.15813088 -3.12828398]]  <= ip2
data/check/0060029.bmp 28 , true answer => 0 , eval => 0 True
[[  9.99204934e-01   7.95091386e-04]] <= prob
[[ 3.56998134 -3.56627679]]  <= ip2
data/check/0060030.bmp 29 , true answer => 0 , eval => 0 True
[[ 0.99647921  0.00352086]] <= prob
[[ 2.83586335 -2.8096602 ]]  <= ip2
data/check/0060031.bmp 30 , true answer => 0 , eval => 0 True
[[ 0.99423426  0.00576578]] <= prob
[[ 2.57602    -2.57401204]]  <= ip2
data/check/0060032.bmp 31 , true answer => 0 , eval => 0 True
[[ 0.99844068  0.00155928]] <= prob
[[ 3.24583077 -3.21614099]]  <= ip2
data/check/0060033.bmp 32 , true answer => 0 , eval => 0 True
[[ 0.95326477  0.04673528]] <= prob
[[ 1.53531289 -1.4800806 ]]  <= ip2
data/check/0060034.bmp 33 , true answer => 0 , eval => 0 True
[[ 0.96600479  0.03399523]] <= prob
[[ 1.70796311 -1.63898551]]  <= ip2
data/check/0060035.bmp 34 , true answer => 0 , eval => 0 True
[[ 0.98875147  0.01124856]] <= prob
[[ 2.25061965 -2.22558308]]  <= ip2
data/check/0060036.bmp 35 , true answer => 0 , eval => 0 True
[[  2.99871118e-07   9.99999642e-01]] <= prob
[[-7.52946043  7.49045277]]  <= ip2
data/check/0060037.bmp 36 , true answer => 1 , eval => 1 True
[[  2.70791808e-14   1.00000000e+00]] <= prob
[[-15.45818996  15.78182125]]  <= ip2
data/check/0060038.bmp 37 , true answer => 1 , eval => 1 True
[[  1.79429603e-17   1.00000000e+00]] <= prob
[[-18.48504639  20.07428551]]  <= ip2
data/check/0060039.bmp 38 , true answer => 1 , eval => 1 True
[[  5.74076183e-17   1.00000000e+00]] <= prob
[[-18.05085373  19.34549904]]  <= ip2
data/check/0060040.bmp 39 , true answer => 1 , eval => 1 True
REM <...中略>
[[ 0.98656958  0.01343042]] <= prob
[[ 2.15983582 -2.13687634]]  <= ip2
data/check/0071179.bmp 11178 , true answer => 0 , eval => 0 True
[[ 0.98314559  0.01685444]] <= prob
[[ 2.03822541 -2.02791786]]  <= ip2
data/check/0071180.bmp 11179 , true answer => 0 , eval => 0 True
[[ 0.99142039  0.00857963]] <= prob
[[ 2.39600086 -2.35374713]]  <= ip2
data/check/0071181.bmp 11180 , true answer => 0 , eval => 0 True
10071 / 11181
```

C++からcaffeライブラリを直接呼ぶのは大変そうですが、機会があれば。

追記) 2016/12 caffe-claffisication in C++として、VS2015で作成したプロジェクトを自身のGitHubに挙げましたので、良ければ参考にしてください!!

## 参考文献

+ http://li.nu/blog/2016/03/handwritten-number-classification-with-caffe-part3.html

+ http://tnarihi.github.io/machine%20learning/2014/12/10/CAFFE-Layer/

+ http://pepper.is.sci.toho-u.ac.jp/index.php?%A5%CE%A1%BC%A5%C8%2FCaffe%A4%CE%A5%E2%A5%B8%A5%E5%A1%BC%A5%EB%B5%AD%BD%D2%C8%B4%BF%E8%A1%CAcaffe.prototxt%A1%CB