def test_boston_housing_no_fit_invalid(self): (x_train, y_train), (x_test, y_test) = TestUtil.get_boston_housing() explained_model = RandomForestRegressor(n_estimators=64, max_depth=5, random_state=1) explained_model.fit(x_train, y_train) model_builder = MLPModelBuilder(num_layers=2, num_units=32, activation="relu", p_dropout=0.2, verbose=0, batch_size=32, learning_rate=0.001, num_epochs=2, early_stopping_patience=128) masking_operation = ZeroMasking() loss = mean_squared_error explainer = CXPlain(explained_model, model_builder, masking_operation, loss) with self.assertRaises(AssertionError): explainer.predict(x_test, y_test) with self.assertRaises(AssertionError): explainer.score(x_test, y_test)
def test_time_series_valid(self): num_samples = 1024 fixed_length = 99 (x_train, y_train), (x_test, y_test) = TestUtil.get_random_fixed_length_dataset( num_samples=num_samples, fixed_length=fixed_length) model_builder = RNNModelBuilder(with_embedding=False, num_layers=2, num_units=32, activation="relu", p_dropout=0.2, verbose=0, batch_size=32, learning_rate=0.001, num_epochs=2, early_stopping_patience=128) explained_model = MLPClassifier() explained_model.fit(x_train.reshape((-1, np.prod(x_train.shape[1:]))), y_train) masking_operation = ZeroMasking() loss = binary_crossentropy explainer = CXPlain(explained_model, model_builder, masking_operation, loss, flatten_for_explained_model=True) explainer.fit(x_train, y_train) eval_score = explainer.score(x_test, y_test) train_score = explainer.get_last_fit_score() median = explainer.predict(x_test) self.assertTrue(median.shape == x_test.shape)
def test_boston_housing_load_save_valid(self): (x_train, y_train), (x_test, y_test) = TestUtil.get_boston_housing() explained_model = RandomForestRegressor(n_estimators=64, max_depth=5, random_state=1) explained_model.fit(x_train, y_train) model_builder = MLPModelBuilder(num_layers=2, num_units=32, activation="relu", p_dropout=0.2, verbose=0, batch_size=32, learning_rate=0.001, num_epochs=2, early_stopping_patience=128) masking_operation = ZeroMasking() loss = mean_squared_error num_models_settings = [1, 2] for num_models in num_models_settings: explainer = CXPlain(explained_model, model_builder, masking_operation, loss, num_models=num_models) explainer.fit(x_train, y_train) median_1 = explainer.predict(x_test) tmp_dir_name = tempfile.mkdtemp() explainer.save(tmp_dir_name) with self.assertRaises(ValueError): explainer.save(tmp_dir_name, overwrite=False) explainer.save(tmp_dir_name, overwrite=True) explainer.load(tmp_dir_name) median_2 = explainer.predict(x_test) self.assertTrue(np.array_equal(median_1, median_2)) shutil.rmtree(tmp_dir_name) # Cleanup.
def test_boston_housing_valid(self): (x_train, y_train), (x_test, y_test) = TestUtil.get_boston_housing() explained_model = RandomForestRegressor(n_estimators=64, max_depth=5, random_state=1) explained_model.fit(x_train, y_train) model_builder = MLPModelBuilder(num_layers=2, num_units=32, activation="relu", p_dropout=0.2, verbose=0, batch_size=32, learning_rate=0.001, num_epochs=2, early_stopping_patience=128) masking_operation = ZeroMasking() loss = mean_squared_error explainer = CXPlain(explained_model, model_builder, masking_operation, loss) explainer.fit(x_train, y_train) self.assertEqual(explainer.prediction_model.output_shape, (None, np.prod(x_test.shape[1:]))) eval_score = explainer.score(x_test, y_test) train_score = explainer.get_last_fit_score() median = explainer.predict(x_test) self.assertTrue(median.shape == x_test.shape)
def test_boston_housing_confidence_level_invalid(self): (x_train, y_train), (x_test, y_test) = TestUtil.get_boston_housing() explained_model = RandomForestRegressor(n_estimators=64, max_depth=5, random_state=1) explained_model.fit(x_train, y_train) model_builder = MLPModelBuilder(num_layers=2, num_units=32, activation="relu", p_dropout=0.2, verbose=0, batch_size=32, learning_rate=0.001, num_epochs=3, early_stopping_patience=128) masking_operation = ZeroMasking() loss = mean_squared_error num_models = 2 explainer = CXPlain(explained_model, model_builder, masking_operation, loss, num_models=num_models) explainer.fit(x_train, y_train) invalid_confidence_levels = [1.01, -0.5, -0.01] for confidence_level in invalid_confidence_levels: with self.assertRaises(ValueError): explainer.predict(x_test, confidence_level=confidence_level)
def test_mnist_unet_valid(self): num_subsamples = 100 (x_train, y_train), (x_test, y_test) = TestUtil.get_mnist(flattened=False, num_subsamples=num_subsamples) explained_model = MLPClassifier(solver='lbfgs', alpha=1e-5, hidden_layer_sizes=(64, 32), random_state=1) explained_model.fit(x_train.reshape((len(x_train), -1)), y_train) masking_operation = ZeroMasking() loss = categorical_crossentropy downsample_factors = [(2, 2), (4, 4), (4, 7), (7, 4), (7, 7)] with_bns = [True if i % 2 == 0 else False for i in range(len(downsample_factors))] for downsample_factor, with_bn in zip(downsample_factors, with_bns): model_builder = UNetModelBuilder(downsample_factor, num_layers=2, num_units=64, activation="relu", p_dropout=0.2, verbose=0, batch_size=256, learning_rate=0.001, num_epochs=2, early_stopping_patience=128, with_bn=with_bn) explainer = CXPlain(explained_model, model_builder, masking_operation, loss, downsample_factors=downsample_factor, flatten_for_explained_model=True) explainer.fit(x_train, y_train) eval_score = explainer.score(x_test, y_test) train_score = explainer.get_last_fit_score() median = explainer.predict(x_test) self.assertTrue(median.shape == x_test.shape)
def test_mnist_unet_with_shape_valid(self): num_subsamples = 100 (x_train, y_train), (x_test, y_test) = TestUtil.get_mnist(flattened=False, num_subsamples=num_subsamples) explained_model_builder = MLPModelBuilder(num_layers=2, num_units=64, activation="relu", p_dropout=0.2, verbose=0, batch_size=256, learning_rate=0.001, num_epochs=2, early_stopping_patience=128) input_shape = x_train.shape[1:] input_layer = Input(shape=input_shape) last_layer = Flatten()(input_layer) last_layer = explained_model_builder.build(last_layer) last_layer = Dense(y_train.shape[-1], activation="softmax")(last_layer) explained_model = Model(input_layer, last_layer) explained_model.compile(loss="categorical_crossentropy", optimizer="adam") explained_model.fit(x_train, y_train) masking_operation = ZeroMasking() loss = categorical_crossentropy downsample_factors = [(2, 2), (4, 4), (4, 7), (7, 4), (7, 7)] with_bns = [ True if i % 2 == 0 else False for i in range(len(downsample_factors)) ] for downsample_factor, with_bn in zip(downsample_factors, with_bns): model_builder = UNetModelBuilder(downsample_factor, num_layers=2, num_units=64, activation="relu", p_dropout=0.2, verbose=0, batch_size=256, learning_rate=0.001, num_epochs=2, early_stopping_patience=128, with_bn=with_bn) explainer = CXPlain(explained_model, model_builder, masking_operation, loss, downsample_factors=downsample_factor) explainer.fit(x_train, y_train) eval_score = explainer.score(x_test, y_test) train_score = explainer.get_last_fit_score() median = explainer.predict(x_test) self.assertTrue(median.shape == x_test.shape)
def test_mnist_valid(self): num_subsamples = 100 (x_train, y_train), (x_test, y_test) = TestUtil.get_mnist(flattened=False, num_subsamples=num_subsamples) explained_model = MLPClassifier(solver='lbfgs', alpha=1e-5, hidden_layer_sizes=(64, 32), random_state=1) explained_model.fit(x_train.reshape((len(x_train), -1)), y_train) model_builder = MLPModelBuilder(num_layers=2, num_units=64, activation="relu", p_dropout=0.2, verbose=0, batch_size=256, learning_rate=0.001, num_epochs=3, early_stopping_patience=128) masking_operation = ZeroMasking() loss = categorical_crossentropy downsample_factors = [(2, 2), (4, 4), (4, 7), (7, 4), (7, 7)] for downsample_factor in downsample_factors: explainer = CXPlain(explained_model, model_builder, masking_operation, loss, num_models=2, downsample_factors=downsample_factor, flatten_for_explained_model=True) explainer.fit(x_train, y_train) eval_score = explainer.score(x_test, y_test) train_score = explainer.get_last_fit_score() median, confidence = explainer.predict(x_test, confidence_level=0.95) self.assertTrue(median.shape == x_test.shape) self.assertTrue(confidence.shape == x_test.shape[:-1] + (2, )) # Flatten predictions for iteration below. median = median.reshape((len(x_test), -1)) confidence = confidence.reshape((len(x_test), -1, 2)) for sample_idx in range(len(x_test)): for feature_idx in range(len(x_test[sample_idx])): self.assertTrue(confidence[sample_idx][feature_idx][0] <= median[sample_idx][feature_idx] <= confidence[sample_idx][feature_idx][1]) self.assertTrue( confidence[sample_idx][feature_idx][0] >= 0) self.assertTrue( confidence[sample_idx][feature_idx][1] >= 0)
def test_overwrite_ensemble_model_invalid(self): (x_train, y_train), (x_test, y_test) = TestUtil.get_boston_housing() model_builder = MLPModelBuilder() explained_model = RandomForestRegressor(n_estimators=64, max_depth=5, random_state=1) explained_model.fit(x_train, y_train) masking_operation = ZeroMasking() loss = binary_crossentropy num_models = 5 explainer = CXPlain(explained_model, model_builder, masking_operation, loss, num_models=num_models) file_names = [ CXPlain.get_config_file_name(), CXPlain.get_explained_model_file_name(".pkl"), CXPlain.get_loss_pkl_file_name(), CXPlain.get_model_builder_pkl_file_name(), CXPlain.get_masking_operation_pkl_file_name() ] # Test with untrained explanation model. for file_name in file_names: tmp_dir = TestExplanationModel.make_at_tmp(file_name) with self.assertRaises(ValueError): explainer.save(tmp_dir, overwrite=False) # Test with trained explanation model. explainer.fit(x_train, y_train) file_names = [ CXPlain.get_config_file_name(), CXPlain.get_explained_model_file_name(".pkl"), CXPlain.get_loss_pkl_file_name(), CXPlain.get_model_builder_pkl_file_name(), CXPlain.get_masking_operation_pkl_file_name() ] + [ CXPlain.get_prediction_model_h5_file_name(i) for i in range(num_models) ] for file_name in file_names: tmp_dir = TestExplanationModel.make_at_tmp(file_name) with self.assertRaises(ValueError): explainer.save(tmp_dir, overwrite=False)
def test_boston_housing_valid(self): (x_train, y_train), (x_test, y_test) = TestUtil.get_boston_housing() explained_model = RandomForestRegressor(n_estimators=64, max_depth=5, random_state=1) explained_model.fit(x_train, y_train) model_builder = MLPModelBuilder(num_layers=2, num_units=32, activation="relu", p_dropout=0.2, verbose=0, batch_size=32, learning_rate=0.001, num_epochs=3, early_stopping_patience=128) masking_operation = ZeroMasking() loss = mean_squared_error for num_models in [2, 5, 10]: explainer = CXPlain(explained_model, model_builder, masking_operation, loss, num_models=num_models) explainer.fit(x_train, y_train) eval_score = explainer.score(x_test, y_test) train_score = explainer.get_last_fit_score() median, confidence = explainer.predict(x_test, confidence_level=0.95) self.assertTrue(median.shape == x_test.shape) self.assertTrue(confidence.shape == x_test.shape + (2, )) # Flatten predictions for iteration below. median = median.reshape((len(x_test), -1)) confidence = confidence.reshape((len(x_test), -1, 2)) for sample_idx in range(len(x_test)): for feature_idx in range(len(x_test[sample_idx])): self.assertTrue(confidence[sample_idx][feature_idx][0] <= median[sample_idx][feature_idx] <= confidence[sample_idx][feature_idx][1]) self.assertTrue( confidence[sample_idx][feature_idx][0] >= 0) self.assertTrue( confidence[sample_idx][feature_idx][1] >= 0)
def test_mnist_confidence_levels_valid(self): num_subsamples = 100 (x_train, y_train), (x_test, y_test) = TestUtil.get_mnist(flattened=False, num_subsamples=num_subsamples) explained_model = MLPClassifier(solver='lbfgs', alpha=1e-5, hidden_layer_sizes=(64, 32), random_state=1) explained_model.fit(x_train.reshape((len(x_train), -1)), y_train) model_builder = MLPModelBuilder(num_layers=2, num_units=64, activation="relu", p_dropout=0.2, verbose=0, batch_size=256, learning_rate=0.001, num_epochs=3, early_stopping_patience=128) masking_operation = ZeroMasking() loss = categorical_crossentropy confidence_levels = [0.0, 1.0, 1.01, -0.01] for confidence_level in confidence_levels: downsample_factor = (2, 2) explainer = CXPlain(explained_model, model_builder, masking_operation, loss, num_models=2, downsample_factors=downsample_factor, flatten_for_explained_model=True) explainer.fit(x_train, y_train) with self.assertRaises(ValueError): _ = explainer.predict(x_test, confidence_level=confidence_level)
def get_feature_importances(self, model): from cxplain import ZeroMasking from cxplain.util.test_util import TestUtil from cxplain.backend.masking.masking_util import MaskingUtil from cxplain.backend.causal_loss import calculate_delta_errors from cxplain.backend.numpy_math_interface import NumpyInterface x, y = self.test_set[0], self.test_set[1] masking = ZeroMasking() if isinstance(model, Pipeline): transform = model.steps[0][1] x = transform.transform(np.array(x)) model = model.steps[1][1] num_features = np.array(x).shape[-1] max_num_feature_groups = int( np.rint(self.args["max_num_feature_groups"])) if max_num_feature_groups >= num_features: _, y_pred, all_y_pred_imputed = masking.get_predictions_after_masking( model, x, y, batch_size=len(x), downsample_factors=(1, ), flatten=True) auxiliary_outputs = y_pred all_but_one_auxiliary_outputs = all_y_pred_imputed all_but_one_auxiliary_outputs = TestUtil.split_auxiliary_outputs_on_feature_dim( all_but_one_auxiliary_outputs) delta_errors = calculate_delta_errors( np.expand_dims(y, axis=-1), auxiliary_outputs, all_but_one_auxiliary_outputs, NumpyInterface.binary_crossentropy, math_ops=NumpyInterface) group_importances = np.mean(delta_errors, axis=0) feature_groups = np.expand_dims(np.arange(x[0].shape[-1]), axis=-1).tolist() else: class ModelWrapper(object): def __init__(self, wrapped_model, real_data, dummy_to_real_mapping): self.wrapped_model = wrapped_model self.real_data = real_data self.dummy_to_real_mapping = dummy_to_real_mapping def map_from_dummy(self, dummy): mask = np.ones(np.array(self.real_data).shape) for i, row in enumerate(dummy): for j, group in enumerate(self.dummy_to_real_mapping): if row[j] == 0.: mask[i, group] = 0 return self.real_data * mask def predict(self, x): x = self.map_from_dummy(x) y = MaskingUtil.predict_proxy(model, x) if len(y.shape) == 1: y = np.expand_dims(y, axis=-1) return y num_groups = 1 feature_groups = [np.random.permutation(np.arange(x[0].shape[-1]))] group_importances = [1.0] while num_groups < max_num_feature_groups: num_groups += 1 # Recurse into largest relative importance group. did_find_splittable = False highest_importances = np.argsort(group_importances)[::-1] for highest_importance in highest_importances: if len(feature_groups[highest_importance]) != 1: did_find_splittable = True break else: continue if not did_find_splittable: # max_num_groups > len(features) - abort. break rest = len(feature_groups[highest_importance]) % 2 if rest != 0: carry = feature_groups[highest_importance][-rest:].tolist() feature_groups[highest_importance] = feature_groups[ highest_importance][:-rest] else: carry = [] feature_groups[highest_importance] = np.split( feature_groups[highest_importance], 2) feature_groups[highest_importance][0] = np.array( feature_groups[highest_importance][0].tolist() + carry) recombined = feature_groups[:highest_importance] + \ feature_groups[highest_importance] + \ feature_groups[highest_importance + 1:] assert 0 not in map(len, recombined) feature_groups = recombined wrapped_model = ModelWrapper(model, x, feature_groups) dummy_data = np.ones((len(x), num_groups)) _, y_pred, all_y_pred_imputed = masking.get_predictions_after_masking( wrapped_model, dummy_data, y, batch_size=len(x), downsample_factors=(1, ), flatten=True) auxiliary_outputs = y_pred all_but_one_auxiliary_outputs = all_y_pred_imputed all_but_one_auxiliary_outputs = TestUtil.split_auxiliary_outputs_on_feature_dim( all_but_one_auxiliary_outputs) delta_errors = calculate_delta_errors( np.expand_dims(y, axis=-1), auxiliary_outputs, all_but_one_auxiliary_outputs, NumpyInterface.binary_crossentropy, math_ops=NumpyInterface) group_importances = np.mean(delta_errors, axis=0) return feature_groups, group_importances
def cxpl(model_dir, data_dir, results_subdir, random_seed, resolution): np.random.seed(random_seed) tf.set_random_seed(np.random.randint(1 << 31)) session_conf = tf.ConfigProto(intra_op_parallelism_threads=1, inter_op_parallelism_threads=1) sess = tf.Session(graph=tf.get_default_graph(), config=session_conf) set_session(sess) # parser config config_file = model_dir+ "/config.ini" print("Config File Path:", config_file,flush=True) assert os.path.isfile(config_file) cp = ConfigParser() cp.read(config_file) output_dir = os.path.join(results_subdir, "classification_results/test") print("Output Directory:", output_dir,flush=True) if not os.path.isdir(output_dir): os.makedirs(output_dir) # default config image_dimension = cp["TRAIN"].getint("image_dimension") gan_resolution = resolution batch_size = cp["TEST"].getint("batch_size") use_best_weights = cp["TEST"].getboolean("use_best_weights") if use_best_weights: print("** Using BEST weights",flush=True) model_weights_path = os.path.join(results_subdir, "classification_results/train/best_weights.h5") else: print("** Using LAST weights",flush=True) model_weights_path = os.path.join(results_subdir, "classification_results/train/weights.h5") print("** DenseNet Input Resolution:", image_dimension, flush=True) print("** GAN Image Resolution:", gan_resolution, flush=True) # get test sample count test_dir = os.path.join(results_subdir, "inference/test") shutil.copy(test_dir+"/test.csv", output_dir) # Get class names class_names = get_class_names(output_dir,"test") tfrecord_dir_te = os.path.join(data_dir, "test") test_counts, _ = get_sample_counts(output_dir, "test", class_names) # get indicies (all of csv file for validation) print("** test counts:", test_counts, flush=True) # compute steps test_steps = int(np.floor(test_counts / batch_size)) print("** test_steps:", test_steps, flush=True) log2_record = int(np.log2(gan_resolution)) record_file_ending = "*"+ np.str(log2_record)+ ".tfrecords" print("** resolution ", gan_resolution, " corresponds to ", record_file_ending, " TFRecord file.", flush=True) # Get Model # ------------------------------------ input_shape=(image_dimension, image_dimension, 3) img_input = Input(shape=input_shape) base_model = DenseNet121( include_top = False, weights = None, input_tensor = img_input, input_shape = input_shape, pooling = "avg") x = base_model.output predictions = Dense(len(class_names), activation="sigmoid", name="predictions")(x) model = Model(inputs=img_input, outputs = predictions) print(" ** load model from:", model_weights_path, flush=True) model.load_weights(model_weights_path) # ------------------------------------ print("** load test generator **", flush=True) test_seq = TFWrapper( tfrecord_dir=tfrecord_dir_te, record_file_endings = record_file_ending, batch_size = batch_size, model_target_size = (image_dimension, image_dimension), steps = None, augment=False, shuffle=False, prefetch=True, repeat=False) print("** make prediction **", flush=True) test_seq.initialise() x_all, y_all = test_seq.get_all_test_data() print("X-Test Shape:", x_all.shape,flush=True) print("Y-Test Shape:", y_all.shape,flush=True) print("----------------------------------------", flush=True) print("Test Model AUROC", flush=True) y_pred = model.predict(x_all) current_auroc = [] for i in range(len(class_names)): try: score = roc_auc_score(y_all[:, i], y_pred[:, i]) except ValueError: score = 0 current_auroc.append(score) print(i+1,class_names[i],": ", score, flush=True) mean_auroc = np.mean(current_auroc) print("Mean auroc: ", mean_auroc,flush=True) print("----------------------------------------", flush=True) downscale_factor = 8 num_models_to_use = 3 num_test_images = 100 print("Number of Models to use:", num_models_to_use, flush=True) print("Number of Test images:", num_test_images, flush=True) x_tr, y_tr = x_all[num_test_images:], y_all[num_test_images:] x_te, y_te = x_all[0:num_test_images], y_all[0:num_test_images] downsample_factors = (downscale_factor,downscale_factor) print("Downsample Factors:", downsample_factors,flush=True) model_builder = UNetModelBuilder(downsample_factors, num_layers=2, num_units=8, activation="relu", p_dropout=0.0, verbose=0, batch_size=32, learning_rate=0.001) print("Model build done.",flush=True) masking_operation = ZeroMasking() loss = categorical_crossentropy explainer = CXPlain(model, model_builder, masking_operation, loss, num_models=num_models_to_use, downsample_factors=downsample_factors, flatten_for_explained_model=False) print("Explainer build done.",flush=True) explainer.fit(x_tr, y_tr); print("Explainer fit done.",flush=True) try: attr, conf = explainer.explain(x_te, confidence_level=0.80) np.save(output_dir+"/x_cxpl.npy", x_te) np.save(output_dir+"/y_cxpl.npy", y_te) np.save(output_dir+"/attr.npy", attr) np.save(output_dir+"/conf.npy", conf) print("Explainer explain done and saved.",flush=True) except Exception as ef: print(ef,flush=True)