日本語(ひらがな)をKerasで転移学習させたモデルで識別分類する手順方法。
今回の記事ではKerasのモジュールを用いてひらがなの「あ」「い」を判別させる学習モデルを作成する方法について記載いたします。
ひらがな全部を判別させる場合は適宜フォルダなどを増やしていく必要が有ります。
大変でなおかつ時間がかかると思いますが私のコードを参考にしていただければ可能ではあると思われます。
概要としては学習用の画像を揃え、その画像を配列に変換して、Kerasモジュールに突っ込んでいき転移学習を行なっていきます。
正直Kerasのモジュールがあるので作業としては簡単になっております。
Keras作った人神です。
Kerasはスタンドアローンを使用していますが、tf.kerasでもいけるのでどちらを使っていただいてもOKです。
実行環境
私はdocker上にTensorflow環境を構築し、そのdocker環境にてjupyter notebookを起動しているといった感じです。環境構築については下記記事に内容細かく記載しているのできになる方は下記参照してください。
実装用コード
import os
import cv2
import numpy
import keras
import tensorflow
import re
from keras.callbacks import EarlyStopping
from keras.applications.inception_v3 import InceptionV3
from keras.callbacks import ModelCheckpoint
#モジュールのimport関連です。今回の転移学習の元学習データはInceptionV3です。
次にフォルダ階層を分けて写真を保存します。一つのフォルダ(photo)内に下記の様に保存しております。
photo
├── a
│ ├── a.jpg
│ ├── a0.jpg
│ ├── a1.jpg
│ ├── a10.jpg
│ ├── a11.jpg
│ ├── a12.jpg
│ ├── a2.jpg
│ ├── a3.jpg
│ ├── a4.jpg
│ ├── a5.jpg
│ ├── a6.jpg
│ ├── a7.jpg
│ ├── a8.jpg
│ └── a9.jpg
└── i
├── i.jpg
├── i0.jpg
├── i1.jpg
├── i10.jpg
├── i11.jpg
├── i12.jpg
├── i2.jpg
├── i3.jpg
├── i4.jpg
├── i5.jpg
├── i6.jpg
├── i7.jpg
├── i8.jpg
└── i9.jpg
各画像14枚ごとでまずは学習を行って見ます。まずは様子見。
次にフォルダ画像の読み込みの関数を定義します。
def create_image_list():
main_path = "/photo/"
files = os.listdir(main_path)
files_dirs = [f for f in files if os.path.isdir(os.path.join(main_path, f))]
description_value = None
objective_value = []
now_index_number = 0
for dir_item in files_dirs:
if dir_item == ".ipynb_checkpoints":
pass
else:
print(dir_item + "読み込み中")
sub_path = main_path + "/" + dir_item
sub_files = os.listdir(sub_path)
sub_files_dirs = [f for f in sub_files if os.path.isdir(os.path.join(sub_path, f))]
sub_files = [f for f in sub_files if re.search('jpg', f, re.IGNORECASE)]
image_list = []
loop_count = 0
if len(sub_files) != 0:
for image_path_item in sub_files:
image_path = sub_path + "/" + image_path_item
img = cv2.imread(image_path ,cv2.COLOR_BGR2RGB)
#一時措置
img = cv2.resize(img, (150,150))
image_list.append(img.tolist())
index_number = now_index_number
objective_value.append(index_number)
loop_count += 1
if loop_count >= 1500:
break
if description_value is None:
description_value = numpy.array(image_list)
else:
now_array = numpy.array(image_list)
description_value = numpy.concatenate([description_value,now_array], axis=0)
image_list = None
now_index_number += 1
return[description_value,objective_value]
次にメインの関数になる学習のコードを記載します。
def main():
description_value,objective_value = create_image_list()
description_value = description_value.astype('float32') / 255#
objective_value = numpy.array(objective_value)
objective_value = keras.utils.to_categorical(objective_value, 2)
print(description_value.shape[1:])
model = InceptionV3(include_top=True,weights=None, input_shape=description_value.shape[1:], classes=2)
print(model.summary())
model.compile(loss='categorical_crossentropy', optimizer="sgd", metrics=['accuracy'])
MODEL_DIR = "/test_model/"
if not os.path.exists(MODEL_DIR): # ディレクトリが存在しない場合、作成する。
os.makedirs(MODEL_DIR)
checkpoint = ModelCheckpoint(
filepath=os.path.join(MODEL_DIR, "test.hdf5"), save_best_only=True) # 精度が向上した場合のみ保存する。
es_cb = EarlyStopping(monitor='val_loss', patience=2, verbose=1, mode='auto')
history = model.fit(description_value, objective_value, batch_size=64, epochs=150, verbose=1, validation_data=(description_value, objective_value), shuffle=True, callbacks=[checkpoint])
open(os.path.join("/test_model/",'keras_model.json'), 'w').write(model.to_json())
if __name__ == "__main__":
main()
こちらも少しコードの解説を行います。
InceptionはKerasのモジュールに入っていますのでそのモジュールを使用して転移学習を行なっていきます。
学習はfitで行なっています。エポック回数等を指定できますのでそこで行います。
これで実行を行うと学習がはじまります。
今回作成したモデルは精度としてはイマイチでした。
確認の仕方としては下記のコードにて任意の画像を分類テストができます。
試しにひらがなの「あ」の画像をテストしてみたところ「い」と認識されていました。しかし他の画像で調べてみても同じような結果(最高値の確率)が同じ値になっていることがわかりました。
from keras.models import load_model
import numpy as np
from keras.preprocessing.image import img_to_array, load_img
model = load_model(r"/test_model/test.hdf5")
print(model.input,model.output)
import glab
img_dir = glob.glob(r"/test_image/*.jpg")
print(img_dir)
#今回は['/test_image/test_img.jpg']test_imageフォルダのtest_img.jpg(あの画像)の一枚をテスト
img1 = load_img(img_dir[0], target_size=(150,150))
img_nad = img_to_array(img1)/255
img_nad = img_nad[None, ...]
pred = model.predict(img_nad, batch_size=1, verbose=0)
print(pred)
#[[0.49381995 0.50618005]]
#[[0.49507388 0.50492615]](全然関係ない画像)
#「あ」「い」の順番なのでいと判別されている確率の方が高い
#しかし、たの結果でも同じような出力結果になった
全然関係ない画像でも同じような比重の確率が出力されたのでおそらく少し特徴量が多くなってこの出力形式になったと考えられる。
このことからさすがに学習枚数が数なすぎて分類できていないのかと考える。
一度画像の水増しを行ってみた。角度を変えてしまうとさすがに文字として違う形になってしまうような気がしたので輝度のみを変更して画像を各14枚×4枚程度作成し、計56枚の画像を作成。
画像の水増しに関する記事は下記をご参照ください。下記のフォルダを少しいじればこちらでも水増し可能です。
その結果dockerが落ちてしまった。多分学習量が増えてメモリ不足になってしまったためjupyter karnelがダウンしたと考えられます。
解決策としてはdockerのメモリ変更をすれば済む話ですのでそれをします。
ただ、今回は画像量が少なく、途中から学習時の識別率が100%になっており過学習かな?と感じていたので、少し学習量を減らしてbatchを64から32に、epochを150から100に変更して行ったところ落ちませんでした。メモリに関係しているのはbatchですのでそちらの数値を調節してみてください。
これで上記のテストを行ったところある程度識別できているようでした。
今回はここまでです。
ひらがな全文字を学習させたかたは是非みてみたいので記事にしてください。笑
コメント
[…] 【Keras】Kerasで転移学習を行い「ひらがな」を分類する方法。 […]
[…] 【Keras】Kerasで転移学習を行い「ひらがな」を分類する方法。 […]