diff --git a/modules/deeplearning/mc_dropout_regression.py b/modules/deeplearning/mc_dropout_regression.py new file mode 100644 index 0000000000000000000000000000000000000000..fbf1873fb0bf2aeb208d01dad1baa5709c46aacb --- /dev/null +++ b/modules/deeplearning/mc_dropout_regression.py @@ -0,0 +1,221 @@ +import tensorflow as tf +import numpy as np +import matplotlib.pyplot as plt + +drop_out_rate = 0.5 + +def create_mnist_dataset(): + return tf.keras.datasets.mnist.load_data() + + +def create_toy_regression_dataset(xmin=-10., xmax=10, noise_std=.2): + x_trn = np.linspace(-2.0, 2.0, 1000, dtype=np.float32) + y_trn = np.sin(x_trn) + np.random.normal(0, noise_std, size=1000).astype(np.float32) + + x_gt = np.linspace(xmin, xmax, 1000, dtype=np.float32) + y_gt = np.sin(x_gt) + + x_tst = np.linspace(xmin, xmax, 1000, dtype=np.float32) + y_tst = np.sin(x_tst) + np.random.normal(0, noise_std, size=1000).astype(np.float32) + return x_gt, y_gt, x_trn, y_trn, x_tst, y_tst + + +def plot_regression_model_analysis(gt=None, trn=None, tst=None, + pred=None, xlim=None, ylim=None, + title=None): + if gt: + x_gt, y_gt = gt + plt.plot(x_gt, y_gt, c='#F0AA00', + alpha=.8, lw=2, label="ground truth") + if trn: + x_trn, y_trn = trn + plt.scatter(x_trn, y_trn, + s=8, ec='black', lw=1, fc=None, alpha=1, + label='train samples') + + if tst: + x_tst, y_tst = tst + plt.scatter(x_tst, y_tst, s=5, c='blue', alpha=.1, label='test samples') + + if pred: + x_tst, yhat_mean, yhat_std = pred + plt.scatter(x_tst, yhat_mean, s=5, c='magenta', alpha=1, label='preds') + if yhat_std is not None: + plt.fill_between(x_tst, (yhat_mean - 1. * yhat_std), (yhat_mean + 1. * yhat_std), lw=1, + ec='blue', fc='blue', alpha=.3, label='preds 1*std') + plt.fill_between(x_tst, (yhat_mean - 2. * yhat_std), (yhat_mean + 2. * yhat_std), lw=1, + ec='blue', fc='blue', alpha=.2, label='preds 2*std') + + if xlim: + plt.xlim(*xlim) + + if ylim: + plt.ylim(*ylim) + + if title: + plt.title(title) + + plt.xlabel('x') + plt.ylabel('y') + plt.legend(bbox_to_anchor=(1.35, 1.03), loc='upper right', fancybox=False, framealpha=1.0) + + +def plot_probabilities(probs): + plt.bar(np.arange(probs.shape[0]), probs) + plt.xticks(np.arange(probs.shape[0])) + plt.xlabel('category') + plt.ylabel('probability') + + +def plot_calibration_plot(probs, labels, bins=10): + predicted_label = np.argmax(probs, axis=-1) + predicted_score = np.max(probs, axis=-1) + correct_prediction = predicted_label == label + + step_size = 1.0 / bins + + mean_probabilities = [] + fraction_correct = [] + + for i in range(bins): + beg = i * step_size + end = start + step_size + mask = (predicted_scores > beg) & (predicted_scores < end) + cnt = mask.astype(np.float32).sum() + correct = (label[mask] == predicted_label[mask]).astype(np.float32).sum() + + mean_probabilities.append((beg + end) / 2.) + fraction_crrect.append((correct + 1e-10) / (cnt + 1e-10)) + + return mean_probabilities, fraction_correct + + +def multiclass_calibration_curve(probs, labels, bins=10): + step_size = 1.0 / bins + n_classes = probs.shape[1] + labels_ohe = np.eye(n_classes)[labels.astype(np.int64)] + + midpoints = [] + mean_confidences = [] + accuracies = [] + + for i in range(bins): + beg = i * step_size + end = (i + 1) * step_size + + bin_mask = (probs >= beg) & (probs < end) + bin_cnt = bin_mask.astype(np.float32).sum() + bin_confs = probs[bin_mask] + bin_acc = labels_ohe[bin_mask].sum() / bin_cnt + + midpoints.append((beg + end) / 2.) + mean_confidences.append(np.mean(bin_confs)) + accuracies.append(bin_acc) + + return midpoints, accuracies, mean_confidences + + +def plot_multiclass_calibration_curve(probs, labels, bins=10, title=None): + title = 'Reliability Diagram' if title is None else title + midpoints, accuracies, mean_confidences = multiclass_calibration_curve(probs, labels, bins=bins) + plt.bar(midpoints, accuracies, width=1.0 / float(bins), align='center', lw=1, ec='#000000', fc='#2233aa', alpha=1, + label='Model', zorder=0) + plt.scatter(midpoints, accuracies, lw=2, ec='black', fc="#ffffff", zorder=2) + plt.plot(np.linspace(0, 1.0, 20), np.linspace(0, 1.0, 20), '--', lw=2, alpha=.7, color='gray', + label='Perfectly calibrated', zorder=1) + plt.xlim(0.0, 1.0) + plt.ylim(0.0, 1.0) + plt.xlabel('\nconfidence') + plt.ylabel('accuracy\n') + plt.title(title + '\n') + plt.xticks(midpoints, rotation=-45) + plt.legend(loc='upper left') + return midpoints, accuracies, mean_confidences + + +def gaussian_nll(y_true, y_pred): + """ + Gaussian negative log likelihood + + Note: to make training more stable, we optimize + a modified loss by having our model predict log(sigma^2) + rather than sigma^2. + """ + + y_true = tf.reshape(y_true, [-1]) + mu = y_pred[:, 0] + si = y_pred[:, 1] + loss = (si + tf.square(y_true - mu) / tf.math.exp(si)) / 2.0 + return tf.reduce_mean(loss) + + +def define(): + model = tf.keras.models.Sequential([ + tf.keras.layers.InputLayer(shape=(1,)), + tf.keras.layers.Dense(10, activation='relu'), + tf.keras.layers.Dense(10, activation='tanh'), + tf.keras.layers.Dropout(drop_out_rate), + tf.keras.layers.Dense(2, activation=None) + ]) + optim = tf.keras.optimizers.Adam(1e-3) + model.compile(optimizer=optim, loss=gaussian_nll) + return model + + +def train(x, y, model, epochs=100): + model.fit(x, y, + batch_size=32, + epochs=epochs, + verbose=0) + return model + +def predict(model, x, samples=20): + ''' + Args: + model: The trained keras model + x: the input tensor with shape [N, M] + samples: the number of monte carlo samples to collect + Returns: + y_mean: The expected value of our prediction + y_std: The standard deviation of our prediction + ''' + mu_arr = [] + si_arr = [] + + for t in range(samples): + y_pred = model(x, training=True) + mu = y_pred[:, 0] + si = y_pred[:, 1] + + mu_arr.append(mu) + si_arr.append(si) + + mu_arr = np.array(mu_arr) + si_arr = np.array(si_arr) + var_arr = np.exp(si_arr) + + y_mean = np.mean(mu_arr, axis=0) + y_variance = np.mean(var_arr + mu_arr**2, axis=0) - y_mean**2 + y_std = np.sqrt(y_variance) + return y_mean, y_std + +def run(): + xmin = -10. + xmax = 10. + + x_gt, y_gt, x_trn, y_trn, x_tst, y_tst = create_toy_regression_dataset(xmin=xmin, xmax=xmax, noise_std=0.05) + + model = define() + model = train(x_trn[:, np.newaxis], + y_trn[:, np.newaxis], + model) + + yhat_mean, yhat_std = predict(model, x_tst[:, np.newaxis], samples=20) + + plot_regression_model_analysis(gt=(x_gt, y_gt), + trn=(x_trn, y_trn), + pred=(x_tst, yhat_mean, yhat_std), + xlim=(-11, 11), + ylim=(-5, 5), + title='MC Dropout Regression') + plt.savefig('/Users/thomasrink/mcdrop_regression.svg', bbox_inches='tight')