Edited at

MacOS+docker+Caffeで画像分類

More than 1 year has passed since last update.


やること

ゴリラの画像とチンパンジーの画像を分類してくれる分類器を作ろうと思います。

ゴリラの画像16枚、チンパンジーの画像16枚で試してみます。


環境

OS X El Capitan 10.11.6

今回はMacOSにDockerでCaffeを導入しようと思います。Ubuntuで導入した方が色々とよさそうな感じだったんですが、今回はDockerの使い方と軽くCaffeを触りたかっただけなのでMacOSにしました。


docker

DockerをMacにインストールする (更新:2017/5/26)

dockerが無事インストールできたら上のメニューバーに鯨のマークが出ます。可愛いですね。

docker version

Client:
Version: 17.09.1-ce
API version: 1.32
Go version: go1.8.3
Git commit: 19e2cf6
Built: Thu Dec 7 22:22:25 2017
OS/Arch: darwin/amd64

Server:
Version: 17.09.1-ce
API version: 1.32 (minimum version 1.12)
Go version: go1.8.3
Git commit: 19e2cf6
Built: Thu Dec 7 22:28:28 2017
OS/Arch: linux/amd64
Experimental: true

無事にdockerがインストールできました


Caffeの導入

gitでローカルに落としてから、docker buildしていきます。

-tはターミナル起動、-iはインタラクティブだそうです。



mac OS Xに、caffe+jupyter notebook環境構築メモ

git clone https://github.com/BVLC/caffe.git

cd Caffe/docker
docker build -t caffe:cpu cpu #dockerfileにしたがってimageを作ります。
docker run -p 8889:8888 -ti caffe:cpu /bin/bash
root@fl23o7yashof:/# cd /opt/caffe
root@fl23o7yashof:/opt/caffe# jupyter notebook --allow-root --ip 0.0.0.0 --no-browser

Jupyterが起動します。ない場合は適宜pip installしましょう

表示に接続するURLが出ているので8888を8889に変更すればipythonが開けます


前準備

早速訓練とかできるのかと思ったら、事前に前準備が色々と必要ですね。

今回はYahoo Blogの中盤に書いてあるCaffeを特徴抽出器として使った分類をやるために準備します。

①get_caffe_reference_imagenet_model.shを実行

cd examples/imagenet

wget https://raw.githubusercontent.com/sguada/caffe-public/master/models/get_caffe_reference_imagenet_model.sh
chmod u+x get_caffe_reference_imagenet_model.sh
./get_caffe_reference_imagenet_model.sh

②data/ilsvrc12/get_ilsvrc_aux.shを実行

cd ~/caffe/data/ilsvrc12/

./get_ilsvrc_aux.sh

③画像データを取得

cd ~/caffe/

wget http://www.vision.caltech.edu/Image_Datasets/Caltech101/101_ObjectCategories.tar.gz
tar xzvf 101_ObjectCategories.tar.gz

④imagenetのモデル定義ファイルをダウンロードしてきて、自分で編集できるようにコピーして編集

cd examples/imagenet

wget https://raw.githubusercontent.com/aybassiouny/wincaffe-cmake/master/examples/imagenet/imagenet_deploy.prototxt
cp imagenet_deploy.prototxt imagenet_feature.prototxt

imagenet_feature.prototxtの編集


imagenet_feature.prototxt

174   top: "fc6wi" # fc6->fc6wi

175 blobs_lr: 1
176 blobs_lr: 2
177 weight_decay: 1
178 weight_decay: 0
179 inner_product_param {
180 num_output: 4096
181 }
182 }
183 layers {
184 name: "relu6"
185 type: RELU
186 bottom: "fc6wi" # fc6->fc6wi

⑤特徴量を取り出せるようにfeature.pyを作成


feature.py

#! /usr/bin/env python

# -*- coding: utf-8 -*-
import sys, os, os.path, numpy, caffe

MEAN_FILE = 'python/caffe/imagenet/ilsvrc_2012_mean.npy'
MODEL_FILE = 'examples/imagenet/imagenet_feature.prototxt'
PRETRAINED = 'examples/imagenet/caffe_reference_imagenet_model'
LAYER = 'fc6wi'
INDEX = 4

IMAGE_DIR = 'path/to/imagedir'
image_number = 1

net = caffe.Classifier(MODEL_FILE, PRETRAINED)
#caffe.set_phase_test()
caffe.set_mode_cpu()
net.transformer.set_mean('data', numpy.load(MEAN_FILE))
net.transformer.set_raw_scale('data', 255)
net.transformer.set_channel_swap('data', (2,1,0))

for im in os.listdir(IMAGE_DIR):
image = caffe.io.load_image(IMAGE_DIR + '/' + im)
net.predict([ image ])
feat = net.blobs[LAYER].data[INDEX].flatten().tolist()

print(image_number),
for i,f in enumerate(feat):
print(str(i+1) + ":" + str(f)),
print()
image_number += 1


ディレクトリをいちいち指定するのが面倒だったので,feature.py内でディレクトリごと指定できるようにしました。最終的にSVMに入れる時のデータ形式を以下のようなlibsvm形式にしないといけないのでtxtデータも一つにまとめました。

python feature.py  > tmp.txt


tmp.txt

0 1:-44.596577 2:-30.565985 3:-26.004364 4:-1.526159 ...

1 1:-10.0806865692 2:-27.590259552 3:-25.8647613525 4:-2.82715797424 ...

最初の行に(1,1,277,277)みたいなものがプリントされましたが、今回は不要なので削除しました。

⑥SVMにかける

Ubuntuを触ったのは初めてなのですが、どうやらinstall libsvmではなくinstall libsvm-toolsじゃないとダメみたいです。

apt-get install libsvm-tools

svm-scale -s scale.txt tmp.txt > train_scaled.txt

#scale.txtとtrain_scaled.txtは新しく作られるファイルです。
svm-scale -r scale.txt test.txt > test_scaled.txt
svm-train -c 0.03 train_scaled.txt gorilla_chimp.model
#gorilla_chimp.model は新しく作られるファイル名です
svm-predict test_scaled.txt gorilla_chimp.model result.txt

これでうまくいくやろ!と思ったのですが、どうやらモデルを作成する時にクラスが教師の数だけ(今回はゴリラとチンパンジーを8枚ずつ入れたので、16クラス)出来てしまったので、正答率がめちゃめちゃ低くなってしまいました。そもそも正解値を入れるところなんてどっかにあったか?

調べてもよくわからなかったので、今回はsklearnを使ってcross validationを使うことにしました。

cross validationならばデータは一緒にまとめちゃっていいので、32枚のデータ全てでtmp.txtを作りスケーリングしたtxtデータをdata.txtとしました。0~15がゴリラ、16~31がチンパンジーの画像です。


learning.py

import sklearn

from sklearn import datasets
from sklearn.model_selection import train_test_split

#txtデータを加工
f = open("data.txt",'r')
string = f.readlines()
this_data = []
for i in range(len(string)):
x = string[i][string[i].find(" ") +1:].split(" ")
x.pop(len(x)-1)
sublist = []
for j in x:
j = float(j[j.find(":")+1:])
sublist.append(j)
this_data.append(sublist)

#正解値付与
this_target = []
for i in range(16):
this_target.append(0)
for i in range(16):
this_target.append(1)

#分類
X_train, X_test, Y_train, Y_test = train_test_split(this_data, this_target, random_state=1)
#random_stateはシード値

#学習
from sklearn.svm import SVC
model = SVC()
model.fit(X_train,Y_train)
from sklearn import metrics
predicted = model.predict(X_test)

#実行
metrics.accuracy_score(Y_test,predicted)


sklearn.model_sectionはcross_validationと書いてあるサイトが多かったですが、アップデートで場所が変わったみたいです。accuracy87.5でまあいい精度が出ました。

結局docker(Caffe)で使ったのは画像を4096次元のデータにするだけであとは全部sklearn頼りでした。もう少しdockerについて学ぼうと思います。


参考資料

CaffeのImageNetで特徴量抽出器を動かすまで

”Caffeで手軽に画像分類”の”Caffeを特徴抽出器として使った分類”をやってみた1

『Caffeで手軽に画像分類』が手軽にできない。

【Caffe】特徴量抽出を行いSVMで物体識別する