VGG16のファインチューニングコード
このブログでも2016年以降、ディープラーニングネタをいくつか投入しておりますが。
そういえば、最近は基本となりつつある「ファインチューニング」ってやつを紹介してませんね。
てことで、VGG16を用いたファインチューニングのコードを、載せておきますね。
【学習用コード】(vgg16_ft_train.py)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import sys
import cv2
import numpy as np
import tensorflow as tf
import tensorflow.python.platform
import keras
from keras.utils import np_utils
from keras.models import Sequential,Model
from keras.layers import Dense,Dropout,Flatten
from keras.layers import Conv2D,MaxPooling2D,GlobalAveragePooling2D,Input
from keras.preprocessing.image import array_to_img,img_to_array,load_img
from keras import backend as K
from sklearn.model_selection import train_test_split
from keras.models import load_model
from keras.callbacks import ModelCheckpoint
from keras.applications.vgg16 import VGG16
path=os.getcwd()+'/data/'
checkDir=os.getcwd()+'/checkpoints/'
if not os.path.exists(checkDir):
os.mkdir(checkDir)
class_count = 0
folder_list=os.listdir(path)
for folder in folder_list:
class_count = class_count+1
label_filenm = './label.txt'
NUM_CLASSES = class_count
IMAGE_SIZE = 224
batch_size = 64
epochs = 200
count=0
folder_list = sorted(os.listdir(path))
train_image = []
train_label = []
test_image = []
test_label = []
X = []
Y = []
f = open(label_filenm, 'w')
for folder in folder_list:
subfolder = os.path.join(path,folder)
file_list = sorted(os.listdir(subfolder))
filemax = 0
i = 0
for file in file_list:
i = i + 1
img = img_to_array(load_img('./data/' + folder + '/'
+ file,target_size=(224,224)))
X.append(img)
Y.append(count)
label_name = folder + ' ' + str(count) + '\n'
f.write(label_name)
count +=1
X = np.asarray(X)
Y = np.asarray(Y)
X = X.astype('float32')
X = X / 255.0
Y = np_utils.to_categorical(Y, NUM_CLASSES)
train_image, test_image, train_label, test_label = train_test_split(X,Y,test_size=0.10)
f.close()
print(u'画像読み込み終了')
input_tensor = Input(shape=(IMAGE_SIZE, IMAGE_SIZE, 3))
base_model = VGG16(weights='imagenet', include_top=False, input_tensor = input_tensor)
x = base_model.output
x = GlobalAveragePooling2D()(x)
x = Dense(1024, activation='relu')(x)
x = Dropout(0.5)(x)
predictions = Dense(NUM_CLASSES, activation='softmax')(x)
model = Model(inputs=base_model.input,outputs=predictions)
for layer in base_model.layers:
layer.trainable = False
model.compile(loss='categorical_crossentropy',
optimizer=keras.optimizers.Adagrad(lr=0.01, epsilon=None, decay=0.0),
metrics=['accuracy']
)
chkpt = os.path.join(checkDir, 'model_.{epoch:02d}-{val_loss:.2f}.h5')
cp_cb = ModelCheckpoint(filepath = chkpt, monitor='val_loss', verbose=1,
save_best_only=True, mode='auto')
model.fit(train_image, train_label,
batch_size=batch_size,
epochs=epochs,
verbose=1,
validation_data=(test_image, test_label),
callbacks=[cp_cb],
)
model.summary()
score = model.evaluate(test_image, test_label, verbose=0)
【推論用コード】(vgg16_ft_app.py)
#!/usr/bin/env python
import os
import sys
import numpy as np
import tensorflow as tf
import keras
from keras.utils import np_utils
from keras.layers import Dense,Dropout,Flatten
from keras.layers import Conv2D,MaxPooling2D
from keras.preprocessing.image import array_to_img,img_to_array,load_img
from keras import backend as K
from sklearn.model_selection import train_test_split
from keras.models import load_model
import cv2
import math
from PIL import Image
path=os.getcwd()+'/analysis/'
file_list=os.listdir(path)
i = 0
label_name = []
label_filenm = './label.txt'
f = open(label_filenm,'r')
for line in f:
line = line.rstrip()
l = line.rstrip()
label_name.append(l)
i = i + 1
NUM_CLASSES = i
IMAGE_SIZE = 224
test_image = []
path=os.getcwd()+'/analysis/'
outpath = os.getcwd() + '/visible/'
if not os.path.exists(outpath):
os.mkdir(outpath)
file_list=os.listdir(path)
def Grad_Cam(input_model, x, layer_name):
X = np.expand_dims(x, axis=0)
X = X.astype('float32')
preprocessed_input = X / 255.0
predictions = model.predict(preprocessed_input)
class_idx = np.argmax(predictions[0])
class_output = model.output[:, class_idx]
conv_output = model.get_layer(layer_name).output
grads = K.gradients(class_output, conv_output)[0]
gradient_function = K.function([model.input], [conv_output, grads])
output, grads_val = gradient_function([preprocessed_input])
output, grads_val = output[0], grads_val[0]
weights = np.mean(grads_val, axis=(0, 1))
cam = np.dot(output, weights)
cam = cv2.resize(cam, (224, 224), cv2.INTER_LINEAR)
cam = np.maximum(cam, 0)
cam = cam / cam.max()
jetcam = cv2.applyColorMap(np.uint8(255 * cam), cv2.COLORMAP_JET)
jetcam = cv2.cvtColor(jetcam, cv2.COLOR_BGR2RGB)
jetcam = (np.float32(jetcam) + x / 2)
return jetcam
model = load_model('model.h5')
model.summary()
for file in file_list:
img = img_to_array(load_img('./analysis/' + file, target_size=(224,224)))
test_image = np.asarray(img)
test_image = test_image.astype('float32')
test_image = test_image / 255.0
test_image = test_image.reshape((1,) + test_image.shape)
y_prob = model.predict(test_image)
pred = y_prob.argmax(axis=-1)
value_pred = max(model.predict(test_image)[0])
gdst = Grad_Cam(model, img, 'block5_pool')
gcnt_filenm = outpath + 'gradcam_' + label_name[pred[0]] + '_' + file
cv2.imwrite(gcnt_filenm, gdst)
print(u'ファイル : ', file, u'は ', label_name[pred[0]], u'です。 ' , value_pred)
コードの行間が妙に空いてるところがありますが、いくら直してもココログが勝手に空けちゃうんです。
なんかこのブログ、どんどんと使いにくくなって……申し訳ありません、あらかじめ、ご了承願います。
使い方ですが、
【準備】
(1) Windows版Pythonをインストール (おすすめはpython 3.7.9の64ビット版)
このサイトが便利 : 非公式Pythonダウンロードリンク - Python downloads
パスを通すオプションがあるので、それをチェックしてインストールしてください。
(2) Windows PowerShellを開く。(以下、コマンドはすべてWindows PowerShellで実行)
(3) pipコマンドで、tensorflow 1.14.0、keras 2.2.4、OpenCV (最新版)、PILLOWを入れておく。
【学習】
(1)「data」フォルダを作り、その中にラベルごとのフォルダを複数作って、画像を入れる
(inu、neko、……のように、半角英数で名前を付けてください)
(2) 上の学習用コードをテキストエディタなどで張り付けて保存(以下、ファイル名は「vgg16_ft_train.py」)。
(3) コマンドで、「python vgg16_ft_train.py」を実行。
(4) 終了したら、「checkpoints」フォルダ内にある一番最後のファイルを上のフォルダに移動し、「model.h5」と名前を変えておく。
【推論】
(1) 上の推論用コードをテキストエディタなどで張り付けて保存(以下、ファイル名は「vgg16_ft_app.py」)。
(2) コマンドで「python vgg16_ft_app.py」を実行。
こんな感じの結果が出れば、OK。
ちなみに、Grad Camを入れてるので、「visible」フォルダにヒートマップが出力されます。
注目部位が赤くなるってやつです。
いつも使うお城のデータセットでやってみたんですが……なんかちょっと妙な感じ。なぜだか、お城そのものよりも周囲に色がついてますね。
それはともかく、一応動きました。
会社では、かなり使ってますね、VGG16。ResNet50だの、InceptionV3だのとより深層のモデルもあるんですが、VGG16ベースの方がなぜか精度、汎用性が高い印象。
最近は、新規ネットワークで学習させるより、既存のモデルをベースにファインチューニングする方が増えましたね。
あ、ところで、モデルを流用して学習させる方法には「転移学習」と「ファインチューニング」という言葉があって、それぞれちょっと意味が異なります。
ものの本によれば、
・転移学習とは、ベースモデル部分をそのまま使い、結合層以降を学習すること。
・ファインチューニングとは、ベースモデル部分の一部も再学習すること。
という意味のようです。
で、ここに載せたコードは、厳密には「転移学習」と呼ぶのがふさわしいみたいなのですが、そういうのも含めてファインチューニングと呼んでいる節があるので、いつの間にか私もまとめてファインチューニングと呼んでますね。
まあ、いずれにせよ、この数年でディープラーニングも随分と簡単、一般化したものだと感じます。様々な分野の製品検査や効率化に、使われ始めてますね。
で、このコードが、うちの新メインPCであるGALLERIAで動いてます。
これを使ってなにか、やらかしたいですねぇ……できれば、Raspberry Piも使って。現在、思案中です。
« うちのGALLERIAでゲーム系ベンチマークテストを動かしてみた | トップページ | Amazonを名乗る「あなたのアカウントは停止されました」という詐称メール »
「数値解析系」カテゴリの記事
- Tanuki-8Bの4ビット量子化ggufモデルでRAGをやってみました(2024.09.14)
- 純日本産なローカルLLM「Tanuki-8B」を試してみた(2024.09.02)
- 東京のセールスフォースに行ってきました(2024.07.24)
- ローカルLLM「Llama-3-ELYZA-JP-8B」にいろいろ聞いてみた(2024.07.01)
- ElyzaのLlama3ベースの言語モデル「Llama-3-ELYZA-JP-8B」のRAGが予想以上に賢かった件(2024.06.27)
コメント
« うちのGALLERIAでゲーム系ベンチマークテストを動かしてみた | トップページ | Amazonを名乗る「あなたのアカウントは停止されました」という詐称メール »
コードにコメントって入ってないんですか?
明日の自分は赤の他人なので、出来るだけ
コメントをつけるのが良いかなぁって思います。
ダウンロードしたものでも、勉強のために残すのは有益です。
学校の勉強で見ただけで出来たと勘違いするのと一緒なので。
投稿: mokekyo | 2021年1月 9日 (土) 21時47分
> mokekyoさん
元ファイルには、コメントだらけです。ですが、ブログに載せる際に長くなり過ぎてしまったため、泣く泣く削りました。
会社内にあるコードは、もうちょっと凝ってて、import文の直後にパラメータを集めて目立つコメント文をつけて、ユーザーはここだけ変えればいいというのを分かる様にしてます。本当はそれを載せたかったんですが、会社にあるファイルは、持ち出し禁止なので……
投稿: ディープタイピング | 2021年1月10日 (日) 02時43分