Edited at

Caffeで回帰をしてみる - deploy(予測)編 -

More than 1 year has passed since last update.

前回のCaffeで回帰をしてみるの続編といいますか,

実際の予測で結果がちょっと怪しかったので,正しく予測をする方法を紹介します

前回の記事と比較して利点は


  • meanファイルとして.npyを作らなくてよい

  • 手慣れたtrainコマンドで予測ができる

といった点でしょうか.


regression.prototxt を作成

学習する際のsolver.prototxtとほぼ同じです.


  • net: "val.prototxt"

  • test**: の行は全て削除

  • base_lr: 0

  • lr_policy: "fixed"

  • display: 1

  • max_iter: [予測する画像の枚数]

  • solver_mode: GPU(GPU使える人は)


regression.prototxt

# reduce the learning rate after 8 epochs (4000 iters) by a factor of 10

# The train/test net protocol buffer definition
net: "val.prototxt"
# test_iter specifies how many forward passes the test should carry out.
# In the case of MNIST, we have test batch size 100 and 100 test iterations,
# covering the full 10,000 testing images.
#test_iter: 113
# Carry out testing every 500 training iterations.
#test_interval: 100
# The base learning rate, momentum and the weight decay of the network.
base_lr: 0
momentum: 0.9
weight_decay: 0.004
# The learning rate policy
lr_policy: "fixed"
gamma: 0.1
stepvalue: 10000
stepvalue: 15000
# Display every 100 iterations
display: 1
# The maximum number of iterations
max_iter: 5522
# snapshot intermediate results
snapshot: 10000
snapshot_prefix: "snapshots/__ss"
# solver mode: CPU or GPU
solver_mode: GPU



val.prototxt を作成

train_test.prototxtと内容はほぼ同じです.

- DataLayer TRAIN のdata_param source: を,バリデーション用データのleveldb(lmdb)に変更.

- batch_size: 1

- mean_file は学習時に使用したものと同じものを指定.

- DataLayer TESTはコメントアウト

- LossのLayerをコメントアウト

これにより,val.prototxtで構成されるNNではlabelとprobの接続先がないということで,予測時(trainコマンド時)この2つが出力されるのが肝です.


val.prototxt

name: "foo"

layer {
name: "foo"
type: "Data"
top: "data"
top: "label"
include {
phase: TRAIN
}
data_param {
source: "val_leveldb"
backend: LEVELDB
batch_size: 1
}
transform_param {
scale: 0.00390625
mean_file: "train_mean.binaryproto"
}
}
# layer {
# name: "foo"
# type: "Data"
# top: "data"
# top: "label"
# include {
# phase: TEST
# }
# data_param {
# source: "train_leveldb"
# backend: LEVELDB
# batch_size: 50
# }
# transform_param {
# scale: 0.00390625
# mean_file: "train_mean.binaryproto"
# }
# }

... # convolutionとかpoolingとか

layer {
name: "prob"
type: "InnerProduct"
bottom: "pool4"
top: "prob"
param {
lr_mult: 1
}
param {
lr_mult: 2
}
inner_product_param {
num_output: 1
weight_filler {
type: "gaussian"
std: 0.1
}
bias_filler {
type: "constant"
}
}
}
# layer {
# name: "loss"
# type: "EuclideanLoss"
# bottom: "prob"
# bottom: "label"
# top: "loss"
# }



trainコマンドで予測

caffe train --solver=regression.prototxt --weights=**.caffemodel 2>&1 | tee val.log

当たり前ですが,caffemodelは学習済のもの.

2>&1は標準エラー出力を標準出力する.

| tee ***.logはその標準出力をログに吐き出すということです.

参考:シェルの入出力制御あれこれ

このとき,以下のような出力がコマンドラインにもlogにも吐き出されます


val.log

I0107 10:51:36.504703  6703 caffe.cpp:218] Using GPUs 0

I0107 10:51:36.513270 6703 caffe.cpp:223] GPU 0: TITAN X (Pascal)
I0107 10:51:36.948774 6703 solver.cpp:44] Initializing solver from parameters:
... # regression.prototxtの内容
... # val.prototxtの内容
... # NNを構成する際の出力
I0107 10:51:37.176156 6703 caffe.cpp:248] Starting Optimization
I0107 10:51:37.176247 6703 solver.cpp:272] Solving foo
I0107 10:51:37.176275 6703 solver.cpp:273] Learning Rate Policy: fixed
I0107 10:51:37.189388 6703 solver.cpp:218] Iteration 0 (0 iter/s, 0.0130379s/1 iters), loss = 0
I0107 10:51:37.189575 6703 solver.cpp:237] Train net output #0: label = 81
I0107 10:51:37.189663 6703 solver.cpp:237] Train net output #1: prob = 82.8668
I0107 10:51:37.189707 6703 sgd_solver.cpp:105] Iteration 0, lr = 0
I0107 10:51:37.195212 6703 solver.cpp:218] Iteration 1 (176.211 iter/s, 0.00567501s/1 iters), loss = 0
I0107 10:51:37.195333 6703 solver.cpp:237] Train net output #0: label = 66
I0107 10:51:37.195384 6703 solver.cpp:237] Train net output #1: prob = 65.0752
I0107 10:51:37.195420 6703 sgd_solver.cpp:105] Iteration 1, lr = 0
...
I0107 10:52:03.775938 6703 solver.cpp:218] Iteration 5521 (192.882 iter/s, 0.00518451s/1 iters), loss = 0
I0107 10:52:03.776058 6703 solver.cpp:237] Train net output #0: label = 48
I0107 10:52:03.776125 6703 solver.cpp:237] Train net output #1: prob = 48.4188
I0107 10:52:03.776163 6703 sgd_solver.cpp:105] Iteration 5521, lr = 0
I0107 10:52:03.776477 6703 solver.cpp:447] Snapshotting to binary proto file snapshots/__ss_iter_5522.caffemodel
I0107 10:52:03.867763 6703 sgd_solver.cpp:273] Snapshotting solver state to binary proto file snapshots/__ss_iter_5522.solverstate
I0107 10:52:03.909924 6703 solver.cpp:310] Iteration 5522, loss = 0
I0107 10:52:03.910029 6703 solver.cpp:315] Optimization Done.
I0107 10:52:03.910054 6703 caffe.cpp:259] Optimization Done.


この中から

Train net output #0: label = **

Train net output #1: prob = **

だけ取り出して,各値を対応させたcsvが作ることができたらゴール.


予測結果csvを作成


make_csv.sh

#!/bin/sh

if [ "$1" = "" ]; then
echo 'Usage: ./make_csv.sh ***.log'
exit 2
fi
ext=".csv"
name=$1$ext

cat $1 | grep "Train net output #0: label = " | awk '{print substr($0, index($0,"label"))}' | tr -d "label = " > .label.txt
cat $1 | grep "Train net output #1: prob = " | awk '{print substr($0, index($0,"prob"))}' | tr -d "prob = " > .prob.txt

paste -d "," .label.txt .prob.txt > $name

rm .label.txt .prob.txt

echo "saved results in "$name


./make_csv.sh val.log等とすれば,val.logを元にval.log.csvという名でデータが保存されます.

1列目:正解値

2列目:予測値