5種類くらいの画像認識やってみる【keras】

キノコを分類している方がいたのでやってみる。


```
https://www.nicovideo.jp/mylist/64449263
Yoideaさんのページ
```

#環境の構築
アナコンダの入っている状態で

```
conda install python=3.6
```
conda createで別の環境をつくってやってもいいと思います。
この環境構築は、3.7だと動かないパッケージがあるためです。
(エラーを確認したらおそらくnumpyの何かが3.7だと動かなくなってる様子)

画像を学習させるpythonのコードを写経します。

```python
#ファイル名はtrain.py
from keras.models import Sequential
from keras.layers import Activation, Dense
from keras.layers import Conv2D, MaxPooling2D, Flatten
from keras.preprocessing.image import ImageDataGenerator

def main():
    model = Sequential()
    model.add(Conv2D(64, (3,3), input_shape=(64,64,3)))
    model.add(Activation("relu"))
    model.add(MaxPooling2D(pool_size=(2,2)))
    model.add(Conv2D(64,(3,3)))
    model.add(Activation("relu"))
    model.add(MaxPooling2D(pool_size=(2,2)))
    model.add(Flatten())
    model.add(Dense(256))
    model.add(Activation("relu"))
    model.add(Dense(2))
    model.add(Activation("softmax"))
    #model.summary()
    model.compile(
        optimizer="adam",
        loss="categorical_crossentropy",
        metrics=["accuracy"])
    train_datagen = ImageDataGenerator(rescale=1./255)
    test_datagen = ImageDataGenerator(rescale=1./255)
    train_generator = train_datagen.flow_from_directory(
        "data/train",
        target_size = (64,64),
        batch_size=10)
    validation_generator = test_datagen.flow_from_directory(
        "data/validation",
        target_size = (64,64),
        batch_size=10)

    model.fit_generator(
        train_generator,
        steps_per_epoch=10,
        epochs=20,
        validation_data = validation_generator,
        validation_steps=10)
    model.save("data/model/model.h5")
    

if __name__ == "__main__":
    main()

```

判別してもらうスクリプトを写経します。

```python
#classify.py
import sys
from PIL import Image
#pip install は pillow
from keras.models import load_model
import numpy as np

def main():
    name = sys.argv[1]
    #print(name)
    image = Image.open(name)
    image = image.resize((64,64))
    image.show()
    model = load_model("data/model/model.h5")
    np_image = np.array(image)
    np_image = np_image / 255
    np_image = np_image[np.newaxis, :, :, :]
    result = model.predict(np_image)
    #print(result)
    if result[0][0] > result[0][1]:
        print("fol_A")
    else:
        print("fol_B")

if __name__ == "__main__":
    main()

```

学習用画像を入れておくフォルダを作成します。

例えば作業場所をデスクトップにしたいのなら

```
デスクトップにdataというフォルダを作成
data
 |-train
    |-学習用の画像を入れるフォルダ（フォルダ名は任意）
    |-学習用の画像を入れるフォルダ
 |-validation
    |-テストデータ入りフォルダ(フォルダ名はtrain内と同じ)
    |-テストデータ入りフォルダ
 |-model
    |-#train.pyを走らせるとmodel.h5が出来上がる場所。

```

スクリプトはすべてdesktopに直置きしてあるとする。
まずdataというフォルダがデスクトップならコマンドプロンプトをdesktopにうつしてから、train.pyを走らせる

```
C:\user> cd desktop
C:\user\desktop\ >python train.py 
```
スクリプト中のエポックの回数だけ学習が始まる。
終了するとmodelフォルダの中に学習結果が残る。

#画像判別

```
C:\user\desktop\ >python classify.py 判別したい画像のpath
```
画像のpathはいちいち書いてもいいが、dos画面にドラック&ドロップすると勝手にpathに書き換えてくれるので便利。
動かしてみると、

```
fol_B
```
二個目のフォルダの画像です
という結果がでました。

コメントアウトにしているresult部分を見てみると、

```
[[1.1806654e-12 1.0000000e+00]]
```
このような中身になっています。
右側がfol_Bというフォルダに入っている画像である確率です。


#少し応用する
二種類だけではさみしいので、5つくらいのフォルダを作って分類してみます。

```python
#train.py
    model.add(Dense(2))　
#の部分がフォルダ数(classes)になってるので書き換える
    model.add(Dense(5))　
```

classifyの方はif分が二つのフォルダに対しての場合で書いてあります。
これを書き換えます。最も高い確率のものをprintしてもらえるようにします。

resultの中身は[0,0,0,0,1]
のように5つの要素でできています。
IF文の部分を一致する要素を探すスクリプトに変更します。

```python
    result = np.argmax(result)
    if result == 0:
        print("A")
    elif result == 1:
        print("B")
    elif result == 2:
        print("C")
    elif result == 3:
        print("D")
    elif result == 4:
        print("E")
```
argmaxを使うと最大値のインデックスを引っ張ってきてくれるので便利。
最大値が全く同じ値になる場合は問題あり。

ここまで書き換えたら後は学習用の画像データを5種類分用意してフォルダー作成しておけば、あとは同じように走らせるだけです。

```
python classify.py #画像名
#print(result)のコメントアウトを外しただけの場合
#[[1.4949641e-04 8.2176529e-02 1.7416185e-02 8.1030893e-01 8.9948930e-02]]
#if文を書き換えた場合
# D
```

これで応用できたと思われます。