hellkite 日記と雑記とメモ。

Shiki Kazamaの駄文と音楽と、時々技術な感じ

Chainerで画像カテゴリ分類(学習したモデルで任意画像を分類する)


スポンサーリンク


モデルの保存処理等に問題があったため、修正しました。2016/10/25

前回CIFAR-10で学習したモデルデータを使って、任意の画像ファイルをカテゴリ分類してみます。ネットでよく見かけるのは学習して終わり、というも内容ですが、ここでは学習後のモデルデータを使った分類の方法です。
ひとまず、CIFAR-10のテストデータを使ってカテゴリ分類する方法を整理します。事前に必要なライブラリはインポートしておいてください。基本的に前回と同様にインポートすれば問題と思います。

前回記事はこちらです。
hellkite.hatenablog.com

モデルデータのロード

Chainerの学習済みモデルをロードします。pickleを使います。pickleは事前に定義が必要なので、以下のようにロードします。

# 保存したモデル定義
class Model(Chain):
    def __init__(self):
        super(Model, self).__init__(
            conv1=F.Convolution2D(3, 32, 3, pad=1),
            conv2=F.Convolution2D(32, 32, 3, pad=1),
            conv3=F.Convolution2D(32, 32, 3, pad=1),
            conv4=F.Convolution2D(32, 32, 3, pad=1),
            conv5=F.Convolution2D(32, 32, 3, pad=1),
            conv6=F.Convolution2D(32, 32, 3, pad=1),
            l1=F.Linear(512, 512),
            l2=F.Linear(512, 10)
        )
    def __call__(self, x):
        h1 = F.relu(self.conv1(x))
        h2 = F.max_pooling_2d(F.relu(self.conv2(h1)), 2)
        h3 = F.relu(self.conv3(h2))
        h4 = F.max_pooling_2d(F.relu(self.conv4(h3)), 2)
        h5 = F.relu(self.conv5(h4))
        h6 = F.max_pooling_2d(F.relu(self.conv6(h5)), 2)
        h7 = F.dropout(F.relu(self.l1(h6)),  train=False)
        y = self.l2(h7)
        return y

model = L.Classifier(Model())
optimizer = optimizers.Adam()
optimizer.setup(model)

# 保存したモデルを読み込み(2016/10/26更新!)
serializers.load_npz('model_cifar10.model', model)
serializers.load_npz('model_cifar10.state', optimizer)

pickleの使い方が良くわらからず、ハマりました・・・。ちゃんと調べればすぐ情報があるのに・・・。
serializersを使うとCPU/GPUを意識せずにセーブ/ロードできるそうです。便利。

CIFAR-10のテストデータを準備

モデルに入力するためのテストデータを準備します。画像ファイルを入れる前にCIFAR-10のテストデータを入れてみます。前回のコードを流用します。

import sys

def unpickle(file):
    fp = open(file, 'rb')
    data = pickle.load(fp, encoding='latin-1')
    fp.close()
    
    return data

# テスト画像を準備
test_data_dic = unpickle(os.getcwd()+"\\cifar-10\\test_batch")
X_test = test_data_dic['data']
X_test = X_test.reshape(len(X_test), 3, 32, 32)

# 正解データを準備
y_test = np.array(test_data_dic['labels'])

# 結果表示用のラベルを準備
batch_meta = unpickle(os.getcwd()+"\\cifar-10\\batches.meta")
label_names = batch_meta['label_names']

CIFAR-10のテストデータでの予測

predictorメソッドを使って結果を取得できます。X_testから1枚選んで予測します。

# 選ぶ画像のインデックス
index = 1

# 予測
test_data = test_data_dic['data'][index]
test_data = test_data.reshape(3, 32, 32)
test_data = test_data.astype(np.float32)
test_data /= 255

result = model.predictor(Variable(np.array([test_data])))

# 予測出力
for i in range(10):
    print (label_names[i] + " : " + str(result.data[0,i]))

出力結果がこんな感じ。とても船。

airplane : 4.58905
automobile : -2.67672
bird : -8.51865
cat : -9.40089
deer : -14.1304
dog : -9.87916
frog : -5.56871
horse : -9.97257
ship : 14.8575
truck : -12.6762

前回のコードを使って表示させてみると、確かに船。

f:id:deis:20161005101405p:plain

渡し方が分かったので任意の画像を渡してみる

ようやく本題です。model.predictor()に渡す形式が分かったので読み込んだ画像ファイルを使って評価してみます。
形式の変換部分は怪しいです・・・。結果が出ているのでいいことにしましたが・・・。

# 画像ファイルのインポート
import cv2
img_cv = cv2.imread(os.getcwd()+"\\data\\test.jpg")
img = img_cv[:,:,::-1].copy()

# 32×32にリサイズする
img_32 = cv2.resize(img, (32, 32))

# 形式を変換 (32, 32, 3)から(3, 32, 32)に変更してfloat32に変換
X = img_32.transpose(2, 0, 1)
x = X.astype(np.float32)
x /= 255

result = model.predictor(Variable(np.array([x])))

# 予測出力
for i in range(10):
    print (label_names[i] + " : " + str(result.data[0,i]))

テスト画像はGoogle画像検索で持ってきた画像なので載せませんが車の画像です。結果はこんな感じに。

airplane : -19.2472
automobile : 17.372
bird : -16.9361
cat : -11.5837
deer : -34.1684
dog : -14.336
frog : -6.05738
horse : -23.5941
ship : 6.34067
truck : 10.9464

人工物である車、トラック、船が大きな値になっていますね。今回一番高い数値は車なので合格ですね。
今回はCIFAR-10を利用しましたが、画像を使ったカテゴリ分類を一通り体験することができました。色々試せる下地になるかなと思います。