3
6

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.

【画像分類】犬の表情分析

Posted at

#1.はじめに
動物の表情分析に興味本位で手を出してみた。

#2.参考文献
"Kerasで「笑っている犬」と「怒っている犬」を判別する機械学習モデルを作る"
https://qiita.com/ariera/items/545d48c961170a784075

#3.内容
##3-1.データ前処理

# 画像を読み込んで、行列に変換する関数を定義
from keras.preprocessing.image import load_img, img_to_array
def img_to_traindata(file, img_rows, img_cols, rgb):
    if rgb == 0:
        img = load_img(file, color_mode = "grayscale", target_size=(img_rows,img_cols)) # grayscaleで読み込み
    else:
        img = load_img(file, color_mode = "rgb", target_size=(img_rows,img_cols)) # RGBで読み込み
    x = img_to_array(img)
    x = x.astype('float32')
    x /= 255
    return x

# 学習データ、テストデータ生成
import glob, os

img_rows = 224 # 画像サイズはVGG16のデフォルトサイズとする
img_cols = 224
nb_classes = 2 # 怒っている、笑っているの2クラス
img_dirs = ["./dog_angry", "./dog_smile"] # 怒っている犬、笑っている犬の画像を格納したディレクトリ

X_train = []
Y_train = []
X_test = []
Y_test = []
for n, img_dir in enumerate(img_dirs):
    img_files = glob.glob(img_dir+"/*.jpg")   # ディレクトリ内の画像ファイルを全部読み込む
    for i, img_file in enumerate(img_files):  # ディレクトリ(文字種)内の全ファイルに対して
        x = img_to_traindata(img_file, img_rows, img_cols, 1) # 各画像ファイルをRGBで読み込んで行列に変換
        if i < 8: # 1~8枚目までを学習データ
            X_train.append(x) # 学習用データ(入力)に画像を変換した行列を追加
            Y_train.append(n) # 学習用データ(出力)にクラス(怒=0、笑=1)を追加
        else:       # 9枚目以降をテストデータ
            X_test.append(x) # テストデータ(入力)に画像を変換した行列を追加
            Y_test.append(n) # テストデータ(出力)にクラス(怒=0、笑=1)を追加

import numpy as np
# 学習、テストデータをlistからnumpy.ndarrayに変換
X_train = np.array(X_train, dtype='float') 
Y_train = np.array(Y_train, dtype='int')
X_test = np.array(X_test, dtype='float')
Y_test = np.array(Y_test, dtype='int')

# カテゴリカルデータ(ベクトル)に変換
from keras.utils import np_utils
Y_train = np_utils.to_categorical(Y_train, nb_classes)
Y_test = np_utils.to_categorical(Y_test, nb_classes)

# 作成した学習データ、テストデータをファイル保存
np.save('models/X_train_2class_120.npy', X_train)
np.save('models/X_test_2class_120.npy', X_test)
np.save('models/Y_train_2class_120.npy', Y_train)
np.save('models/Y_test_2class_120.npy', Y_test)

# 作成したデータの型を表示
print(X_train.shape)
print(Y_train.shape)
print(X_test.shape)


from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation, Flatten
from keras.layers import Conv2D, MaxPooling2D

# 【パラメータ設定】
batch_size = 20
epochs = 30

input_shape = (img_rows, img_cols, 3)
nb_filters = 32
# size of pooling area for max pooling
pool_size = (2, 2)
# convolution kernel size
kernel_size = (3, 3)

# 【モデル定義】
model = Sequential()
model.add(Conv2D(nb_filters, kernel_size, # 畳み込み層
                        padding='valid',
                        activation='relu',
                        input_shape=input_shape))
model.add(Conv2D(nb_filters, kernel_size, activation='relu')) # 畳み込み層
model.add(MaxPooling2D(pool_size=pool_size)) # プーリング層
model.add(Conv2D(nb_filters, kernel_size, activation='relu')) # 畳み込み層
model.add(MaxPooling2D(pool_size=pool_size)) # プーリング層
model.add(Dropout(0.25)) # ドロップアウト(過学習防止のため、入力と出力の間をランダムに切断)

model.add(Flatten()) # 多次元配列を1次元配列に変換
model.add(Dense(128, activation='relu'))  # 全結合層
model.add(Dropout(0.2))  # ドロップアウト
model.add(Dense(nb_classes, activation='sigmoid'))  # 2クラスなので全結合層をsigmoid

# モデルのコンパイル
model.compile(loss='binary_crossentropy', # 2クラスなのでbinary_crossentropy
              optimizer='adam', # 最適化関数のパラメータはデフォルトを使う
              metrics=['accuracy'])

# 【各エポックごとの学習結果を生成するためのコールバックを定義(前回より精度が良い時だけ保存)】
from keras.callbacks import ModelCheckpoint
import os
model_checkpoint = ModelCheckpoint(
    filepath=os.path.join('models','model_2class120_{epoch:02d}.h5'),
    monitor='val_accuracy',
    mode='max',
    save_best_only=True,
    verbose=1)
print("filepath",os.path.join('models','model_.h5'))

# 【学習】
result = model.fit(X_train, Y_train, batch_size=batch_size, epochs=epochs, verbose=1, validation_data=(X_test, Y_test),
                   callbacks=[model_checkpoint],validation_split=0.1)

##3-2.学習

from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation, Flatten
from keras.layers import Conv2D, MaxPooling2D

# 【パラメータ設定】
batch_size = 20
epochs = 30

input_shape = (img_rows, img_cols, 3)
nb_filters = 32
# size of pooling area for max pooling
pool_size = (2, 2)
# convolution kernel size
kernel_size = (3, 3)

# 【モデル定義】
model = Sequential()
model.add(Conv2D(nb_filters, kernel_size, # 畳み込み層
                        padding='valid',
                        activation='relu',
                        input_shape=input_shape))
model.add(Conv2D(nb_filters, kernel_size, activation='relu')) # 畳み込み層
model.add(MaxPooling2D(pool_size=pool_size)) # プーリング層
model.add(Conv2D(nb_filters, kernel_size, activation='relu')) # 畳み込み層
model.add(MaxPooling2D(pool_size=pool_size)) # プーリング層
model.add(Dropout(0.25)) # ドロップアウト(過学習防止のため、入力と出力の間をランダムに切断)

model.add(Flatten()) # 多次元配列を1次元配列に変換
model.add(Dense(128, activation='relu'))  # 全結合層
model.add(Dropout(0.2))  # ドロップアウト
model.add(Dense(nb_classes, activation='sigmoid'))  # 2クラスなので全結合層をsigmoid

# モデルのコンパイル
model.compile(loss='binary_crossentropy', # 2クラスなのでbinary_crossentropy
              optimizer='adam', # 最適化関数のパラメータはデフォルトを使う
              metrics=['accuracy'])

# 【各エポックごとの学習結果を生成するためのコールバックを定義(前回より精度が良い時だけ保存)】
from keras.callbacks import ModelCheckpoint
import os
model_checkpoint = ModelCheckpoint(
    filepath=os.path.join('models','model_2class120_{epoch:02d}_{val_acc:.3f}.h5'),
    monitor='val_acc',
    mode='max',
    save_best_only=True,
    verbose=1)

# 【学習】
result = model.fit(X_train, Y_train, batch_size=batch_size, epochs=epochs, verbose=1, validation_data=(X_test, Y_test),
                   callbacks=[model_checkpoint])

##3-3.分類

from keras.models import load_model
from keras.preprocessing.image import load_img, img_to_array
import matplotlib.pyplot as plt

model = load_model('models/model_2class120_04.h5')
model.summary()

def img_to_traindata(file, img_rows, img_cols, rgb):
    if rgb == 0:
        img = load_img(file, color_mode = "grayscale", target_size=(img_rows,img_cols)) # grayscaleで読み込み
    else:
        img = load_img(file, color_mode = "rgb", target_size=(img_rows,img_cols)) # RGBで読み込み
    x = img_to_array(img)
    x = x.astype('float32')
    x /= 255
    return x

import numpy as np
img_rows = 224 # 画像サイズはVGG16のデフォルトサイズとする
img_cols = 224

## 画像読み込み
filename = "dog_smile/n02085936_37.jpg"
x = img_to_traindata(filename, img_rows, img_cols, 1) # img_to_traindata関数は、学習データ生成のときに定義
x = np.expand_dims(x, axis=0)

## どのクラスかを判別する
preds = model.predict(x)
pred_class = np.argmax(preds[0])
print("識別結果:", pred_class)
print("確率:", preds[0])

from keras import backend as K
import cv2

# モデルの最終出力を取り出す
model_output = model.output[:, pred_class]

# 最後の畳込み層を取り出す
last_conv_output = model.get_layer('conv2d_3').output #'block5_conv3').output

# 最終畳込み層の出力の、モデル最終出力に関しての勾配
grads = K.gradients(model_output, last_conv_output)[0]
# model.inputを入力すると、last_conv_outputとgradsを出力する関数を定義
gradient_function = K.function([model.input], [last_conv_output, grads]) 

# 読み込んだ画像の勾配を求める
output, grads_val = gradient_function([x])
output, grads_val = output[0], grads_val[0]

# 重みを平均化して、レイヤーのアウトプットに乗じてヒートマップ作成
weights = np.mean(grads_val, axis=(0, 1))
heatmap = np.dot(output, weights)

heatmap = cv2.resize(heatmap, (img_rows, img_cols), cv2.INTER_LINEAR)
heatmap = np.maximum(heatmap, 0) 
heatmap = heatmap / heatmap.max()

heatmap = cv2.applyColorMap(np.uint8(255 * heatmap), cv2.COLORMAP_JET)  # ヒートマップに色をつける
heatmap = cv2.cvtColor(heatmap, cv2.COLOR_BGR2RGB)  # 色をRGBに変換

img = plt.imread(filename, cv2.IMREAD_UNCHANGED)
print(img.shape)  # (330, 440, 4)

fig, ax = plt.subplots()
ax.imshow(img)

plt.show()

#4.分類結果

2020-04-26 21:12:46.904489: I tensorflow/compiler/xla/service/service.cc:168] XLA service 0x7fded852e7f0 initialized for platform Host (this does not guarantee that XLA will be used). Devices:
2020-04-26 21:12:46.904528: I tensorflow/compiler/xla/service/service.cc:176]   StreamExecutor device (0): Host, Default Version
Model: "sequential_1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1 (Conv2D)            (None, 222, 222, 32)      896       
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 220, 220, 32)      9248      
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 110, 110, 32)      0         
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 108, 108, 32)      9248      
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 54, 54, 32)        0         
_________________________________________________________________
dropout_1 (Dropout)          (None, 54, 54, 32)        0         
_________________________________________________________________
flatten_1 (Flatten)          (None, 93312)             0         
_________________________________________________________________
dense_1 (Dense)              (None, 128)               11944064  
_________________________________________________________________
dropout_2 (Dropout)          (None, 128)               0         
_________________________________________________________________
dense_2 (Dense)              (None, 2)                 258       
=================================================================
Total params: 11,963,714
Trainable params: 11,963,714
Non-trainable params: 0
_________________________________________________________________
識別結果: 1
確率: [0.27252397 0.6845933 ]
(375, 500, 3)

#5.今後の課題
精度をあげるための問題点を絞り込む必要がある。

3
6
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
3
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?