Experiments¤
Imports¤
from keras_tuner import RandomSearch
environ["TF_FORCE_GPU_ALLOW_GROWTH"] = "true"
Experiments¤
For our experiments, we employ the datasets used by the authors of Certified Monotonic Network [1] and COMET [2]. We use the exact train-test split provided by the authors. Their respective repositories are linked below in the references. We directly load the saved train-test data split which have been saved after running the codes from respective papers’ authors.
References:
- Xingchao Liu, Xing Han, Na Zhang, and Qiang Liu. Certified monotonic neural networks. Advances in Neural Information Processing Systems, 33:15427–15438, 2020
Github repo: https://github.com/gnobitab/CertifiedMonotonicNetwork
- Aishwarya Sivaraman, Golnoosh Farnadi, Todd Millstein, and Guy Van den Broeck. Counterexample-guided learning of monotonic neural networks. Advances in Neural Information Processing Systems, 33:11936–11948, 2020
Github repo: https://github.com/AishwaryaSivaraman/COMET
_download_data("auto", force_download=True)
!ls -l data
assert (Path("data") / "train_auto.csv").exists()
train_auto.csv: 49.2kB [00:01, 48.4kB/s]
test_auto.csv: 16.4kB [00:00, 20.2kB/s]
total 257812
-rw-rw-r-- 1 davor davor 11161 Jun 2 13:28 test_auto.csv
-rw-rw-r-- 1 davor davor 11340054 May 25 04:48 test_blog.csv
-rw-rw-r-- 1 davor davor 101210 May 25 04:48 test_compas.csv
-rw-rw-r-- 1 davor davor 15798 May 25 04:48 test_heart.csv
-rw-rw-r-- 1 davor davor 13339777 May 25 04:48 test_loan.csv
-rw-rw-r-- 1 davor davor 44626 Jun 2 13:28 train_auto.csv
-rw-rw-r-- 1 davor davor 79478767 May 25 04:48 train_blog.csv
-rw-rw-r-- 1 davor davor 405660 May 25 04:48 train_compas.csv
-rw-rw-r-- 1 davor davor 62282 May 25 04:48 train_heart.csv
-rw-rw-r-- 1 davor davor 79588030 May 25 04:48 train_loan.csv
-rw-rw-r-- 1 davor davor 79588030 May 29 13:57 {prefix}_{name}.csv
_sanitize_col_names(pd.DataFrame({"a b": [1, 2, 3]}))
get_train_n_test_data¤
get_train_n_test_data (dataset_name:str, data_path:Union[pathlib.Path,str,NoneType]='./data ')
Download data
Args: dataset_name: name of the dataset, one of “auto”, “heart”, compas”, “blog”, “loan” data_path: root directory where to download data to
train_df, test_df = get_train_n_test_data("auto")
display(train_df)
display(test_df)
Upload skipped, file /home/davor/work/projects/airt/mono-dense-keras/nbs/data/train_auto.csv exists.
Upload skipped, file /home/davor/work/projects/airt/mono-dense-keras/nbs/data/test_auto.csv exists.
314 rows × 8 columns
78 rows × 8 columns
peek¤
peek (ds:tensorflow.python.data.ops.dataset_ops.DatasetV2)
Returns the first element of the dataset
Args: ds: dataset
Returns: the first element of the dataset
df2ds¤
df2ds (df:pandas.core.frame.DataFrame)
Converts DataFrame to Dataset
Args: df: input DataFrame
Returns: dataset
x, y = peek(df2ds(train_df).batch(8))
display(x)
display(y)
expected = {
"Acceleration",
"Cylinders",
"Displacement",
"Horsepower",
"Model_Year",
"Origin",
"Weight",
}
assert set(x.keys()) == expected
for k in expected:
assert x[k].shape == (8,)
assert y.shape == (8,)
{'Cylinders': <tf.Tensor: shape=(8,), dtype=float32, numpy=
array([1.4828068, 1.4828068, 1.4828068, 1.4828068, 1.4828068, 1.4828068,
1.4828068, 1.4828068], dtype=float32)>,
'Displacement': <tf.Tensor: shape=(8,), dtype=float32, numpy=
array([1.0730283, 1.4829025, 1.0444324, 1.0253685, 2.235927 , 2.474226 ,
2.3407786, 1.8641808], dtype=float32)>,
'Horsepower': <tf.Tensor: shape=(8,), dtype=float32, numpy=
array([0.65056413, 1.5489933 , 1.1639522 , 0.9072582 , 2.3960838 ,
2.9608107 , 2.8324637 , 2.1907284 ], dtype=float32)>,
'Weight': <tf.Tensor: shape=(8,), dtype=float32, numpy=
array([0.6066247, 0.828131 , 0.5234134, 0.5421652, 1.5875812, 1.602817 ,
1.5535934, 1.0121336], dtype=float32)>,
'Acceleration': <tf.Tensor: shape=(8,), dtype=float32, numpy=
array([-1.2755462, -1.4525175, -1.2755462, -1.8064601, -1.9834315,
-2.3373742, -2.5143454, -2.5143454], dtype=float32)>,
'Model_Year': <tf.Tensor: shape=(8,), dtype=float32, numpy=
array([-1.6318026, -1.6318026, -1.6318026, -1.6318026, -1.6318026,
-1.6318026, -1.6318026, -1.6318026], dtype=float32)>,
'Origin': <tf.Tensor: shape=(8,), dtype=float32, numpy=
array([-0.7016686, -0.7016686, -0.7016686, -0.7016686, -0.7016686,
-0.7016686, -0.7016686, -0.7016686], dtype=float32)>}
<tf.Tensor: shape=(8,), dtype=float32, numpy=array([18., 15., 16., 17., 15., 14., 14., 15.], dtype=float32)>
train_df, test_df = get_train_n_test_data("auto")
train_ds = df2ds(train_df)
test_ds = df2ds(test_df)
build_model_f = lambda: _build_mono_model_f(
monotonicity_indicator={
"Cylinders": 0,
"Displacement": -1,
"Horsepower": -1,
"Weight": -1,
"Acceleration": 0,
"Model_Year": 0,
"Origin": 0,
},
final_activation=None,
loss="mse",
metrics="mse",
train_ds=train_ds,
batch_size=8,
units=16,
n_layers=3,
activation="elu",
learning_rate=0.01,
weight_decay=0.001,
dropout=0.25,
decay_rate=0.95,
)
model = build_model_f()
model.summary()
model.fit(train_ds.batch(8), validation_data=test_ds.batch(256), epochs=1)
Upload skipped, file /home/davor/work/projects/airt/mono-dense-keras/nbs/data/train_auto.csv exists.
Upload skipped, file /home/davor/work/projects/airt/mono-dense-keras/nbs/data/test_auto.csv exists.
Model: "model"
__________________________________________________________________________________________________
Layer (type) Output Shape Param # Connected to
==================================================================================================
Acceleration (InputLayer) [(None, 1)] 0 []
Cylinders (InputLayer) [(None, 1)] 0 []
Displacement (InputLayer) [(None, 1)] 0 []
Horsepower (InputLayer) [(None, 1)] 0 []
Model_Year (InputLayer) [(None, 1)] 0 []
Origin (InputLayer) [(None, 1)] 0 []
Weight (InputLayer) [(None, 1)] 0 []
dense_Acceleration (Dense) (None, 4) 8 ['Acceleration[0][0]']
dense_Cylinders (Dense) (None, 4) 8 ['Cylinders[0][0]']
mono_dense_Displacement_decrea (None, 4) 8 ['Displacement[0][0]']
sing (MonoDense)
mono_dense_Horsepower_decreasi (None, 4) 8 ['Horsepower[0][0]']
ng (MonoDense)
dense_Model_Year (Dense) (None, 4) 8 ['Model_Year[0][0]']
dense_Origin (Dense) (None, 4) 8 ['Origin[0][0]']
mono_dense_Weight_decreasing ( (None, 4) 8 ['Weight[0][0]']
MonoDense)
preprocessed_features (Concate (None, 28) 0 ['dense_Acceleration[0][0]',
nate) 'dense_Cylinders[0][0]',
'mono_dense_Displacement_decreas
ing[0][0]',
'mono_dense_Horsepower_decreasin
g[0][0]',
'dense_Model_Year[0][0]',
'dense_Origin[0][0]',
'mono_dense_Weight_decreasing[0]
[0]']
mono_dense_0 (MonoDense) (None, 16) 464 ['preprocessed_features[0][0]']
dropout (Dropout) (None, 16) 0 ['mono_dense_0[0][0]']
mono_dense_1_increasing (MonoD (None, 16) 272 ['dropout[0][0]']
ense)
dropout_1 (Dropout) (None, 16) 0 ['mono_dense_1_increasing[0][0]']
mono_dense_2_increasing (MonoD (None, 1) 17 ['dropout_1[0][0]']
ense)
==================================================================================================
Total params: 809
Trainable params: 809
Non-trainable params: 0
__________________________________________________________________________________________________
40/40 [==============================] - 4s 12ms/step - loss: 150.6315 - mse: 150.6315 - val_loss: 342.8134 - val_mse: 342.8134
<keras.callbacks.History>
def hp_params_f(hp: HyperParameters):
return dict(
units=hp.Fixed(name="units", value=3),
layers=hp.Fixed(name="units", value=1),
)
with TemporaryDirectory() as d:
tuner = RandomSearch(
hypermodel=TestHyperModel(
monotonicity_indicator={
"Cylinders": 0,
"Displacement": -1,
"Horsepower": -1,
"Weight": -1,
"Acceleration": 0,
"Model_Year": 0,
"Origin": 0,
},
hp_params_f=lambda hp: {"units": hp.Fixed(name="units", value=3)},
final_activation=None,
loss="mse",
metrics="mse",
train_ds=train_ds,
batch_size=8,
),
directory=d,
project_name="testing",
max_trials=2,
objective="val_loss",
)
tuner.search(
train_ds.shuffle(len(train_ds)).batch(8).prefetch(2),
validation_data=test_ds.batch(256),
epochs=2,
)
Trial 2 Complete [00h 00m 03s]
val_loss: 28.08372688293457
Best val_loss So Far: 28.08372688293457
Total elapsed time: 00h 00m 07s
INFO:tensorflow:Oracle triggered exit
find_hyperparameters¤
find_hyperparameters (dataset_name:str, monotonicity_indicator:Dict[str,int], final_activat ion:Union[str,Callable[[Union[tensorflow.python.typ es.core.Tensor,tensorflow.python.types.core.TensorP rotocol,int,float,bool,str,bytes,complex,tuple,list ,numpy.ndarray,numpy.generic],Union[tensorflow.pyth on.types.core.Tensor,tensorflow.python.types.core.T ensorProtocol,int,float,bool,str,bytes,complex,tupl e,list,numpy.ndarray,numpy.generic]],Union[tensorfl ow.python.types.core.Tensor,tensorflow.python.types .core.TensorProtocol,int,float,bool,str,bytes,compl ex,tuple,list,numpy.ndarray,numpy.generic]]], loss: Union[str,Callable[[Union[tensorflow.python.types.c ore.Tensor,tensorflow.python.types.core.TensorProto col,int,float,bool,str,bytes,complex,tuple,list,num py.ndarray,numpy.generic],Union[tensorflow.python.t ypes.core.Tensor,tensorflow.python.types.core.Tenso rProtocol,int,float,bool,str,bytes,complex,tuple,li st,numpy.ndarray,numpy.generic]],Union[tensorflow.p ython.types.core.Tensor,tensorflow.python.types.cor e.TensorProtocol,int,float,bool,str,bytes,complex,t uple,list,numpy.ndarray,numpy.generic]]], metrics:U nion[str,Callable[[Union[tensorflow.python.types.co re.Tensor,tensorflow.python.types.core.TensorProtoc ol,int,float,bool,str,bytes,complex,tuple,list,nump y.ndarray,numpy.generic],Union[tensorflow.python.ty pes.core.Tensor,tensorflow.python.types.core.Tensor Protocol,int,float,bool,str,bytes,complex,tuple,lis t,numpy.ndarray,numpy.generic]],Union[tensorflow.py thon.types.core.Tensor,tensorflow.python.types.core .TensorProtocol,int,float,bool,str,bytes,complex,tu ple,list,numpy.ndarray,numpy.generic]]], hp_params_ f:Optional[Callable[[keras_tuner.engine.hyperparame ters.hyperparameters.HyperParameters],Dict[str,Any] ]]=None, max_trials:int=100, max_epochs:int=50, batch_size:int=8, objective:Union[str,keras_tuner.e ngine.objective.Objective], direction:str, dir_root:Union[pathlib.Path,str]='tuner', seed:int=42, executions_per_trial:int=3, max_consecutive_failed_trials:int=5, patience:int=10)
Search for optimal hyperparameters
Args: monotonicity_indicator: monotonicity indicator as used in
MonoDense.__init__
final_activation: final activation of the neural network loss:
Tensorflow loss function metrics: Tensorflow metrics function
hp_params_f: a function constructing sampling hyperparameters using
Keras Tuner max_trials: maximum number of trials max_epochs: maximum
number of epochs in each trial batch_size: batch size objective:
objective, typically f”val_{metrics}” direction: direction of the
objective, either “min” or “max” dir_root: root directory for storing
Keras Tuner data seed: random seed used to guarantee reproducibility of
results executions_per_trial: number of executions per trial. Set it to
number higher than zero for small datasets
max_consecutive_failed_trials: maximum number of failed trials as used
in Keras Tuner patience: number of epoch with worse objective before
stopping trial early
Returns: An instance of Keras Tuner
shutil.rmtree("tuner", ignore_errors=True)
tuner = find_hyperparameters(
"auto",
monotonicity_indicator={
"Cylinders": 0,
"Displacement": -1,
"Horsepower": -1,
"Weight": -1,
"Acceleration": 0,
"Model_Year": 0,
"Origin": 0,
},
max_trials=2,
final_activation=None,
loss="mse",
metrics="mse",
objective="val_mse",
direction="min",
max_epochs=1,
executions_per_trial=1,
)
Trial 2 Complete [00h 00m 03s]
val_mse: 32.87412643432617
Best val_mse So Far: 32.87412643432617
Total elapsed time: 00h 00m 06s
INFO:tensorflow:Oracle triggered exit
create_tuner_stats¤
create_tuner_stats (tuner:keras_tuner.engine.tuner.Tuner, num_models:int=10, max_epochs:int=50, batch_size:int=8, patience:int=10, verbose:int=0)
Calculates statistics for the best models found by Keras Tuner
Args: tuner: an instance of Keras Tuner num_models: number of best
models to use for calculating statistics max_epochs: maximum number of
epochs used in runs batch_size: batch_size patience: maximum number of
epochs with worse objective before stopping trial early verbose:
verbosity level of Model.fit
function
Returns: A dataframe with statistics
stats = create_tuner_stats(tuner, verbose=0)
Upload skipped, file /home/davor/work/projects/airt/mono-dense-keras/nbs/data/train_auto.csv exists.
Upload skipped, file /home/davor/work/projects/airt/mono-dense-keras/nbs/data/test_auto.csv exists.
WARNING:tensorflow:6 out of the last 8 calls to <function Model.make_test_function.<locals>.test_function> triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has reduce_retracing=True option that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/guide/function#controlling_retracing and https://www.tensorflow.org/api_docs/python/tf/function for more details.