【深層学習、keras】mnistの数字の回帰モデルをkerasで作る

やりたいこと

kerasでmnistの数字の画像を入力したら、その数字を出力するような回帰モデルを
作ってみます。
0と書いてある画像を入力したら、0を出力し、
9と書いてある画像を入力したら、9と出力するようにモデルを作成します。
以下はイメージ図

f:id:ttt242242:20190331135232j:plain

ちなみにCNNは使いません!

実装

では、実装していきます。
ソースコードはgithubにもあげてあります。
https://github.com/tocom242242/aifx_blog_codes/blob/master/nn_tf2/mnist_reg.ipynb

まず必要なモジュールをimportします。keras等を入れてなかったならimportしておいてください。

import keras
from keras.datasets import mnist
import numpy as np
from keras.models import Sequential
from keras.layers.core import Dense, Activation

データセットの取得と確認

次にmnistデータを取得します。
mnistは手書き文字の認識用データセットです。
0〜9までの手書きの数字の画像が、学習用、テスト用でそれぞれ60000枚、10000枚用意されています。
データは以下のコード取得できます。

(x_train, y_train), (x_test, y_test) = mnist.load_data()

ちょっと取得したデータを表示してみます。

def plot_images(images_arr):
    fig, axes = plt.subplots(1, 5, figsize=(20,20))
    axes = axes.flatten()
    for img, ax in zip(images_arr, axes):
        ax.imshow(img)
        ax.axis('off')
    plt.tight_layout()
    plt.show()

plot_images(x_train[0:5])

上記のコードを実行すると、以下のように入力データを5つ出力します。しっかり数字の画像データであることがわかります。

データの成形

今回は単純なフィードフォワード型のネットワークを用いるので、入力データを1次元配列にしたり成形しておきます。

# 二次元配列から一次元に変換
x_train = np.array(x_train).reshape(len(x_train), 784)  
x_test = np.array(x_test).reshape(len(x_test), 784)
x_train = np.array(x_train).astype("float32")
x_test = np.array(x_test).astype("float32")

# 0〜1に正規化
x_train /= 255
x_test /= 255
y_train = np.array(y_train)
y_test = np.array(y_test)

また、0〜1の間に入力データを正規化しておきます。

モデルの構築と学習

では、学習モデルの構築と学習をしてみます。
まず、モデルを構築していきます。Keras を用いるので以下のコードで簡単に構築できます。

# モデルの構築
model = Sequential()
model.add(Dense(256, input_shape=(784,)))
model.add(Activation('relu'))
model.add(Dense(126))
model.add(Activation('relu'))
model.add(Dense(32))
model.add(Activation('relu'))
model.add(Dense(1))
model.add(Activation('linear'))

# 誤差関数は平均二乗誤差、最適化手法はrmsprop
model.compile(loss="mean_squared_error", optimizer="rmsprop")

学習前にはどのように出力するかを見てみます。試しに2つのテストデータを入れてみると

print("正解:予測")
predicted_y = model.predict(np.array([x_test[0]]))[0][0]
print("{}:{}".format(y_test[0],predicted_y)) 
predicted_y = model.predict(np.array([x_test[2]]))[0][0]
print("{}:{}".format(y_test[2],predicted_y))

以下が出力になります。

正解:予測
7:-0.4196610450744629
1:-0.38544222712516785

予測が正解とまったく異なることがわかります。
予測が正解に近くなるように学習させてみます。

次に学習させます。Kerasはfit関数によって簡単に学習させられます。

# 学習
history = model.fit(x_train, y_train,
                    batch_size=32, epochs=100,
                    verbose=1, validation_split=0.2)

評価

まず、modelのevaluate関数を使ってテストデータに対しては正解率を見てみます。

では、学習前に比較したデータで同様に出力してみます。

予測が正解にかなり近くなっています。

さらに横軸を正解、縦軸を予測値としてグラフを作ってみます。

x = np.arange(0, 10, 0.1)
plt.plot(x,x, label="optimal", color="red")

y_preds = []
for x, y in zip(x_test[0:100], y_test[0:100]):
    predicted_y = model.predict(np.array([x]))[0][0]
    y_preds.append(predicted_y)
plt.scatter(y_test[0:100], y_preds, label="(pred_y,y)")
plt.xlabel("y")
plt.ylabel("pred_y")
plt.legend()

正解と予測が同じ値ならば、直線の上にプロットされることになります。

グラフから非常に近い値を予測として出していることがわかります。

終わりに

さすがにkerasを使うとシンプルに記述できます。
kerasでもう少しいろいろやってみたいです。

https://rcm-fe.amazon-adsystem.com/e/cm?ref=qf_sp_asin_til&t=tky242242-22&m=amazon&o=9&p=8&l=as1&IS1=1&detail=1&asins=4061529021&linkId=bc02f3e5f38cf45d82e7c8957b0be1a3&bc1=ffffff&lt1=_top&fc1=333333&lc1=0066c0&bg1=ffffff&f=ifr

コメント

タイトルとURLをコピーしました