External Memory

プログラミング周辺知識の備忘録メイン

MNIST学習データを使ってWin10の標準フォントの数字識別

タイトルの通り、MNIST手書きデータを学習用として用いてフォントの数字を識別した。
機械学習の検証というより、画像データ編集の練習のために行った。
一般のデータを機械学習に用いるには当然学習やテストで使えるように加工しなければならない。
また、精度を上げるためのデータ加工を行うこともあるだろう。

今回はWindows10に元から入っているフォントをテストデータとして使った。
使用したフォントは"Arial"、"MS明朝"、"MSゴシック"、"Times New Roman"、Impact"、"Segoe Print"。
Arial
f:id:taka74k4:20170819182432p:plain
MS明朝
f:id:taka74k4:20170819182455p:plain
MSゴシック
f:id:taka74k4:20170819182512p:plain
Times New Roman
f:id:taka74k4:20170819182524p:plain

最後の二つは個人的になじみはないが、
Impactは下記のようなはっきりとした太字フォントであり
f:id:taka74k4:20170819182533p:plain
Segoe Printは以下のような手書き風のフォントである。
f:id:taka74k4:20170819182544p:plain

データ加工

データの加工はPythonライブラリのpillowsを使った。
プログラムは以下の通りである。

from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont

def get_num_img(numlist,fontpath,size=(28,28)):

    font = ImageFont.truetype(fontpath,int(size[1]*0.8))
    imglist = []
    for i in numlist:
        img = Image.new('1',size)
        draw = ImageDraw.Draw(img)
        num_imgsize = font.getsize(i)
        draw.text(((size[0]-num_imgsize[0])//2,(size[1]-num_imgsize[1])//2),i,1,font=font)
        imglist.append(img)
    return imglist

def save_img(imglist,savepath,numlist):
    for img,num in zip(imglist,numlist):
        img.save(open("{}_{}.png".format(savepath,num),"w+b"),'png')
    

if __name__ == '__main__':
    numlist = [str(i)for i in range(10)]
    num_img = get_num_img(numlist,"C:/Windows/Fonts/arial.ttf")
    save_img(num_img,"fontimg/arial",numlist)

画像のサイズはMNISTデータと同じく28*28 pixelとした。
数字が画像に収まるようにサイズ調整をして、真ん中に来るよう位置調整を行っている。
Segoe Printは上記コードでは真ん中に来ないため、位置調整のために少しスライドさせたデータも作成した。

フォント別の分類精度

以下が出力結果である。
画像は10種類しかないので、正答率は10%刻みである。
使ったニューラルネットワークはすべて全結合層のFFNN(多層パーセプトロン)である。
Incorrect_numは間違った回答を出した数字である。

units                   step         loss    accurancy
--------------------------------------------------------
*** keep_prob = 0.8 ***
Font:arial
784,392,392,10         30000       0.3942       0.9000
Incorrect_num:[6]

Font:msmincho
784,392,392,10         30000       0.3028       1.0000
Incorrect_num:[]

Font:msgothic
784,392,392,10         30000       0.7880       0.8000
Incorrect_num:[4, 6]

Font:times
784,392,392,10         30000       1.2134       0.8000
Incorrect_num:[2, 4]

Font:impact
784,392,392,10         30000       1.8541       0.5000
Incorrect_num:[2, 3, 4, 6, 9]

Font:segoepr
784,392,392,10         30000      13.0504       0.2000
Incorrect_num:[0, 1, 2, 4, 5, 6, 8, 9]

また畳み込みネットワーク(CNN)でもテストを行った。
ネットワーク構造はtensorflowサンプルプログラムのmnist-deep.pyと同じである。

 step           loss      accurancy
--------------------------------------
*** keep_prob = 0.5 ***
Font:arial
20000         0.8216         0.8000
Incorrect_num:[6, 9]

Font:msmincho
20000         1.0366         0.7000
Incorrect_num:[4, 6, 7]

Font:msgothic
20000         0.2568         0.9000
Incorrect_num:[6]

Font:times
20000         0.8701         0.7000
Incorrect_num:[2, 4, 9]

Font:impact
20000         1.8348         0.7000
Incorrect_num:[4, 6, 9]

Font:segoepr
20000         5.9540         0.3000
Incorrect_num:[0, 2, 4, 5, 6, 8, 9]

MNISTデータほど正答率はよくないものもあるようである。
また、FFNNとCNNの正答率やloss値を互いに見比べて、分類が得意なフォントも違うようでCNNが全てのケースでFFNNより良いパフォーマンスを示すわけではないようである。

4や6、9の間違いが目立つように見える。
6と9は手書きと形が明らかに特徴が異なるのでなんとなくわかるが、4を間違うのはなぜか?
4は手書きでは9に似ているので、4を9と勘違いしたりしているのだろうか。

画像上の数字の位置について

一方、手書きの数字とは似つかないデータほど正答率は落ちる傾向があると考えたが、SegoePrintが正答率が低いのは疑問である。
画像上の数字の位置が原因のひとつとして考え、位置を真ん中寄りに変更して再度テストした。

FFNN
units                   step         loss    accurancy
--------------------------------------------------------
Font:segoepr2
784,392,392,10         30000       0.1172       0.9000
Incorrect_num:[1]
CNN
 step           loss      accurancy
--------------------------------------
Font:segoepr2
20000         0.0035         1.0000
Incorrect_num:[]

位置を変更することで、よい分類精度を得ることができた。
loss値も低いので、SegoePrintがMNISTデータのような手書き数字に似ていることを示しているのだろう。

MNISTデータは飽くまで手書き数字の分類が得意であって、フォント数字の分類は苦手であるといえる。
分類したいデータに対して学習データをうまく選んだり加工しないといけないことを示唆している。
逆にフォントの形状の多様性から、多くのフォントデータをいろいろ加工して学習し、様々な数字を分類することはおそらく効果的であると予想される。

また、CNNは対象の画像上の位置に対してそれなりの柔軟性を持っていると思っていたが、この結果だけを見るとそうでもないようである。