kerasで指の本数を認識させる！（１）

kerasで指の本数を認識するモデルを作成しました。
最終的に転移学習により学習することで落ち着きました。

##環境
 Ubuntu 18.04.1 LTS
- python 3.6.6
- keras 2.2.2
- OpenCV 3.4.1
- tensorflow 1.10.0
- 
##ディレクトリ構成
hand/
　｜ーf0/img
　｜ーf1/img
　｜ーf2/img
　｜ーf3/img
　｜ーf4/img
　┗ーf5/img

learning.py

##最終的なコード
```py:learning.py
import os
import glob
import numpy as np
import cv2

from keras.models import Sequential, Model
from keras.applications.vgg16 import VGG16
from keras.layers import Dense, Dropout, Convolution2D, Flatten, MaxPooling2D, GlobalAveragePooling2D, Input
from keras.utils.np_utils import to_categorical
from keras.optimizers import Adagrad, Adam, SGD
from keras.callbacks import EarlyStopping

# parameter
data_dir = "hand"
W, H = 100,100
epoch = 10

input_dir = glob.glob(data_dir + "/*")
learn_class = len(os.listdir(data_dir))


def data_create():
    """ Read Images """

    label = []
    datas = []

    for i in input_dir:
        L = i[-1:]
        files = glob.glob(i + "/*")

        for j in files:
            label.append(L)
            img = cv2.imread(j)
            img = cv2.resize(img, (W, H))
            datas.append(img / 255.0)

    datas = np.array(datas,dtype="fload16")
    labels = to_categorical(label)
    return datas, labels


data = data_create()
# model Set Up
model_vgg = VGG16(
    include_top=False, weights="imagenet",
    input_tensor=Input(shape=(W, H, 3)))

set_model = model_vgg.output
set_model = GlobalAveragePooling2D()(set_model)
set_model = Dense(1024, activation="relu")(set_model)
set_model = Dense(512, activation="relu")(set_model)
pred = Dense(learn_class, activation="softmax")(set_model)
model = Model(input=model_vgg.input, output=pred)

for i in model_vgg.layers[:15]:
    i.trainable = False

sgd = SGD(lr=0.0001, momentum=0.9)
loss = "categorical_crossentropy"

model.compile(optimizer=sgd, loss=loss, metrics=["accuracy"])
model.summary()

early = EarlyStopping(monitor="val_loss", patience=3)

model.fit(
    data[0], data[1], epochs=epoch, batch_size=25,
    validation_split=0.15, callbacks=[early])

# create model file
model_json = model.to_json()
open("./hand_detection.json", "w").write(model_json)
model.save_weights("./hand_detection.h5")
```
生画像が、指一本に対し７００枚、認識に使った画像は指一本に対し約４０００枚づつです。
#解説

### 画像読み込み、正規化
ここで画像の読み込み、正規化を行います。クラス分けはディレクトリにより判別しています。

```py
def data_create():
    """ Read Images """
# クラスを格納
    label = []
# 画像データを格納
    datas = []
# handの中身（f0~f6）をリスト化
    for i in input_dir:
        L = i[-1:]
        files = glob.glob(i + "/*")
# 各ディレクトリの画像データをdatasへ格納
        for j in files:
# 各画像の格納ディレクトリをラベルとしてlabeolに格納
            label.append(L)
# 画像を読み込み
            img = cv2.imread(j)
# 画像をリサイズ
            img = cv2.resize(img, (W, H))
# 画像データをkerasにて読み込みさせるため画像データを0~1の
            datas.append(img / 255.0)

    datas = np.array(datas, dtype="float16")
    labels = to_categorical(label)
    return datas, labels
```

### モデル作成
VGG16を14層分使い以降を足して作成しました。
下記を参考にしました。
>引用　https://qiita.com/God_KonaBanana/items/2cf829172087d2423f58

```py
model_vgg = VGG16(
    include_top=False, weights="imagenet",
    input_tensor=Input(shape=(W, H, 3)))

set_model = model_vgg.output
# ここから自分で足したモデル
set_model = GlobalAveragePooling2D()(set_model)
set_model = Dense(1024, activation="relu")(set_model)
set_model = Dense(512, activation="relu")(set_model)
pred = Dense(learn_class, activation="softmax")(set_model)
model = Model(input=model_vgg.input, output=pred)
# ここでVGG16のモデル14層までの重みを固定
for i in model_vgg.layers[:15]:
    i.trainable = False
```

###　モデルを保存

```py
model_json = model.to_json()
open("./hand_detection.json", "w").write(model_json)
model.save_weights("./hand_detection.h5")
```
###　結果
最終的に val_accが約90％の結果になりました。
やはり転移学習はさすがの精度です。

```

```
###　あとがき
記事を書いてみて長くなりましたので試行錯誤したところは次回書きたいと思います。
学習に使ったツール、学習を使用してコマンドを実行するプログラムもGitHubに上げております。

>https://github.com/shun-yae/Hand-Gesture-Control

>https://github.com/shun-yae/keras-Hand-Detection