4 手書き文字認識
4.1 データの読み込み
ここでは手書きで描いた数字の画像データを読み込んでそれが何という数字を書いたかを認識(予測)します。
今回は機械学習の練習で使うデータセットの8x8の手書き画像を読み込みます。 ファイル deep_digits.ipynb に以下を記述します。
from sklearn import datasets
digits = datasets.load_digits()
x = digits.images
y = digits.target
最初のデータを表示してみます。
digits.images[0]
二次元配列になっており、0~15までの数が入っています。これが手書き文字の画像です。データは縦8ドット×横8ドットで、数字が大きいほど色が濃いドットを表しています。
この数字が何を表しているかは、digits.target に答えが入っています。
digits.target[0]
4.2 画像の表示
数値ではわかりにくいので画像で表示してみましょう。 matplotlibでimshow関数にこのデータを渡すと画像として表示されます。
for文を使って最初の15個を表示してみましょう。 matplotlibのsubplot機能を使って3行×5列の複数の画像を表示してみます。
import matplotlib.pyplot as plt
for i in range(15):
plt.subplot(3, 5, i+1)
plt.axis("off")
plt.title( str(digits.target[i]) )
plt.imshow( digits.images[i], cmap="gray" )
4.3 学習と評価
では、これを学習しましょう。
二次元のリストであるxを一次元のリストに変換にし、訓練データと学習データに分けます。
x = x.reshape(-1, 64)
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=0)
モデルを構築します。今回は隠れ層を3層配置します。
from sklearn.neural_network import MLPClassifier
model = MLPClassifier(
hidden_layer_sizes=(100,50,50), # 隠れ層
max_iter=100, # 最大反復回数
random_state=0
)
今回はまず、最初に8x8で64個あるニューロンを100個の層に結合します。その後、50個、50個と結合し、最後に10個のニューロンになる出力層があります。
この出力層10個が0~9の数値に対応します。0番目の数値が一番大きいなら0と予測されたことになります。
学習し、予測して評価を出してみます。
# 学習
model.fit(x_train, y_train)
# 評価
model.score(x_test, y_test)
決定木、ランダムフォレストよりも高い結果がでます。 このようにニューラルネットワークは画像認識により高い精度を発揮します。
4.4 確率表示
実際に、確率を表示してみます。テストデータの1番目を出してみましょう。
index = 1
proba = model.predict_proba(x_test) # 確率取得
for x in range(10):
print(f"{x} の確率: {proba[index][x]:.4f}")
print(f"正解:{y_test[index]}")
4.5 誤差のグラフ表示
誤差を学習回数毎にグラフで表示してみます。model.loss_curve_ に記録されています。
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme(font=["Meiryo"])
plt.plot(model.loss_curve_)
plt.title('学習の損失推移')
plt.xlabel('反復回数')
plt.ylabel('損失')
plt.show()
4.6 パラメータ数
パラメータの総数を計算してみます。
param_sum = 0
for i, coef in enumerate(model.coefs_):
print(f"Layer {i+1} 重み付け : {coef.shape} パラメータ数:{coef.shape[0] * coef.shape[1]}")
param_sum += coef.shape[0] * coef.shape[1]
for i, bias in enumerate(model.intercepts_):
print(f"Layer {i+1} バイアス : {bias.shape[0]}")
param_sum += bias.shape[0]
print(f"総パラメータ数: {param_sum}")