Aidemyでの学習を記事にしてみました

#はじめに
私は高校卒業後工場勤務を５年ほどしていました。ある時友人に誘われて無料のプログラミング学習サービスを利用することになりました。それから自分が作成したプログラムがネット上に表示される事に楽しさを感じ理解を深めるためにAidemyを受講する事になりました。

#本記事の概要
・この記事は犬と猫の識別をするアプリのモデルの過程を記事にしました。どのような流れでモデルが作られ、どの様な工程を踏んで一つのアプリが完成するのかがこの記事をご覧いただいたら理解出来ると思います。
・この記事は何か始めたいけどキッカケが掴めない方、IT関係に興味があるけど難しそうだからなかなか一歩を踏み出せない方が、プログラムを触るキッカケになればと思いこの記事を書かせてもらってます。
・この記事ではpythonでの開発になりますのでpython関連以外の言語等は扱いませんのでご了承ください。


#アイデミーで学習した内容
・環境構築
・Python入門
・Numpy
・Pandas
・Matplotlib
・データクレンジング
・機械学習概論
・教師あり学習（分類）
・スクレイピング
・ディープラーニング基礎
・CNN
・男女認識
・HTML／CSS
・Flask入門
・MNISTを用いた手書き文字認識アプリ作成
・アプリ作成
・コマンドライン入門
・Git入門
・デプロイ
以上がカリキュラムの内容になります。この中でも特に理解に時間がかかったのは機械学習概論とディープラーニングです。

#犬猫識別アプリの開発
アプリをご覧いただきたい方は[こちら](https://sikibetu.herokuapp.com)から。

###モデル作成の詳細
####モデルの作成時はGoodle Colaboratoryを使用。
Google Colabのセルで下記コマンドを入力&実行すると、インストールが開始されます。

```
!pip install icrawler
```
次に画像を収集するプログラムを書きます。
下記を実行すると、catフォルダが作成され、100枚の画像が収集できます。

```python
from icrawler.builtin import BingImageCrawler

# 猫の画像を100枚取得
crawler = BingImageCrawler(storage={"root_dir": "cat"})
crawler.crawl(keyword="猫", max_num=100)
```
次に犬の画像を100枚収集します。

```python
from icrawler.builtin import BingImageCrawler

# 犬の画像を100枚取得
crawler = BingImageCrawler(storage={"root_dir": "dog"})
crawler.crawl(keyword="犬", max_num=100)
```
同様に上記実行すると、dogフォルダが作成され100枚の画像が収集出来ます。
ここまでで、100枚猫と犬の画像をダウンロードする事ができました。
それでは、そのうち1枚の猫の画像を表示してみます。

```python
# 猫の画像を表示
from IPython.display import Image,display_jpeg
display_jpeg(Image("./cat/000001.jpg"))
```
####データの整形と学習データの作成
画像をダウンロードしたので、次に入力データ（画像）の前処理とデータの分割を行います。

```python
from PIL import Image
import os, glob
import numpy as np
from PIL import ImageFile
# IOError: image file is truncated (0 bytes not processed)回避のため
ImageFile.LOAD_TRUNCATED_IMAGES = True

classes = ["dog", "cat"]
num_classes = len(classes)
image_size = 64
num_testdata = 25

X_train = []
X_test  = []
y_train = []
y_test  = []

for index, classlabel in enumerate(classes):
    photos_dir = "./" + classlabel
    files = glob.glob(photos_dir + "/*.jpg")
    for i, file in enumerate(files):
        image = Image.open(file)
        image = image.convert("RGB")
        image = image.resize((image_size, image_size))
        data = np.asarray(image)
        if i < num_testdata:
            X_test.append(data)
            y_test.append(index)
        else:

            # angleに代入される値
            # 画像を5度ずつ回転
            for angle in range(-20, 20, 5):

                img_r = image.rotate(angle)
                data = np.asarray(img_r)
                X_train.append(data)
                y_train.append(index)
                # FLIP_LEFT_RIGHT　は 左右反転
                img_trains = img_r.transpose(Image.FLIP_LEFT_RIGHT)
                data = np.asarray(img_trains)
                X_train.append(data)
                y_train.append(index)

X_train = np.array(X_train)
X_test  = np.array(X_test)
y_train = np.array(y_train)
y_test  = np.array(y_test)

xy = (X_train, X_test, y_train, y_test)
np.save("./dog_cat.npy", xy)
```
numpyのsave()によって、dog_cat.npyというファイル名で、データセットが作成出来ました。
1行目のPILはPython Imaging Librarという画像処理のためのライブラリになります。
####学習

ここでは認識モデルを作るためのメインのプログラムになります。
このプログラムを実行すると、機械学習を行います。
（機械学習では学習と推論の2つの工程があり、ここでは学習にあたります。）
#####グーグルコラボラトリーのランタイムをGPUにしている場合、1分かからない程で学習が終わります。


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

classes = ["dog", "cat"]
num_classes = len(classes)
image_size = 64

#データを読み込む関数

def load_data():
    X_train, X_test, y_train, y_test = np.load("./dog_cat.npy", allow_pickle=True)
    # 入力データの各画素値を0-1の範囲で正規化(学習コストを下げるため)
    X_train = X_train.astype("float") / 255
    X_test  = X_test.astype("float") / 255
    # to_categorical()にてラベルをone hot vector化
    y_train = np_utils.to_categorical(y_train, num_classes)
    y_test  = np_utils.to_categorical(y_test, num_classes)

    return X_train, y_train, X_test, y_test

#モデルを学習する関数

def train(X, y, X_test, y_test):
    model = Sequential()

    # Xは(1200, 64, 64, 3)
    # X.shape[1:]とすることで、(64, 64, 3)となり、入力にすることが可能です。
    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.1))

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

    model.add(Flatten())
    model.add(Dense(512))
    model.add(Activation('relu'))
    model.add(Dropout(0.45))
    model.add(Dense(2))
    model.add(Activation('softmax'))

    # https://keras.io/ja/optimizers/
    # 今回は、最適化アルゴリズムにRMSpropを利用
    opt = RMSprop(lr=0.00005, decay=1e-6)
    # https://keras.io/ja/models/sequential/
    model.compile(loss='categorical_crossentropy',optimizer=opt,metrics=['accuracy'])
    model.fit(X, y, batch_size=28, epochs=40)
    # HDF5ファイルにKerasのモデルを保存
    model.save('./cnn.h5')

    return model


#メイン関数データの読み込みとモデルの学習を行います。

def main():
    # データの読み込み
    X_train, y_train, X_test, y_test = load_data()

    # モデルの学習
    model = train(X_train, y_train, X_test, y_test)

main()
```
上記、プログラムをグーグルコラボラトリーのGPU環境の場合、数分で処理が終わります。
処理が終わると、cnn.h5がColab上に生成されます。

####推論
予測させたい犬や猫の画像をダウンロード&アップロードしましょう。
次のプログラムを貼り付けて、実行しダウンロードした画像をアップロードしましょう。
今回は、ダウンロードした犬の画像をdog1.jpgというファイル名でアップロードし、変数testpic に代入します。
画像はダウンロードしてきました。

```python
import keras
import sys, os
import numpy as np
from keras.models import load_model

imsize = (64, 64)

testpic     = "./dog1.jpg"
keras_param = "./cnn.h5"

def load_image(path):
    img = Image.open(path)
    img = img.convert('RGB')
    # 学習時に、(64, 64, 3)で学習したので、画像の縦・横は今回 変数imsizeの(64, 64)にリサイズします。
    img = img.resize(imsize)
    # 画像データをnumpy配列の形式に変更
    img = np.asarray(img)
    img = img / 255.0
    return img

model = load_model(keras_param)
img = load_image(testpic)
prd = model.predict(np.array([img]))
print(prd) # 精度の表示
prelabel = np.argmax(prd, axis=1)
if prelabel == 0:
    print(">>> 犬")
elif prelabel == 1:
    print(">>> 猫")
```
先ほどの犬の画像を予測させて見ると、次のように正しく認識できています。

```python
>>> 犬
```
念のために猫の画像でも検証を行います。
犬の画像と同様の方法で変数testpicを「./dog1.jpg」から「./cat1.jpg」に変更し、先ほどのコードを再度実行します 。
猫の画像は、インターネットからダウンロードしてアップロードしてください。
#####もし、より精度を上げたい場合には画像収集時の引数max_numを増やすことで学習に使うデータ数を増やして再学習させてみましょう。



#アプリを作成してみて
アプリの開発内容は自由だったので私は犬も猫を飼っているいるので犬と猫の識別アプリを作成することに決めました。アプリを開発する上で一番大事だと思ったことはモデルを作る過程で、モデルの出来次第でアプリの完成度はだいぶ変わってくる事に気付かされました。
今回は凝った内容のアプリを作成する事ができなかったのですが、次アプリを作成する際には今回の経験を生かしさらに完成度の高いアプリを作成しようと思います。

#最後に
Aidemyを受講しプログラムについて学べたことは私にとって良い経験になりました。プログラマーといえば独学で取得したり無料のサイトで勉強する事も可能ですが、お金を払って受講する事によって中途半端に理解が追いつかずに挫折する事もなく、理解できないところはチューターにカウンセリングをしてもらい問題解決することでモチベーションを保ち最後までやり抜く事ができました。