1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

画像識別アプリの作成プロセスと成果物

Last updated at Posted at 2022-12-25
1 / 2

◆アプリ制作のプロセス◆

STEP0.はじめに

 AidemyでAIアプリコースを受講しました。
 もともとプログラミングに興味があり、プログラミングスクールでRubyや
 Javaの習得を検討していましたが、似たようなコンテンツとサービスの
 スクールが多く、どちらで受講しようか悩んでいました。
 そんな中、Pythonという今後需要が高まるであろう言語で、AIアプリを作る
 コースを提供しているAidemyに出会い、折角習うなら面白そうなものをという
 思いで、Aidemyを選択しました。

 本稿では、AIアプリ作成コースでの最終課題の作成プロセスと成果物を紹介します。

 【実行環境】
  PC:Windows10
  Python:-3.9.12

STEP1.アプリのテーマを決める

 作りたいと思ったのは以下の4つ。
 中でもKaggleにデータがあったキノコの判別にしました。

 候補テーマ
  ◇雲の形から名称を判断
  ◇空の写真から、晴れ・曇り等の天候を判断
  ◆キノコの種類を判別 ←←←採用!
  ◇動物の足跡の識別

STEP2.データの取得・**

 データの取得方法は幾つかありますが、
 今回は目的にかなうデータがあったKaggleから調達しました。
 ダウンロードした後、解凍してGoogleDrive内に保存し、ディレクトリを取得します。

STEP3.Flaskサイド(環境:Google Colaboratery)

 モデルの生成のプログラムとして最初に作成したものがこちら↓

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
#import pickle 
#from google.colab import drive

#データの取得 12種類のキノコ
path_Amanita_Caesarea= os.listdir('/content/drive/MyDrive/Mashroomdata/Amanita_Caesarea-Edible')
path_Amanita_Citrina= os.listdir('/content/drive/MyDrive/Mashroomdata/Amanita_Citrina-Edible')
path_Amanita_Pantherina= os.listdir('/content/drive/MyDrive/Mashroomdata/Amanita_Pantherina-NotEdible')
path_Boletus_Regius= os.listdir('/content/drive/MyDrive/Mashroomdata/Boletus_Regius-Edible')
path_Entoloma_Lividum= os.listdir('/content/drive/MyDrive/Mashroomdata/Entoloma_Lividum-NotEdible')
path_Gyromitra_Esculenta= os.listdir('/content/drive/MyDrive/Mashroomdata/Gyromitra_Esculenta-NotEdible')
path_Helvella_Crispa= os.listdir('/content/drive/MyDrive/Mashroomdata/Helvella_Crispa-Edible')
path_Hydnum_Rufescens= os.listdir('/content/drive/MyDrive/Mashroomdata/Hydnum_Rufescens-NotEdible')
path_Morchella_Deliciosa= os.listdir('/content/drive/MyDrive/Mashroomdata/Morchella_Deliciosa-Edible')
path_Phallus_Impudicus= os.listdir('/content/drive/MyDrive/Mashroomdata/Phallus_Impudicus-NotEdible')
path_Russula_Cyanoxantha= os.listdir('/content/drive/MyDrive/Mashroomdata/Russula_Cyanoxantha-Edible')
path_Russula_Delica= os.listdir('/content/drive/MyDrive/Mashroomdata/Russula_Delica-NotEdible')


#データの処理

img_Amanita_Caesarea=[]    #タマゴダケ
img_Amanita_Citrina=[]     #コタマゴテングダケ
img_Amanita_Pantherina=[]  #テングダケ
img_Boletus_Regius=[]      #ヤマドリダケ   
img_Entoloma_Lividum=[]    #イッポンシメジ
img_Gyromitra_Esculenta=[] #シャグマアミガサタケ
img_Helvella_Crispa=[]     #ノボリリュウ
img_Hydnum_Rufescens=[]    #アミタケ
img_Morchella_Deliciosa=[]        #アシボソアミガサタケ
img_Phallus_Impudicus=[]          #スッポンタケ
img_Russula_Cyanoxantha=[]        #カワリハツ
img_Russula_Delica=[]             #シロハツ

for i in range(len(path_Amanita_Caesarea)):
  img=cv2.imread('/content/drive/MyDrive/Mashroomdata/Amanita_Caesarea-Edible/'+path_Amanita_Caesarea[i])
  img=cv2.resize(img,(50,50))
  img_Amanita_Caesarea.append(img)

for i in range(len(path_Amanita_Citrina)):
  img=cv2.imread('/content/drive/MyDrive/Mashroomdata/Amanita_Citrina-Edible/'+path_Amanita_Citrina[i])
  img=cv2.resize(img,(50,50))
  img_Amanita_Citrina.append(img)

for i in range(len(path_Amanita_Pantherina)):
  img=cv2.imread('/content/drive/MyDrive/Mashroomdata/Amanita_Pantherina-NotEdible/'+path_Amanita_Pantherina[i])
  img=cv2.resize(img,(50,50))
  img_Amanita_Pantherina.append(img)

for i in range(len(path_Boletus_Regius)):
  img=cv2.imread('/content/drive/MyDrive/Mashroomdata/Boletus_Regius-Edible/'+path_Boletus_Regius[i])
  img=cv2.resize(img,(50,50))
  img_Boletus_Regius.append(img)

for i in range(len(path_Entoloma_Lividum)):
  img=cv2.imread('/content/drive/MyDrive/Mashroomdata/Entoloma_Lividum-NotEdible/'+path_Entoloma_Lividum[i])
  img=cv2.resize(img,(50,50))
  img_Entoloma_Lividum.append(img)

for i in range(len(path_Gyromitra_Esculenta)):
  img=cv2.imread('/content/drive/MyDrive/Mashroomdata/Gyromitra_Esculenta-NotEdible/'+path_Gyromitra_Esculenta[i])
  img=cv2.resize(img,(50,50))
  img_Gyromitra_Esculenta.append(img)

for i in range(len(path_Helvella_Crispa)):
  img=cv2.imread('/content/drive/MyDrive/Mashroomdata/Helvella_Crispa-Edible/'+path_Helvella_Crispa[i])
  img=cv2.resize(img,(50,50))
  img_Helvella_Crispa.append(img)

for i in range(len(path_Hydnum_Rufescens)):
  img=cv2.imread('/content/drive/MyDrive/Mashroomdata/Hydnum_Rufescens-NotEdible/'+path_Hydnum_Rufescens[i])
  img=cv2.resize(img,(50,50))
  img_Hydnum_Rufescens.append(img)

for i in range(len(path_Morchella_Deliciosa)):
  img=cv2.imread('/content/drive/MyDrive/Mashroomdata/Morchella_Deliciosa-Edible/'+path_Morchella_Deliciosa[i])
  img=cv2.resize(img,(50,50))
  img_Morchella_Deliciosa.append(img)

for i in range(len(path_Phallus_Impudicus)):
  img=cv2.imread('/content/drive/MyDrive/Mashroomdata/Phallus_Impudicus-NotEdible/'+path_Phallus_Impudicus[i])
  img=cv2.resize(img,(50,50))
  img_Phallus_Impudicus.append(img)

for i in range(len(path_Russula_Cyanoxantha)):
  img=cv2.imread('/content/drive/MyDrive/Mashroomdata/Russula_Cyanoxantha-Edible/'+path_Russula_Cyanoxantha[i])
  img=cv2.resize(img,(50,50))
  img_Russula_Cyanoxantha.append(img)

for i in range(len(path_Russula_Delica)):
  img=cv2.imread('/content/drive/MyDrive/Mashroomdata/Russula_Delica-NotEdible/'+path_Russula_Delica[i])
  img=cv2.resize(img,(50,50))
  img_Russula_Delica.append(img)

#学習データと学習データに対応するラベルを作成
X=np.array(img_Amanita_Caesarea+img_Amanita_Citrina+img_Amanita_Pantherina+img_Boletus_Regius+img_Entoloma_Lividum+img_Gyromitra_Esculenta+img_Helvella_Crispa+img_Hydnum_Rufescens+img_Morchella_Deliciosa+img_Phallus_Impudicus+img_Russula_Cyanoxantha+img_Russula_Delica)
y=np.array([0]*len(img_Amanita_Caesarea)+[1]*len(img_Amanita_Citrina)+[2]*len(img_Amanita_Pantherina)+[3]*len(img_Boletus_Regius)+[4]*len(img_Entoloma_Lividum)+[5]*len(img_Gyromitra_Esculenta)+[6]*len(img_Helvella_Crispa)+[7]*len(img_Hydnum_Rufescens)+[8]*len(img_Morchella_Deliciosa)+[9]*len(img_Phallus_Impudicus)+[10]*len(img_Russula_Cyanoxantha)+[11]*len(img_Russula_Delica))
#画像をシャッフル
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(Dense(64,activation="relu"))
top_model.add(Dropout(rate=0.5))
top_model.add(Dense(12, activation="softmax"))

#モデルの連結
model = Model(inputs = vgg16.input, outputs = top_model(vgg16.output))

# vgg16の重みの固定
for layer in model.layers[:19]:
   layer.trainable=False

model.compile(loss="categorical_crossentropy",optimizer=optimizers.Adam(), metrics=["accuracy"])

model.fit(X_train,y_train,batch_size=128,epochs=40,validation_data=(X_test,y_test))

#モデルの保存(精度調整後)
model.save('model.h5')

#判定する関数を定義
#画像を一枚受け取り、キノコの種類を判定して返す関数
def pred_mashroom(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 "コタマゴテングダケ"
  elif pred == 2:
    return "テングダケ"
  elif pred == 3:
    return "ヤマドリダケ"
  elif pred == 4:
    return "イッポンシメジ"
  elif pred == 5:
    return "シャグマアミガサタケ"
  elif pred == 6:
    return "ノボリリュウ"
  elif pred == 7:
    return "アミタケ"
  elif pred == 8:
    return "アシボソアミガサタケ"
  elif pred == 9:
    return "スッポンタケ"
  elif pred == 10:
    return "カワリハツ"
  else:
    return "シロハツ"

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

#識別評価を行う
for i in range(5):
  img=cv2.imread('/content/drive/MyDrive/Mashroomdata/Amanita_Caesarea-Edible/'+ path_Amanita_Caesarea[i])
  b,g,r = cv2.split(img) 
  img = cv2.merge([r,g,b])
  plt.imshow(img)
  plt.show()
  print(pred_mashroom(img))

ここでの精度は57.3%

そこで幾つか要素を変更し、最も良い精度を出す条件を探しました。

 ◇size 50 → 100
  判別するデータのサイズは大きい方が実行時間は長くなるものの、
  精度は上がるたため、100に固定
 ◇判別する種類 12種類 < 6種類 < 4種類
  判別させるキノコの数を減らせば、精度は高くなります。
  アプリとして判別できる種類が減らすのは本末転倒ではあるが、
  試しに4種類まで減らして実行  
 ◇epochs 40 ~ 100
  epochsは高すぎても精度上がらないが、判別数との相性があるかと思い、
  幾つか試しました。

epochsと判別数を変更した場合の精度:

12type 6type 4type
epochs=40  76.3 None None
epochs=50 80.1 88.5 None
epochs=60 76.4 89.3 85.1
epochs=70 None 87.7 93.1
epochs=80 None None 90.2
epochs=100 75.3 None None

→結果、4種類のタイプのキノコの識別(epochs=70)としました。

STEP4.サーバーサイド(HTML/CSS)

 こちらの工程は、Aidemyの講座で使用したものをベースに
 少しアレンジして使用。

STEP5.Qiitaでブログ作成

 こちらの工程は、モデルの精度向上でプログラムを実行している間に
 少しずつ進めてきました。
 マークアップ手法も幅広く、興味と工夫次第で凝った仕上がりにできます。

◆出来上がったアプリのサイトはこちら◆

 ***URL***
キノコの判別アプリ

結果:これはタマゴダケです(正解!)

結果:これは コタマゴテングダケです(正解!)

結果:これは テングダケです(正解!)

結果:これは テングダケです(不正解!正解はイッポンシメジ)

◆◆NEXT STEP◆◆

 ◆データの水増し
 (データ数はキノコ1種に対して100~300と、あまり多くないため。)
 ◆レイヤー構成を変更

◆◆感想◆◆

 Aidemyを受講してみて、プログラミング未経験者が自走でスキルを身に着けるのは、
 難しいと感じました。
 講義のスタイルは基本、与えられた教材を自分で理解して進めていく方式。
 わからないことがあれば、技術カウンセリングかSlackなどで質問できますが、
 わからないことが多く、わかった気になれない中で進めている感じ。
 教材も、全ても説明することはないので、疑問点は自分で適宜検索して消化していく
 必要があります。
 
 振り返れば反省点は、早いうちからカウンセリングを使えばよかったな~ということ。
 技術サポートは回数制限されているため、出し惜しんで最初の方は、自走できるよう
 にならなくては!と気負って、何日も悩んで疲れて、終いにはちょっと嫌になってPC
 を開かなくなる時期もありました:laughing:
 でも、カウンセラーさんに相談すれば親切に且つ多面的に教えてくださるので、一人
 で調べているより、理解が深まり、視界が開けます。
 今後受講する方、特に初学者の方は是非、負担になる前にカウンセラーさんに相談す
 ることをお勧めします。
 
 受講を終えて、まだまだ理解できていない部分が多いですが、
 何とか課題を終えられたのは、技術カウンセリングでサポートいただいたお陰です!
 感謝:blush:

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?