サナギわさわさ.json

サナギさんとキルミーベイベーとプログラミングが好きです

Vagrant上のUbuntuでTorch7のCPU開発環境を作る

男もすなるTorch7といふものを、女もしてみむとてするなり。
まずはVagrant上にUbuntuを立てて開発環境を作ります。
Vagrant上ではGPUは使えませんが、あくまで体験版という事で。あと私は男です。

インストール〜開発環境構築まで

UbuntuVagrantを作成してログイン

$ vagrant box add ubuntu-14.04 https://cloud-images.ubuntu.com/vagrant/trusty/current/trusty-server-cloudimg-amd64-vagrant-disk1.box
$ vagrant init ubuntu-14.04
$ vagrant up
$ vagrant ssh 

Torchのインストール

続いてTorchのインストールを行います。
不明点あればhttp://torch.ch/docs/getting-started.htmlをどうぞ。

$ curl -s https://raw.githubusercontent.com/torch/ezinstall/master/install-deps | bash
$ git clone https://github.com/torch/distro.git ~/torch --recursive
$ cd ~/torch; ./install.sh
$ source ~/.bashrc
$ th #Torchのコンソールが立ち上がる事を確認

Torchでよく使うパッケージのインストール

参考:http://ultraist.hatenablog.com/entry/2015/01/30/221102
※cutorch,cunnはCUDAを使うパッケージなので、GPU環境が無い場合は使えません。

$ luarocks install cwrap
$ luarocks install torch
$ luarocks install optim
$ luarocks install nn
$ luarocks install image
$ luarocks install cutorch
$ luarocks install cunn

Tutorial

ここまででTorchのインストールは終了ですが、せっかくなので簡単なTutorialをやります。
今回はCaffeの学習済みモデルをそのままTorchのモジュールに変換できるloadcaffeを使って、Network-in-Network Imagenetのモデルで分類をやってみます。

CUDAをインストール

vagrant上ではGPUは使えませんが、後々必要なのでCUDAのインストールを行います。
参考:https://github.com/BVLC/caffe/wiki/Ubuntu-14.04-VirtualBox-VM

$ sudo apt-get install build-essential
$ sudo apt-get install linux-headers-`uname -r`
$ sudo apt-get install curl
$ curl -O "http://developer.download.nvidia.com/compute/cuda/6_5/rel/installers/cuda_6.5.14_linux_64.run"
$ chmod +x cuda_6.5.14_linux_64.run
$ sudo ./cuda_6.5.14_linux_64.run --kernel-source-path=/usr/src/linux-headers-`uname -r`/
Do you accept the previously read EULA? (accept/decline/quit): accept #利用規約に同意
Install NVIDIA Accelerated Graphics Driver for Linux-x86_64 340.29? ((y)es/(n)o/(q)uit): n #VM上なのでグラフィックドライバは入れない
Install the CUDA 6.5 Toolkit? ((y)es/(n)o/(q)uit): y #Toolkitをインストールする
Enter Toolkit Location [ default is /usr/local/cuda-6.5 ]: #Toolkitのパスはデフォルト
Do you want to install a symbolic link at /usr/local/cuda? ((y)es/(n)o/(q)uit): y #シンボリックリンクをインストール
Install the CUDA 6.5 Samples? ((y)es/(n)o/(q)uit): y #CUDAサンプルをインストール
Enter CUDA Samples Location [ default is /root ]: #CUDAサンプルのパスはデフォルト

CUDAのパス設定及び依存関係のインストール

最後のapt-getはCaffeを使うために必要な依存関係なんですが、loadcaffeを使う場合必要ないものが混じっているかと思います。

$ echo 'export PATH=/usr/local/cuda/bin:$PATH' >> ~/.bashrc
$ echo 'export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/cuda/lib64:/usr/local/lib' >> ~/.bashrc
$ source ~/.bashrc
$ sudo apt-get update --fix-missing
$ sudo apt-get install -y libprotobuf-dev libleveldb-dev libsnappy-dev libopencv-dev libboost-all-dev libhdf5-serial-dev protobuf-compiler gfortran libjpeg62 libfreeimage-dev libatlas-base-dev git python-dev python-pip libgoogle-glog-dev libbz2-dev libxml2-dev libxslt-dev libffi-dev libssl-dev libgflags-dev liblmdb-dev python-yaml
sudo easy_install pillow

loadcaffeのインストール

ソースのダウンロード

luarocks install loadcaffeで簡単にインストールしたいところですが、
CPU環境で走らせた時にエラーが出てしまったので、git cloneでソースを落としてきて一部書き換えてからインストールを行います。GPU環境の人は普通にインストールして大丈夫かと思います。

$ git clone https://github.com/szagoruyko/loadcaffe
$ cd loadcaffe

ソースの一部書き換え

loadcaffeはデフォルトでCPU環境で使えないモジュールをrequireするためそのまま使うとエラーが出てしまいます。 なので、CPU環境でも動くようにloadcaffe/loadcaffe.cppのconvertProtoToLuaV1,convertProtoToLuaV2関数内の以下の箇所を書き換えます。
※SpatialStochasticPoolingはnnモジュールに無かったので、CPU環境では使えないかと思います。

変更前
ofs << "require '" << cuda_package << "'\n";
ofs << "require 'cunn'\n";
ofs << "local model = {}\n";
if(std::string(cuda_package)=="ccn2")
    ofs<< "table.insert(model, {'torch_transpose_dwhb', nn.Transpose({1,4},{1,3},{1,2})})\n";
else if(std::string(cuda_package)=="nn" || std::string(cuda_package)=="cudnn")
    ofs<< "require 'inn'\n";
case NN:
  if(param.pool() == caffe::PoolingParameter::MAX)
    sprintf(buf, "nn.SpatialMaxPooling(%d, %d, %d, %d, %d, %d):ceil()", kW, kH, dW, dH, padW, padH);
  else if(param.pool() == caffe::PoolingParameter::AVE)
    sprintf(buf, "inn.SpatialAveragePooling(%d, %d, %d, %d)", kW, kH, dW, dH); // padding is not supported yet
  else if(param.pool() == caffe::PoolingParameter::STOCHASTIC)
    sprintf(buf, "inn.SpatialStochasticPooling(%d, %d, %d, %d)", kW, kH, dW, dH);
  break;
変更後
ofs << "require '" << cuda_package << "'\n";
ofs << "local model = {}\n";
if(std::string(cuda_package)=="ccn2")
    ofs<< "table.insert(model, {'torch_transpose_dwhb', nn.Transpose({1,4},{1,3},{1,2})})\n";
else if(std::string(cuda_package)=="cudnn")
    ofs<< "require 'inn'\n";
case NN:
  if(param.pool() == caffe::PoolingParameter::MAX)
    sprintf(buf, "nn.SpatialMaxPooling(%d, %d, %d, %d, %d, %d):ceil()", kW, kH, dW, dH, padW, padH);
  else if(param.pool() == caffe::PoolingParameter::AVE)
    sprintf(buf, "nn.SpatialAveragePooling(%d, %d, %d, %d)", kW, kH, dW, dH); // padding is not supported yet
  else if(param.pool() == caffe::PoolingParameter::STOCHASTIC)
    sprintf(buf, "inn.SpatialStochasticPooling(%d, %d, %d, %d)", kW, kH, dW, dH);
  break;

コンパイル

ソースを書き換えたらコンパイルします。

$ luarocks make
$ th #Torchコンソール立ち上げ
$ require 'loadcaffe' #エラーが出ない事を確認

Tutorialプログラムの実行

事前準備

Torch7公式Tutorialの7_imagenet_classification/classify.luaを実行すると、
CaffeのNetwork-in-Network Imagenet学習済みモデルを用いて分類が行えます。
classify.luaはcuda()を使っておりそのままでは動かないので、cuda()関数を空実装に置き換えてくれるfakecudaモジュールを使います。(classify.lua内のcuda()を消すのでも大丈夫です)

$ luarocks install https://raw.githubusercontent.com/soumith/fakecuda/master/fakecuda-scm-1.rockspec
$ git clone https://github.com/torch/tutorials.git
$ cd tutorial/7_imagenet_classification
$ vi classify.lua
#ファイル頭に以下の2行を追加
use_cpu = true
require('fakecuda').init(use_cpu)

実行

デフォルトでは金魚画像の分類を行います。無事に分類されたら成功です。
あとは好きな画像で分類してみてください。

$ th classify.lua 
==> Loading network    
Successfully loaded ./nin_imagenet.caffemodel
.
.
.
predicted class 1:     goldfish, Carassius auratu
predicted class 2:     macaw   
predicted class 3:     lorikeet    
predicted class 4:     flamingo    
predicted class 5:     pinwheel

ちなみに

http://bunya1126.com/images/image/bunya_top_naikan.jpg

で分類してみた結果

predicted class 1:    restaurant, eating house, eating place, eatery
predicted class 2:     library 
predicted class 3:     bookshop, bookstore, bookstall
predicted class 4:     barber chair    
predicted class 5:     pool table, billiard table, snooker table

悪くないですね。

以上です。機械学習はモデルが既にあるなら特に難しい事は無いはずなのですが、何故かとっつきにくいイメージありますね。 次回があればOpenRestyを用いた簡易APIの作成や、Fine-Tuningを用いた独自分類モデルの作成を行いたいと思います。