2014年12月22日月曜日

OpenCV4Tegra の configuration 情報を表示させてみた

nVidiaが提供しているJetson k1向けのOpenCV4Tegraに問題があったが最近ようやく修正された。

OpenCV4Tegraは、nVidiaの特別なチューニング(ARM NEON SIMD optimizations, multi-core CPU optimizations and some GLSL GPU optimizations)が施されたバージョンであるとのこと


OpenCV4Tegraが、どのようなconfigurationでビルドされているのか表示させてみた。

nonfreeのモジュールが無効化されているのでsiftが使えない

General configuration for OpenCV 2.4.10.1 =====================================
  Version control:               2.4.10.1

  Platform:
    Host:                        Linux 3.10.40-ge9b32d4 armv7l
    CMake:                       2.8.12.1
    CMake generator:             Unix Makefiles
    CMake build tool:            /usr/bin/make
    Configuration:               Release

  C/C++:
    Built as dynamic libs?:      YES
    C++ Compiler:                /usr/bin/c++  (ver 4.8.2)
    C++ flags (Release):         -fweb -fwrapv -frename-registers -fsched2-use-superblocks -fsched2-use-traces -fsched-stalled-insns-dep=100 -fsched-stalled-insns=2   -fsigned-char -W -Wall -Werror=return-type -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wundef -Winit-self -Wpointer-arith -Wshadow -Wsign-promo -Wno-narrowing -Wno-delete-non-virtual-dtor -fdiagnostics-show-option -pthread -fomit-frame-pointer -mfpu=neon -ffunction-sections -O3 -DNDEBUG  -DNDEBUG
    C++ flags (Debug):           -fweb -fwrapv -frename-registers -fsched2-use-superblocks -fsched2-use-traces -fsched-stalled-insns-dep=100 -fsched-stalled-insns=2   -fsigned-char -W -Wall -Werror=return-type -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wundef -Winit-self -Wpointer-arith -Wshadow -Wsign-promo -Wno-narrowing -Wno-delete-non-virtual-dtor -fdiagnostics-show-option -pthread -fomit-frame-pointer -mfpu=neon -ffunction-sections -g  -O0 -DDEBUG -D_DEBUG
    C Compiler:                  /usr/bin/cc
    C flags (Release):           -fweb -fwrapv -frename-registers -fsched2-use-superblocks -fsched2-use-traces -fsched-stalled-insns-dep=100 -fsched-stalled-insns=2   -fsigned-char -W -Wall -Werror=return-type -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wundef -Winit-self -Wpointer-arith -Wshadow -Wno-narrowing -fdiagnostics-show-option -pthread -fomit-frame-pointer -mfpu=neon -ffunction-sections -O3 -DNDEBUG  -DNDEBUG
    C flags (Debug):             -fweb -fwrapv -frename-registers -fsched2-use-superblocks -fsched2-use-traces -fsched-stalled-insns-dep=100 -fsched-stalled-insns=2   -fsigned-char -W -Wall -Werror=return-type -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wundef -Winit-self -Wpointer-arith -Wshadow -Wno-narrowing -fdiagnostics-show-option -pthread -fomit-frame-pointer -mfpu=neon -ffunction-sections -g  -O0 -DDEBUG -D_DEBUG
    Linker flags (Release):    
    Linker flags (Debug):      
    Precompiled headers:         YES

  OpenCV modules:
    To be built:                 core flann imgproc highgui features2d calib3d ml objdetect video contrib legacy photo gpu stitching tegra videostab esm_panorama facedetect imuvstab python superres ts vstab
    Disabled:                    nonfree world
    Disabled by dependency:      -
    Unavailable:                 androidcamera dynamicuda java ocl viz

  GUI:
    QT:                          NO
    GTK+ 2.x:                    YES (ver 2.24.23)
    GThread :                    YES (ver 2.40.2)
    GtkGlExt:                    NO
    OpenGL support:              NO
    VTK support:                 NO

  Media I/O:
    ZLib:                        /usr/lib/arm-linux-gnueabihf/libz.so (ver 1.2.8)
    JPEG:                        /usr/lib/arm-linux-gnueabihf/libjpeg.so (ver )
    PNG:                         /usr/lib/arm-linux-gnueabihf/libpng.so (ver 1.2.50)
    TIFF:                        /usr/lib/arm-linux-gnueabihf/libtiff.so (ver 42 - 4.0.3)
    JPEG 2000:                   /usr/lib/arm-linux-gnueabihf/libjasper.so (ver 1.900.1)
    OpenEXR:                     NO

  Video I/O:
    DC1394 1.x:                  NO
    DC1394 2.x:                  NO
    FFMPEG:                      YES
      codec:                     YES (ver 54.35.0)
      format:                    YES (ver 54.20.4)
      util:                      YES (ver 52.3.0)
      swscale:                   YES (ver 2.1.1)
      gentoo-style:              YES
    GStreamer:                   NO
    OpenNI:                      NO
    OpenNI PrimeSensor Modules:  NO
    PvAPI:                       NO
    GigEVisionSDK:               NO
    UniCap:                      NO
    UniCap ucil:                 NO
    V4L/V4L2:                    NO/YES
    XIMEA:                       NO
    Xine:                        NO

  Other third-party libraries:
    Use IPP:                     NO
    Use Eigen:                   YES (ver 3.2.0)
    Use TBB:                     NO
    Use OpenMP:                  NO
    Use GCD                      NO
    Use Concurrency              NO
    Use C=:                      NO
    Use Cuda:                    YES (ver 6.5)
    Use OpenCL:                  NO

  NVIDIA CUDA
    Use CUFFT:                   YES
    Use CUBLAS:                  NO
    USE NVCUVID:                 NO
    NVIDIA GPU arch:             32
    NVIDIA PTX archs:
    Use fast math:               NO

  Python:
    Interpreter:                 /usr/bin/python2 (ver 2.7.6)
    Libraries:                   /usr/lib/arm-linux-gnueabihf/libpython2.7.so (ver 2.7.6)
    numpy:                       /usr/lib/python2.7/dist-packages/numpy/core/include (ver 1.8.2)
    packages path:               lib/python2.7/dist-packages

  Java:
    ant:                         NO
    JNI:                         NO
    Java tests:                  NO

  Documentation:
    Build Documentation:         NO
    Sphinx:                      NO
    PdfLaTeX compiler:           NO

  Tests and samples:
    Tests:                       YES
    Performance tests:           YES
    C/C++ Examples:              NO

  Install path:                  /usr

  cvconfig.h is in:              /hdd/buildbot/slave_jetson_tk1_2/52-O4T-L4T/build
-----------------------------------------------------------------

General configuration for OpenCV4Tegra =====================================
  inner version                  2.4.10.1
  memory allocator               NO
  hardware link                  YES
  compact sources                NO
  logging enabled                NO
-----------------------------------------------------------------

以上

2014年12月21日日曜日

ODROID-XU3 Lite向けにOpenCV2.4.10をビルドした

ODROID-XU3 Liteが入手できたので、OpenCV2.4.10をビルドしてみた。

関連モジュールがすでに整っていたようなので、USB HDDにOpenCV2.4.10のソースを入れて、ODROIDに接続し、

cmake、 make、 make install ldconfigを行うことで使用できるようになった。

cmakeのオプション

cmake -DCMAKE_BUILD_TYPE=RELEASE -DWITH_1394=off -DBUILD_TESTS=off -DBUILD_PERF_TESTS=OFF -DBUILD_DOCS=OFF -DWITH_CUDA=OFF -DWITH_CUFFT=OFF -DWITH_GIGEAPI=OFF -DENABLE_NEON=ON -DWITH_TBB=ON -DBUILD_TBB=ON -DBUILD_GPU=off ..

8コアのため make -j8 の指定で、30分もかからない。基本的なモジュールは動作しているようである。

問題点
cmakeでtbbを指定してみたが、できたものはtbb対応ではなかった。

opencv/3rdparty/tbb/CMakeLists.txtを見てみると

BUILD_TBB option supports Windows on ARM only!
Use regular official TBB build instead of the BUILD_TBB option!

とあり、surfaceしか有効ではな気がする。

tbbが使用できないと8コアの意味がないので引き続き調査する。

todo
OpenCLが使えるか
pythonでimport opencvができな対策

Raspberry Pi のOpenCV configuration情報を表示させてみた

raspberry pi で OpenCVをビルドすると一晩コースと言われている。

簡単に既存のものをインストールするには、
sudo apt-get install libopencv-dev
を実行すれば良い

以前は、2.3系がインストールされたが、最近では、2.4系がインストールされるようになった。
どのようなconfigurationでビルドされているのか表示させてみた。


General configuration for OpenCV 2.4.1 =====================================

  Platform:
    Host:                        Linux 3.8.0-19-generic armv7l
    CMake:                       2.8.9
    CMake generator:             Unix Makefiles
    CMake build tool:            /usr/bin/make
    Configuration:               Release

  C/C++:
    Built as dynamic libs?:      YES
    C++ Compiler:                /usr/bin/c++ (ver 4.6.3)
    C++ flags (Release):         -Wall -pthread -fomit-frame-pointer -ffunction-sections -g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security -D_FORTIFY_SOURCE=2   -DNDEBUG
    C++ flags (Debug):           -Wall -pthread -fomit-frame-pointer -ffunction-sections -g  -O0 -DDEBUG -D_DEBUG -ggdb3
    C Compiler:                  /usr/bin/gcc
    C flags (Release):           -Wall -pthread -fomit-frame-pointer -ffunction-sections -g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security -D_FORTIFY_SOURCE=2  -DNDEBUG
    C flags (Debug):             -Wall -pthread -fomit-frame-pointer -ffunction-sections -g  -O0 -DDEBUG -D_DEBUG -ggdb3
    Linker flags (Release):      -Wl,-z,relro -Wl,--as-needed
    Linker flags (Debug):       

  OpenCV modules:
    To be built:                 calib3d contrib core features2d flann highgui imgproc legacy ml objdetect photo python stitching ts video videostab
    Disabled:                    -
    Disabled by dependency:      gpu(deps: )
    Unavailable:                 androidcamera java

  GUI:
    QT 4.x:                      NO
    GTK+ 2.x:                    YES (ver 2.24.10)
    GThread :                    YES (ver 2.37.5)
    GtkGlExt:                    NO
    OpenGL support:              NO

  Media I/O:
    ZLib:                        /usr/lib/arm-linux-gnueabihf/libz.so (ver 1.2.7)
    JPEG:                        /usr/lib/arm-linux-gnueabihf/libjpeg.so (ver 80)
    PNG:                         /usr/lib/arm-linux-gnueabihf/libpng.so (ver 1.2.49)
    TIFF:                        /usr/lib/arm-linux-gnueabihf/libtiff.so (ver 42 - 3.9.6)
    JPEG 2000:                   /usr/lib/arm-linux-gnueabihf/libjasper.so (ver 1.900.1)
    OpenEXR:                     /usr/lib/libImath.so /usr/lib/libIlmImf.so /usr/lib/libIex.so /usr/lib/libHalf.so /usr/lib/libIlmThread.so (ver 1.6.1)

  Video I/O:
    DC1394 1.x:                  NO
    DC1394 2.x:                  YES (ver 2.2.0)
    FFMPEG:                      YES
      codec:                     YES (ver 54.35.0)
      format:                    YES (ver 54.20.4)
      util:                      YES (ver 52.3.0)
      swscale:                   YES (ver 2.1.1)
      gentoo-style:              YES
    GStreamer:                   NO
    OpenNI:                      NO
    OpenNI PrimeSensor Modules:  NO
    PvAPI:                       NO
    UniCap:                      NO
    UniCap ucil:                 NO
    V4L/V4L2:                    Using libv4l (ver 1.0.0)
    Xine:                        NO

  Other third-party libraries:
    Use TBB:                     NO
    Use Cuda:                    NO
    Use Eigen:                   NO

  Python:
    Interpreter:                 /usr/bin/python2 (ver 2.7.3)
    Libraries:                   /usr/lib/libpython2.7.so (ver 2.7.3)
    numpy:                       /usr/lib/pymodules/python2.7/numpy/core/include (ver 1.6.2)
    packages path:               lib/python2.7/dist-packages

  Documentation:
    Build Documentation:         YES
    Sphinx:                      /usr/bin/sphinx-build (ver 1.1.3)
    PdfLaTeX compiler:           /usr/bin/pdflatex

  Tests and samples:
    Tests:                       NO
    Performance tests:           YES
    Examples:                    YES

  Install path:                  /usr

  cvconfig.h is in:              /usr/src/packages/BUILD/opencv-2.4.1+dfsg/obj-arm-linux-gnueabihf
-----------------------------------------------------------------

2014年12月20日土曜日

OpenCVで処理時間を調べる

以前は、処理時間の計測に
cv::getTickCount()
の差分を使用し処理時間の計算をしていた。

しかし、OpenCV2.4系のUtilityモジュールに計測用のクラス cv::TickMeter が準備されている。
なぜか、ドキュメントには記載されていない。

使用例

cv::TickMeter    tmeter; 
tmeter.start();
for (int i = 0 ; i < LOOP ; i++) {
    処理
}
tmeter.stop();
std::cout << tmeter.getTimeMilli() / LOOP;

単位はmsecである。

処理時間にばらつきが生じるので、複数回実行し、平均を求めている。

また、小数点1桁表示には
std::cout << cvRound(time / LOOP * 10.0)/ 10.0 << std::endl;
とすればよい。

残念ながら、3.0betaでは、使用できないので注意

OpenCVの計算の並列化

2.4.10では、IPPに対応していないが、TBBを使用することができる。

TBBを有効にしていないと、opencv_traincascadeでの学習時間が非常にかかってしまう。

有効にするには、cmakeのオプションに
 -DWITH_TBB=ON -DBUILD_TBB=ON
を指定すれば良い。途中でソースがダウンロードされ自動でビルドされる。

マニュアルのページでTBBで検索すると、対応しているAPIでは
The function is parallelized with the TBB library
のコメントが記載されている。

2.4.10で対応しているAPIは下記のものである。

CascadeClassifier::detectMultiScale()
solvePnPRansac()
CvDTree::train()
SURF::operator()
detail::FeaturesMatcher::operator()
CvGBTrees::predict()
CvKNearest::find_nearest()
distanceTransform()
calcOpticalFlowPyrLK()
CvANN_MLP::train()
CvNormalBayesClassifier::predict()
CvRTrees::train()
opencv_traincascade

以上

2014年12月15日月曜日

CaffeでMNISTの学習を試してみた。

ここに記載された手順に従い、CaffeでMNISTの学習をさせてみた。


1 データの取得と変換

MNISTのページはここ
手書きデータは、20x20の8bitグレースケールの画像を28x28の中心にanti-aliasingを行い変換したものとのこと

cd $CAFFE_ROOT
スクリプト
data/mnist/get_mnist.sh
の実行により data/mnist/ に、データがダウンロードされる

-rw-r--r-- 1 root root  7840016 Jul 21  2000 t10k-images-idx3-ubyte
-rw-r--r-- 1 root root    10008 Jul 21  2000 t10k-labels-idx1-ubyte
-rw-r--r-- 1 root root 47040016 Jul 21  2000 train-images-idx3-ubyte
-rw-r--r-- 1 root root    60008 Jul 21  2000 train-labels-idx1-ubyte

lmdbへのデータ登録
スクリプト
examples/mnist/create_mnist.sh
の実行により examples/mnist に、2つのlmdbデータができている

drwxr--r--  2 root root  4096 Dec  3 02:08 mnist_test_lmdb
drwxr--r--  2 root root  4096 Dec  3 02:08 mnist_train_lmdb

3 ソルバー定義をCPUに変更に変更
examples/mnist/lenet_solver.prototxt の最後の1行を

# solver mode: CPU or GPU
solver_mode: CPU
に変更

3 学習開始
スクリプト
examples/mnist/train_lenet.sh
を実行する。

train_lenet.sh のスクリプト中身は、
./build/tools/caffe train --solver=examples/mnist/lenet_solver.prototxt
である。

tools/caffeは、シンボリックリンクであり実体は、
lrwxrwxrwx 1 root root 55 Dec  7 06:39 ./build/tools/caffe -> /home/caffe/caffe-master/.build_release/tools/caffe.bin
である。

テストは、
lenet_solver.prototxtの
# The maximum number of iterations
max_iter: 10000
に記載された回数行われる。

最後のメッセージ

Snapshotting to examples/mnist/lenet_iter_10000.caffemodel
Snapshotting solver state to examples/mnist/lenet_iter_10000.solverstate
Iteration 10000, loss = 0.00377495
Iteration 10000, Testing net (#0)
Test net output #0: accuracy = 0.9907
Test net output #1: loss = 0.0270027 (* 1 = 0.0270027 loss)
Optimization Done.
Optimization Done.

精度は、0.9907となった。
CPUの場合Caffeの計算は、シングルコアで行われており、使用したマシンでは、計算時間に約23分使用した。

生成物
examples/mnist/に4個のファイルができている。

-rw-r--r--  1 root root 1724895 Dec  7 08:26 lenet_iter_10000.caffemodel
-rw-r--r--  1 root root 1724485 Dec  7 08:26 lenet_iter_10000.solverstate
-rw-r--r--  1 root root 1724895 Dec  7 08:14 lenet_iter_5000.caffemodel
-rw-r--r--  1 root root 1724484 Dec  7 08:14 lenet_iter_5000.solverstate

手書き文字の認識には、
MODEL_FILEには、lenet_iter_10000.caffemodelを使用する。

以上

CaffeによるMNISTのLeNetの学習を訳してみた

原文 Training LeNet on MNIST with Caffe は、ここ


Caffeがコンパイルできているものとする。このチュートリアルでは、CAFFE_ROOTにCaffeがインストールされているものとする

データセットの準備

MNISTのWebサイトからデータをダウンロードし変換する必要がある。以下のコマンドを実行する
cd $CAFFE_ROOT
./data/mnist/get_mnist.sh
./examples/mnist/create_mnist.sh

wgetやgunzipをインストールしておくこと コマンド終了後に、mnist_train_lmdb と mnist_test_lmdbのデータができている

LeNet: the MNIST Classification Model

学習プログラムを実行する前に、何が行われるか説明する。数字分類タスクで有名なLeNetを使用する。
オリジナルと若干異なるバージョンを使用する。
sigmoid activationsの代わりに、ニューロン用のRectified Linear Unit (ReLU) activationsを代わりに使用する

LeNetのデザインは、ImageNetのようなおおきなモデルに依然として使用されているCNNの本質を含んでいる。
一般的に、プーリング層に続く畳み込み層、別のプーリング層に続く畳み込み層、従来の多層パーセプトロンに似ている2つの全結合層からなる。
$CAFFE_ROOT/examples/mnist/lenet_train_test.prototxtに、層の定義を行う

MNISTネットワークの定義

MNISTの手書き数字分類タスクのためのLeNetモデル向け、lenet_train_test.prototxt モデル定義の説明を行う。
Google Protobufに関して知っているものとする。また、$CAFFE_ROOT/src/caffe/proto/caffe.proto にある、
Caffeが使用しているprotobufの定義を読んでいるものとする。

具体的には、caffe::NetParameter protobufを記述する

ネットワーク名から始める
name: "LeNet"

データ層の記述

デモで作成したlmdbからMNISTデータを読み込む。データ層に定義される

layers {
  name: "mnist"
  type: DATA
  data_param {
    source: "mnist_train_lmdb"
    backend: LMDB
    batch_size: 64
    scale: 0.00390625
  }
  top: "data"
  top: "label"
}

具体的にはこの層は、data タイプで、mnistの名前を有する。lmdbからデータを読み込む
バッチサイズ64を使用する。入力されるピクセルのレンジが[0,1)にスケーリングする

なぜ、0.00390625なのか、それは、1を256で割った値である。
この層は、データブロブとラベルブロブを出力する。

畳み込み層の記述

最初の畳み込み層を定義しよう

layers {
  name: "conv1"
  type: CONVOLUTION
  blobs_lr: 1.
  blobs_lr: 2.
  convolution_param {
    num_output: 20
    kernelsize: 5
    stride: 1
    weight_filler {
      type: "xavier"
    }
    bias_filler {
      type: "constant"
    }
  }
  bottom: "data"
  top: "conv1"
}

データ層により与えられるデータブロブを受け取り、conv1層を作成する。畳み込み関数のカーネルサイズ5で、ストライド1で、畳み込まれ、20チャンネルを出力する。
fillerは、ランダムに、重みとバイアスの初期化を行う。weight fillerには、入力と出力ニューロンの数を基準にし、初期化のスケールを決定する、xavierアルゴリズムを使用する。
bias fillerには、デフォルト値0の定数を単純に使用する。
blobs_lrは、層の学習可能なパラメータために、学習率の調整用である。

このケースでは、重み用の学習率を、実行時のソルバーにより与えられた学習率よ同じとし、バイアス学習率は、実行時のソルバーにより与えられた学習率の2倍とする。
通常より良く収束する、

プーリング層の記述

プーリング層の定義は簡単である

layers {
  name: "pool1"
  type: POOLING
  pooling_param {
    kernel_size: 2
    stride: 2
    pool: MAX
  }
  bottom: "conv1"
  top: "pool1"
}

プールカーネルのサイズを2でストライド2(隣の領域との重なりはないことを意味する)として、max poolingを行う。

同様に、2回めの畳込みとプーリングを記述する。詳細は、
$CAFFE_ROOT/examples/mnist/lenet_train_test.prototxt
をみること

全結合層の記述
結合層記述は単純

layers {
  name: "ip1"
  type: INNER_PRODUCT
  blobs_lr: 1.
  blobs_lr: 2.
  inner_product_param {
    num_output: 500
    weight_filler {
      type: "xavier"
    }
    bias_filler {
      type: "constant"
    }
  }
  bottom: "pool2"
  top: "ip1"
}

出力500の、内部的事情で、innerproductとcaffeでは呼んでいる全結合層の定義である。ほかは馴染ものものである。

ReLU層の記述
ReLU層の記述は単純

layers {
  name: "relu1"
  type: RELU
  bottom: "ip1"
  top: "ip1"
}

ReLU は要素ごとの操作なので、メモリー節約のために、 in-place操作とする

これは単に、top ブロブと bottomブロブの名前を同じにする。
もちろん、他の層と同じブロブ名を使用しないこと。

ReLU層のあとに、別のinnerproduct層を記述できる

layers {
  name: "ip2"
  type: INNER_PRODUCT
  blobs_lr: 1.
  blobs_lr: 2.
  inner_product_param {
    num_output: 10
    weight_filler {
      type: "xavier"
    }
    bias_filler {
      type: "constant"
    }
  }
  bottom: "ip1"
  top: "ip2"
}

Loss層の記述
最後にLoss層

layers {
  name: "loss"
  type: SOFTMAX_LOSS
  bottom: "ip2"
  bottom: "label"
}

Loss層には、softmaxとmultinomial logistic loss (時間の節約と安定性の向上)を定義できる。2つのブロブを持つ。
1つは、予測であり、もうひとつは、データ層により与えられたラベルである。これは、何も出力しない。損失関数の値を計算することではない。
バックプロパゲーションが開始され、ip2に関して勾配を開始した時に報告する。
すべての魔法が始まるところである。

記述ルール
層の定義は、ネットワークの定義の中に、含めるべきかどうか、あるいはいつ含めるかのルールを、下記のように含めることができる。
layers {
  // ...layer definition...
  include: { phase: TRAIN }
}

現在のネットワークの状態に基づき、ネットワーク層のインクルードを制御するルールである。
 $CAFFE_ROOT/src/caffe/proto/caffe.protoを参照すれば、モデルのスキーマと、層のルールの情報を得ることができる。

上記の例では、この層は学習フェーズでインクルードされる。もし、学習をテストに変えれば、テストフェーズのインクルードされるだろう。
デフォルトでは、層のルールがない場合、層は常にネットワークにインクルードされる。
lenet_train_test.prototxtでは、異なるバッチサイズの2つのデータ層を有し、1つは学習用、1つはテスト用である。
lenet_solver.prototxtに定義されているように、テストフェーズだけに含まれる、100回の繰り返しごとに、モデルの精度を報告する、精度層がある。

MNISTソルバーの定義

$CAFFE_ROOT/examples/mnist/lenet_solver.prototxtの各行の説明用のコメントを調べてみて下さい。

(別の機会に)

学習とテストモデル

ネットワーク定義protobufとソルバーprotobufを記述すれば、モデルのテストは簡単である。
train_lenet.shを実行するか、下記のコマンドを実行する。
cd $CAFFE_ROOT
./examples/mnist/train_lenet.sh

train_lenet.shは、簡単なスクリプトであり、簡単な説明を行う。学習用のメインのツールはcaffeであり、学習を行い、solver protobuf ファイルが引数である。

コードを実行すると下記のメッセージが表示され流れていく。このメッセージは、各層の詳細(各層の接続や出力形式)を示しており、デバッグに役立つだろう。

初期化のあと学習が始まる。
I1203 net.cpp:142] Network initialization done.
I1203 solver.cpp:36] Solver scaffolding done.
I1203 solver.cpp:44] Solving LeNet

ソルバーの設定により、100回の繰り返し事に学習ロスが表示される。
そして1000回の繰り返しごとに、ネットワークのテストを行い、下記のようなメッセージを見るだろう。

I1203 solver.cpp:204] Iteration 100, lr = 0.00992565
I1203 solver.cpp:66] Iteration 100, loss = 0.26044
...
I1203 solver.cpp:84] Testing net
I1203 solver.cpp:111] Test score #0: 0.9785
I1203 solver.cpp:111] Test score #1: 0.0606671

学習の繰り返しごとに、lrは、その繰り返しにおける、学習率である。lossは学習関数である。
学習フェーズの出力の場合、 score #0 は、精度で、score #1は、 損失関数である。

数分後に完了する。

I1203 solver.cpp:84] Testing net
I1203 solver.cpp:111] Test score #0: 0.9897
I1203 solver.cpp:111] Test score #1: 0.0324599
I1203 solver.cpp:126] Snapshotting to lenet_iter_10000
I1203 solver.cpp:133] Snapshotting solver state to lenet_iter_10000.solverstate
I1203 solver.cpp:78] Optimization Done.

バイナリーのprotobufファイルとして、lenet_iter_10000にモデルは保存される。
もし、実世界のデータを使用していたなら、あなたのアプリにモデルとして展開できる

CPUでの学習

全ての学習はGPUで行われた。もし、CPUで学習を行う場合、lenet_solver.prototxt ファイルの1行を

# solver mode: CPU or GPU
solver_mode: CPU

に変更すれば良い

MNISTのデータセットは小さいので、GPUは、データの転送のオーバヘッドが大きいので、恩恵が少ない。ImageNetのような巨大なデータセットでは、計算速度は非常に重要である。

以上

2014年12月9日火曜日

Caffeのインストール

一度挫折したが、本家の手順通りにやればほぼ問題なかった。ただし、クリーンなUbuntuを準備し、必要なモジュールは新規にインストールしている。
また、Caffeはmasterを使用している。

本家の手順を見なおしたら、cuDNN Caffeに関しての説明が追加されており、また、cuda関連も変わっている。今回、CUDAを使用せず、CPUモードなので関係がない。

Python版

Caffeのビルドが無事終了すると、Caffeのインストールディレクトリ python/caffe に_caffe.soができている。
pythonのパスに PYTHONPATH=cafferoot/pythonを追加し、python起動後にimport caffeが成功すればよい。

_caffe.soを含む、Caffeのpython一式を他のPCにコピーすれば、他のPCでもすぐにCaffeが使用できるかと一瞬考えたが、関連する共有ライブラリがターゲットのPC側にinstallしていないと結局動作しないことに気付き諦めた。

ldd _caffe.so で依存関係を調べるてみると、多くのモジュールを使用しており、共有ライブラリごとコピーするのも問題を起こしそうだ。

Caffeのmodelデータを取得してみた

モデル配布を行うmodel zooの説明はここ

./modelsには、以下のモデル情報が準備されている

drwxr-xr-x  2 root root 4096 Oct 20 20:53 bvlc_alexnet
drwxr-xr-x  2 root root 4096 Oct 20 20:53 bvlc_reference_caffenet
drwxr-xr-x  2 root root 4096 Oct 20 20:53 bvlc_reference_rcnn_ilsvrc13
drwxr-xr-x  2 root root 4096 Oct 20 20:53 finetune_flickr_style

ダウンロードには、予め
apt install python-yaml
でyamlのインストールが必要

Caffeのrootディレクトリで、model_zooの説明に従い、スクリプトを実行し、各モデルデータを取得する。

  • python scripts/download_model_binary.py models/bvlc_alexnet
  • python scripts/download_model_binary.py models/bvlc_reference_rcnn_ilsvrc13
  • python scripts/download_model_binary.py models/bvlc_reference_caffenet
  • python scripts/download_model_binary.py models/finetune_flickr_style


モデルファイルは、download_model_binary.pyで指定したフォルダーにダウンロードされる。

各モデルのファイルサイズは、以下である。

  • bvlc_alexnet.caffemodel 232M
  • bvlc_reference_rcnn_ilsvrc13.caffemodel 220M
  • bvlc_reference_caffenet.caffemodel 232M
  • finetune_flickr_style.caffemodel 217M

Caffe のモデル配布に関して訳してみた

オリジナルのドキュメントはここ

Caffe Model Zoo

多くの人が、AlexNet-alikesのような単純な回帰から、音声アプリケーションへの画像の類似性のためのSiameseネットワークまで、Caffeを異なる構成のモデル学習に使用し、異なる課題に適用した。これらのモデルの共有の摩擦を少なくするため、モデルZOOのフレームワークを紹介する

  • Caffeモデル情報をパッケージするための共通フォーマット
  • Githubへのモデルのuploadツールや、学習済み.caffemodel binariesのダウンロードツール
  • モデル情報共有のwiki

学習済みデータの取得方法

まずはじめに学習済みのモデルデータを提供する。
scripts/download_model_binary.py <dirname> 
のスクリプトを実行することで各データをダウンロードできる

dirnameは以下のものが使用できる

models/bvlc_reference_caffenet
 BVLC Reference CaffeNet : ILSVRC 2012で学習, NIPS 2012 paperを若干変更.

models/bvlc_alexnet
 BVLC AlexNet : ILSVRC 2012で学習, NIPS 2012とほぼ同じ

models/bvlc_reference_rcnn_ilsvrc13
 BVLC Reference R-CNN ILSVRC-2013 : caffe版のR-CNN

ユーザが作成したモデルは、wiki pageにUPされている。

モデル情報フォーマット

以下の内容を含むディレクトリーでモデルは配布されている
・Solver/model prototxt
・readme.md
 学習用のcaffeのバージョン
 オプション caffemodelのファイルURLとSHA1
 オプション githubのgist id
 何のモデルかの情報
 ライセンス情報
・オプションで、役立つスクリプト

モデル情報のホスティング

Github Gistは、複数のファイルを含むことができ、バージョン管理ができ、ブラウザで見れる記述ができるので、モデル配布に適したフォーマットである。

scripts/upload_model_to_gist.sh <dirname> で、Github Gistへのバイナリーを含まないモデルディレクトリーのファイルをUPし、Gist IDを表示する。
もし、gist_idが、<dirname>/readme.mdのfront matterの一部の場合、従来のものを更新する。

scripts/upload_model_to_gist.sh models/bvlc_alexnet を試してみれば良い。削除を忘れずに
scripts/download_model_from_gist.sh <gist_id> <dirname>でダウンロードできる

学習データのホスティング

Caffe modelファイルのホストは、ユーザ次第である。BVLCのモデルは、我々のサーバを使用している。Dropboxはふさわしいであろう。?dl=1をURLにつけるていることを確認

scripts/download_model_binary.py <dirname> は、<dirname>/readme.md のURLを使用し、Caffe modelをダウンロードし、SHA1の検査を行う。

OpenCV CMakeのTIPS

OpenCVのCMakeを使用してOpenCVのプログラムのビルドする方法は、ここに記載されている。
もし、CMakeで、find_package(OpenCV REQUIRED)のところでエラーになる場合には、

CMake関連ファイルを一旦削除し、パスを設定し、
export OpenCV_DIR=/usr/local/share/OpenCV
再度CMake . を実行すれば解決できる

OpenCV 3.0.0でLatentSVMを使用してみた

OpenCV3.0.0betaでは、LatentSVMは、Contribに移動した。モジュール一式は、opencv_contrib-master/modules/latentsvm/にある。

2.4.10との差異

2.4.10では、samples/c++にlatentsvm_multidetect.cppがあったが、3.0.0ではみつからない。
また、2.4.10のマニュアルは、ここにあるが、3.0.0betaでは、ドキュメントのWebページでの検索ではみつからない。一応、ドキュメントは、
opencv_contrib-master/modules/latentsvm/doc/latent_svm_cascade.rst
に準備されているので、概要を知ることができる。

辞書データの差異

2.4.10では、辞書を自分でダウンロードしないと行けない。ブラウザで
https://github.com/Itseez/opencv_extra/tree/master/testdata/cv/latentsvmdetector/models_VOC2007
を開き、対象の辞書をクリックし、右側のRAWのボタンを押すとxmlファイルがダウンロードされる。
3.0.0では、
opencv_contrib-master/modules/latentsvm/testdata/latentsvm/models_VOC2007_cascade/に
予めxmlファイルが準備されている。

試しに3.0.0の辞書データ(xmlファイル)を、2.4.10で読み込んでみると、コンストラクターのところでSegmentation faultになる。

LatentSVMのxmlファイルは、バイナリーデータが埋め込まれているので、エディタやブラウザーではうまく開けないが、それぞれ無理やりcat.xmlデータを開いて比較してみた。

2.4.10版
<Model>
    <!-- Number of components -->
    <NumComponents>2</NumComponents>
    <!-- Number of features -->
    <P>31</P>
    <!-- Score threshold -->
    <ScoreThreshold>-0.9846930000000000</ScoreThreshold>
    <Component>
        <!-- Root filter description -->
        <RootFilter>
            <!-- Dimensions -->
            <sizeX>11</sizeX>
            <sizeY>7</sizeY>
            <!-- Weights (binary representation) -->
            <Weights>

3.0.0版

<Model>
    <!-- Number of components -->
    <NumComponents>6</NumComponents>
    <!-- Number of features -->
    <P>32</P>
<PCAcoeff>

やはりデータフォーマットが異っている。3.0.0では、コンポーネントの数が増えているので性能が上がっているかもしれない。

CaffeのImageNetモデルを使用した分類の説明を訳してみた

Masaki Saito氏が、Caffeのチュートリアルに関する資料を公開してくれたが、理解できないことが多数あったので、本家のドキュメントを訳してみた。
専門家でないので、訳のおかしなところがあるのでご了承を

ImageNetによる分類

Caffeは、python/caffe/pycaffe.pyのcaffe.Netにより、python用のインタフェースを提供している。簡単に既成の分類ができるように、caffe.Classifierクラスと、classify.pyスクリプトを提供している。Python and MATLAB向けのラッパーを提供している。Python ラッパーは多くの特徴を有しており、ここで説明する。MATLAB向けは、matlab/caffe/matcaffe_demo.mを参考に

注意
ソースコードのコメントに、触れられていないが、ソースのコメントは重要である。


In [1]:
 説明なし

In [2]:
ネットワークの読み込みは簡単。caffe.Classifierがすべて面倒を見る
入力の前処理用のパラメータ構成
平均配列(mean)を与えることにより平均値の減算を行う
入力チャネルの入れ替え(channel_swap)は、RGBの並びを、ImageNetのBGR並びにする
スケール変換(raw_scale)は、入力値の[0:1]スケールをImageNet モデルの[0,255]に変更する

In [3]:
テストを行うなうので、フェーズをテストに設定する。最初は、計算をCPUで行う。

In [4]:
Out[4]:
Caffeの読み込みを利用し、サンプル画像を見てみる。


In [5]:
デフォルトでは、入力画像の、中心と4隅を切り出し、また、それぞれ反転画像を使用し、10回予測を行い、平均を計算する。
予測は1000次元で、希薄であることがわかる。予測クラスID281は、Tabby catである。
もし、 ../data/ilsvrc12/get_ilsvrc_aux.shを使用して、imagenetのデータを取得した場合は、我々のモデルは、 ../data/ilsvrc12/synset_words.txtに記されている、synsetのIDを使用している。予測スコアの最大値が示してるものを見ると、猫、キツネ、および他の可愛い哺乳類である。おかしくない結果ではないか

In [6]:
oversamplingをやめて中心の切り取り画像で分類してみよう。これは、1つの入力を示している。もし、モデル定義のprototxtを見てみると、networkのバッチサイズは10であることがわかる。pythonラッパが、バッチの処理を行う。

In [7]:
分類にかかる時間を見ることはできないのか。今回、Intel i5 CPUを使用しており、パフォーマンスの違いを見てみよう。
1回の処理 355msec
若干遅い気がするが、これには、切り出し、pythonインタフェース、10回の計算が含まれている。もう少し予測を速くしたいのであれば、C++で記述し、パイプライン処理を行うとよい。プロトタイプには、これくらいの速度があれば良い

In [8]:
前処理により、1枚の画像で分類してみる。
1回の処理 210msec

In [9]:
GPUを使用した場合はどうか、設定は簡単

In [10]:
Out[10]:
結果が同じか見てみよう。すべて同じである。

In [11]:
GTX 770 GPUを使用した同じマシンで、GPUの処理時間を見てみよう
Full pipeline timing.
1回の処理 174msec

Forward pass timing.
1回の処理 34.2msec

十分速いだろうが、期待した速度ではないかもしれない。Pythonデモで4倍の速度向上を得ている。GPUのコードは、実際とても速いが、データの転送、フォーマット変換などのオーバヘッドに数倍時間がかかっている。

GPUの処理能力を活かすには、
・バッチを大きくする、python呼び出しや、データ転送のオーバヘッドを小さくする
・subprocessに分割し、パイプライン処理を行う
・データセットが大きい場合には、面倒だがC++を使用する

最後に

これは、Pyhonである。十分に使いやすい。boost::pythonのラッパーであり、pycaffe.pyのpython/caffeクラスにメインのインタフェースのソースが書かれている。
また、classifier.pyに、分類用のラッパーがある。
あなた自身のカスタマイズを行うことができるので、改良を行い、我々にpull requestを送って欲しい。