keras データセット作成、画像分類　

kerasでサンプルのmnistだけやって、そのまま放置していたけどちょっと頑張ってやってみよう！と思い立ったのでその記録。
mnistのサンプルだとデータセットも用意されているし、なにより一つのファイルで全部やってるのでよくわかんなかったので
個別に作ってみようと思います。(numpyの使い方を理解していないので、先人の知恵を拝借しまくりました）




#データセット作成1（画像の準備）
女優さんの顔を分類するのがやってて苦ではないので黒木華さん、多部未華子さん、忽那汐里さん、松岡茉優さん、福原遥さんの5人で
やってみようかと思います。
一枚一枚集めるの大変なので、グーグルで画像検索した画面をプリントスクリーンしました。
![サンプル.png](https://qiita-image-store.s3.amazonaws.com/0/90606/cda6f39c-63d8-0d3c-910a-ae2aa8b7cab1.png)




そのファイルからopenCVで顔のみを検出しています。（顔じゃないファイルや違う人のファイルも複数出来てしまうのでそれの削除は手作業で）
画像ファイルが少ないので、またopenCVで左右反転、ぼかし、左右反転＋ぼかしをして水増ししてみました

```python:face_detect.py
import cv2
import matplotlib.pyplot as plt
import sys
from keras.preprocessing.image import array_to_img,img_to_array,load_img
import numpy as np
import os

cascade_path="/usr/local/lib/python3.5/dist-packages/cv2/data/haarcascade_frontalface_alt.xml"

X_train=[]
Y_train=[]

X_test=[]
Y_test=[]

l=os.listdir("/home/MyDataSets/input_file")
for i in l:
    result_dir=i.split(".")[0]
    os.mkdir("/home/MyDataSets/face/"+result_dir)

    m=os.listdir("/home/MyDataSets/input_file/"+i)
    n=0
    for target_file in m:
        origin_image=("/home/MyDataSets/input_file/"+i+"/"+target_file)
        print(origin_image)
        cascade=cv2.CascadeClassifier(cascade_path)
        image=cv2.imread(origin_image)

        image=cv2.cvtColor(image,cv2.COLOR_BGR2RGB)
        gray=cv2.cvtColor(image,cv2.COLOR_RGB2GRAY)

        facerect=cascade.detectMultiScale(gray,scaleFactor=1.1,minNeighbors=1,minSize=(10,10))

        for x,y,w,h in facerect:
            face=gray[y:y+h,x:x+w]
            face=cv2.resize(face,(128,128))
            save_path="/home/MyDataSets/face/"+result_dir+"/image_"+str(n)+".jpg"
            cv2.imwrite(save_path,face)
            n=n+1
            face=cv2.flip(face,1)
            save_path="/home/MyDataSets/face/"+result_dir+"/image_"+str(n)+".jpg"
            cv2.imwrite(save_path,face)
            n=n+1
            face=cv2.blur(face,(10,10))
            save_path="/home/MyDataSets/face/"+result_dir+"/image_"+str(n)+".jpg"
            cv2.imwrite(save_path,face)
            n=n+1
            face=cv2.blur(cv2.flip(face,1),(10,10))
            save_path="/home/MyDataSets/face/"+result_dir+"/image_"+str(n)+".jpg"
            cv2.imwrite(save_path,face)
            n=n+1
```

#データセット作成２
先ほど作ったファイルをkerasで読み込める形に変換（５個だけテスト用とし残りは訓練用にしました）

```python:make_dataset.py
import matplotlib.pyplot as plt
import sys
from keras.preprocessing.image import array_to_img,img_to_array,load_img
import numpy as np
import os

X_train=[]
Y_train=[]

X_test=[]
Y_test=[]

data=os.listdir("/home/MyDataSets/face")
for row in data:
    i=os.listdir("/home/MyDataSets/face/"+row)
    n=0
    for target_file in i:
        image=("/home/MyDataSets/face/"+row+"/"+target_file)
        if n>5:
            temp_img=load_img(image)
            temp_img_array=img_to_array(temp_img)
            X_train.append(temp_img_array)
            Y_train.append(row.split(".")[0])
            n=n+1
        else:
            temp_img=load_img(image)
            temp_img_array=img_to_array(temp_img)
            X_test.append(temp_img_array)
            Y_test.append(row.split(".")[0])
            n=n+1

np.savez("/home/MyDataSets/mydatasets.npz",x_train=X_train,y_train=Y_train,x_test=X_test,y_test=Y_test)
```

#訓練開始！
modelの設計は、ごく一般的なものではないかなと思います。
epochsを16としたのは、epochsを20で回した時に16epochs目が一番accがよかったので
そうしました（90くらい）
訓練時間は、古いノートPCで1時間半くらいでした

```python:train.py
import numpy as np
import keras
from keras import layers,models
from keras import optimizers
from keras.utils import np_utils

categories=["kuroki","kutuna","matuoka","tabe","fukuhara"]
nb_classes=len(categories)

f=np.load("/home/MyDataSets/mydatasets.npz")
X_train,Y_train=f['x_train'],f['y_train']
X_test,Y_test=f['x_test'],f['y_test']
f.close()

x_train=X_train.astype("float")/255
x_test=X_test.astype("float")/255
y_train=np_utils.to_categorical(Y_train,nb_classes)
y_test=np_utils.to_categorical(Y_test,nb_classes)

model=models.Sequential()
model.add(layers.Conv2D(32,(3,3),activation="relu",input_shape=(128,128,3)))
model.add(layers.MaxPool2D((2,2)))
model.add(layers.Conv2D(64,(3,3),activation="relu"))
model.add(layers.MaxPool2D((2,2)))
model.add(layers.Conv2D(128,(3,3),activation="relu"))
model.add(layers.MaxPool2D((2,2)))
model.add(layers.Conv2D(128,(3,3),activation="relu"))
model.add(layers.MaxPool2D((2,2)))
model.add(layers.Dropout(0.5))
model.add(layers.Flatten())
model.add(layers.Dense(512,activation="relu"))
model.add(layers.Dropout(0.25))
model.add(layers.Dense(nb_classes,activation="softmax"))
model.summary()

json_string=model.to_json()
open("/home/MyDataSets/train.json","w").write(json_string)

model.compile(loss="categorical_crossentropy",optimizer="rmsprop",metrics=["acc"])

model.fit(x_train,y_train,epochs=16,batch_size=128,validation_data=(x_test,y_test))

model.save_weights("/home/MyDataSets/train.hdf5")

score=model.evaluate(x_test,y_test,verbose=0)
print("test loss : ",score[0])
print("test acc : ",score[1])

```
#分類

下記のコードで実際にやってみましたが、うまく分類できているようでした（あんまりたくさんやってないのでなんとも言えませんが）

```python:features.py
import cv2
from keras import models
from keras.models import model_from_json
from keras.preprocessing.image import array_to_img,img_to_array,load_img
import numpy as np
cascade_path="/usr/local/lib/python3.5/dist-packages/cv2/data/haarcascade_frontalface_alt.xml"
model=model_from_json(open("/home/MyDataSets/train.json").read())

model.load_weights("/home/MyDataSets/train.hdf5")

cat=["黒木華","忽那しおり","松岡みゆ","多部未華子","福原遥"]
test_image=("/home/MyDataSets/test.jpg")
cascade=cv2.CascadeClassifier(cascade_path)
image=cv2.imread(test_image)
image=cv2.cvtColor(image,cv2.COLOR_BGR2RGB)
gray=cv2.cvtColor(image,cv2.COLOR_RGB2GRAY)
facerect=cascade.detectMultiScale(gray,scaleFactor=1.1,minNeighbors=1,minSize=(10,10))

x=facerect[0][0]
y=facerect[0][1]
w=facerect[0][2]
h=facerect[0][3]

face=gray[y:y+h,x:x+w]
face=cv2.resize(face,(128,128))
save_path="/home/MyDataSets/check.jpg"
cv2.imwrite(save_path,face)

img=load_img(save_path)
x=img_to_array(img)
x=np.expand_dims(x,axis=0)

f=model.predict(x)
if f[0,0]==1:
    print("黒木さんだと思われます")
elif f[0,1]==1:
    print("忽那さんだと思われます")
elif f[0,2]==1:
    print("松岡さんだと思われます")
elif f[0,3]==1:
    print("多部さんだと思われます")
elif f[0,4]==1:
    print("福原さんだと思われます")
```

#感想
ほとんどネットにある先人のコードをつまんだだけですがやってみると少し理解が深まったような気がします。。

#次回は・・

 [GANで画像生成をしてみます。](https://qiita.com/skyfish20ch/items/ef8b7e0db4a6903c730b "GANで画像生成をしてみます。")