あなたはどの犬に似ている?そっくり犬診断AIを作ってみた!

今回は、機械学習を用いて、人の顔がどの犬の種類に似ているのか判別するAIを作ってみました!

下記のリンクにアプリを作成したので、皆さんの自撮りを送信してどの犬種に似ているのか試してみてください!

【犬診断AIはこちら!】 https://aidemyml.herokuapp.com/


この記事では、今回開発した「そっくり犬診断AI」の開発過程を紹介していきます。

開発環境

 – Google Colablatory
 – Python3

モデルの紹介

今回の学習に使用したモデルは、2014年のILSVRC(大規模画像認識競技会)で優勝したGoogLeNetをファインチューニングしたものです。このモデルは大きく2つの特徴があります。1つ目の特徴としては、複数の畳み込み層やプーリング層からなるネットワークを定義し(下図参照)、これを通常の畳み込み層と同様に重ねて1つのCNNを作り出しています。

2つ目の特徴としては、GlobalAveragePooling(GAP)が使用されていることです。GAPは入力された特徴マップのサイズと同じサイズのAveragePoolingを行うPooling層です。全結合層を使用しないことでパラメータ数を大きく削減し、従来のモデルで問題となっていた過学習を防ぐことができます。このGAPの利用は、現在ではクラス分類を行うベストプラクティスとなっています。

使用するデータ

オックスフォード大学が提供している下記データが扱いやすそうだったので、それを使用しました。中身は12種類の猫の画像および25種類の犬の画像が、それぞれ約200枚入っています。
今回は犬の画像のみを使用して犬種判別器を作成します。

【リンク】https://www.robots.ox.ac.uk/~vgg/data/pets/

データの前処理

データがかなり重かったので、Google Colablatoryにて学習器の生成を実施しました。データのダウンロードから学習前までのデータの前処理に使用したコードを下記に記載します。

まずはデータのダウンロードから展開までです。

#Googleドライブをマウント
from google.colab import drive
drive.mount('/content/drive')
#今回の学習器生成に使用するデータをダウンロード
!wget -P "/content/drive/My Drive/download" https://www.robots.ox.ac.uk/~vgg/data/pets/data/images.tar.gz
#ダウンロードしたデータを展開
!tar zxvf "/content/drive/MyDrive/donwload/images.tar.gz"

データを展開した後は種類ごとにディレクトリを作成して、そのなかにそれぞれの種類の画像が入るようにします。

#必要なモジュールをインポート
import glob
import shutil
import os
 
#犬+猫の種類のリスト
kind_list = ['Abyssinian','Bengal','Birman','Bombay','British_Shorthair','Egyptian_Mau','Maine_Coon','Persian','Ragdoll','Russian_Blue','Siamese','Sphynx','american_bulldog','american_pit_bull_terrier','basset_hound','beagle','boxer','chihuahua', 'english_cocker_spaniel','english_setter', 'german_shorthaired','great_pyrenees','havanese','japanese_chin','keeshond','leonberger','miniature_pinscher','newfoundland','pomeranian','pug','saint_bernard','samoyed','scottish_terrier','shiba_inu','staffordshire_bull_terrier','wheaten_terrier','yorkshire_terrier']
#猫のリスト
cat_kind = ['Abyssinian','Bengal','Birman','Bombay','British_Shorthair','Egyptian_Mau','Maine_Coon','Persian','Ragdoll','Russian_Blue','Siamese','Sphynx']
#犬のリスト
dog_kind = ['american_bulldog','american_pit_bull_terrier','basset_hound','beagle','boxer','chihuahua', 'english_cocker_spaniel','english_setter', 'german_shorthaired','great_pyrenees','havanese','japanese_chin','keeshond','leonberger','miniature_pinscher','newfoundland','pomeranian','pug','saint_bernard','samoyed','scottish_terrier','shiba_inu','staffordshire_bull_terrier','wheaten_terrier','yorkshire_terrier']
 
#ダウンロードして展開した後のデータが見やすくなるように種別ごとにディレクトリを作成して画像を格納する。
 
for j in kind_list:
 if os.path.exists('/content/images/'+str(j)+'/') == True:
   pass
 else:
   os.mkdir('/content/images/'+str(j)+'/')
 
for j in kind_list:
 for i in range (1,500):
   if os.path.exists('/content/images/'+str(j)+'_'+str(i)+'.jpg') == False:
     pass
   else:
shutil.move('/content/images/'+str(j)+'_'+str(i)+'.jpg',"/content          /images/"+str(j)+'/')

次は犬の画像を読み込み、訓練データとテストデータに分割します。

#必要なモジュールをインポート
import tensorflow as tf
from tensorflow import keras
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from keras.preprocessing.image import load_img,save_img,img_to_array
from sklearn.model_selection import train_test_split
 
#読み込んだデータを格納するための空の配列を用意
data_img = []
kind_label = []
 
#読み込んだ画像を(224×224)にリサイズするために定義
img_size = 224
 
#dog_kindのリストに含まれている画像を読み込んでいく。
for j in dog_kind:
 for i in range(1,300):
   if os.path.exists('/content/images/'+str(j)+'/'+str(j)+'_'+str(i)+'.jpg') == False:
     pass
   else:
     file_path = glob.glob('/content/images/'+str(j)+'/'+str(j)+'_'+str(i)+'.jpg')
     img = load_img(file_path[0],target_size=(img_size,img_size))
     x = img_to_array(img)
     x = preprocess_input(x)
     data_img.append(x)
     kind_label.append(j)
 
#kind_labelをダミーデータに変換
Y_dummy = pd.get_dummies(kind_label)
 
#訓練データとテストデータを8:2で分割する
X_train,X_test,y_train,y_test = train_test_split(
   data_img,Y_dummy,test_size=0.2,random_state=42)
 
#numpy形式に変換しておく
X_train = np.array(X_train)
X_test = np.array(X_test)
y_train = np.array(y_train)
y_test = np.array(y_test)

モデル構成

今回は参考文献を参照して、InceptionV3をファインチューニングしてモデルを構成しました。なお、InceptionV3の重みは変更しないように固定しました。

#必要なモジュールをインポート
from keras.layers import Input,Dropout
from keras.applications.inception_v3 import InceptionV3,preprocess_input
from keras.models import Model
from keras.layers.core import Dense
from keras.layers.pooling import GlobalAveragePooling2D
from keras.optimizers import Adam
 
#転移学習に使用するmodelはInceptionV3
input_tensor = Input(shape=(224,224,3))
base_model = InceptionV3(include_top=False,weights='imagenet',input_tensor=input_tensor)
 
#出力を犬種の種別数を一致するようにカスタマイズ
x = base_model.output
x = GlobalAveragePooling2D()(x)
x = Dense(1024,activation='relu')(x)
predictions = Dense(len(dog_kind),activation='softmax')(x)
 
#モデルを連結させる。
transfer_model = Model(inputs=base_model.input,outputs=predictions)
 
#InceptionV3の重みは変更しないようにする
for layer in base_model.layers:
 layer.trainable = False
 
#モデルをコンパイルする
transfer_model.compile(loss='categorical_crossentropy',
                      optimizer='adam',
                      metrics=['accuracy'])

モデルの学習

下記の条件で学習を行いました。

#モデルの学習を行う
transfer_model.fit(X_train,y_train,batch_size=32,
                 epochs=10,
                 validation_data=(X_test,y_test))

学習状況はこんな感じです。訓練データで99%、テストデータで92%の精度が出ているので、200枚の画像でここまで精度が出ればいい方かなと思います。さらに分類精度を高めるにはさらに多くの画像が必要となることが予想され、imagedatageneratorを使用して学習データの水増しをすると、さらに分類精度が高まるのではないかと思います。

予測結果

いざ、筆者自身が何に似ているのか、今回作成したモデルで検証してみました。検証までのコードを下記に記載します。上位3種まで表示するようにしました。

#自分の顔が何の犬種に似ているのか判別する
file_path = "/content/自撮り.JPG"
img = load_img(file_path, target_size=(img_size,img_size))
img = img_to_array(img)
img = preprocess_input(img)
data = np.array([img])
 
#変換したデータをモデルに渡して予測した後、上位3種を抜き出す
unsorted_max_indices = []
result = transfer_model.predict(data)[0]
pred = np.argmax(result)
unsorted_max_indices = np.argpartition(-result,3)[:3]
y = result[unsorted_max_indices]
predict_list = []
for i in range(3):
 predict_list_index = [dog_kind[unsorted_max_indices[i]],y[i]]
 predict_list.append(predict_list_index)
predict_list = sorted(predict_list,key=lambda x:x[1],reverse=True)
for i in range(3):
 print("{}. {}".format(i+1,predict_list[i][0])))

果たして結果はというと。。

測結果全てに共通して言えることは茶色が多いことであり、日に焼けているという特徴を捉えることができていると思います。最初にミニチュアピンスチャーが出てきた理由としては黒いシャツを着ていたこと、2番目のヨークシャーテリアは入力した際の髪型がセンター分けで少し長めだったこと、3番目のチワワは目が大きいという特徴をそれぞれ捉えたのではないかと考えられます。

下記のリンクにアプリを作成したので、皆さんの自撮りを送信してどの犬種に似ているのか試してみてください!

【リンク】 https://aidemyml.herokuapp.com/

参考文献

(1)畳み込みニューラルネットワークの最新研究動向(〜2017)
(2)転移学習で猫の品種を当ててみる
(3)ネコと犬の種類判別器を作ってみた

プログラミング未経験からでもAIスキルが身につくAidemy Premium Plan

PythonやAIプログラミングを学ぶなら、オンライン制スクールのAidemy Premium Planがおすすめです。
「機械学習・ディープラーニングに興味がある」
「AIをどのように活用するのだろう?」
「文系の私でもプログラミング学習を続けられるだろうか?」
少しでも気になることがございましたら、ぜひお気軽にAidemy Premium Planの【オンライン無料相談会】にご参加いただき、お悩みをお聞かせください!