全くの初心者が機械学習で雲の画像診断に挑戦したら

## はじめに
はじめまして。Qiita初投稿。エンジニア職を目指しAidemyで勉強中です。
初めてのAIアプリを作ってみての自分なりの経験をまとめます。先に結果を言いますと非常にできの悪いアプリになったため、温かい目で感想、アドバイスなどあればよろしくお願いします。

## 概要
何のアプリを作ろうか何も考えてなく、ぼーっと空を見ていてふと雲の画像識別を作ろうと考えました。
まず雲の種類は１０種類あるので、それぞれの画像がどの雲に該当するかを判断するモデルを作る。

## 流れ
1. まずは雲の写真を収集（１種類１００枚前後）
2. 写真からそれぞれの種類の雲を分類
3. 機械学習で雲の種類を学習させたモデルを作成
4. 結果と反省。モデルの精度向上を目指して
5. まとめ
 
言語はPython、環境はGoogle Colaboratoryを使用しました。

## 1. まずは雲の写真を収集（１種類１００枚前後）
１０種類の雲は「"巻積雲","巻層雲","巻雲","高積雲","高層雲","乱層雲","積乱雲","積雲","層積雲","層雲"」という風に分かれています。
!["巻積雲"](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2742491/cdf03cc8-0f06-4eb8-74d3-6e011bde29f8.jpeg) "巻積雲"
!["巻層雲"](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2742491/39cefd4a-6718-0e22-abbe-21da81aa894e.jpeg) "巻層雲"
!["巻雲"](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2742491/0c7ccc76-3a35-5960-ce28-403e7f933086.jpeg) 
"巻雲"
!["高積雲"](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2742491/1753bb7e-f146-1899-02a7-51237f1c2357.jpeg)
"高積雲"
!["高層雲"](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2742491/a15a3cf7-d78a-cfeb-4810-4bee16164873.jpeg)"高層雲"
!["乱層雲"](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2742491/9ca94807-3aad-1fcd-4980-0b12cd3faa8f.jpeg) 
"乱層雲"
!["積乱雲"](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2742491/6011e7ac-a5fd-52d9-3e12-12a5d1c60371.jpeg)
 "積乱雲"
!["積雲"](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2742491/15c9afaf-6be8-6566-5495-d435a24797fe.jpeg) "積雲"
!["層積雲"](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2742491/ced8b13c-1c63-5f65-7b84-f954c5844b19.jpeg) 
"層積雲"
!["層雲"](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2742491/e24b3347-83d4-e536-6eda-af8bf0043593.jpeg) "層雲"

画像を集める際にicrawlerという便利なPythonのパッケージを使いました。
icrawlerとはGoogle、Bing、Baidu、Flickrなどの画像検索サービスから画像をダウンロードしてくれる便利なPythonのパッケージです

使い方は下記のサイトを参考にしました。
https://atmarkit.itmedia.co.jp/ait/articles/2010/28/news018.html

１０種類の雲をそれぞれスクレイピングしフォルダに格納しました。

## 2. 写真からそれぞれの種類の雲を分類
画像を集めたものをチェックします。まず関係ない画像やイラストもとってきてたのでそれ削除し、スクレイピングしたものと違う雲の画像も多かったので正しいフォルダに画像を写す。
また、1つの画像に複数の種類の雲が写っていた場合は特定の種類の雲のみ切り取る。
ほぼ全ての画像に複数の種類の雲が写っていたので、この作業だけでも一苦労でした。

## 3. 機械学習で雲の種類を学習させたモデルを作成
インターネットから取得した画像は、cv２を用いて50×50にリサイズしてます。　
まず最初にvgg16モデルを使えば、それなりの精度のものが作れると思いモデルの作成を始めました。
VGG16というのは，「ImageNet」と呼ばれる大規模画像データセットで学習された16層からなるCNNモデルです。ここに全結合層を再度学習させてみました。
<details><summary>転移学習のコード</summary>

```py
input_tensor = Input(shape=(50, 50, 3))
vgg16 = VGG16(include_top=False, weights='imagenet', input_tensor=input_tensor)

top_model = Sequential()
top_model.add(Flatten(input_shape=vgg16.output_shape[1:]))
top_model.add(Dense(256, activation='relu'))
top_model.add(Dropout(0.3))
top_model.add(Dense(128, activation='relu'))
top_model.add(Dropout(0.3))
top_model.add(Dense(10, activation='softmax'))

model = Model(vgg16.input, top_model(vgg16.output))

for layer in model.layers[:15]:
    layer.trainable = False

model.compile(loss='categorical_crossentropy',
              optimizer=optimizers.SGD(lr=1e-4, momentum=0.8),
              metrics=['accuracy'])
```
</details>

しかし正答率が10％強にしかならず、層を増やしてもあまり変わらず、転移学習を使わずにやってみると
こちらではおおよそ30％の正答率になったのでこちらでモデルを作ることにしました。
<details><summary>転移学習を使わない場合</summary>

```py
model = Sequential()
model.add(Conv2D(filters=32, kernel_size=(2, 2), input_shape=(50, 50, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Flatten())
model.add(Dense(225))
model.add(Activation('relu'))
model.add(Dense(110))
model.add(Dropout(0.3))
model.add(Dense(255))
model.add(Activation('relu'))
model.add(Dense(110))
model.add(Dense(10))
model.add(Activation('softmax'))

model.compile(loss='categorical_crossentropy',
              optimizer='adadelta', 
              metrics=['accuracy'])
```
</details>

!["正解率"](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2742491/4d291ab4-390f-f66f-3a5c-00fa98517ba9.png)

訓練データは40回あたりから右肩上がりだが、検証データに対してはずっと横ばい。

## 4. 反省、モデルの精度向上を目指して
機械学習では、データ集めや前処理が大切と言われている通り、作業の中でいちばん時間を割くことになりました。特に雲の場合１枚１枚千差万別で１枚の画像の中に複数の雲が混じっていることなど当たり前で、あまり良く撮れてない画像などもあり、目で見てもどの種類か判別に苦労しました。また色や形など（半透明やしろ〜黒に近いグレー）で見分けるにしても、朝方や夕方、日が落ちる直前などの画像は見た目でもほぼ判別不可能だったので学習する画像から排除したりして正答率が若干上がりました。

こちらのサイトでもわかるように変種や部分的な特徴もだいぶ被っているので振り分けるのに苦労しました。
http://www1.linkclub.or.jp/~kinoko/AboutCloud.html

例えば、「積雲」の一種の雄大積雲と、無毛の「積乱雲」（いわゆる雷雲）の違いは雷があるかどうかだけなので画像で判別しようがないと思い、雄大積雲は積乱雲の方に入れました（一般の人にはどちらも入道雲と呼ばれている）。その他も少しの大きさの違いや厚み、雲の高さなどで分かれるのでかなり大変でした。

改良点ばかりなので、まず考えられるのは
・画像を増やす（集めたり、左右反転、水平移動、高いところの雲は回転させてもいいかも）
・空は「高層、中層、低層」に分かれているのでそれぞれの層別にモデルを作る。
・他の転移学習も試してみる。　　　
　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　など

## まとめ
自分がこの数カ月で学んだことはわずかだと思います。
これからの課題は山ほどありますが、とりあえず何かを作って行ったり、実践することが上達の近道だと思いますので、色々なアプリを作ったり、kaggleやsignateへの挑戦、数学的・統計的な知識などを積極的に学んでいこうと思います。

長く内容も薄いものになりましたが、ここまで読んでくださりありがとうございました。