LoginSignup
5

More than 5 years have passed since last update.

Coursera Machine Learningの課題をPythonで: ex4(ニューラルネットワークで手書き数字認識)

Posted at

はじめに

Coursera Machine Learningの課題をPythonで: ex3(ロジスティック回帰で手書き数字認識)に触発されて書きました。
昨年scikit-learnにNeural Networkが実装されたこともあり、本記事では、課題ex4をPythonで書いてみます。

ex4の概要

ex4は、ニューラルネットワークを用いて手書き数字を認識するタスク。データセットはex3に引き続きMNISTのサブセットということで、20x20ピクセルのグレースケール画像が5000枚、これがMatlab/Octaveの.matというデータ形式で与えられています。

前編

まずは5000枚の画像を読み込み、ランダムに選ばれた100枚を表示します。
(Coursera Machine Learningの課題をPythonで: ex3(ロジスティック回帰で手書き数字認識)を参考にしました)

ex4.py
import numpy as np
import matplotlib.pyplot as plt
import scipy.io as scio
from sklearn.model_selection import train_test_split
from sklearn.neural_network import MLPClassifier

# scipy.io.loadmat()を使ってmatlabデータを読み込み
data = scio.loadmat('ex4data1.mat')
X = data['X']  # X は 5000x400 行列
y = data['y'].ravel()  # y は 5000 x 1 行列、ravel()を使って5000次元ベクトルに変換

sel = np.random.randint(0,len(X),100)
fig = plt.figure()
plt.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=None, hspace=None)
for i in range(0,100):
    ax = fig.add_subplot(10,10,i+1)
    ax.axis('off')
    ax.imshow(X[sel[i]].reshape(20,20).T, cmap = plt.get_cmap('gray'))
plt.show()

実行結果はこちら
Unknown.png

中編

続いて、以下のように25個のユニットを持つ隠れ層を1層持つニューラルネットワークを実装します。
スクリーンショット 2017-02-02 19.31.20.png

とは言っても、scikit-learnのMLPClassifierを使うだけなのでコードはシンプルです。

ex4.py
#1 hidden units (size 25)
model = MLPClassifier(hidden_layer_sizes=(25, ), solver="sgd",
                      random_state=0,max_iter=1000,
                      alpha = 0.0001, tol=1e-9)
model.fit(X, y)
model.score(X, y)

引数は色々取ることができます。詳しくはこちら(公式)

実行すると、訓練データでの正答率は 0.96579 と表示されました。

Courseraでは伝達関数にシグモイド関数を使っていますが、MLPClassifierではデフォルトだとReLU(ランプ関数)が使われます。
こちらの方が一般的に精度が高いようなので、Courseraの課題とは違いますがReLUを利用しました。もしシグモイド関数を使いたい場合は、activation='logistic'と引数を指定すればOKです。
(因みに上記のコードのままシグモイド関数を使った場合の正答率は 0.91859 となりました。結構下がりましたね。。)

後編

課題の最後に、隠れ層を可視化してみるコーナーがあります。
こちらはCoursera上では宿題ではありませんが、以下、pythonで書いてみます。

ex3_hidden.py
fig, axes = plt.subplots(5, 5)
vmin, vmax = model.coefs_[0].min(), model.coefs_[0].max()
for coef, ax in zip(model.coefs_[0].T, axes.ravel()):
    ax.matshow(coef.reshape(20, 20), cmap=plt.cm.gray, vmin=.5 * vmin,
               vmax=.5 * vmax)
    ax.set_xticks(())
    ax.set_yticks(())

plt.show()

隠れ層を見るには、学習後のcoefにアクセスすればOKです。
隠れ層の全てのユニットを同じスケールで可視化するために、vminとvmaxにmodel.coefs_[0]の最小値と最大値をセットしました。

実行結果はこちら
Unknown-1.png

ほとんど使われていないユニットもあることがわかります。

おまけ

また、Coursera Machine Learningの課題をPythonで: ex3(ロジスティック回帰で手書き数字認識)から認識を間違えたデータを表示するコードもお借りして、表示してみました。

ex4_omake.py
wrong_index = np.array(np.nonzero(np.array([model.predict(X) != y]).ravel())).ravel()
wrong_sample_index = np.random.randint(0,len(wrong_index),25)
fig = plt.figure()
plt.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=0.5, hspace=0.5)
for i in range(0,25):
    ax = fig.add_subplot(5,5,i+1)
    ax.axis('off')
    ax.imshow(X[wrong_index[wrong_sample_index[i]]].reshape(20,20).T, cmap = plt.get_cmap('gray'))
    ax.set_title(str(model.predict(X[wrong_index[wrong_sample_index[i]]].reshape(1,-1))[0]))
plt.show()

※ ax.set_title部分のみ、scikit-learnのバージョン0.18に対応して少しだけ書き換えました。具体的には、1次元配列を渡すことが奨励されないようになったことを受け、サンプルデータをreshape(1, -1)とreshapeしました。

実行結果はこちら
Unknown-2.png
人間が見てもけっこう惜しいものがあって、面白いです。
しかしチューニングが必要ですね。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5