【AI×ねこ】雑種猫の品種割合を当ててみる
実家で雑種の兄弟猫たちを飼っています。 その2匹が全然似ていないので、「ねこ品種判定AI」LINEbotをつくって品種割合を推定してみることにしました。
ねこ画像をLINE画面で送ると、構成される品種の割合が返される仕様です。
第二の目的として、Tensolflowの転移学習モデルInception-v3を試してみたかったというのもあります。
では早速実装の手順を解説していきます。 結果だけ知りたい人は、スクロールして最後の章へ...
システム構成
システム構成は簡単に書くとこんな感じ。 学習モデルをherokuサーバに置いて、WebhookでLINEbotから呼び出します。
使用したデータセット
画像を集める手段はいくつかありますが、スクレイピングは枚数の制限等が面倒で、オックスフォード大が公開しているデータセットを使いました。 (http://www.robots.ox.ac.uk/~vgg/data/pets/)
ねこちゃんいっぱい...
少し枚数は少ないですが、品種ごとにラベリングされた犬猫画像がまとめられています。今回はこのデータセットのうち猫の画像セットを使用します。 犬の画像を使えば犬種判定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%の確率でブリティッシュショートヘアー。確かにちょっとふてぶてしい表情とか似てる。 画像引用:https://madoguchi.iyell.jp/british_short_hair_cat/
結論
転移学習を使えば、大量の画像を用意しなくても、なんとなく当たってそうな識別器が出来た。 テストデータで正解率を見たら8割弱くらい。まだ改善の余地はあるが、少しのデータでここまでのモデルが出来るの結構すごい。