楚簡の文字認識
CNNの勉強(?)。
とりあえず画像を読み込んで分類する的なことをしてもらおうとした。
なにか手持ちのデータで良いデータがないかと思ったがなかった。
MNISTを見て、楚簡の字なら読めるんじゃないかと思った。
《楚簡帛字典》より、清華簡(貳~柒)の「一」「二」「三」字を抜き出し、「一」が35字、「二」102字、「三」が86字からなるデータセットを作成。少ない気がするけど簡単そうだし多分大丈夫でしょ。
それぞれを「./inputfolder/1」「./inputfolder/2」「./inputfolder/3」的なフォルダに入れて読み込んだ。楚簡の図版は古いのや簡報のものは白黒写真も多いので、そいつらにも対応してくれるように白黒にした。
from keras.preprocessing.image import load_img, img_to_array
from keras.utils import np_utils
for i, folder in enumerate(inputfolder.glob("*/")):
for file in folder.glob("*.gif"):
img = load_img(file, grayscale=True, target_size=(64, 64))
imgarray = img_to_array(img)
xarray.append(imgarray)
yarray.append([i])
yarray = np_utils.to_categorical(yarray, i+1)
このあとデータセットのうちランダムに9割を学習、1割をテスト用に分割した。
ネットワーク(コピペ)。
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten, Conv2D, MaxPooling2D
model = Sequential()
model.add(Conv2D(32, (3, 3), activation="relu",
padding="same", input_shape=img_shape))
model.add(Conv2D(32, (3, 3), activation="relu"))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))model.add(Conv2D(64, (3, 3), activation="relu", padding="same"))
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(512, activation="relu"))
model.add(Dense(256, activation="relu"))
model.add(Dense(i, activation="softmax"))model.compile(loss="categorical_crossentropy",
optimizer="SGD",
metrics=["accuracy"])
400回くらいまわしてみる。
history = model.fit(X_train, y_train,
batch_size=64, epochs=400,
verbose=1,
validation_data=(X_test, y_test))
まわった。
Epoch 1/400
198/198 [==============================] - 5s 25ms/step - loss: 1.1098 - acc: 0.1616 - val_loss: 1.0876 - val_acc: 0.4400
Epoch 100/400
198/198 [==============================] - 0s 752us/step - loss: 0.6844 - acc: 0.7273 - val_loss: 0.4319 - val_acc: 0.8000
Epoch 200/400
198/198 [==============================] - 0s 746us/step - loss: 0.3169 - acc: 0.8889 - val_loss: 0.6147 - val_acc: 0.8400
Epoch 300/400
198/198 [==============================] - 0s 764us/step - loss: 0.0851 - acc: 0.9747 - val_loss: 0.5639 - val_acc: 0.8800
Epoch 400/400
198/198 [==============================] - 0s 754us/step - loss: 0.0119 - acc: 1.0000 - val_loss: 0.9266 - val_acc: 0.8800
まわった。
上博簡から「一」「二」「三」字を適当に拾ってモデルに放り込んでみた。
model.predict_classes(np.array(inputarray).astype(np.float32)/255)
# 0=「一」,1=「二」,2=「三」
結果。
array([0, 1, 2, 1, 0, 1, 2])
四枚目は右上がりがきついがどうみても「三」なのに「二」と予測した。無能だな。
とりあえずちゃんと回るコードが書けたということがわかった。