IT未経験 文系女子が、画像分析アプリを作成してみた🙌

:::note info
このブログはAidemy Premiumのカリキュラムの一環で、受講修了条件を満たすために公開しています
:::
# はじめに
もともとITやプログラミングは自分とは無関係かなと思っていた文系の私ですが、
業務効率化のためにVBAを学ぶ機会があり、自力で業務を自動化できる楽しさに目覚めた、という経緯がありました。
なんとなく理系男子だけのもの、と思っていたのですが、自分で書いたコードが動くのは面白く、
やってみたら思ったよりも適性があったなと感じた、という経緯がありました。

そうして事務仕事を効率化しながらぼんやり過ごしていたある日、そう、奴が現れたのです。。。 ChatGPT！！！

これから何が起きるんだろう。。。
当時私が従事していた仕事は、私よりも上位レイヤーの方々も失業するであろう未来が見えました。
そんなことがきっかけとなり、もともとデータを扱うことが好きだったこともあり、
Aidemyのデータ分析講座に申し込みました。

Aidemyでは、学び放題という制度を利用して、当初申し込んがデータ分析コース以外の講座も学ぶことができたので、
課題は画像分別アプリにて取り組むことにしました。
それでは以下にて、キリン、シマウマ、ウサギ、３種類の動物の画像を学習させて、
どの動物の画像か判別させるアプリを作成したいと思います。

# 実行環境
・Visual Studio Code
・Google Colaboratory

# データを集めよう！
データ収集については、以下の記事を参考にして、ネット上から収集しました。
Ptyhonのライブラリであるicrowlerを使うと、画像を簡単に収集することができるんですね。

https://zenn.dev/robes/articles/fb617fc0144e80

以下のようなコードを実行して、GoogleCoraborate上にフォルダを作成して、
データを保存していきます。

```python
!pip install icrawler
from icrawler.builtin import BingImageCrawler

crawler = BingImageCrawler(storage = {'root_dir' : './image'})
keywords = ['rabbit', 'zebra', 'giraff']

for keyword in keywords:
    crawler = BingImageCrawler(storage = {'root_dir' : './image/' + keyword})
    crawler.crawl(keyword = keyword, max_num = 50)    
```
これでGoogleCoraborateのimageフォルダ上に、キリン、シマウマ、ウサギの画像を
収集することができました！

# データを学習できる形式へ加工
それでは以下のようにして、データを学習できるように、各画像のパスを配列として格納したうえで、
データを学習用とテスト用に分割します。

```python
import os
import cv2
import numpy as np
import matplotlib.pyplot as plt
from tensorflow.keras.utils import to_categorical
from tensorflow.keras.layers import Dense, Dropout, Flatten, Input
from tensorflow.keras.applications.vgg16 import VGG16
from tensorflow.keras.models import Model, Sequential
from tensorflow.keras import optimizers

path_rabbit = os.listdir('./image/rabbit/')
path_zebra = os.listdir('./image/zebra/')
path_giraff = os.listdir('./image/giraff/')

img_rabbit = []
img_zebra = []
img_giraff = []

for i in range(len(path_rabbit)):
    img = cv2.imread('./image/rabbit/' + path_rabbit[i])
    b,g,r = cv2.split(img)
    img = cv2.merge([r,g,b])
    img = cv2.resize(img, (50,50))
    img_rabbit.append(img)

for i in range(len(path_zebra)):
    img = cv2.imread('./image/zebra/' + path_zebra[i])
    b,g,r = cv2.split(img)
    img = cv2.merge([r,g,b])
    img = cv2.resize(img, (50,50))
    img_zebra.append(img)

for i in range(len(path_giraff)):
    img = cv2.imread('./image/giraff/' + path_giraff[i])
    b,g,r = cv2.split(img)
    img = cv2.merge([r,g,b])
    img = cv2.resize(img, (50,50))
    img_giraff.append(img)

X = np.array(img_rabbit + img_zebra + img_giraff)
y =  np.array([0]*len(img_rabbit) + [1]*len(img_zebra) + [2]*len(img_giraff))

rand_index = np.random.permutation(np.arange(len(X)))
X = X[rand_index]
y = y[rand_index]

# データの分割
X_train = X[:int(len(X)*0.8)]
y_train = y[:int(len(y)*0.8)]
X_test = X[int(len(X)*0.8):]
y_test = y[int(len(y)*0.8):]

# 正解ラベルをone-hotの形にします
y_train = to_categorical(y_train)
y_test = to_categorical(y_test)
```

# 転移学習をしよう！

今回はモデルの作成に当たって、画像の特徴について、すでに大量のデータを読み込んで、
より深く学んでいるVGG16という学習済みモデルの頭脳を拝借します。
転移学習ですね。
これによって学習コストを大幅に削減することができます。

```python
# モデルにvggを使います
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.5))
top_model.add(Dense(3, activation='softmax'))

# vggと、top_modelを連結します
model = Model(vgg16.inputs, top_model(vgg16.output))

# vggの層の重みを変更不能にします
for layer in model.layers[:19]:
    layer.trainable = False

model.compile(loss='categorical_crossentropy',
              optimizer=optimizers.SGD(lr=1e-4, momentum=0.9),
              metrics=['accuracy'])

model.fit(X_train, y_train, batch_size=15, epochs=10, validation_data=(X_test, y_test))
```

# こんなアプリをつくりました
htmlなどのフォーマットはAidemyのものを使わせていただきまして、
このようなアプリを作成しました。
https://animal-classification-app.onrender.com/
よかったら画像を入れて遊んでみてください。

（精度的には7割程度なので、馬とゴリラでモデルに学習させて、
人間の顔をぶちこんだら、馬面かゴリラ顔かを判別するとして、
不正解という概念がないアプリをつくるのも面白いかなと思ったのですが、
悪ふざけがすぎると思い断念しました。。。）

# 考察
モデルの精度を向上させるため、学習の妨げとなるような、イラスト風のデータや、
動物が複数映り込んでしまい、輪郭が捉えがたくなるようなものは排除しました。
やはりデータのクレンジングが重要であり工程としても手間がかかる部分であるのは、
今回の課題を通してあらためて実感しました。
また、現在ではより上位のモデルも出ているので、それらを使用することであったり、
計算負荷が高くなってしまうのですが、画像の解像度をあげることも
より精度の向上に直結すると思います。

# 感想
機械学習の勉強やアプリ制作を通じて、今表に出ている技術の裏側を少し理解することができたように思います。
また、独学でこなしていくには内容が難しく、つらく感じることもあったのですが、
やっぱり理解ができて、コードが動く面白みはクセになりますね。
生成AIの登場で、プログラミングの学習は昔よりも格段に容易になったので、
はじめたタイミングもよかったなと思いました。

とはいえ実際に現役エンジニアの方から直接コツや改善方法をすぐに聞けたのもありがたかったです。
学んだ先にこういう世界があるんだなとイメージできるのは、将来のために勉強しているのだし、
やっぱり大事なことだなと実感しました。
ありがとうございました。