メモ > 技術 > プログラミング言語: Python > TensorFlow+Keras(ディープラーニング)でカタカナを判定
TensorFlow+Keras(ディープラーニング)でカタカナを判定
■文字データベースのダウンロード
etlcdb
http://etlcdb.db.aist.go.jp/?lang=ja
画面上部の「DOWNLOAD」から利用申請できる。
申請すると、すぐにメールアドレスにダウンロードリンクとパスワードが送られてくる。
今回はダウンロードページから「ETL-1」をダウンロードする。
ダウンロードしたファイルを展開すると、「ETL-1」というフォルダの中に14個のファイルが作成される。
■データベースを画像に変換
# ETL1Cのファイルを読み込む
import struct
from PIL import Image, ImageEnhance
import glob, os
# 出力ディレクトリ
outdir = "png-etl1/"
if not os.path.exists(outdir): os.mkdir(outdir)
# ETL1ディレクトリ以下のファイルを処理する
files = glob.glob("ETL1/*")
for fname in files:
if fname == "ETL1/ETL1INFO": continue # 情報ファイルは飛ばす
print(fname)
# ETL1のデータファイルを開く
f = open(fname, 'rb')
f.seek(0)
while True:
# メタデータ+画像データの組を一つずつ読む
s = f.read(2052)
if not s: break
# バイナリデータなのでPythonが理解できるように抽出
r = struct.unpack('>H2sH6BI4H4B4x2016s4x', s)
code_ascii = r[1]
code_jis = r[3]
# 画像データとして取り出す
iF = Image.frombytes('F', (64, 63), r[18], 'bit', 4)
iP = iF.convert('L')
# 画像を鮮明にして保存
dir = outdir + "/" + str(code_jis)
if not os.path.exists(dir): os.mkdir(dir)
fn = "{0:02x}-{1:02x}{2:04x}.png".format(code_jis, r[0], r[2])
fullpath = dir + "/" + fn
#if os.path.exists(fullpath): continue
enhancer = ImageEnhance.Brightness(iP)
iE = enhancer.enhance(16)
iE.save(fullpath, 'PNG')
print("ok")
■画像をリサイズしてバイナリにまとめる
import glob
import numpy as np
import cv2
import matplotlib.pyplot as plt
import pickle
# 保存先や画像サイズの指定
out_dir = "./png-etl1" # 画像データがあるディレクトリ
im_size = 25 # 画像サイズ
save_file = out_dir + "/katakana.pickle" # 保存先
plt.figure(figsize=(9, 17)) # 出力画像を大きくする
# カタカナの画像が入っているディレクトリから画像を取得
kanadir = list(range(177, 220+1))
kanadir.append(166) # ヲ
kanadir.append(221) # ン
result = []
for i, code in enumerate(kanadir):
img_dir = out_dir + "/" + str(code)
fs = glob.glob(img_dir + "/*")
print("dir=", img_dir)
# 画像を読み込んでグレイスケールに変換しリサイズする
for j, f in enumerate(fs):
img = cv2.imread(f)
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img = cv2.resize(img_gray, (im_size, im_size))
result.append([i, img])
# Jupyter Notebookで画像を出力
if j == 3:
plt.subplot(11, 5, i + 1)
plt.axis("off")
plt.title(str(i))
plt.imshow(img, cmap='gray')
# メモリ消費対策に読み込む数を制限
#print(str(j) + ' / ' + f)
if j >= 99:
break
# ラベルと画像のデータを保存
pickle.dump(result, open(save_file, "wb"))
plt.show()
# 画像に保存する
plt.savefig("output.png")
print("ok")
■多層パーセプトロン(Multilayer perceptron)で学習
import numpy as np
import cv2, pickle
from sklearn.model_selection import train_test_split
import keras
# データファイルと画像サイズの指定
data_file = "./png-etl1/katakana.pickle"
im_size = 25
in_size = im_size * im_size
out_size = 46 # ア-ンまでの文字の数
# 保存した画像データ一覧を読み込む
data = pickle.load(open(data_file, "rb"))
# 画像データを0-1の範囲に直す
y = []
x = []
for d in data:
(num, img) = d
img = img.reshape(-1).astype('float') / 255
y.append(keras.utils.np_utils.to_categorical(num, out_size))
x.append(img)
x = np.array(x)
y = np.array(y)
# 学習用とテスト用に分離する
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size = 0.2, train_size = 0.8, shuffle = True)
# モデル構造を定義
Dense = keras.layers.Dense
model = keras.models.Sequential()
model.add(Dense(512, activation='relu', input_shape=(in_size,)))
model.add(Dense(out_size, activation='softmax'))
# モデルをコンパイルして学習を実行
model.compile(
loss='categorical_crossentropy',
optimizer='adam',
metrics=['accuracy'])
model.fit(x_train, y_train,
batch_size=20, epochs=50, verbose=1,
validation_data=(x_test, y_test))
# モデルを評価
score = model.evaluate(x_test, y_test, verbose=1)
print('正解率=', score[1], 'loss=', score[0])
正解率= 0.6391304135322571 loss= 1.788340950012207
※読み込む画像を100に制限しているので、正解率は低い。
■畳み込みニューラルネットワーク(Convolutional Neural Network)で学習
import numpy as np
import cv2, pickle
from sklearn.model_selection import train_test_split
import keras
from keras.models import Sequential
from keras.models import load_model
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
from keras.optimizers import RMSprop
from keras.datasets import mnist
import matplotlib.pyplot as plt
# データファイルと画像サイズの指定
data_file = "./png-etl1/katakana.pickle"
im_size = 25
out_size = 46 # ア-ンまでの文字の数
im_color = 1 # 画像の色空間/グレイスケール
in_shape = (im_size, im_size, im_color)
# カタカナ画像のデータセットを読み込む
data = pickle.load(open(data_file, "rb"))
# 画像データを変形して0-1の範囲に直す
y = []
x = []
for d in data:
(num, img) = d
img = img.astype('float').reshape(im_size, im_size, im_color) / 255
y.append(keras.utils.np_utils.to_categorical(num, out_size))
x.append(img)
x = np.array(x)
y = np.array(y)
# 学習用とテスト用に分離する
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size = 0.2, train_size = 0.8, shuffle = True)
## CNNモデル構造を定義
#model = Sequential()
#model.add(Conv2D(32, kernel_size=(3, 3), activation='relu', input_shape=in_shape))
#model.add(Conv2D(64, (3, 3), activation='relu'))
#model.add(MaxPooling2D(pool_size=(2, 2)))
#model.add(Dropout(0.25))
#
#model.add(Flatten())
#model.add(Dense(128, activation='relu'))
#model.add(Dropout(0.5))
#
#model.add(Dense(out_size, activation='softmax'))
#model.compile(
# loss='categorical_crossentropy',
# optimizer=RMSprop(),
# metrics=['accuracy'])
#
## モデルを保存
#model.save('katakana_cnn-model.h5')
# モデルを読み込み
model = load_model('katakana_cnn-model.h5')
## 学習を実行して評価
#hist = model.fit(x_train, y_train,
# batch_size=128,
# epochs=12,
# verbose=1,
# validation_data=(x_test, y_test))
#
## 学習結果を保存
#model.save_weights('katakana_cnn-weight.h5')
# 学習結果を読み込み
model.load_weights('katakana_cnn-weight.h5')
# モデルを評価
score = model.evaluate(x_test, y_test, verbose=1)
print('正解率=', score[1], 'loss=', score[0])
正解率= 0.7630434632301331 loss= 0.9600743656573089
※読み込む画像を100に制限しているので、正解率は低い。
それでも多層パーセプトロンよりは向上している。
※読み込む画像は800まで耐えられた。
800の画像をもとに判定すると、正解率は以下になった。
正解率= 0.9686141014099121 loss= 0.12908870187871482
■畳み込みニューラルネットワーク(Convolutional Neural Network)の学習結果から画像を判定
import numpy as np
import cv2, pickle
from sklearn.model_selection import train_test_split
import keras
from keras.models import Sequential
from keras.models import load_model
from keras.optimizers import RMSprop
from keras.datasets import mnist
import matplotlib.pyplot as plt
# データファイルと画像サイズの指定
data_file = "./png-etl1/katakana.pickle"
im_size = 25
out_size = 46 # ア-ンまでの文字の数
im_color = 1 # 画像の色空間/グレイスケール
in_shape = (im_size, im_size, im_color)
# カタカナ画像のデータセットを読み込む
data = pickle.load(open(data_file, "rb"))
# 画像データを変形して0-1の範囲に直す
y = []
x = []
for d in data:
(num, img) = d
img = img.astype('float').reshape(im_size, im_size, im_color) / 255
y.append(keras.utils.np_utils.to_categorical(num, out_size))
x.append(img)
x = np.array(x)
y = np.array(y)
# 学習用とテスト用に分離する
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size = 0.2, train_size = 0.8, shuffle = True)
# モデルを読み込み
model = load_model('katakana_cnn-model.h5')
# 学習結果を読み込み
model.load_weights('katakana_cnn-weight.h5')
# モデルを評価
score = model.evaluate(x_test, y_test, verbose=1)
print('正解率=', score[1], 'loss=', score[0])