OSX10.10でCaffeをインストール、リファレンスモデルで画像を分類

**2015年4月22日現在の情報です**
**caffeは頻繁にアップデートを行うので今現在動くかは保証しかねます**

インストールからリファレンスモデルを用いて画像判別をします．
リファレンスモデルbvlc_reference_caffenet.caffemodelとclassify.pyを使用した画像識別についてまでです．


#caffeとは
ディープラーニングフレームワーク
非常に高速かつ開発が活発で人気の高いフレームワークです
詳しくは公式を見ましょう
http://caffe.berkeleyvision.org/

少し性能を見たい方は
[Caffe Demos](http://demo.caffe.berkeleyvision.org/)
に分類したい画像のURLを貼ると
公式のリファレンスモデルで画像分類を行ってくれます


#MacOSX10.10.3(yosemite)にインストールする
以下の記事も参考になるかと思います
[OS X 10.10（Yosemite）にCaffeをインストールする（libstdc++問題解決）](http://qiita.com/Leonhalt2714/items/8d7054f044b4f4603264)

#インストール環境について
・iMac 27-inch, Late 2013
・CPU 3.5 GHz Intel Core i7
・16 GB 1600 MHz DDR3
・GPU NVIDIA GeForce GTX 775M 2048 MB
・OS MaxOSX10.10.3 yosemite

#依存ライブラリを導入する
##Python
公式でAnacondaを推奨されているのでAnaconda-2.1.0を使用
Anacondaとはpythonに数値計算環境を構築するためにいろんなパッケージを導入したディストリビューションです。これを使用します

pyenvによって管理する
[pyenvを使ってMacにPythonの環境を構築する](http://qiita.com/1000ch/items/93841f76ea52551b6a97)
を参考に導入してください

本稿ではbrewを使用せずにpyenvをホームディクトリに作成
python環境をAnacondaに変更しました
2系と3系がありますが2系がベターかと

```bash:
pyenv install anaconda-2.1.0
pyenv global anaconda-2.1.0
pyenv local anaconda-2.1.0
```
anaconda-2.1.0にすでに導入されているはずですが、一応パッケージを確認しておきます．

```bash:
pip install -r caffe/python/python/requirements.txt
```
で必要パッケージを導入しましょう

##CUDA7.0
NAVIDIAから7.0以上を導入
現在は正式にリリースされたので登録不要
7.0以上であればlibc++でのコンパイルが可能
[NAVIDIA CUDA7 Downloads](https://developer.nvidia.com/cuda-downloads)


##その他のライブラリ
Homebrewでインストールします

```bash:
brew install --fresh -vd snappy leveldb gflags glog szip lmdb
```

##boost boost-pythonのインストール
ちまたではver1.55でないと動かないという情報がありましたが
boost1.57 と boost-python1.57で動いたのでそのまま

```bash:
brew install --build-from-source --fresh -vd boost boost-python
```
##protobufのインストール
必ず--with-pythonオプションを忘れないようにしましょう
つけないと、ビルド時にPROTOCうんぬんと怒られます

```bash:
brew install --build-from-source --with-python --fresh -vd protobuf
```



##openBLASのインストール

```bash:
brew tap homebrew/science
brew install homebrew/science/openblas
```

##hdf5のインストール
**おそらく、アップデートで改善されるので、問題なくruntestが行える場合はFormulaの変更の必要はありません**

runtestを行う際
**libhdf5_hl.8.dylib**
が見つからない、とエラーが出る場合があります（2015/4/22現在）

どうやらhdf5-1.8.14では
**libhdf5_hl.9.dylib**
がインストールされてしまうもよう、そこでHomebrewのFormulaを変更して
hdf5-1.8.13を導入します

```bash:
brew edit hdf5
```
urlとsha1を変更します

```ruby:
class Hdf5 < Formula
  homepage "http://www.hdfgroup.org/HDF5"
 --> url "http://www.hdfgroup.org/ftp/HDF5/releases/hdf5-1.8.13/src/hdf5-1.8.13.tar.bz2"
 --> sha1 "712955025f03db808f000d8f4976b8df0c0d37b5"
```

```bash:
brew install --build-from-source --fresh -vd hdf5
```

ひとまずこれで依存ライブラリは導入完了です

##makefileとmakefile.configの修正
[OS X 10.10（Yosemite）にCaffeをインストールする（libstdc++問題解決）](http://qiita.com/Leonhalt2714/items/8d7054f044b4f4603264)
ここも参考にしてください

##Makefileの修正
Makefileを修正しましょう

```bash:

#stdlib=libstdc++を-stdlib=libc++に変更
CXXFLAGS += -stdlib=libc++
LINKFLAGS += -stdlib=libc++
			
#BLAS_INCLUDEも通す（２行あるので一応両方通しておきましょう）			
BLAS_INCLUDE ?= /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/Headers/
```
			
##Makefile.comfigの修正
```bash:
#コンパイルをclangに変更
# To customize your choice of compiler, uncomment and set the following.
# N.B. the default for Linux is g++ and the default for OSX is clang++
CUSTOM_CXX := /usr/bin/clang++

#7以上なのでコメントアウト
# For CUDA < 6.0, comment the *_50 lines for compatibility.
CUDA_ARCH := -gencode arch=compute_20,code=sm_20 \
		-gencode arch=compute_20,code=sm_21 \
		-gencode arch=compute_30,code=sm_30 \
		-gencode arch=compute_35,code=sm_35 \
#-gencode arch=compute_50,code=sm_50 \
#-gencode arch=compute_50,code=compute_50

#アナコンダまわり
# Anaconda Python distribution is quite popular. Include path:
# Verify anaconda location, sometimes it's in root.
# ANACONDA_HOME := $(HOME)/anaconda
#ややこしいのでANACONDA_HOMEは使わないで、↓にパスかいていく
 PYTHON_INCLUDE := /Users/name/.pyenv/versions/anaconda-2.1.0/include /Users/name/.pyenv/versions/anaconda-2.1.0/include/python2.7 /Users/name/.pyenv/versions/anaconda-2.1.0/lib/python2.7/site-packages/numpy/core/include

# open for OpenBlas
BLAS := open

 BLAS_INCLUDE := /usr/local/Cellar/openblas/0.2.14/include
 BLAS_LIB := /usr/local/Cellar/openblas/0.2.14/lib

pythonのパスを通しておく
# We need to be able to find libpythonX.X.so or .dylib.
PYTHON_LIB := /Users/name/.pyenv/versions/anaconda-2.1.0/lib

libパス通しておく
# Whatever else you find you need goes here.
INCLUDE_DIRS := $(PYTHON_INCLUDE) /usr/local/include
LIBRARY_DIRS := $(PYTHON_LIB) /usr/local/lib /usr/lib /Developer/NVIDIA/CUDA-7.0/lib
```

#ビルドする
caffeの先頭のフォルダで

```bash:
make all -j8
make test -j8
```
-j8はコンパイルを並列化するオプションです，数字は並列数ですので環境にあわせて変えてください、シングルでビルドするとかなり時間がかかると思います．

テストを行う

```bash:
make runtest
```
しばらくいろんなテスト結果が出力された後

```bash:
YOU HAVE 2 DISABLED TESTS
```
と表示されれば大丈夫です

##pythonでCaffeを使用するためビルド
caffeの先頭フォルダで

```bash:
make pycaffe
```
を叩く！
今回はpython経由で動かすので忘れずに！

.bash_profileでパスをかけておく

```bash:
PYTHONPATH=/Users/name/caffe/pythonを通す
```

ビルド中に下記のようなエラーが出た場合は

```bash:
python/caffe/_caffe.cpp:1:10: fatal error: 'Python.h' file not found
#include <Python.h>  // NOLINT(build/include_alpha)
```
以下のpathを.bash_profileに追加

```bash:
CPLUS_INCLUDE_PATH=/Users/name/.pyenv/versions/anaconda-2.1.0/include/python2.7
```

##pythonでcaffeをimport
Protocが必要なので，pipでpythonに導入

```
pip install protobuf
```

pythonをインタラクティブモードで起動して

```python:
>>> import caffe
```
これで通ればok
こちらの環境では

```python:
caffe Fatal Python error: PyThreadState_Get: no current thread
```
とpythonが強制終了したので，以下のpathを.bash_profileで通した

```bash:
export DYLD_FALLBACK_LIBRARY_PATH=/Users/name/.pyenv/versions/anaconda-2.1.0/lib:/usr/local/cuda/lib:/usr/local/lib:/usr/local/cuda/lib:/usr/local/lib
```



#リファレンスモデルで画像分類を行う
[Caffeで手軽に画像分類](http://techblog.yahoo.co.jp/programming/caffe-intro/)
という記事がありますが，バージョンが変わっており，お手軽とはいかないです．
今回はこのページの最初の部分まで行います．

##リファレンスモデルのダウンロード

```bash:
caffe/models/bvlc_reference_caffenet/readme.md
```
によると以下のURLに存在するらしいので
http://dl.caffe.berkeleyvision.org/bvlc_reference_caffenet.caffemodel
からダウンロード

```bash:
caffe/models/bvlc_reference_caffenet/
```
以下に保存しておきます

##関連ファイルのダウンロード
caffe/data/ilsvrc12/get_ilsvrc_aux.sh
スクリプトを実行，
モデルの関連データを入手します．

##物体認識の画像
サンプルとして
![Serengeti_Elefantenbulle.jpg](http://upload.wikimedia.org/wikipedia/commons/5/59/Serengeti_Elefantenbulle.jpg)
このアフリカ象の画像について分類をしてみます．

```bash:
caffe/python/Elefante.jpg
```
として保存しておきます．

##classify.pyを使用して画像分類
```bash:
caffe/python/
```
で以下のコマンドを叩いて，分類を行います

```bash:
python classify.py --raw_scale 255 ./Elefante.jpg  ./result.npy
```
ここですんなりとクリアできればokですが
バージョンによって

```bash:
  File "classify.py", line 137, in <module>

    main(sys.argv)

  File "classify.py", line 109, in main

    channel_swap=channel_swap)

  File "/Users/name/caffe/python/caffe/classifier.py", line 34, in __init__

    self.transformer.set_mean(in_, mean)

  File "/Users/name/caffe/python/caffe/io.py", line 255, in set_mean

    raise ValueError('Mean shape incompatible with input shape.')

ValueError: Mean shape incompatible with input shape.
```
といったエラーがかえってくることがあります．

入力した'caffe/imagenet/ilsvrc_2012_mean.npy'をうまく扱えないようです．
原因はclassify.pyが使用している

```bash:
caffe/python/caffe/io.py
```
の253-254行目

```python:
if ms != self.inputs[in_][1:]:
	raise ValueError('Mean shape incompatible with input shape.')
```
にあるようです．
どうやら，新しく作られた部分がうまく機能していないようなので，古いCaffeで書かれていた書き方で書き直します

```python:
if ms != self.inputs[in_][1:]:
	print(self.inputs[in_])
	in_shape = self.inputs[in_][1:]
	m_min, m_max = mean.min(), mean.max()
	normal_mean = (mean - m_min) / (m_max - m_min)
	mean = resize_image(normal_mean.transpose((1,2,0)),in_shape[1:]).transpose((2,0,1)) * (m_max - m_min) + m_min
	#raise ValueError('Mean shape incompatible with input shape.')
```

以下のURLにも同じ問題があげられています
http://stackoverflow.com/questions/28692209/using-gpu-despite-setting-cpu-only-yielding-unexpected-keyword-argument



変更後もう一度，classify.pyを使用し

##実行結果
```
Loading file: ./Elefante.jpg
Classifying 1 inputs.
Done in 0.90 s.
Saving results into ./result.npy
```
と出ればokです.
判別結果がresult.pnyに保存されています.

result.npyの内容については
[Caffeで手軽に画像分類](http://techblog.yahoo.co.jp/programming/caffe-intro/)
で公開されている

```bash:
show_result.py
```
を使用すると結果を数値で見ることができます．

```bash:
$ python show_result.sh ../data/ilsvrc12/synset_words.txt result.npy 
1 | n02504458 African elephant, Loxodonta africana | 81.2%
2 | n01871265 tusker | 14.9%
3 | n02504013 Indian elephant, Elephas maximus |  3.3%
```
81％の確率でアフリカ象
14％で牙の生えた大きな生き物
3％でインド象であると
判断されました