import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import random
import keras
from keras.models import Sequential
from keras.layers import Dense
from tensorflow import set_random_seed
from sklearn.model_selection import train_test_split
In this example, we will be working with the "Boston Housing" dataset. This dataset contains data for 506 census tracts of Boston from the 1970 census.
The dataset contains the following 19 pieces of information for each census tract:
town
- name of towntract
- census tractlon
- longitude of census tractlat
- latitude of census tract medv
- median value of owner-occupied homes in USD 1000'scmedv
- corrected median value of owner-occupied homes in USD 1000'scrim
- per capita crime rate by townzn
- proportion of residential land zoned for lots over 25,000 sq.ftindus
- proportion of non-retail business acres per townchas
- Charles River dummy variable (= 1 if tract bounds river; 0 otherwise)nox
- nitric oxides concentration (parts per 10 million)rm
- average number of rooms per dwellingage
- proportion of owner-occupied units built prior to 1940dis
- weighted distances to five Boston employment centresrad
- index of accessibility to radial highwaystax
- full-value property-tax rate per USD 10,000ptratio
- pupil-teacher ratio by townb
- 1000(B - 0.63)^2 where B is the proportion of blacks by townlstat
- percentage of lower status of the populationWe will start by importing the dataset from a text file, and then viewing the first 10 rows.
df = pd.read_csv('data/BostonHousingV2.txt', sep='\t')
df.head(n=10)
print(df.shape)
X = df.iloc[:,6:].values
y = df.iloc[:,5].values
print(X.shape)
print(y.shape)
X_train, X_holdout, y_train, y_holdout = train_test_split(X, y, test_size=0.4, random_state=1)
X_val, X_test, y_val, y_test = train_test_split(X_holdout, y_holdout, test_size=0.5, random_state=1)
print(X_train.shape)
print(X_val.shape)
print(X_test.shape)
We will start by using Scikit-Learn to fit a linear regression model to serve as a baseline to compare our later models against.
from sklearn.linear_model import LinearRegression
lin_mod = LinearRegression()
lin_mod.fit(X_train, y_train)
print('Training r-Squared: ', lin_mod.score(X_train, y_train))
print('Validation r-Squared:', lin_mod.score(X_val, y_val))
We will use StandardScaler
from sklearn
to scale our features.
#from sklearn.preprocessing import MinMaxScaler
from sklearn.preprocessing import StandardScaler
#scaler = MinMaxScaler()
scaler = StandardScaler()
scaler.fit(X_train)
Xs_train = scaler.transform(X_train)
Xs_val = scaler.transform(X_val)
Xs_test = scaler.transform(X_test)
Unfortunately, Keras does not come equipped with a metric for reporting r-squared values in a regression problem. We can, however, create our own custom metrics to use with Keras.
import keras.backend as K
def r2(y_true, y_pred):
SS_res = K.sum(K.square( y_true-y_pred ))
SS_tot = K.sum(K.square( y_true - K.mean(y_true) ) )
return ( 1 - SS_res/(SS_tot + K.epsilon()) )
#####################################################
# Design and Train Model
#####################################################
np.random.seed(1)
set_random_seed(1)
model_1 = Sequential()
model_1.add(Dense(32, input_shape=(13,), activation='relu'))
model_1.add(Dense(16, activation='relu'))
model_1.add(Dense(1, activation='linear'))
opt = keras.optimizers.Adam(lr=0.01)
model_1.compile(loss='mean_squared_error', optimizer=opt, metrics=[r2])
h = model_1.fit(Xs_train, y_train, batch_size=500, epochs=2000, validation_data = [Xs_val, y_val], verbose=0)
#####################################################
# Visualize Training Progress
#####################################################
m = 50
rng = range(m, len(h.history['loss']))
plt.figure(figsize=[10,4])
plt.subplot(1,2,1)
plt.plot(rng, h.history['loss'][m:], label='Training')
plt.plot(rng, h.history['val_loss'][m:], label='Validation')
plt.title('Loss')
plt.ylabel('Loss')
plt.xlabel('Epoch')
plt.legend()
plt.subplot(1,2,2)
plt.plot(rng, h.history['r2'][m:], label='Training')
plt.plot(rng, h.history['val_r2'][m:], label='Validation')
plt.title('r2')
plt.ylabel('r2')
plt.xlabel('Epoch')
plt.legend()
plt.show()
#####################################################
# Find Minimum Validation Loss
#####################################################
print('-- Minimum Validation Loss --')
print('Loss: ', min(h.history['val_loss']))
print('Epoch:', np.argmin(h.history['val_loss']))
print()
print('-- Maximum Validation r2 --')
print('r2: ', max(h.history['val_r2']))
print('Epoch:', np.argmax(h.history['val_r2']))
np.random.seed(1)
set_random_seed(1)
model_2 = Sequential()
model_2.add(Dense(32, input_shape=(13,), activation='relu'))
model_2.add(Dense(16, activation='relu'))
model_2.add(Dense(1, activation='linear'))
opt = keras.optimizers.Adam(lr=0.01)
model_2.compile(loss='mean_squared_error', optimizer=opt, metrics=[r2])
h = model_2.fit(Xs_train, y_train, batch_size=500, epochs=215, validation_data = [Xs_val, y_val], verbose=0)
tr_results = model_2.evaluate(Xs_train, y_train, verbose=0)
va_results = model_2.evaluate(Xs_val, y_val, verbose=0)
print('Training Loss: ', tr_results[0])
print('Training r2: ', tr_results[1], '\n')
print('Validation Loss:', va_results[0])
print('Validation r2: ', va_results[1])
We will now train the same model, this time adding an L2 regularization term to the loss. In this scenario, our learning algorithm will try to minimize the following function:
$$\Large Loss = \frac{1}{n} SSE + \lambda \sum \left[w^{(d)}_{i,j} \right]^2$$
Where $w^{(d)}_{i,j}$ is the weight that leads from node i
in layer d-1
to node j
in layer d
. The sum in the penalty term is only calculated over the non-bias weights.
The constant $\lambda$ is a model hyperparameter that we are free to choose.
from keras import regularizers
#####################################################
# Design and Train Model
#####################################################
np.random.seed(1)
set_random_seed(1)
model_3 = Sequential()
model_3.add(Dense(32, input_shape=(13,), activation='relu', kernel_regularizer=regularizers.l2(0.2)))
model_3.add(Dense(16, activation='relu', kernel_regularizer=regularizers.l2(0.2)))
model_3.add(Dense(1, activation='linear', kernel_regularizer=regularizers.l2(0.2)))
opt = keras.optimizers.Adam(lr=0.01)
model_3.compile(loss='mean_squared_error', optimizer=opt, metrics=[r2])
h = model_3.fit(Xs_train, y_train, batch_size=500, epochs=2000, validation_data = [Xs_val, y_val], verbose=0)
#####################################################
# Visualize Training Progress
#####################################################
m = 50
rng = range(m, len(h.history['loss']))
plt.figure(figsize=[10,4])
plt.subplot(1,2,1)
plt.plot(rng, h.history['loss'][m:], label='Training')
plt.plot(rng, h.history['val_loss'][m:], label='Validation')
plt.title('Loss')
plt.ylabel('Loss')
plt.xlabel('Epoch')
plt.legend()
plt.subplot(1,2,2)
plt.plot(rng, h.history['r2'][m:], label='Training')
plt.plot(rng, h.history['val_r2'][m:], label='Validation')
plt.title('r2')
plt.ylabel('r2')
plt.xlabel('Epoch')
plt.legend()
plt.show()
#####################################################
# Find Minimum Validation Loss
#####################################################
print('-- Minimum Validation Loss --')
print('Loss: ', min(h.history['val_loss']))
print('Epoch:', np.argmin(h.history['val_loss']))
print()
print('-- Maximum Validation r2 --')
print('Loss: ', max(h.history['val_r2']))
print('Epoch: ', np.argmax(h.history['val_r2']))
from keras.layers import Dropout
#####################################################
# Design and Train Model
#####################################################
np.random.seed(1)
set_random_seed(1)
model_4 = Sequential()
model_4.add(Dense(32, input_shape=(13,), activation='relu'))
model_4.add(Dropout(0.1))
model_4.add(Dense(16, activation='relu'))
model_4.add(Dropout(0.1))
model_4.add(Dense(1, activation='linear'))
opt = keras.optimizers.Adam(lr=0.001)
model_4.compile(loss='mean_squared_error', optimizer=opt, metrics=[r2])
h = model_4.fit(Xs_train, y_train, batch_size=500, epochs=2000, validation_data = [Xs_val, y_val], verbose=0)
#####################################################
# Visualize Training Progress
#####################################################
m = 200
rng = range(m, len(h.history['loss']))
plt.figure(figsize=[10,4])
plt.subplot(1,2,1)
plt.plot(rng, h.history['loss'][m:], label='Training')
plt.plot(rng, h.history['val_loss'][m:], label='Validation')
plt.title('Loss')
plt.ylabel('Loss')
plt.xlabel('Epoch')
plt.legend()
plt.subplot(1,2,2)
plt.plot(rng, h.history['r2'][m:], label='Training')
plt.plot(rng, h.history['val_r2'][m:], label='Validation')
plt.title('r2')
plt.ylabel('r2')
plt.xlabel('Epoch')
plt.legend()
plt.show()
#####################################################
# Find Minimum Validation Loss
#####################################################
print('-- Minimum Validation Loss --')
print('Loss: ', min(h.history['val_loss']))
print('Epoch:', np.argmin(h.history['val_loss']))
print()
print('-- Maximum Validation r2 --')
print('Loss: ', max(h.history['val_r2']))
print('r2: ', np.argmax(h.history['val_r2']))
testing_results = model_3.evaluate(Xs_test, y_test, verbose=0)
print('Testing Loss: ', testing_results[0])
print('Testing r2: ', testing_results[1])