Help us understand the problem. What is going on with this article?

Caffeで機械学習 -1- リファレンスモデルを使って画像をカテゴリ分類

More than 3 years have passed since last update.

※ WIP。

はじめに

  • caffeいれたばかりで使い方よくわからない
  • 機械学習で何か実装してみたい
  • 論文読むより実装を通じて理解を深めていきたい
  • pythonはやったことない。インデントが大事だということぐらい
  • プログラミングはそれなりにやったことがある

ゴール

Caffeのリファレンスモデル(※有名な論文で使われているパラメータチューニングも終わってるモデル)を使って、Caltechの画像を分類すること。具体的に目に見える形として、以下のようなアウトプットを出すことがゴール。

(画像。無事実装が完了したら乗っける)

おおまかな手順

STEP1. 分類する画像データセットをダウンロード
STEP2. データセットの画像から特徴を抽出する
STEP3. 抽出した特徴を線形SVMで分類するためにSVMを学習させる。
STEP4. 学習させたSVMで特徴量からクラス分類

1. 分類する画像データセットをダウンロード

以下のページに飛び、Download。
http://www.vision.caltech.edu/Image_Datasets/Caltech101/#Download

2. データセットの画像から特徴を抽出する

2-1. リファレンスモデルのダウンロード

$ scripts/download_model_binary.py models/bvlc_reference_caffenet

2-2. 画像の特徴を抽出するためのコードの実装

リファレンスモデルを使って画像の特徴データを抽出。
色がRGBという3つの数値で表されるみたいに、今回のモデルでは1つの画像の特徴は 4096個の数値 で表される。
2-2.では入力:jpgデータ、出力:4096の数値データ、な処理を行うスクリプトを作成する。

以下をcaffeのルート・ディレクトリに作成。

feature_extraction.py
#! /usr/bin/env python
# -*- coding: utf-8 -*-
import sys, os, os.path, numpy as np, caffe

# path to git-cloned caffe dir
CAFFE_DIR  = os.getenv('CAFFE_ROOT')

MEAN_FILE  = os.path.join(CAFFE_DIR, 'python/caffe/imagenet/ilsvrc_2012_mean.npy')
MODEL_FILE = os.path.join(CAFFE_DIR, 'models/bvlc_reference_caffenet/deploy.prototxt')
PRETRAINED = os.path.join(CAFFE_DIR, 'models/bvlc_reference_caffenet/bvlc_reference_caffenet.caffemodel')

LAYER = 'fc7'
INDEX = 4

class FeatureExtraction:

    def __init__(self):
        net = caffe.Classifier(MODEL_FILE, PRETRAINED)
        caffe.set_mode_cpu()
        net.transformer.set_mean('data', np.load(MEAN_FILE))
        net.transformer.set_raw_scale('data', 255)
        net.transformer.set_channel_swap('data', (2,1,0))
        self.net = net

    def extract_features(self):
        imageDirPath = sys.argv[1]
        previousLabelName = ''
        labelIntValue = 0
        for root, dirs, files in os.walk(imageDirPath):
            for filename in files:
                if filename == '.DS_Store': 
                    continue
                fullPath  = os.path.join(root, filename)
                dirname   = os.path.dirname(fullPath)
                labelName = dirname.split("/")[-1]
                if labelName != previousLabelName:
                    labelIntValue += 1
                    previousLabelName = labelName
                image = caffe.io.load_image(fullPath)
                feat = self.extract_features_from_image(image)
                self.print_feature_with_libsvm_format(labelIntValue, feat)

    def build_test_data(self, imagePaths):
        for fullPath in imagePaths:
            image = caffe.io.load_image(fullPath)
            feat = self.extract_features_from_image(image)
            self.print_feature_with_libsvm_format(-1, feat)

    def extract_features_from_image(self, image):
        self.net.predict([image])
        feat = self.net.blobs[LAYER].data[INDEX].flatten().tolist()
        return feat 

    def print_feature_with_libsvm_format(self, labelIntValue, feat):
        formatted_feat_array = [str(index+1)+':'+str(f_i) for index, f_i in enumerate(feat)]
        print str(labelIntValue) + " " + " ".join(formatted_feat_array)

2-3. STEP1 でダウンロードした全画像の特徴データを一つのファイルに書き出す

上記の実行用のスクリプトを用意しておいて、

exec.py
#! /usr/bin/env python
# -*- coding: utf-8 -*-
import sys
from feature_extraction import FeatureExtraction 
FeatureExtraction().extract_features()

以下を実行して、特徴データ(feature.txt)を作成する。

$ python exec.py path/to/images_dir > feature.txt

手元のマシンでは1行目に

(10, 3, 227, 227)

という文字列が入ってしまう。
コレは特徴データではなく、別処理でのゴミprintみたいなものなので消しておく。

補足: 出力した特徴データのフォーマットについて

STEP3.ではlibsvmによるSVMの学習を行う。libsvmで扱うために、特徴データを以下のような形に書き出す必要がある。

...
4 1:0.89 2:0.19 3:0.10 ...  4096:0.77 
1 1:0.01 2:0.99 3:0.11 ...  4096:0.97 
...

1データが、

(labelの番号) 1:1番目の特徴量の数値 2:2番目の特徴量の数値 ...

という形で表されている。feature.txtでは画像枚数分の行数がある。

3. 抽出した特徴を線形SVMで分類するためにSVMを学習させる。

SVMには有名なlibsvmというパッケージを使う。
libsvmやsvmの説明はこのあたりが親切。

3-1. libsvmのインストール

$ brew install libsvm

3-2. 学習

SVMを学習させる。
以下のコマンドを打つ。

$ svm-scale -s scale.txt feature.txt > feature.scaled.txt
$ svm-train -c 0.03 feature.scaled.txt caltech101.model

svm-scaleはlibsvmでスケーリングを行うコマンドで、svm-trainが学習を行うコマンド。
各ファイルの意味は以下のとおり。

  • scale.txt: どうscaleしたかが保存してあるファイル。
  • feature.txt: 特徴データのファイル(STEP2で作成したもの)
  • feature.scaled.txt: スケーリング後の特徴データ
  • caltech101.model: 学習させたSVMのパラメータが保存されているファイル

4. 学習させたSVMでカテゴリ分類

※ WIP。多分SVMのところ勘違いしている疑惑。

4-1. 試しに同じデータで実験

$ cp feature.txt feature_test.txt
$ svm-scale -r scale.txt feature_test.txt > feature_test.scaled.txt
$ svm-predict feature_test.scaled.txt caltech101.model result.txt

...精度わるっ! now debugging...

Next Step 候補

  • ファインチューニングする
  • 一からモデル作る
  • Detection

8月中に3つともできれば。。。

参考にしたURLリスト

全体の流れにおいて

libsvm

FAQ

Q1. python/caffe/imagenet/ilsvrc_2012_mean.npyってなんぞ?

A. 平均画像のこと。以下を参照。

http://qiita.com/uchihashi_k/items/8333f80529bb3498e32f

Q2. SVMって2値分類器では?

A. 多値分類もできる。libsvmでは入力した教師データのクラスの数をさりげにカウントして、必要であれば多値分類器をつくるように、よしなにやってくれている...なんて甘い話ではなかった。

finc
健康寿命を伸ばすアプリFiNCの開発・運営を行うモバイルヘルステクノロジーベンチャー
https://finc.com
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした