« うちのGALLERIAでゲーム系ベンチマークテストを動かしてみた | トップページ | Amazonを名乗る「あなたのアカウントは停止されました」という詐称メール »

2020年12月27日 (日)

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。

Vgg16_01

ちなみに、Grad Camを入れてるので、「visible」フォルダにヒートマップが出力されます。

Vgg16_02

注目部位が赤くなるってやつです。

いつも使うお城のデータセットでやってみたんですが……なんかちょっと妙な感じ。なぜだか、お城そのものよりも周囲に色がついてますね。

それはともかく、一応動きました。

会社では、かなり使ってますね、VGG16。ResNet50だの、InceptionV3だのとより深層のモデルもあるんですが、VGG16ベースの方がなぜか精度、汎用性が高い印象。

最近は、新規ネットワークで学習させるより、既存のモデルをベースにファインチューニングする方が増えましたね。

あ、ところで、モデルを流用して学習させる方法には「転移学習」と「ファインチューニング」という言葉があって、それぞれちょっと意味が異なります。

ものの本によれば、

・転移学習とは、ベースモデル部分をそのまま使い、結合層以降を学習すること。

・ファインチューニングとは、ベースモデル部分の一部も再学習すること。

という意味のようです。

で、ここに載せたコードは、厳密には「転移学習」と呼ぶのがふさわしいみたいなのですが、そういうのも含めてファインチューニングと呼んでいる節があるので、いつの間にか私もまとめてファインチューニングと呼んでますね。

まあ、いずれにせよ、この数年でディープラーニングも随分と簡単、一般化したものだと感じます。様々な分野の製品検査や効率化に、使われ始めてますね。

で、このコードが、うちの新メインPCであるGALLERIAで動いてます。

これを使ってなにか、やらかしたいですねぇ……できれば、Raspberry Piも使って。現在、思案中です。


人気ブロガーからあげ先生のとにかく楽しいAI自作教室

« うちのGALLERIAでゲーム系ベンチマークテストを動かしてみた | トップページ | Amazonを名乗る「あなたのアカウントは停止されました」という詐称メール »

数値解析系」カテゴリの記事

コメント

コードにコメントって入ってないんですか?
明日の自分は赤の他人なので、出来るだけ
コメントをつけるのが良いかなぁって思います。
ダウンロードしたものでも、勉強のために残すのは有益です。
学校の勉強で見ただけで出来たと勘違いするのと一緒なので。

> mokekyoさん

元ファイルには、コメントだらけです。ですが、ブログに載せる際に長くなり過ぎてしまったため、泣く泣く削りました。

会社内にあるコードは、もうちょっと凝ってて、import文の直後にパラメータを集めて目立つコメント文をつけて、ユーザーはここだけ変えればいいというのを分かる様にしてます。本当はそれを載せたかったんですが、会社にあるファイルは、持ち出し禁止なので……

コメントを書く

(ウェブ上には掲載しません)

« うちのGALLERIAでゲーム系ベンチマークテストを動かしてみた | トップページ | Amazonを名乗る「あなたのアカウントは停止されました」という詐称メール »

当ブログ内検索

スポンサード リンク

ブログ村

無料ブログはココログ