ニューラルネットワークの実装(回帰)
本章では、前章に引き続き TensorFlow を使用して分類と同じく教師あり学習のトピックである回帰について実装する方法を学んでいきます。基本的には、分類と同じように実装することができるのでシンプルです。
復習ですが、回帰とは目標値 が連続値のデータセットと入力値 の関係を当てはめることを指します。上記の図ではデータセットに対して線を引いていますが、簡単にイメージするとこのようにデータセットを十分に表現できる線を引きたいということです。
本章の流れ
- データセットの準備
- モデルの定義
- モデルの学習
- 練習問題
データセットの準備
それではデータセットを準備しましょう。家賃の予測をする問題設定です。Keras ではいくつかデータセットを準備されており、tf.keras.datasets
の中から選択します。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import tensorflow as tf
家賃が目的変数となっており、家賃を求めるために 13 個の入力変数が用意されています。部屋の広さや犯罪発生率など、皆さんが家の家賃を推定するときに使っていそうな変数が使われていそうです。各変数の説明は下記になりますので、気になる方はチェックしてください。
変数名 | 説明 |
---|---|
CRIM | 人口 1 人当たりの犯罪発生数 |
ZN | 25,000 平方フィート以上の住居区画の占める割合 |
INDUS | 小売業以外の商業が占める面積の割合 |
CHAS | チャールズ川によるダミー変数 (1: 川の周辺, 0: それ以外) |
NOX | NOx の濃度 |
RM | 住居の平均部屋数 |
AGE | 1940 年より前に建てられた物件の割合 |
DIS | 5 つのボストン市の雇用施設からの距離 (重み付け済) |
RAD | 環状高速道路へのアクセスしやすさ |
TAX | $10,000 ドルあたりの不動産税率の総計 |
PTRATIO | 町毎の児童と教師の比率 |
B | 町毎の黒人 (Bk) の比率を次の式で表したもの。 |
LSTAT | 給与の低い職業に従事する人口の割合 (%) |
tf.keras.datasets.boston_housing
と名前がついたデータセットを使用します。load_data()
を使って、データをダウンロードしてきています。
# データセットの準備
dataset = tf.keras.datasets.boston_housing
train, test = dataset.load_data()
# 学習用データセット
train
# テスト用データセット
test
load_data()
を使用すると、便利な機能ですでに学習用データセット (train) とテスト用データセット (test) に分かれて、さらに入力変数と目標値にも分かれて準備されています。それぞれのサンプル数を確認しましょう。
# サンプル数
train[0].shape, test[0].shape
ただし、このまますぐに学習に向かうことはできず、目標値と入力値に分割する必要があります。今回のデータセットの形式では、(入力値, 目標値)
で用意されているので、それぞれを定義します。NumPy の array 形式に格納し、さらにデータ型を 32bit へと変更しておきます。こちらは前章の分類と同じ作業です。
# 学習用データセット
x_train = np.array(train[0], np.float32)
t_train = np.array(train[1], np.int32)
# テスト用データセット
x_test = np.array(test[0], np.float32)
t_test = np.array(test[1], np.uint32)
x_train.dtype, x_train.shape
x_test.dtype, x_test.shape
t_train
を除くと、x_train
は 404 行 13 列であることが確認できます。また、テスト用データセットでは、102 行 13 列であることがわかりますので、これはサンプル数全体が 506、入力変数が 13 あることを意味しています。
モデルの定義と学習
モデルの定義から学習まで行います。回帰と分類では、目的関数や最終層の活性化関数が違いますので、注意しながら定義していきましょう。
import os, random
def reset_seed(seed=0):
os.environ['PYTHONHASHSEED'] = '0'
random.seed(seed)
np.random.seed(seed)
tf.random.set_seed(seed)
今回定義するモデルの全体像はこちらの図です。入力層のノード数が 13、中間層のノード数が 32、出力層のノード数が 1 としています。
モデルのコンパイルでは、最適化手法に adam
を使用し、目的関数は平均ニ乗誤差 (mse
)、評価指標は平均絶対誤差 (mae
) を定義しました。
平均ニ乗誤差や平均絶対誤差は、回帰でよく扱われる指標です。簡単に数式を紹介しておくと、 このデータにおける 番目のサンプルの目標値を 、予測値を をすると、
が平均ニ乗誤差 (Mean Squeard Error:MSE) の式として表され、
が平均絶対誤差 (Mean Absolute Error:MAE) の式として表されます。
この段階では数式を完璧に理解する必要はありませんので、イメージとして正解と予想の離れ具合を評価している、と思っておいていただければ大丈夫です。
# シードの固定
reset_seed(0)
# モデルの定義
model = tf.keras.models.Sequential([
tf.keras.layers.Dense(32, activation='relu', input_shape=(13, )),
tf.keras.layers.Dense(1),
])
# モデルのコンパイル
model.compile(optimizer='adam',
loss='mse',
metrics=['mae'])
このままモデルの学習に移ることができるのですが、いくつか便利な機能をご紹介します。
上のセルで定義したモデルの構造の詳細を確認する方法があります。model.summary()
と実行してもらうと、層の順番や出力形状、パラメータの数が一覧で表記することができます。
# モデル構造の確認
model.summary()
各層の構造、モデル全体のパラメータの数 (Total params) や学習するパラメータの数 (Trainable params) などがひと目でわかります。
また、tf.keras.utils.plot_model()
を使用するとインプットからアウトプットまでの一連の流れを把握することができます。こちらもよく使用しますので、覚えておきましょう。
# モデル構造の可視化
tf.keras.utils.plot_model(model)
このように目で見て直感的に構築したモデルを確認できるので、便利な機能です。さらに、デフォルトで model.png
という名前で保存されているので何か誰かに説明する際にも使用することができます。
# モデルの学習
history = model.fit(x_train, t_train,
epochs=30,
batch_size=32,
validation_data=(x_test, t_test))
学習済みモデルを評価する方法として、.evaluate()
があります。学習が終了した一番最後の状態で、テスト用データセットを入力として目的関数の値 (loss) と評価指標の値 (metrics) を表示します。
# 学習済みモデルの評価
score = model.evaluate(x_test, t_test)
score
具体的に出力された [73.44642639160156, 6.115375995635986]
の意味としては、最初の73.446・・
に目的関数の値 (loss) が、6.1153・・
に評価指標の値 (metrics) が格納されています。
それでは前章でも扱ったように、結果の可視化を Pandas を使って行いましょう。
# 結果の可視化
result = pd.DataFrame(history.history)
# 目的関数の可視化
result[['loss', 'val_loss']].plot();
# 評価指標の可視化
result[['mae', 'val_mae']].plot();
練習問題
上記の結果のように、平均ニ乗誤差 (MSE) が検証データに対して約 73 となっており、誤差を二乗しているとしても少し予測誤差が大きいことがわかります。この原因を考え、対策をうち、平均ニ乗誤差が小さくなるようなモデルを考えてみましょう。
ヒント
- Batch Normalization をいれる
- エポック数を増やす
- 最適化手法 (
optimizer
) を変更する - データセットを可視化し、必要な特徴量を選択する or 増やす
試行錯誤することで、実際の動作などの理解が深まるのでぜひ取り組りくんでください。