概要
Tensorflowを使ってMNISTの手書き文字をClassificationではなくRegressionで予測するという特に意味のない行為。
バージョン情報
- tensorflow==1.3.1
学習処理
よくあるCNNでの手書き文字認識のモデル。
変わっているところはlayersの最後が Dense(1) になっているところとoptimizerがRMSPropOptimizerになっているところ。
TensorflowのチュートリアルにあるようなDence(10)にして10個のクラスを予測するのではなくDense(1)で1つの数値を予測する形になっている。
またlossにはmse(mean squared error)を使っている。
import tensorflow as tf from tensorflow.keras import layers from sklearn import model_selection (x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data() x_train = x_train.reshape([60000, 28, 28, 1]) x_test = x_test.reshape([10000, 28, 28, 1]) # testデータの1/10をvalidationデータに使う x_test, x_val, y_test, y_val = model_selection.train_test_split( x_test, y_test, test_size=0.1, stratify=y_test) model = tf.keras.models.Sequential([ layers.Convolution2D(64, (4, 4), activation='relu', input_shape=(28, 28, 1)), layers.MaxPooling2D((2, 2)), layers.Dropout(0.1), layers.Convolution2D(64, (4, 4), activation='relu'), layers.MaxPooling2D((2, 2)), layers.Dropout(0.3), layers.Flatten(), layers.Dense(256, activation='relu'), layers.Dropout(0.5), layers.Dense(64, activation='relu'), layers.BatchNormalization(), layers.Dense(1) ]) optimizer = tf.train.RMSPropOptimizer(0.001) model.compile(loss='mse', optimizer=optimizer, metrics=['mae']) tensorboard_callback = tf.keras.callbacks.TensorBoard(log_dir="logs") history = model.fit( x_train, y_train, epochs=200, validation_split = 0.2, verbose=0, callbacks=[tensorboard_callback])
tensor boardで学習状況の確認
lossにはmseの値が入っている。
metricsで指定したmae(mean absolute error)の値。
val_lossはイマイチなことになっている。
historyの確認
historyのラストの値を確認。
pd.DataFrame(history.history).tail(1)
loss | mean_absolute_error | val_loss | val_mean_absolute_error | |
---|---|---|---|---|
199 | 0.375688 | 0.476193 | 0.682941 | 0.711386 |
テストデータでモデルを評価
model.evaluateで評価してみる。
import numpy as np loss, mae = model.evaluate(x_test, y_test, verbose=2) #=> - 0s - loss: 0.6494 - mean_absolute_error: 0.6806
validation dataでの結果とだいたい同じ値。
テストデータでplot
実際の画像と推定結果を並べて表示してみる。
from matplotlib import pylab as plt f, ax_list = plt.subplots(5, 5, figsize=(10, 10)) for i, p in enumerate(model.predict(x_test[:25])): test_image = x_test[i].reshape(28, 28) ax = ax_list[int(i / 5)][i % 5] ax.imshow(test_image, cmap='gray', vmin=0, vmax=255) ax.set_title(str(p)) ax.axis('off')
そこまで大きくはずれた結果になっている画像は見当たらない。
実際に差がいくつになっているか1%刻みでパーセンタイルで表示してみる。
percentile = np.percentile(np.abs(y_pred.reshape(len(y_test)) - y_test), q=[i for i in range(101)]) for i, p in enumerate(percentile): print('%d%% : %f ' % (i, p), end='') if i % 5 == 4: print('') #=> 0% : 0.000015 1% : 0.010779 2% : 0.020681 3% : 0.028143 4% : 0.033981 #=> 5% : 0.040912 6% : 0.047804 7% : 0.055319 8% : 0.066414 9% : 0.162870 #=> 10% : 0.204350 11% : 0.222296 12% : 0.235256 13% : 0.246413 14% : 0.258070 #=> 15% : 0.268439 16% : 0.279743 17% : 0.292645 18% : 0.310170 19% : 0.324281 #=> 20% : 0.336159 21% : 0.346213 22% : 0.354617 23% : 0.363465 24% : 0.369943 #=> 25% : 0.375881 26% : 0.382982 27% : 0.391841 28% : 0.403090 29% : 0.421755 #=> 30% : 0.440723 31% : 0.455754 32% : 0.469524 33% : 0.482156 34% : 0.492203 #=> 35% : 0.502215 36% : 0.510913 37% : 0.520904 38% : 0.531517 39% : 0.542054 #=> 40% : 0.551697 41% : 0.562289 42% : 0.572216 43% : 0.584174 44% : 0.595658 #=> 45% : 0.609094 46% : 0.622925 47% : 0.644110 48% : 0.663562 49% : 0.687310 #=> 50% : 0.705858 51% : 0.723974 52% : 0.736585 53% : 0.749156 54% : 0.759072 #=> 55% : 0.770889 56% : 0.779675 57% : 0.787372 58% : 0.795873 59% : 0.805422 #=> 60% : 0.814253 61% : 0.821961 62% : 0.829439 63% : 0.837790 64% : 0.845326 #=> 65% : 0.853941 66% : 0.860545 67% : 0.866964 68% : 0.875309 69% : 0.883531 #=> 70% : 0.892430 71% : 0.900244 72% : 0.908062 73% : 0.915675 74% : 0.923948 #=> 75% : 0.931080 76% : 0.937270 77% : 0.946038 78% : 0.954966 79% : 0.965360 #=> 80% : 0.974450 81% : 0.984057 82% : 0.996121 83% : 1.007325 84% : 1.019098 #=> 85% : 1.030877 86% : 1.042961 87% : 1.056136 88% : 1.068431 89% : 1.084204 #=> 90% : 1.096824 91% : 1.112234 92% : 1.132662 93% : 1.153828 94% : 1.177927 #=> 95% : 1.206677 96% : 1.238960 97% : 1.287427 98% : 1.363786 99% : 1.635719 #=> 100% : 6.303422
99%の予測は1.63の差に収まり、最もハズレている結果は6.3の差が出ている。
35%の時点で0.5を超えてしまうのでroundした結果を正とした場合、accuracyはたったの34%になる。酷い数字だ。
np.mean(np.round(y_pred).reshape(len(y_test)) == y_test) #=> 0.3472222222222222
類似のモデルを調べてみるとDense(64)からDense(1)に一気にやっているところがどうもイマイチなようで、下記のように16→4を挟むことでaccuracyが97%まで改善した。
model = tf.keras.models.Sequential([ layers.Convolution2D(64, (4, 4), activation='relu', input_shape=(28, 28, 1)), layers.MaxPooling2D((2, 2)), layers.Dropout(0.1), layers.Convolution2D(64, (4, 4), activation='relu'), layers.MaxPooling2D((2, 2)), layers.Dropout(0.3), layers.Flatten(), layers.Dense(256, activation='relu'), layers.Dropout(0.5), layers.Dense(64, activation='relu'), layers.BatchNormalization(), layers.Dropout(0.5), layers.Dense(16, activation='relu'), layers.Dense(4, activation='relu'), layers.Dense(1) ])
loss | mean_absolute_error | val_loss | val_mean_absolute_error | |
---|---|---|---|---|
499 | 0.778615 | 0.513578 | 0.18739 | 0.182132 |
y_pred = model.predict(x_test) np.mean(np.round(y_pred).reshape(len(y_test)) == y_test) #=> 0.973
普通にやったら99%以上の精度が出るものなので97%出てもだからなんだという感じではあるけど。
改定履歴
Author: Masato Watanabe, Date: 2020-03-28, 記事投稿