#やること
ゴリラの画像とチンパンジーの画像を分類してくれる分類器を作ろうと思います。
ゴリラの画像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の編集
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を作成
#! /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
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がチンパンジーの画像です。
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で物体識別する