【入門】深層学習で犬・猫を分類してみる【2値分類, Tensorflow】

今回は、犬・猫を判別できるモデル(AI)を作っていこうと思います。

ディープラーニングのライブラリとしてTensorflow(Keras)を使っていきます。

tensorflow

Pythonが多少使えれば、TensorFlowもすぐ理解できると思います。

開発環境の用意

開発環境ですが、Python 3が使える環境であればなんでも大丈夫です。

無料でGPUが使えるColabというブラウザ上でPythonコードを書いて実行できるサービスがあるので、それを使うのもおすすめです。

もし、自分のPC内で実行するのであれば、コマンドラインや端末から以下のようにTensorflowなどをインストールして始めてください

pip install tensorflow

実装

では、実装していきます。

ソースコードは以下のリポジトリにあげています。
https://github.com/tocom242242/dog_cat_classification/blob/main/baseline.ipynb

使うモジュールのimport

今回、使うモジュール群を先にimportしておきます。

import os
import numpy as np
import matplotlib.pyplot as plt
import tensorflow as tf
from tensorflow.keras.models import Model, Sequential
from tensorflow.keras.layers import Dense, Conv2D, Flatten, MaxPooling2D, BatchNormalization
import copy
from IPython import display
from sklearn.model_selection import train_test_split

データの用意

cifar10というデータセットを使います。

cifar10は32×32のカラー画像のデータセットです。

cifar10
cifar10

このcifar10の中の犬・猫のデータを用います。

まず、データセットをimportします。
tensorflowに入っているものを使います。

(x_train, y_train), (x_test, y_test) = tf.keras.datasets.cifar10.load_data()

y_train = np.squeeze(y_train)
y_test = np.squeeze(y_test)

ラベルデータ(y_train,y_test)は無駄な次元があるので削除しています。

その後にcifar10から犬と猫だけ抽出します。

まずは犬・猫を抽出してみます。犬猫のラベルが猫:3, 犬:5となっているので、以下のように取得します。

cat_idx = 3
dog_idx = 5

x_cat_train = x_train[np.where(y_train==cat_idx)]
x_cat_test = x_test[np.where(y_test==cat_idx)]

x_dog_train = x_train[np.where(y_train==dog_idx)]
x_dog_test = x_test[np.where(y_test==dog_idx)]

取得した画像が、どんな画像か見てみます。まずは、犬の画像

def plot_imgs(input_imgs):
    plt.figure(figsize=(10,10))
    plt_idx = 1
    for i in range(36):
        plt.subplot(6,6,i+1)
        plt.xticks([])
        plt.yticks([])
        plt.grid(False)
        plt.imshow(np.squeeze(input_imgs[i]), cmap="gray", vmin=0, vmax=1)
    plt.show()

plot_imgs(x_dog_test)
犬の画像

猫の画像は

plot_imgs(x_cat_train)
猫の画像

犬と猫の画像が取得できていることがわかります。

次に、猫と犬の画像群を1つにして、入力データをつくります。正解ラベルとして犬は1、猫は0としていきます。

x_train = np.concatenate((x_cat_train, x_dog_train))
x_test = np.concatenate((x_cat_test, x_dog_test))

y_train = np.concatenate((np.zeros(x_cat_train.shape[0]),np.ones(x_dog_train.shape[0])))
y_test = np.concatenate((np.zeros(x_cat_test.shape[0]),np.ones(x_dog_test.shape[0])))

学習で使うデータの中で、実際に学習に使うデータと、学習中の性能評価で使うデータで分けておきます。


x_train, x_valid, y_train, y_valid = train_test_split(x_train,y_train,test_size=0.33, random_state=42)

これで、データは作り終えました。

モデル(ディープラーニングモデル)の作成

犬・猫を分類するモデルを作っていきます。畳込みニューラルネットワークを実装していきます。


では、実装していきます。

model = Sequential([
    Conv2D(16, 3, padding='same', activation='relu', input_shape=(32, 32 ,3)),
    MaxPooling2D(),
    Conv2D(32, 3, padding='same', activation='relu'),
    MaxPooling2D(),
    Conv2D(64, 3, padding='same', activation='relu'),
    MaxPooling2D(),
    Flatten(),
    Dense(512, activation='relu'),
    Dense(1, activation='sigmoid')
])

直感的に理解出来るかも知れませんが、modelのaddメソッドによって層を追加していっています。

まずは畳み込み層(CNN)を加えます。次にPooling層を加えて、それを何回か繰り返した後に、
最後に全結合の層を付けて、0か1を出力するようにします。

あとは最適化関数・誤差関数を定義します。modelのcompile関数で簡単に設定できます。

model.compile(optimizer='adam',
              loss='binary_crossentropy',
              metrics=['accuracy'])

学習

学習自体は簡単で、fit関数にデータを入れてあげるだけです。

history = model.fit(x_train, y_train, epochs=50, batch_size=32,validation_data=(x_valid, y_valid))

学習時の誤差の推移と正答率の推移をプロットしてみます。

history = history.history
plt.plot(np.arange(len(history["loss"])),history["loss"], label="loss")
plt.plot(np.arange(len(history["val_loss"])),history["val_loss"], label="val_loss")
plt.legend()
誤差の推移
plt.plot(np.arange(len(history["accuracy"])), history["accuracy"], label="accuracy")
plt.plot(np.arange(len(history["val_accuracy"])), history["val_accuracy"], label="val_accuracy")
plt.legend()
正答率の推移

loss(誤差)は減少していっていて、accuracy(正答率)は上がっていることがわかります。

学習しているデータに対してはかなり正確に答えられているようです。

一方で、学習に使っていないデータに対しての正答率はそこまで高くないです。

これは過学習が起きていることが考えれるのですが、また別の機会に記事にしたいと思います。

評価

まずは、学習に使ったデータに対してどのような出力したかを見ていきます。

一枚ずつ入れてみてどれを猫・犬と判定したかを見ていきます。

def plot_imgs_labels(model,input_imgs):
    plt.figure(figsize=(10,10))
    plt_idx = 1
    outputs = model(input_imgs, training=True)
    outputs = tf.squeeze(outputs).numpy()
    labels = np.round(outputs)

    plt_indexs = np.random.randint(0,len(labels),size=36)
    print(labels.shape)
    for i in range(36):
        plt.subplot(6,6,i+1)
        plt.xticks([])
        plt.yticks([])
        plt.grid(False)
        plt_i = plt_indexs[i]
        if plt_i == 1:
            label = "dog"
        else:
            label = "cat"
        plt.title("{}".format(label))
        plt.imshow(np.squeeze(input_imgs[plt_i]), cmap="gray", vmin=0, vmax=1)
    plt.show()

plot_imgs_labels(model, x_train)

訓練データに対してはうまく答えれているようです。

一方でテスト用データに対しては、

plot_imgs_labels(model, x_test)

先程の学習曲線でわかっていましたが、やはり微妙な結果ですね。これは先程も言った通り過学習が原因だと考えられます。

次回は過学習対策としていくつか工夫を加えたモデルを作って性能改善を目指す予定です。

終わりに

今回は簡単な犬・猫を分類するモデルを作って試してみました。

学習データに対しては良い性能を見せる一方で、テストデータに対しては今回のモデルではうまくいかないことを確認しました。

次回はテストデータに対しても良い性能を得ることができるモデルを作成してみようと思います。

参考文献

コメント

タイトルとURLをコピーしました