画像認識で「レタスとキャベツと人参を判定する」AIをつっくてみた

## はじめに
Udemyの[画像判定AI自作にチャレンジ！]をやってみたのでアウトプット用として記事をかきました。
##環境
・windows
・anaconda
・python3.6
##画像収集
[pythonライブラリicrawlerを使い簡単に画像データを集める](https://qiita.com/NakaokaRei/items/8c7e7b1f2c0c7ef8b3a3)を参考にして画像を集めました。
集めてた画像を質の良いものだけにするために手作業で選択しました。


#実装概要
1.画像を学習/検証データにする
2.モデルを構築/学習する
3.flaskを使ってwebアプリ化

##1.画像を学習/検証データにする 
データについてラベリングを実施して学習用と評価用に分割します。

```gen_data.py
from PIL import Image
import os, glob
import numpy as np
import sklearn
from sklearn import model_selection

classes = ["cabbage","lettuce","gensing"]
num_classes = len(classes)
image_size = 80

# 画像の読み込み
#画像データをnumpyの配列に変換
X = []
Y = []
for index, classlabel in enumerate(classes):
    photos_dir = "./" + classlabel
    files = glob.glob(photos_dir + "/*.jpg")
    for i, file in enumerate(files):
        if i >= 93: break
        image = Image.open(file)
        image = image.convert("RGB")
        image = image.resize((image_size, image_size))
        data = np.asarray(image)
        X.append(data)
        Y.append(index)
#listからnumpyに変換
X = np.array(X)
Y = np.array(Y)
#データを学習用と評価用に分割する
#学習用と評価用を3:1の比率に分割
X_train, X_test, y_train, y_test = model_selection.train_test_split(X, Y)
xy = (X_train, X_test, y_train, y_test)
np.save("./vegetable.npy", xy)
```
##2.モデルを構築/学習する

トレーニングを実行するためのメインの関数を定義します。

```vegetable_cnn.py
from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D
from keras.layers import Activation, Dropout, Flatten, Dense
from keras.utils import np_utils
import keras
import numpy as np

classes = ["cabbage","lettuce","gensing"]
num_classes = len(classes)
image_size = 100

# メインの関数を定義する

def main():
    X_train, X_test, y_train, y_test = np.load("./vegetable.npy")#ファイルからデータを配列に読み込む
    X_train = X_train.astype("float") / 256#データを正規化
    X_test = X_test.astype("float") / 256
    y_train = np_utils.to_categorical(y_train, num_classes)
    y_test = np_utils.to_categorical(y_test, num_classes)

#トレーニング関数と評価関数の呼び出し
    model = model_train(X_train, y_train)
    model_eval(model, X_test, y_test)
```

次にトレーニング関数を作成します。
**シンプルにモデルを構築。**

```vegetable_cnn.py
#モデルの構築
#kerasのドキュメントを参考
def model_train(X, y):
    model = Sequential()
    model.add(Conv2D(32,(3,3), padding='same',input_shape=X.shape[1:]))
    model.add(Activation('relu'))
    model.add(Conv2D(32,(3,3)))
    model.add(Activation('relu'))
    model.add(MaxPooling2D(pool_size=(2,2)))
    model.add(Dropout(0.25))

    model.add(Conv2D(64,(2,2), padding='same'))
    model.add(Activation('relu'))
    model.add(Conv2D(64,(3,3)))
    model.add(Activation('relu'))
    model.add(MaxPooling2D(pool_size=(3,3)))
    model.add(Dropout(0.25))

    model.add(Flatten())
    model.add(Dense(512))
    model.add(Activation('relu'))
    model.add(Dropout(0.5))
    model.add(Dense(3))#画像の種類数によって変える
    model.add(Activation('softmax'))
#最適化の処理
    opt = keras.optimizers.rmsprop(lr=0.0001, decay=1e-6)
#正解と推定値の誤差が小さくなるようにする
    model.compile(loss='categorical_crossentropy',optimizer=opt,metrics=['accuracy'])
    model.fit(X, y, batch_size=20, epochs=75)

    # モデルの保存
    model.save('./vegetable_cnn.h5')

    return model
```

評価関数の作成です。

```vegetable_cnn.py
def model_eval(model, X, y):
    scores = model.evaluate(X, y, verbose=1)
    print('Test Loss: ', scores[0])
    print('Test Accuracy: ', scores[1])#精度の表示

if __name__ == "__main__":
    main()
```
##3.flaskを使ってwebアプリ化
[flask](http://flask.pocoo.org/docs/1.0/patterns/fileuploads/)のドキュメントを参考しています。



学習結果を載せときます。


```
204/204 [==============================] - 12s 57ms/step - loss: 1.1278 - acc: 0.4412
Epoch 2/50
204/204 [==============================] - 11s 51ms/step - loss: 0.9492 - acc: 0.5343
Epoch 3/50
204/204 [==============================] - 11s 52ms/step - loss: 0.8064 - acc: 0.6078
中略
Epoch 48/50
204/204 [==============================] - 14s 67ms/step - loss: 0.2428 - acc: 0.8922
Epoch 49/50
204/204 [==============================] - 15s 75ms/step - loss: 0.2876 - acc: 0.8676
Epoch 50/50
204/204 [==============================] - 17s 81ms/step - loss: 0.2715 - acc: 0.8676
69/69 [==============================] - 2s 28ms/step
Test Loss:  0.4421425206937652
Test Accuracy:  0.7971014501391978
```
学習用データでは86%で評価用では79%になりました。

##おわりに
今回は評価用では79%でしたが元の画像を増やすことや画像を回転・反転させ水増しさせるこによるなどの精度を上げるための策はまだあります。

記事にミスや改善点等がありましたらご指摘いただけると幸いです。