はじめに
最近pythonを使ってめっちゃ簡単なAIを作ってみるのにハマってるので、その過程を記事にしてみます。
もっといいコードがあれば教えてください✨
実装
今回作ったもの
りんご、ぶどう、みかんの3つの分類を行うようにVGG16を再学習させました。
画像収集にはicrawlerを利用しました。また実行環境は以下のとおりです。
Google Colab
python 3.10
Apple M2チップ MacBook Air
macOS Venture13.1
icrawlerで画像収集
icrawlerで画像を収集します。
!pip install icrawler
# ライブラリのインポート
from icrawler.builtin import BingImageCrawler
pipでライブラリをインストールしその後importまで済ませます。
今回画像を収集するフォルダを作成します。今回はimagesフォルダを作成しその中にりんご
みかん
ぶどう
のフォルダを作成しそこに画像を収集します。
!mkdir images
!cd images
画像を収集します。
labels =["りんご", "みかん", "ぶどう"]
for label in labels:
path = "/content/images/" + label
crawler = BingImageCrawler(storage = {'root_dir' : path})
crawler.crawl(keyword = i, max_num = 150)
labelsというリストに今回収集したいラベルを入れ、その後のfor文中でそれぞれ150枚ずつ画像を収集しようとしています。
画像を収集する過程で、ERROR:downloader:Response status code 403, file
のようなエラーが出力される場合がありますが、これは上手くファイルを取れなかった時に出るものなので無視してOKです。
実行が終わると、google colabのランタイムの中に画像が収集されてい事がわかります。
VGG
次にVGGに転移学習を施します。
まずはライブラリのインポートからです。
import os
import cv2
import numpy as np
from keras.utils import np_utils
import glob as glob
まずはimagesフォルダの画像を読み込む。
path = "/content/images"
n_classes = len(labels)
print(f"num of class = {n_classes} , classes = {labels}")
X = []
Y = []
for label,class_name in enumerate(classes):
files = glob.glob(path + "/" + class_name + "/*.jpg")
for file in files:
img = cv2.imread(file)
img = cv2.resize(img,dsize=(224,224))
X.append(img)
Y.append(label)
次に精度を上げるために配列Xを正規化します。
X = np.array(X)
X = X.astype('float32')
X /= 255.0
次にラベルをone-hotエンコーディングして変換します。
Y = np.array(Y)
Y = np_utils.to_categorical(Y,n_classes)
次に訓練データとテストデータの分割を行います.
from sklearn.model_selection import train_test_split
X_train,X_test,Y_train,Y_test = train_test_split(X,Y,test_size=0.1)
次にVGG設定を行います。16層すべてを再学習させていては、時間が足りないので、学習させない層を指定します。
from keras.applications.vgg16 import VGG16
from keras.models import Sequential
from keras.models import model_from_json
from keras.models import Model
from keras.layers import Input, Activation, Dense, Flatten, Dropout
from tensorflow.keras.optimizers import Adam
input_tensor = Input(shape=(224,224,3))
base_model = VGG16(weights='imagenet', input_tensor=input_tensor,include_top=False)
top_model = Sequential()
top_model.add(Flatten(input_shape=base_model.output_shape[1:]))
top_model.add(Dense(n_classes, activation='softmax'))
model = Model(inputs=base_model.input, outputs=top_model(base_model.output))
for layer in model.layers[:15]:
layer.trainable = False
model.compile(loss='categorical_crossentropy',optimizer='adam',metrics=['accuracy'])
モデルの各層の状態を確認してみましょう。
model.summary()
=================================================================
Total params: 14,789,955
Trainable params: 7,154,691
Non-trainable params: 7,635,264
_________________________________________________________________
のように表示されることから訓練可能な層の数を確認することができると思います。
いよいよ学習させていきたいと思います。
model.fit(X_train, Y_train, epochs=12, batch_size=5)
テストデータに対する精度を確認しましょう
score = model.evaluate(X_test, Y_test, batch_size=5)
これで学習は終了です。精度がイマイチだったりする方は再度データや学習パラーメータを見直したりしましょう。
実際に、任意の画像でテストをしてみましょう。
img = cv2.imread('ここには画像のパスを入れる')
img = cv2.resize(img,dsize=(224,224))
img = img.astype('float32')
img /= 255.0
img = img[None, ...]
result = model.predict(img)
np.set_printoptions(precision=3, suppress=True)
pred = result.argmax()
classes[pred]
ローカル環境でのモデルのロード
ここまではGoogle colabでモデルの訓練をしてきましたが、実際にローカル環境(anacondak環境)で保存したモデルを使ってみたいと思います。
# モデルを保存する
import pickle
pickle.dump(classes, open('classes.sav', 'wb'))
model.save('model.h5')
モデルを保存したらcolabのランタイム、もしくは、driveと接続している方であればdriveの方からclasses.savとmodel.h5をダウンロードしましょう。
from keras.models import load_model
import pickle
#モデルとクラス名の読み込み
model = load_model('model.h5')
classes = pickle.load(open('classes.sav', 'rb'))
kerasとpickleを用いてモデルをロードします。ここまでできればコラボ環境で動作させたのと同じようにmodelをローカル実行することができます。
最後に
ここまでお読みいただきありがとうございました。
コードは一通り実行して動作確認はしておりますが、コピペミスやタイポなどでうまく動作しない箇所がありましたら、コメントなどで 優しく ご指摘いただけると嬉しいです!
それから、もっと良い書き方や、機械学習のロジック的にイケてないコードも 優しく 指摘してもらえると喜びます!
ありがとうございました。