【Python】scikit-learnで手書き数字を判定してみた

 

こんにちは。のっくん(@yamagablog)です。

 

この記事では機械学習を使って手書き数字の認識にチャレンジしてみます。

 

[toc]

 

データセット

 

scikit-learnに付属している手書き数字データセットを使ってみます。

 

「Optical Recognition of Handwritten Digits Data」、手書き数字の光学認識データセットと言う長い名前のデータセットです。

 

8×8ピクセルの手書き数字データが5620個用意されています。

 

https://archive.ics.uci.edu/ml/datasets/optical+recognition+of+handwritten+digits

 

 

環境構築

 

ローカルのMacでやっても良いのですが、今回はUbuntuにsshでアクセスしてその上で環境構築をします。

 

UbuntuにAnacondaがインストール済みの前提で進めていきます。

 

digitsと言う名前の仮想環境を作ります。anacondaのパッケージをインストールするように指定しています。Pythonのバージョンは3.6にします。

 

#仮想環境の作成
$conda create -n digits python=3.6 anaconda

#仮想環境の一覧
$conda info -e
# conda environments:
#
base                  *  /home/matsu/anaconda3
digits                   /home/matsu/anaconda3/envs/digits

# アクティベート
$source activate digits

# opencvのインストール
(digits)$pip install opencv-python

# jupyterの起動
(digits)$jupyter notebook

 

これで、準備が出来ました。macからjupyterにアクセスしてコードを書いていきます。

 

学習

 

from sklearn.model_selection import train_test_split
from sklearn import datasets,svm,metrics
from sklearn.metrics import accuracy_score

digits = datasets.load_digits()
x = digits.images
y = digits.target
#二次元配列を一次元配列に変換
x = x.reshape((-1,64)) 

# データを学習用とテスト用に分割する
x_train,x_test,y_train,y_test = train_test_split(x,y,test_size=0.2)

# データを学習
clf = svm.LinearSVC()
clf.fit(x_train, y_train)

# 予測して精度を確認する
y_pred = clf.predict(x_test)
print(accuracy_score(y_test, y_pred))

 

実行してみると、、

 

0.9444444444444444

 

高精度で識別出来ました。

 

以下のコードを実行して、学習済みデータを保存しておきます。

 

from sklearn.externals import joblib
joblib.dump(clf, 'digits.pkl')

 

自分で書いた文字をテストする

 

さて、ここで自分の書いた文字を試してみます。

 

ちなみに、画像の読み込みにはcv2を使うのですがインポートしてみるとエラーが出ました。

 

 

ん? なんだ?

 

「libSM.so.6が無いよ。ばかやろー」

 

と怒られています。以下のコマンドで必要なライブラリをubuntuに入れましょう。

 

sudo apt-get install libsm6 libxrender1 libfontconfig1

 

これで解決です。

 

では私の書いた美しい「3」を認識できるか試してみます。

 

 

「three.png」と言う名前で保存しました。

 

import cv2
from sklearn.externals import joblib

def predict_digit(filename):
    clf = joblib.load("digits.pkl")
    #画像を読み込む
    my_img = cv2.imread(filename)
    #グレースケールに変換する
    my_img = cv2.cvtColor(my_img, cv2.COLOR_BGR2GRAY)
    # 8 * 8のサイズに変換する
    my_img = cv2.resize(my_img,(8,8))
    #白黒反転する
    my_img = 15 - my_img // 16
    #二次元を一次元に変換
    my_img = my_img.reshape((-1,64))
    res = clf.predict(my_img)
    return res[0]

n = predict_digit("three.png")
print("three.png = " + str(n))

 

さぁ、3来い!

 

three.png = 9

 

[speech_bubble type=”ln” subtype=”L1″ icon=”ilust/cat2_1_idea.png” name=”ネコ”]違ってるー!![/speech_bubble]

 

[speech_bubble type=”ln” subtype=”L1″ icon=”profile_face.png” name=”のっくん”]残念だったねw まぁ、3と9似てるからしょうがないよねw
[/speech_bubble]

 

リベンジで「2」を書いてテストしてみました。

 

 

two.png = 2

 

今度は合ってますね。めでたしめでたし。

 

参考

 

「PythonによるAI・機械学習・深層学習アプリ」のつくり方

 

ABOUTこの記事をかいた人

個人アプリ開発者。Python、Swift、Unityのことを発信します。月間2.5万PVブログ運営。 Twitter:@yamagablog