深層学習 ニューラルネットワークで回帰

ニューラルネットワークで数値データの予測を行う推定モデルを作成します。
住宅情報から価格を予測します。

まずは必要なパッケージをインポートします。

1
2
3
4
5
6
7
8
9
10
# パッケージのインポート
from tensorflow.keras.datasets import boston_housing
from tensorflow.keras.layers import Activation, Dense, Dropout
from tensorflow.keras.models import Sequential
from tensorflow.keras.callbacks import EarlyStopping
from tensorflow.keras.optimizers import Adam
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

データセットの準備を行います。

各データの内容は次の通りです。

変数名 内容
train_data 訓練データの配列
train_labels 訓練ラベルの配列
test_data テストデータの配列
test_labels テストラベルの配列
1
2
# データセットの準備
(train_data, train_labels), (test_data, test_labels) = boston_housing.load_data()

実行結果1

データセットのシェイプを確認します。

1
2
3
4
5
# データセットのシェイプの確認
print(train_data.shape)
print(train_labels.shape)
print(test_data.shape)
print(test_labels.shape)

実行結果2(一部略)
訓練データと訓練ラベルは404件、テストデータとテストラベルは102件です。
データの13は住宅情報の種類数です。

訓練データの先頭10件を表示します。

1
2
3
4
# データセットのデータの確認
column_names = ['CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD', 'TAX', 'PTRATIO', 'B', 'LSTAT']
df = pd.DataFrame(train_data, columns=column_names)
df.head()

実行結果3

訓練ラベルの先頭10件を表示します。

1
2
# データセットのラベルの確認
print(train_labels[0:10])

実行結果4

学習前の準備として、訓練データと訓練ラベルをシャッフルします。
似たデータを連続して学習すると偏りが生じてしまうのを防ぐためです。

1
2
3
4
# データセットのシャッフルの前処理
order = np.argsort(np.random.random(train_labels.shape))
train_data = train_data[order]
train_labels = train_labels[order]

訓練データとテストデータの正規化を行います。
データを一定の方法で変換し同じ単位で比較しやすくするためです。

具体的には平均0、分散1で正規化を行います。

1
2
3
4
5
# データセットの正規化の前処理
mean = train_data.mean(axis=0)
std = train_data.std(axis=0)
train_data = (train_data - mean) / std
test_data = (test_data - mean) / std

データセットのデータが平均0、分散1になっていることを確認します。

1
2
3
4
# データセットの前処理後のデータの確認
column_names = ['CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD', 'TAX', 'PTRATIO', 'B', 'LSTAT']
df = pd.DataFrame(train_data, columns=column_names)
df.head()

実行結果5(一部略)

モデルを作成します。今回は全結合層を3つ重ねた簡単なモデルとなります。

1
2
3
4
5
# モデルの作成
model = Sequential()
model.add(Dense(64, activation='relu', input_shape=(13,)))
model.add(Dense(64, activation='relu'))
model.add(Dense(1))

ニューラルネットワークモデルのコンパイルを行います。

  • 損失関数 mse
    平均二乗誤差 Mean Squared Error - 実際の値と予測値との誤差の二乗を平均したものです。
    0に近いほど予測精度が高いことになります。
  • 最適化関数 Adam
    lrは学習率です。
  • 評価指標 mae
    平均絶対誤差 Mean Absolute Error - 実際の値と予測値との絶対値を平均したものです。
    0に近いほど予測精度が高いことになります。
1
2
# コンパイル
model.compile(loss='mse', optimizer=Adam(lr=0.001), metrics=['mae'])

EarlyStoppingの準備を行います。
任意のエポック数改善がないと学習を停止します。

1
2
# EarlyStoppingの準備
early_stop = EarlyStopping(monitor='val_loss', patience=30)

学習を行います。callbacksにEarlyStoppingを指定しています。

1
2
# 学習
history = model.fit(train_data, train_labels, epochs=500, validation_split=0.2, callbacks=[early_stop])

実行結果6(途中略)

学習中に出力される情報の意味は次の通りです。

情報 説明
loss 訓練データの誤差です。0に近いほどよい結果となります。
mean_absolute_error 訓練データの平均絶対誤差です。0に近いほどよい結果となります。
val_loss 検証データの誤差です。0に近いほどよい結果となります。
val_mean_absolute_error 検証データの平均絶対誤差です。0に近いほどよい結果となります。

上記のデータうち、訓練データの平均絶対誤差(mae)と検証データの平均絶対誤差(val_mae)をグラフ表示します。

1
2
3
4
5
6
7
8
# グラフの表示
plt.plot(history.history['mean_absolute_error'], label='train mae')
plt.plot(history.history['val_mean_absolute_error'], label='val mae')
plt.xlabel('epoch')
plt.ylabel('mae [1000$]')
plt.legend(loc='best')
plt.ylim([0,5])
plt.show()

実行結果7

テストデータとテストラベルを推定モデルに渡して評価を行い、平均絶対誤差を算出します。

1
2
3
# 評価
test_loss, test_mae = model.evaluate(test_data, test_labels)
print('loss:{:.3f}\nmae: {:.3f}'.format(test_loss, test_mae))

実行結果8

平均絶対誤差は2.655となりました。

テストデータの先頭10件の推論を行い、予測結果を出力します。

1
2
3
4
5
6
# 推論する値段の表示
print(np.round(test_labels[0:10]))

# 推論した値段の表示
test_predictions = model.predict(test_data[0:10]).flatten()
print(np.round(test_predictions))

実行結果9

実際の価格に近い価格が推論されているような気がします。

(Google Colaboratoryで動作確認しています。)

参考

AlphaZero 深層学習・強化学習・探索 人工知能プログラミング実践入門 サポートページ