見出し画像

Aidemy AI画像認識アプリ開発コース


はじめに

みなさん、こんにちは。
28歳会社員、プログラミング完全初心者の私が、Aidemy AI画像認識アプリ開発コース3か月プランに挑戦してみました。

30歳手前の会社員をされている方なら共感してもらえると思いますが、これから自分はどういうキャリアを歩んでいくべきなのか、ITスキルがなくてやっていけるのか?という危機感はありませんか?

私はその危機感から独学で学ぼうとしたことはありましたが続きませんでした。そのときに思ったのは実際にプロダクトを作ってみないと面白味が分からずに挫折してしまうということです。

そんなときに株式会社Aidemyのサービスを知って、ここなら会社員で仕事しながらでも短期間でプロダクトを作るところまでやり遂げられると思い3か月コースに挑戦してみました!

また専門実践給付金制度という授業料の還付が受けられる制度もあり、金銭面でのハードルも低いのがよいと思いました。

Aidemyの概要
https://aidemy.net/grit/premium/?utm_source=aidemy&utm_medium=hp&utm_campaign=fv

本記事の概要

この記事は、プログラミング初心者だけど、興味があって学んでみたい!独学で学んでみたけど挫折した、、という人に参考になると思います。

特に教養として学んでみたいという方に役に立つ情報ですので、エンジニアとして転職したとか、玄人の方には物足りない内容だと思います。

この記事を読んだら以下のことがわかりますので興味のある人はぜひ最後まで読んで参考にしてくださいね!

● 教養として学ぶのにこのコースはどうなの?
● 実際に3か月でどんなアプリが作れるようになるの?
● 初心者でも仕事をしながら3か月でアプリ作成まで本当にできるの?

アイデミーでの学習振り返り

・学べる事(コース)

・Pythony入門
・NumPy、Pandas、Matplotlib基礎
・データクレンジング
・機械学習入門
・教師あり学習
・スクレイピング
・ディープラーニング
・男女識別(深層学習)
・手書き文字認識アプリ
・最終成果物作成

主なコースを書いてみましたが、時間に余裕のある人は3か月では学びきれないほどのコースが用意されていますので挑戦しがいがあると思います。

・スケジュール感

完全初心者で、仕事をしながら挑んだ3か月コースでしたが、率直にスケジュールはかなりタイトでした。

最終的に簡単な画像識別アプリの作成まで達成することができましたが、始めの1か月はプログラミング言語のPython基礎講座に時間を費やし、肝心の機械学習やディープラーニング講座にいつ行きつくのかと気が遠くなりそうでした。

そこでお勧めなのは、このコースに申し込んでから実際にスタートするまでに半月ほど時間がありますので、その間にProgateなどのプログラミングの基礎が学べるもので勉強をしておいたほうがいいです。
またこれはチューターの方から頂いたアドバイスなのですが、完全に理解してなくてもとりあえず先に進んだほうがいいです。

意外と続けていくと、何度も同じコードを書いているうちに理解できたりします。そしてわからないことはまとめておいて、カウンセリングのときに一気に解決するのがいいと思います。

・最終プロダクト

実際初心者が3か月でどれだけのものを作れるのかということですが、
私が3か月学んできたことを生かして作ったものは、
犬の3タイプ(柴犬、ポメラニアン、シベリアンハスキー)を識別する画像認識アプリです。

スクリーンショット 2021-07-10 165103



・画像収集

まず行うのは柴犬、ポメラニアン、シベリアンハスキーの画像をそれぞれ収集することでした。
精度の高いプログラムにするためには画像の量を大事になってくるのでいかに効率よく画像収集できるかもポイントになります。
そこで利用したのがPythonのパッケージの1つであるicrawlerです。
GoogleやBingなどから自動的に画像を収集できる優れものです。
コードもたったの3行です。

from icrawler.builtin import GoogleImageCrawler

crawler = GoogleImageCrawler(storage={"root_dir": "images"})
crawler.crawl(keyword="柴犬", max_num=100)
引用:icrawlerによる画像収集方法
https://sleepless-se.net/2018/07/26/icrawler/

・画像の水増し

icrawlerを使ってそれぞれ50枚程度ずつ画像を集めてプログラムを実行してみると正解率がたったの50%でした。
プログラム自体の調整も必要かと思いましたが、他の方のブログを見ていると1000枚以上集めている方もおられたので、私も画像の水増しを行い、画像数を増やしてみました。
以下がコードと参考にさせてもらったブログです。

import os
import glob
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
from google.colab import files


def scratch_image(img, flip=True, thr=False, filt=True, resize=True, erode=False):
   # 水増しの手法を配列にまとめる
   methods = [flip, thr, filt, resize, erode]

       
   # flip は画像の左右反転
   # thr  は閾値処理
   # filt はぼかし
   # resizeはモザイク
   # erode は収縮
   #     をするorしないを指定している
   # 
   # imgの型はOpenCVのcv2.read()によって読み込まれた画像データの型
   # 
   # 水増しした画像データを配列にまとめて返す
   
   # 画像のサイズを習得、収縮処理に使うフィルターの作成
   img_size = img.shape
   filter1 = np.ones((3, 3))
   # オリジナルの画像データを配列に格納
   images = [img]
   
  

   # 手法に用いる関数
   scratch = np.array([
      
       #画像の左右反転のlambda関数を書いてください 
       lambda x: cv2.flip(x, 1),
       
       #閾値処理のlambda関数を書いてください 
       lambda x: cv2.threshold(x, 100, 255, cv2.THRESH_TOZERO)[1],
       
       #ぼかしのlambda関数を書いてください 
       lambda x: cv2.GaussianBlur(x, (5, 5), 0),
       
       #モザイク処理のlambda関数を書いてください 
       lambda x: cv2.resize(x, (img_size[1] // 5, img_size[0] // 5)),
       
       #収縮するlambda関数を書いてください 
       lambda x: cv2.erode(x, filter1)
       
   ])
   
   # 関数と画像を引数に、加工した画像を元と合わせて水増しする関数
   doubling_images = lambda f, imag: (imag + [f(i) for i in imag])
   
   # doubling_imagesを用いてmethodsがTrueの関数で水増ししてください
   for func in scratch[methods]:
       images = doubling_images(func, images)
   
   return images
   


shiba_path_list = glob.glob('/content/drive/MyDrive/dog_types/shiba/*')
hasky_path_list = glob.glob('/content/drive/MyDrive/dog_types/hasky/*')
pome_path_list = glob.glob('/content/drive/MyDrive/dog_types/pome/*')

for img_path in shiba_path_list:
   # 画像ファイル名を取得
   base_name = os.path.basename(img_path)
   
   # 画像ファイル名nameと拡張子extを取得
   name,ext = os.path.splitext(base_name)
   

   # 画像ファイルを読み込む
   img = cv2.imread(img_path, 1)
   scratch_images_shiba = scratch_image(img)
   
   # 画像保存用フォルダ作成
   if not os.path.exists("scratch_images_shiba"):
       os.mkdir("scratch_images_shiba")

   for num, im in enumerate(scratch_images_shiba):
       # まず保存先のディレクトリ"scratch_images/"を指定、番号を付けて保存
       cv2.imwrite("scratch_images_shiba/" + name + str(num) + ext ,im) 

for img_path in pome_path_list:
   # 画像ファイル名を取得
   base_name = os.path.basename(img_path)
  
   # 画像ファイル名nameと拡張子extを取得
   name,ext = os.path.splitext(base_name)
  

   # 画像ファイルを読み込む
   img = cv2.imread(img_path, 1)
   scratch_images_pome = scratch_image(img)
   
   # 画像保存用フォルダ作成
   if not os.path.exists("scratch_images_pome"):
       os.mkdir("scratch_images_pome")

   for num, im in enumerate(scratch_images_pome):
       # まず保存先のディレクトリ"scratch_images/"を指定、番号を付けて保存
       cv2.imwrite("scratch_images_pome/" + name + str(num) + ext ,im) 

for img_path in hasky_path_list:
   # 画像ファイル名を取得
   base_name = os.path.basename(img_path)
   
   # 画像ファイル名nameと拡張子extを取得
   name,ext = os.path.splitext(base_name)
   

   # 画像ファイルを読み込む
   img = cv2.imread(img_path, 1)
   scratch_images_hasky = scratch_image(img)
   
   # 画像保存用フォルダ作成
   if not os.path.exists("scratch_images_hasky"):
       os.mkdir("scratch_images_hasky")

   for num, im in enumerate(scratch_images_hasky):
       # まず保存先のディレクトリ"scratch_images/"を指定、番号を付けて保存
       cv2.imwrite("scratch_images_hasky/" + name + str(num) + ext ,im) 

・学習モデル

VGG16の転移学習を用いたモデルになります。

import os
import glob
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
from google.colab import files


path_Shiba = glob.glob('/content/scratch_images_shiba/*')
path_Pome = glob.glob('/content/scratch_images_pome/*')
path_Hasky = glob.glob('/content/scratch_images_hasky/*')

img_Shiba = []
img_Pome = []
img_Hasky = []

for i in range(len(path_Shiba)):
   img = cv2.imread(path_Shiba[i])
   img = cv2.resize(img, (50,50))
   img_Shiba.append(img)

for i in range(len(path_Pome)):
   img = cv2.imread(path_Pome[i])
   img = cv2.resize(img, (50,50))
   img_Pome.append(img)
   
for i in range(len(path_Hasky)):
   img = cv2.imread(path_Hasky[i])
   img = cv2.resize(img, (50,50))
   img_Hasky.append(img)

X = np.array(img_Shiba + img_Pome + img_Hasky)
y =  np.array([0]*len(img_Shiba) + [1]*len(img_Pome) + [2]*len(img_Hasky))

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):]


y_train = to_categorical(y_train)
y_test = to_categorical(y_test)

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(rate=0.5))
top_model.add(Dense(3, activation="softmax"))

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

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=32, epochs=4, validation_data=(X_test, y_test))

# 画像を一枚受け取り、柴犬かポメラニアンかシベリアンハスキーを判定して返す関数
def pred_DogTypes(img):
   img = cv2.resize(img,(50,50))
   pred= np.argmax(model.predict(img.reshape(1,50,50,3)))
   if pred == 0:
     return "柴犬"
   elif pred == 1:
     return "ポメラニアン"
   else:
     return "シベリアンハスキー"


# 精度の評価
scores = model.evaluate(X_test, y_test, verbose=1)
print('Test loss:', scores[0])
print('Test accuracy:', scores[1])


img = cv2.imread('/content/drive/MyDrive/dog_types/test/Shiba-Inu-standing-in-profile-outdoors.jpg')
b,g,r = cv2.split(img) 
img = cv2.merge([r,g,b])
plt.imshow(img)
plt.show()
print(pred_DogTypes(img))
 #resultsディレクトリを作成 
result_dir = 'results'
if not os.path.exists(result_dir):
   os.mkdir(result_dir)
# 重みを保存
model.save(os.path.join(result_dir, 'model.h5'))

files.download( '/content/results/model.h5' ) 
引用:嵐メンバーの画像認識アプリ
https://toge510.com/2019/12/13/madeappofimagerecognition/

・結果

訓練データの正解率:0.958
テストデータの正解率:0.958

スクリーンショット 2021-07-10 204058

学習する画像数を増やしたところ正解率は96%までアップしました。
学習モデルのチューニングをしたり、画像の前処理などをもっと行えばよりよいモデルになるのではないかと思います。

・おわりに

AIプログラミングとは何ぞや、ということを教養して知りたいという目的のもと3か月取り組んできましたが、満足しています。
私と同じように初心者だけど教養としてプログラミングを理解したい方にはお勧めです。
またこのコースを通じて面白いと感じた方は継続して学んでいけるコースもあるようですし、エンジニアとして転職するサポートも受けられると思いますので、ぜひ挑戦してみてください。


この記事が気に入ったらサポートをしてみませんか?