48
47

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

転移学習で猫の品種を当ててみる

Last updated at Posted at 2018-09-13

実家で雑種の兄弟猫たちを飼っています。
その2匹が全然似ていないので、「ねこ品種判定AILINEbotをつくって品種割合を推定してみることにしました。

ねこ画像をLINE画面で送ると、構成される品種の割合が返される仕様です。

第二の目的として、Tensolflowの転移学習モデルInception-v3を試してみたかったというのもあります。

では早速実装の手順を解説していきます。
結果だけ知りたい人は、スクロールして最後の章へ...

#システム構成
システム構成は簡単に書くとこんな感じ。
学習モデルをherokuサーバに置いて、WebhookでLINEbotから呼び出します。
構成図.jpg

#使用したデータセット
画像を集める手段はいくつかありますが、スクレイピングは枚数の制限等が面倒で、オックスフォード大が公開しているデータセットを使いました。
http://www.robots.ox.ac.uk/~vgg/data/pets/)

cat.png

ねこちゃんいっぱい...

少し枚数は少ないですが、品種ごとにラベリングされた犬猫画像がまとめられています。今回はこのデータセットのうち猫の画像セットを使用します。
犬の画像を使えば犬種判定AIがつくれます。

##枚数
枚数は一品種あたり約200枚。12品種なので全部で2400枚です。
DeepLearningの世界ではちょっと少な目な枚数。

##含まれる品種
・アビシニアン
・ベンガル
・バーマン
・ボンベイ
・ブリティシュショートヘア
・エジプティアンマウ
・メインクーン
・ペルシャ
・ラグドール
・ロシアンブルー
・シャム
・スフィンクス
何やら聞きなれない品種もありますが、ひとまずこれで学習します。

ちなみに、最近Googleがデータセットを検索出来るサービスGoogle Dataset Searchをリリースしたようなので、今度はそれを使ってみたいです。(https://toolbox.google.com/datasetsearch)

#学習器をつくる(転移学習)
学習器はTnsolflowの転移学習モデルInception-v3を使いました。

転移学習とは、学習済みのモデルに、タスク固有のデータを追加で学習させることです。一般に、少ないデータ数でそれなりに高い精度のモデルが得られると言われています。

今回でいうと、様々なカテゴリの画像を学習済みのInception-v3モデルに、猫画像を追加で学習させて、ねこ品種判別に特化したモデルになるようパラメータを調整します。

まずはデータの前準備から。

x_size = 224
y_size = 224
kind_label = []
cat_img = []

#識別する品種のリスト
cat_list = ['Abyssinian','Bengal','Birman','Bombay','British_Shorthair','Egyptian_Mau','Maine_Coon','Persian'
            ,'Ragdoll','Russian_Blue','Siamese','Sphynx']

#データセットのロード
for cat_kind in cat_list:
    print(cat_kind)
    file_list = glob.glob('/path/to/cat/image/*.jpg')
    for file in file_list:
        img_path = file
        img = image.load_img(img_path, target_size=(x_size, y_size))
        x = image.img_to_array(img)
        x = preprocess_input(x)
        cat_img.append(x)
        kind_label.append(cat_kind) 

#品種ラベルをダミー化
Y_dummy = pd.get_dummies(kind_label)

X_train, X_test, y_train, y_test = train_test_split(
    cat_img, Y_dummy, test_size=0.2, random_state=42)

モデルを作っていきます。今回は最終段のみ再学習します。
以下のコードを変えることで再学習する範囲を調整することも可能です。需要があれば追記しようと思います。

model = InceptionV3(weights='imagenet')

# 中間層を出力するモデル
intermediate_layer_model = Model(inputs=model.input, outputs=model.layers[311].output)

feature = intermediate_layer_model.predict(x)
pd.DataFrame(feature.reshape(-1,1)).plot(figsize=(12, 3))

# Denseレイヤーを接続
x = intermediate_layer_model.output
x = Dense(1024, activation='relu')(x)
predictions = Dense(len(cat_list), activation='softmax')(x)

# 転移学習モデル
transfer_model = Model(inputs=intermediate_layer_model.input, outputs=predictions)

# 一旦全レイヤーをフリーズ
for layer in transfer_model.layers:
    layer.trainable = False

# 最終段のDenseだけ再学習する
transfer_model.layers[312].trainable = True
transfer_model.layers[313].trainable = True

transfer_model.compile(loss='categorical_crossentropy',
                       optimizer='adam',
                       metrics=['accuracy'])

#転移学習
transfer_model.fit(np.array(X_train), np.array(y_train), epochs=10,
                   validation_data=(np.array(X_test), np.array(y_test)))

#精度確認用に出力(必要に応じて)
loss, acc = transfer_model.evaluate(np.array(X_test), np.array(y_test))
print('Loss {}, Accuracy {}'.format(loss, acc))

最後にモデルをh5ファイルとして出力します。

transfer_model.save("./model.h5")

#LINEアカウントをつくる
以下のURLからLINE@アカウントを作ります。
https://at.line.me/jp/

「LINE@アカウントを作成する」>「一般アカウントを作成する」からLINEアカウントにログインし、必須項目を入力してアカウントを作成する。

アカウントを作成した後のbot設定は以下の通り。
・LINE@MANAGER画面> Messaging API設定 >API申し込み
・LINE Developersで設定するボタンをクリック
・”Channel Secret”、”アクセストークン”をメモしておく
・利用可能なAPIにREPLY_MESSAGEがあることを確認
・Webhook送信を「利用する」に

#herokuでサーバーを立てる
まずはherokuのアカウント登録から。
https://www.heroku.com/

無料で使えるサーバーを立てていきます。

##heroku環境導入
ローカルにherokuインストール
$ brew install heroku

ログインする
$ heroku login

アプリを作成
$ heroku create アプリ名

Herokuの環境変数にトークン追加
ここで上でメモしたLINEbotの情報が登場。”Channel Secret”、”アクセストークン”を使います。
$ heroku config:set LineMessageAPIChannelAccessToken={アクセストークン} --app アプリ名 $ heroku config:set LineMessageAPIChannelSecret={Channel Secret} --app アプリ名

準備するファイルはこちらの記事を参考にしました。(https://qiita.com/suigin/items/0deb9451f45e351acf92)

上記事中のapp.pyのみ画像を受け取って結果を返す仕様に変更しました。
(こちらもが需要があれば公開予定です。)
先ほど作った学習モデルはここで呼び出します。学習モデルのファイルはこのコードと一緒にherokuにデプロイしましょう。

一通りherokuへのデプロイが済んだところで、
$ heroku open
で出力されたWebhook URLをLINE Developersの設定画面に戻って設定すれば完了!

長かった...

#完成!
やっと完成したので、ひとまずラグドールの画像で試してみたら良い感じ!
そしてかわいい...

##うちの猫たちで試してみる
うちの雑種ちゃん2匹で試してみます。
長毛くんの方は...

53.8%がラグドール、34%でバーマンとのこと。ちゃんと長毛認識してそう。しかもどことなく面影が...?

まっくろちゃんの方は...

98%の確率でブリティッシュショートヘアー。確かにちょっとふてぶてしい表情とか似てる。
BS.jpg
画像引用:https://madoguchi.iyell.jp/british_short_hair_cat/

##結論
転移学習を使えば、大量の画像を用意しなくても、なんとなく当たってそうな識別器が出来た。
テストデータで正解率を見たら8割弱くらい。まだ改善の余地はあるが、少しのデータでここまでのモデルが出来るの結構すごい。

48
47
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
48
47

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?