def histogram_2d(eta, phi, weights_px, weights_py, eta_range, phi_range, nbins, bin_dtype=tf.float32): eta_bins = tf.histogram_fixed_width_bins(eta, eta_range, nbins=nbins, dtype=bin_dtype) phi_bins = tf.histogram_fixed_width_bins(phi, phi_range, nbins=nbins, dtype=bin_dtype) hist_px = tf.zeros((nbins, nbins), dtype=weights_px.dtype) hist_py = tf.zeros((nbins, nbins), dtype=weights_py.dtype) indices = tf.transpose(tf.stack([phi_bins, eta_bins])) hist_px = tf.tensor_scatter_nd_add(hist_px, indices, weights_px) hist_py = tf.tensor_scatter_nd_add(hist_py, indices, weights_py) hist_pt = tf.sqrt(hist_px**2 + hist_py**2) return hist_pt
def binned_average(values, selection_values, value_range, nBins, weights=None): """Computes an average of values binned according to the selection_values array Assumes the following shapes: values.shape = (?, points, features) selection_values.shape = (?, points) returns the following shape: (?, nBins, features) """ outputs = [] all_counts = [] indices = tf.histogram_fixed_width_bins(selection_values, value_range, nbins=nBins) for b in range(nBins): mask = tf.cast(tf.equal(indices, b), tf.float32) if weights is not None: mask = mask * weights mean = tf.reduce_sum(tf.expand_dims(mask, -1) * values, axis=1) counts = tf.reduce_sum(mask, axis=1, keepdims=True) outputs.append(mean / counts) all_counts.append(counts) counts = tf.stack(all_counts, axis=1) result = tf.stack(outputs, axis=1) result = tf.where(tf.is_nan(result), tf.zeros_like(result), result) return result, counts
def bin(img, depth=16, center_u=0., center_v=0., eps=EPS, shrink=1, cs_func=to_uv, flat=False): if shrink != -1 and shrink != 1: img = tf.image.resize(img, (img.shape[0] // shrink, img.shape[1] // shrink)) img_uv, Iy = cs_func(img) bn_cnt = depth # vr = tf.convert_to_tensor(list(range(-bn_cnt // 2, bn_cnt // 2)), dtype=tf.float32) * 0.05 vr_u = [(-bn_cnt // 2 * eps) + center_u, (bn_cnt // 2 * eps) + center_u] vr_v = [(-bn_cnt // 2 * eps) + center_v, (bn_cnt // 2 * eps) + center_v] # vr = tf.scan(lambda x, y: x + y, vr) - 0.4 bins_u = tf.histogram_fixed_width_bins(img_uv[..., 0], value_range=vr_u, nbins=bn_cnt) bins_v = tf.histogram_fixed_width_bins(img_uv[..., 1], value_range=vr_v, nbins=bn_cnt) bins = tf.stack([bins_u, bins_v], axis=-1) if flat: bins = bins[..., 0] * depth + bins[..., 1] return bins, Iy
def discretize_in_bins(x): """Discretize a vector in two bins.""" return tf.histogram_fixed_width_bins( x, [tf.reduce_min(x), tf.reduce_max(x)], nbins=2, )
def _bin_confusion_matrix_by_score( self, pred_labels: Sequence[Sequence[bool]], true_labels: Sequence[Sequence[bool]], binning_score: Sequence[Sequence[float]]) -> Dict[str, tf.Tensor]: """Compute the confusion matrix, binning predictions by a specified score. Computes the confusion matrix over matrices of predicted and true labels. Each element of the resultant confusion matrix is itself a matrix of the same shape as the original input labels. In the typical use of this function in OracleCollaborativeAUC, the variables T and N (in the args and returns sections below) are the number of thresholds and the number of examples, respectively. Args: pred_labels: Boolean tensor of shape [T, N] of predicted labels. true_labels: Boolean tensor of shape [T, N] of true labels. binning_score: Boolean tensor of shape [T, N] of scores to use in assigning labels to bins. Returns: Dictionary of strings to entries of the confusion matrix ('true_positives', 'true_negatives', 'false_positives', 'false_negatives'). Each entry is a tensor of shape [T, nbins]. """ correct_preds = tf.math.equal(pred_labels, true_labels) # Elements of the confusion matrix have shape [M, N] pred_true_positives = tf.math.logical_and(correct_preds, pred_labels) pred_true_negatives = tf.math.logical_and(correct_preds, tf.math.logical_not(pred_labels)) pred_false_positives = tf.math.logical_and( tf.math.logical_not(correct_preds), pred_labels) pred_false_negatives = tf.math.logical_and( tf.math.logical_not(correct_preds), tf.math.logical_not(pred_labels)) # Cast confusion matrix elements from bool to self.dtype. pred_true_positives = tf.cast(pred_true_positives, self.dtype) pred_true_negatives = tf.cast(pred_true_negatives, self.dtype) pred_false_positives = tf.cast(pred_false_positives, self.dtype) pred_false_negatives = tf.cast(pred_false_negatives, self.dtype) bin_indices = tf.histogram_fixed_width_bins( binning_score, tf.constant([0.0, 1.0], self.dtype), nbins=self.num_bins) binned_true_positives = self._map_unsorted_segment_sum( pred_true_positives, bin_indices) binned_true_negatives = self._map_unsorted_segment_sum( pred_true_negatives, bin_indices) binned_false_positives = self._map_unsorted_segment_sum( pred_false_positives, bin_indices) binned_false_negatives = self._map_unsorted_segment_sum( pred_false_negatives, bin_indices) return { "true_positives": binned_true_positives, "true_negatives": binned_true_negatives, "false_positives": binned_false_positives, "false_negatives": binned_false_negatives }
def update_state(self, labels, probabilities, **kwargs): """Updates this metric. This will flatten the labels and probabilities, and then compute the ECE over all predictions. Args: labels: Tensor of shape [..., ] of class labels in [0, k-1]. probabilities: Tensor of shape [..., ], [..., 1] or [..., k] of normalized probabilities associated with the True class in the binary case, or with each of k classes in the multiclass case. **kwargs: Other potential keywords, which will be ignored by this method. """ del kwargs # unused labels = tf.convert_to_tensor(labels) probabilities = tf.cast(probabilities, self.dtype) # Flatten labels to [N, ] and probabilities to [N, 1] or [N, k]. if tf.rank(labels) != 1: labels = tf.reshape(labels, [-1]) if tf.rank(probabilities) != 2 or (tf.shape(probabilities)[0] != tf.shape(labels)[0]): probabilities = tf.reshape(probabilities, [tf.shape(labels)[0], -1]) # Extend any probabilities of shape [N, 1] to shape [N, 2]. # NOTE: XLA does not allow for different shapes in the branches of a # conditional statement. Therefore, explicit indexing is used. given_k = tf.shape(probabilities)[-1] k = tf.math.maximum(2, given_k) probabilities = tf.cond( given_k < 2, lambda: tf.concat([1. - probabilities, probabilities], axis=-1)[:, -k:], lambda: probabilities) pred_labels = tf.math.argmax(probabilities, axis=-1) pred_probs = tf.math.reduce_max(probabilities, axis=-1) correct_preds = tf.math.equal(pred_labels, tf.cast(labels, pred_labels.dtype)) correct_preds = tf.cast(correct_preds, self.dtype) bin_indices = tf.histogram_fixed_width_bins(pred_probs, tf.constant([0., 1.], self.dtype), nbins=self.num_bins) batch_correct_sums = tf.math.unsorted_segment_sum( data=tf.cast(correct_preds, self.dtype), segment_ids=bin_indices, num_segments=self.num_bins) batch_prob_sums = tf.math.unsorted_segment_sum( data=pred_probs, segment_ids=bin_indices, num_segments=self.num_bins) batch_counts = tf.math.unsorted_segment_sum( data=tf.ones_like(bin_indices), segment_ids=bin_indices, num_segments=self.num_bins) batch_counts = tf.cast(batch_counts, self.dtype) self.correct_sums.assign_add(batch_correct_sums) self.prob_sums.assign_add(batch_prob_sums) self.counts.assign_add(batch_counts)
def histogram(self, x, y, nbins=100, range_h=None): shape = tf.shape(y) batch_size = shape[0] x = tf.reshape(x, [-1]) y = tf.reshape(y, [-1]) if range_h is None: range_h = [ tf.reduce_min(tf.concat([x, y], axis=-1)), tf.reduce_max(tf.concat([x, y], axis=-1)) ] # hisy_bins is a Tensor holding the indices of the binned values whose shape matches y. histy_bins = tf.histogram_fixed_width_bins(y, range_h, nbins=nbins, dtype=tf.int32) # and creates a histogram_fixed_width H = tf.map_fn( lambda i: tf.histogram_fixed_width(tf.boolean_mask( x, tf.equal(histy_bins, i)), range_h, nbins=nbins, dtype=tf.int32), tf.range(nbins)) return tf.cast(H, dtype=tf.float32)
def __get_p_vals(data_array): y_pred = data_array[:-1] y_true = data_array[-1] support = [tf.reduce_min(data_array), tf.reduce_max(data_array)] bins = tf.histogram_fixed_width_bins(y_pred, support, nbins=nbins, dtype=tf.dtypes.int32, name=None) probs = tf.math.bincount(bins, minlength=nbins, maxlength=nbins) / y_pred.shape[0] bin_y_true = tf.histogram_fixed_width_bins(y_true, support, nbins=nbins, dtype=tf.dtypes.int32, name=None) res = tf.cast(tf.reduce_sum(probs[probs <= probs[bin_y_true]]), tf.float32) return res
def cross_hist_from_tensor(tensor, num_bins, range_): with tf.name_scope('cross_hist_from_tensor'): bins = tf.histogram_fixed_width_bins( tensor, range_, nbins=num_bins, ) bins_2d = self_cross_sum_with_factors(bins, -2, 1, num_bins) returned_value = hist_from_nonnegative_ints(bins_2d, -1, num_bins**2) return returned_value
def update_state(self, y_true: Sequence[float], y_pred: Sequence[float], confidence: Sequence[float], sample_weight: Optional[Sequence[float]] = None) -> None: """Updates confidence and accuracy statistics. Args: y_true: The ground truth labels. Shape (batch_size, ). y_pred: The predicted labels. Must be integer valued predictions for label index rather than the predictive probability. For multi-label classification problems, `y_pred` is typically obtained as `tf.math.reduce_max(logits)`. Shape (batch_size, ). confidence: The confidence score where higher value indicates lower uncertainty. Values should be within [0, 1]. sample_weight: Optional weighting of each example. Defaults to 1. Can be a Tensor whose rank is either 0, or the same rank as `y_true`, and must be broadcastable to `y_true`. """ batch_size = tf.shape(y_true)[0] # Preprocess `confidence` and `sample_weight` tensors. confidence = tf.cast(tf.convert_to_tensor(confidence), dtype=self.dtype) confidence = tf.reshape(confidence, shape=(batch_size, )) if sample_weight is not None: sample_weight = tf.convert_to_tensor(sample_weight) sample_weight = tf.reshape(sample_weight, shape=(batch_size, )) sample_weight = tf.cast(sample_weight, dtype=self.dtype) else: sample_weight = tf.ones((batch_size, ), dtype=self.dtype) # Computes correct predictions. correct_preds = _compute_correct_predictions(y_true, y_pred, dtype=self.dtype) correct_preds_weighted = correct_preds * sample_weight # Computes batch-specific histogram statistics for confidence score. batch_bin_indices = tf.histogram_fixed_width_bins( confidence, tf.constant([0., 1.], self.dtype), nbins=self.num_approx_bins) batch_total_counts = tf.math.unsorted_segment_sum( data=sample_weight, segment_ids=batch_bin_indices, num_segments=self.num_approx_bins) batch_correct_counts = tf.math.unsorted_segment_sum( data=correct_preds_weighted, segment_ids=batch_bin_indices, num_segments=self.num_approx_bins) self.binned_total_counts.assign_add(batch_total_counts) self.binned_correct_counts.assign_add(batch_correct_counts)
def test_hist_from_nonnegative_ints(): print('\n' + "*" * 20 + '\nhist_from_nonnegative_ints') tensor = tf.histogram_fixed_width_bins( tf.random.normal([100000], dtype=tf.float32, mean=0, stddev=1), [-15., 15.], nbins=30, ) tensor = tf.reshape(tensor, [10000, 10]) hist = tensors.hist_from_nonnegative_ints(tensor, -2, 30) config = tf.ConfigProto(allow_soft_placement=True) config.gpu_options.allow_growth = True with tf.Session(config=config) as sess: print(np.max(sess.run(tensor))) print(sess.run(hist))
def histogram_collector(results, variables): """This function will receive a tensor (result) and the variables corresponding to those integrand results In the example integrand below, these corresponds to `final_result` and `histogram_values` respectively. `current_histograms` instead is the current value of the histogram which will be overwritten""" # Fill a histogram with HISTO_BINS (2) bins, (0 to 0.5, 0.5 to 1) # First generate the indices with TF indices = tf.histogram_fixed_width_bins(variables, [fzero, fone], nbins=HISTO_BINS) t_indices = tf.transpose(indices) # Then consume the results with the utility we provide partial_hist = consume_array_into_indices(results, t_indices, HISTO_BINS) # Then update the results of current_histograms new_histograms = partial_hist + current_histograms cummulator_tensor.assign(new_histograms)
def get_jh(x, y, value_range, nbins): dtype = tf.dtypes.int32 x_range = value_range[0] y_range = value_range[1] histy_bins = tf.histogram_fixed_width_bins(y, y_range, nbins=nbins, dtype=dtype) def masking_info(tf_val): return tf.math.equal(histy_bins, tf_val) H = tf.map_fn( lambda i: tf.histogram_fixed_width( x[masking_info(i)], x_range, nbins=nbins), tf.range(nbins)) return H
def histogram2D(x, y, value_range, x_bins=100, y_bins=None, dtype=tf.float64): """ Generate a 2D histogram This code was copied from: https://gist.github.com/isentropic/a86effab2c007e86912a50f995cac52b And it was modified slightly. This function uses tf instead of np to make the histogram. I had a tremendous amount of confusion about which index correlates to which dimension. After a bunch of testing it seems like the popular convention is the opposite of my intuition. And I have been having this problem before... So in the tensor that this returns, y is the first index and x is the second. Parameters ---------- x, y : 1D tensor The x and y values of the points to bin. value_range : 2x2 array-like The limits to use for the bins in the x and y directions xbins, ybins : int, optional Defaults to 100. The number of bins to use in each dimension dtype : tf.dtype, optional Defaults to tf.float64. The dtype to use for the histogram. """ y_bins = y_bins or x_bins x_range = tf.cast(value_range[0], dtype) y_range = tf.cast(value_range[1], dtype) histy_bins = tf.histogram_fixed_width_bins(y, y_range, nbins=y_bins, dtype=dtype) H = tf.map_fn( lambda i: tf.histogram_fixed_width( x[histy_bins == i], x_range, nbins=x_bins), tf.range(y_bins)) return H
# noise_prob = noise_counts / np.sum(noise_counts) # img_prob = img_counts / np.sum(img_counts) # noise_prob = noise_prob[np.nonzero(noise_prob)] # img_prob = img_prob[np.nonzero(img_prob)] # # assert np.sum(noise_prob) == 1.0, print(np.sum(noise_prob)) # assert np.sum(img_prob) == 1.0, np.sum(img_prob) # # noise_info = np.log2(noise_prob) # img_info = np.log2(img_prob) # # noise_entropy = -np.sum(noise_prob * noise_info) # img_entropy = -np.sum(img_prob * img_info) noise_idx = tf.histogram_fixed_width_bins( tf.reshape(noise, [-1]), [tf.reduce_min(noise), tf.reduce_max(noise)], 64) img_idx = tf.histogram_fixed_width_bins( tf.reshape(img, [-1]), [tf.reduce_min(img), tf.reduce_max(img)], 64) noise_idx = tf.sort(noise_idx) img_idx = tf.sort(img_idx) _, _, noise_counts = tf.unique_with_counts(noise_idx) _, _, img_counts = tf.unique_with_counts(img_idx) noise_prob = noise_counts / tf.reduce_sum(noise_counts) img_prob = img_counts / tf.reduce_sum(img_counts) assert tf.reduce_sum(noise_prob).numpy() == 1.0, tf.reduce_sum(noise_prob) assert tf.reduce_sum(img_prob).numpy() == 1.0, tf.reduce_sum(img_prob) noise_entropy = -tf.reduce_sum(noise_prob * tf.math.log(noise_prob))
import tensorflow as tf import numpy as np import src.utilities.tf_utils as tfu import matplotlib.pyplot as plt from src.test_functions.np_tv_denoise_test import tv_denoise from PIL import Image tf.InteractiveSession() A = tf.constant([[1., 2., 3.], [4., 5., 6.], [7., 8., 9.]]) a_b = tf.histogram_fixed_width_bins(values=A, value_range=[0., 9.], nbins=3) b = tf.constant(2) bi = a_b.eval() x = (a_b + b).eval() ten = tf.ones([6, 5, 3, 3]) drop_out = tf.nn.dropout(ten, keep_prob=2 / 3, noise_shape=[6, 5, 1, 1]) with tf.Session() as sess: dn = sess.run(drop_out) a = 0 img = np.array( plt.imread( "/home/christian/Projects/Lab_SS2019/dataset/2d_slices/png/raw/train/HGG/brats_2013_pat0006_1/VSD.Brain.XX.O.MR_Flair.54542/VSD.Brain.XX.O.MR_Flair.54542_82.png" )) img2 = np.array( plt.imread( "/home/christian/Projects/Lab_SS2019/dataset/2d_slices/png/raw/train/HGG/brats_2013_pat0006_1/VSD.Brain.XX.O.MR_T2.54545/VSD.Brain.XX.O.MR_T2.54545_82.png" ))
def _compute_calibration_bin_statistics(num_bins, logits=None, probabilities=None, labels_true=None, labels_predicted=None): """Compute binning statistics required for calibration measures. Args: num_bins: int, number of probability bins, e.g. 10. logits: Tensor, (n,nlabels), with logits for n instances and nlabels. probabilities: Tensor, (n,nlabels), with probs for n instances and nlabels. labels_true: Tensor, (n,), with tf.int32 or tf.int64 elements containing ground truth class labels in the range [0,nlabels]. labels_predicted: Tensor, (n,), with tf.int32 or tf.int64 elements containing decisions of the predictive system. If `None`, we will use the argmax decision using the `logits`. Returns: bz: Tensor, shape (2,num_bins), tf.int32, counts of incorrect (row 0) and correct (row 1) predictions in each of the `num_bins` probability bins. pmean_observed: Tensor, shape (num_bins,), tf.float32, the mean predictive probabilities in each probability bin. """ if (logits is None) == (probabilities is None): raise ValueError( "_compute_calibration_bin_statistics expects exactly one of logits or " "probabilities.") elif probabilities is None: if logits.get_shape().as_list()[-1] == 1: # pytype: disable=attribute-error raise ValueError( "_compute_calibration_bin_statistics expects logits for binary" " classification of shape (n, 2) for nlabels=2 but got ", logits.get_shape()) # pytype: disable=attribute-error probabilities = tf.math.softmax(logits, axis=1) elif (probabilities.get_shape().as_list()[-1] == 1 or len(probabilities.get_shape().as_list()) == 1): raise ValueError( "_compute_calibration_bin_statistics expects probabilities for binary" " classification of shape (n, 2) for nlabels=2 but got ", probabilities.get_shape()) if labels_predicted is None: # If no labels are provided, we take the label with the maximum probability # decision. This corresponds to the optimal expected minimum loss decision # under 0/1 loss. pred_y = tf.cast(tf.argmax(probabilities, axis=1), tf.int32) else: pred_y = labels_predicted correct = tf.cast(tf.equal(pred_y, labels_true), tf.int32) # Collect predicted probabilities of decisions prob_y = tf.compat.v1.batch_gather(probabilities, tf.expand_dims(pred_y, 1)) # p(pred_y | x) prob_y = tf.reshape(prob_y, (tf.size(prob_y), )) # Compute b/z histogram statistics: # bz[0,bin] contains counts of incorrect predictions in the probability bin. # bz[1,bin] contains counts of correct predictions in the probability bin. bins = tf.histogram_fixed_width_bins(prob_y, [0.0, 1.0], nbins=num_bins) event_bin_counts = tf.math.bincount(correct * num_bins + bins, minlength=2 * num_bins, maxlength=2 * num_bins) event_bin_counts = tf.reshape(event_bin_counts, (2, num_bins)) # Compute mean predicted probability value in each of the `num_bins` bins pmean_observed = tf.math.unsorted_segment_sum(prob_y, bins, num_bins) tiny = np.finfo(np.float32).tiny pmean_observed = pmean_observed / ( tf.cast(tf.reduce_sum(event_bin_counts, axis=0), tf.float32) + tiny) return event_bin_counts, pmean_observed
def hist_1d(values, num_bins, range_, axis): with tf.name_scope('hist_1d'): discrete = tf.histogram_fixed_width_bins(values, range_, num_bins) return hist_from_nonnegative_ints(discrete, axis, num_bins)
def _bin_confusion_matrix_by_score( self, pred_labels: Sequence[Sequence[bool]], true_labels: Sequence[Sequence[bool]], binning_score: Sequence[Sequence[float]]) -> Dict[str, tf.Tensor]: """Compute the confusion matrix, binning predictions by a specified score. Computes the confusion matrix over matrices of predicted and true labels. Each element of the resultant confusion matrix is itself a matrix of the same shape as the original input labels. In the typical use of this function in OracleCollaborativeAUC, the variables T and N (in the args and returns sections below) are the number of thresholds and the number of examples, respectively. Args: pred_labels: Boolean tensor of shape [T, N] of predicted labels. true_labels: Boolean tensor of shape [T, N] of true labels. binning_score: Boolean tensor of shape [T, N] of scores to use in assigning labels to bins. Returns: Dictionary of strings to entries of the confusion matrix ('true_positives', 'true_negatives', 'false_positives', 'false_negatives'). Each entry is a tensor of shape [T, nbins]. If oracle_threshold was set, nbins=2, storing respectively the number of examples below the oracle_threshold (i.e. sent to the oracle) and above it (not sent to the oracle). """ correct_preds = tf.math.equal(pred_labels, true_labels) # Elements of the confusion matrix have shape [M, N] pred_true_positives = tf.math.logical_and(correct_preds, pred_labels) pred_true_negatives = tf.math.logical_and( correct_preds, tf.math.logical_not(pred_labels)) pred_false_positives = tf.math.logical_and( tf.math.logical_not(correct_preds), pred_labels) pred_false_negatives = tf.math.logical_and( tf.math.logical_not(correct_preds), tf.math.logical_not(pred_labels)) # Cast confusion matrix elements from bool to self.dtype. pred_true_positives = tf.cast(pred_true_positives, self.dtype) pred_true_negatives = tf.cast(pred_true_negatives, self.dtype) pred_false_positives = tf.cast(pred_false_positives, self.dtype) pred_false_negatives = tf.cast(pred_false_negatives, self.dtype) histogram_value_range = tf.constant([0.0, 1.0], self.dtype) if self.oracle_threshold is not None: # All predictions with score <= oracle_threshold are sent to the oracle. # With two bins, centering the value range on oracle_threshold yields a # histogram with all examples sent to the oracle in the lower (left) bin. histogram_value_range += self.oracle_threshold - 0.5 # Move the histogram center up by epsilon to ensure <= rather than <. # By default, tf histogram gives [low, high); we want (low, high]. histogram_value_range += tf.keras.backend.epsilon() bin_indices = tf.histogram_fixed_width_bins(binning_score, histogram_value_range, nbins=self.num_bins) binned_true_positives = self._map_unsorted_segment_sum( pred_true_positives, bin_indices) binned_true_negatives = self._map_unsorted_segment_sum( pred_true_negatives, bin_indices) binned_false_positives = self._map_unsorted_segment_sum( pred_false_positives, bin_indices) binned_false_negatives = self._map_unsorted_segment_sum( pred_false_negatives, bin_indices) return { "true_positives": binned_true_positives, "true_negatives": binned_true_negatives, "false_positives": binned_false_positives, "false_negatives": binned_false_negatives }
def f(sample): return tf.histogram_fixed_width_bins( sample, [tf.reduce_min(sample), tf.reduce_max(sample)], nbins=2)
def expected_calibration_error(y_true, y_pred, nbins=20): """Calculates Expected Calibration Error (ECE). ECE is a scalar summary statistic of calibration error. It is the sample-weighted average of the difference between the predicted and true probabilities of a positive detection across uniformly-spaced model confidences [0, 1]. See referenced paper for a thorough explanation. Reference: Guo, et. al, "On Calibration of Modern Neural Networks" Page 2, Expected Calibration Error (ECE). https://arxiv.org/pdf/1706.04599.pdf This function creates three local variables, `bin_counts`, `bin_true_sum`, and `bin_preds_sum` that are used to compute ECE. For estimation of the metric over a stream of data, the function creates an `update_op` operation that updates these variables and returns the ECE. Args: y_true: 1-D tf.int64 Tensor of binarized ground truth, corresponding to each prediction in y_pred. y_pred: 1-D tf.float32 tensor of model confidence scores in range [0.0, 1.0]. nbins: int specifying the number of uniformly-spaced bins into which y_pred will be bucketed. Returns: value_op: A value metric op that returns ece. update_op: An operation that increments the `bin_counts`, `bin_true_sum`, and `bin_preds_sum` variables appropriately and whose value matches `ece`. Raises: InvalidArgumentError: if y_pred is not in [0.0, 1.0]. """ bin_counts = metrics_impl.metric_variable( [nbins], tf.float32, name='bin_counts') bin_true_sum = metrics_impl.metric_variable( [nbins], tf.float32, name='true_sum') bin_preds_sum = metrics_impl.metric_variable( [nbins], tf.float32, name='preds_sum') with tf.control_dependencies([ tf.assert_greater_equal(y_pred, 0.0), tf.assert_less_equal(y_pred, 1.0), ]): bin_ids = tf.histogram_fixed_width_bins(y_pred, [0.0, 1.0], nbins=nbins) with tf.control_dependencies([bin_ids]): update_bin_counts_op = tf.assign_add( bin_counts, tf.to_float(tf.bincount(bin_ids, minlength=nbins))) update_bin_true_sum_op = tf.assign_add( bin_true_sum, tf.to_float(tf.bincount(bin_ids, weights=y_true, minlength=nbins))) update_bin_preds_sum_op = tf.assign_add( bin_preds_sum, tf.to_float(tf.bincount(bin_ids, weights=y_pred, minlength=nbins))) ece_update_op = _ece_from_bins( update_bin_counts_op, update_bin_true_sum_op, update_bin_preds_sum_op, name='update_op') ece = _ece_from_bins(bin_counts, bin_true_sum, bin_preds_sum, name='value') return ece, ece_update_op
def create_hist(self, image, nbins, source_range, normalize): """ Creates a histogram of a given image. The histogram is computed on the flattened image, so for colour images, the function should be used separately on each channel to obtain a histogram for each colour channel. Parameters __________ image: array - an array representation of the image nbins: int (optional) - number of bins used to calculate histogram source_range: string (optional) - 'image' (default) gets the range from the input image, 'dtype' determines the range from the expected range of the images of that data type. normalize: bool (optional) - If True, the histogram will be normalized by the sum of its values. Returns _______ hist: array - the values of the histogram bin_centers: array - the values of center of the bins. Example _______ See main.py for example script """ # check the shape of image shape = tf.shape(image) if (tf.size(shape) == 3): print( "If this is a colour image, the histogram will be computed on the flattened image.\ You can instead apply this function to each color channel.") # setup sess = tf.InteractiveSession() image = tf.constant(image) # flatten image image_flatten = tf.reshape(image, [-1]) # specify the source range if (source_range == 'image'): # general range min_val = tf.reduce_min(image_flatten).eval() max_val = tf.reduce_max(image_flatten).eval() hist_range = tf.constant([min_val, max_val], dtype=tf.float64) elif (source_range == 'dtype'): # get the limits of the type hist_range = tf.DType(image_flatten.dtype).limits hist_range = tf.constant(hist_range, dtype=tf.float64) else: print('Wrong value for `source range` parameter') # cast image_flatten = tf.dtypes.cast(image_flatten, tf.float64) # get values and bin edges of the histogram hist = tf.histogram_fixed_width(image_flatten, hist_range, nbins=nbins) bins = tf.histogram_fixed_width_bins(image_flatten, hist_range, nbins=nbins) bin_centres = (bins[:-1] + bins[1:]) / 2 # normalize if specified if (normalize): hist = hist / tf.reduce_sum(hist) return hist.eval(), bin_centres.eval()
def expected_calibration_error(y_true, y_pred, nbins=20): """Calculates Expected Calibration Error (ECE). ECE is a scalar summary statistic of calibration error. It is the sample-weighted average of the difference between the predicted and true probabilities of a positive detection across uniformly-spaced model confidences [0, 1]. See referenced paper for a thorough explanation. Reference: Guo, et. al, "On Calibration of Modern Neural Networks" Page 2, Expected Calibration Error (ECE). https://arxiv.org/pdf/1706.04599.pdf This function creates three local variables, `bin_counts`, `bin_true_sum`, and `bin_preds_sum` that are used to compute ECE. For estimation of the metric over a stream of data, the function creates an `update_op` operation that updates these variables and returns the ECE. Args: y_true: 1-D tf.int64 Tensor of binarized ground truth, corresponding to each prediction in y_pred. y_pred: 1-D tf.float32 tensor of model confidence scores in range [0.0, 1.0]. nbins: int specifying the number of uniformly-spaced bins into which y_pred will be bucketed. Returns: value_op: A value metric op that returns ece. update_op: An operation that increments the `bin_counts`, `bin_true_sum`, and `bin_preds_sum` variables appropriately and whose value matches `ece`. Raises: InvalidArgumentError: if y_pred is not in [0.0, 1.0]. """ bin_counts = metrics_impl.metric_variable([nbins], tf.float32, name='bin_counts') bin_true_sum = metrics_impl.metric_variable([nbins], tf.float32, name='true_sum') bin_preds_sum = metrics_impl.metric_variable([nbins], tf.float32, name='preds_sum') with tf.control_dependencies([ tf.assert_greater_equal(y_pred, 0.0), tf.assert_less_equal(y_pred, 1.0), ]): bin_ids = tf.histogram_fixed_width_bins(y_pred, [0.0, 1.0], nbins=nbins) with tf.control_dependencies([bin_ids]): update_bin_counts_op = tf.assign_add( bin_counts, tf.cast(tf.bincount(bin_ids, minlength=nbins), dtype=tf.float32)) update_bin_true_sum_op = tf.assign_add( bin_true_sum, tf.cast(tf.bincount(bin_ids, weights=y_true, minlength=nbins), dtype=tf.float32)) update_bin_preds_sum_op = tf.assign_add( bin_preds_sum, tf.cast(tf.bincount(bin_ids, weights=y_pred, minlength=nbins), dtype=tf.float32)) ece_update_op = _ece_from_bins(update_bin_counts_op, update_bin_true_sum_op, update_bin_preds_sum_op, name='update_op') ece = _ece_from_bins(bin_counts, bin_true_sum, bin_preds_sum, name='value') return ece, ece_update_op
def mclahe(x, kernel_size=None, n_bins=128, clip_limit=0.01, adaptive_hist_range=False, use_gpu=True): """ Contrast limited adaptive histogram equalization implemented in tensorflow :param x: numpy array to which clahe is applied :param kernel_size: tuple of kernel sizes, 1/8 of dimension lengths of x if None :param n_bins: number of bins to be used in the histogram :param clip_limit: relative intensity limit to be ignored in the histogram equalization :param adaptive_hist_range: flag, if true individual range for histogram computation of each block is used :param use_gpu: Flag, if true gpu is used for computations if available :return: numpy array to which clahe was applied, scaled on interval [0, 1] """ if kernel_size is None: kernel_size = tuple(s // 8 for s in x.shape) kernel_size = np.array(kernel_size) assert len(kernel_size) == len(x.shape) dim = len(x.shape) # Normalize data x_min = np.min(x) x_max = np.max(x) x = (x - x_min) / (x_max - x_min) # Pad data x_shape = np.array(x.shape) padding_x_length = kernel_size - 1 - ((x_shape - 1) % kernel_size) padding_x = np.column_stack( ((padding_x_length + 1) // 2, padding_x_length // 2)) padding_hist = np.column_stack( (kernel_size // 2, (kernel_size + 1) // 2)) + padding_x x_hist_padded = np.pad(x, padding_hist, 'symmetric') # Set up tf graph with tf.variable_scope("clahe") as scope: tf_x_hist_padded_init = tf.placeholder(tf.float32, shape=x_hist_padded.shape) tf_x_hist_padded = tf.Variable(tf_x_hist_padded_init) tf_x_padded = tf.slice(tf_x_hist_padded, kernel_size // 2, x_shape + padding_x_length) # Form blocks used for interpolation n_blocks = np.ceil(np.array(x.shape) / kernel_size).astype(np.int32) new_shape = np.reshape(np.column_stack((n_blocks, kernel_size)), (2 * dim, )) perm = tuple(2 * i for i in range(dim)) + tuple(2 * i + 1 for i in range(dim)) tf_x_block = tf.transpose(tf.reshape(tf_x_padded, new_shape), perm=perm) shape_x_block = np.concatenate((n_blocks, kernel_size)) # Form block used for histogram n_blocks_hist = n_blocks + np.ones(dim, dtype=np.int32) new_shape = np.reshape(np.column_stack((n_blocks_hist, kernel_size)), (2 * dim, )) perm = tuple(2 * i for i in range(dim)) + tuple(2 * i + 1 for i in range(dim)) tf_x_hist = tf.transpose(tf.reshape(tf_x_hist_padded, new_shape), perm=perm) # Get maps # Get histogram if adaptive_hist_range: hist_ex_shape = np.concatenate((n_blocks_hist, [1] * dim)) tf_x_hist_ex_init = tf.placeholder(tf.float32, shape=n_blocks_hist) tf_x_hist_min = tf.Variable(tf_x_hist_ex_init, dtype=tf.float32) tf_x_hist_max = tf.reduce_max(tf_x_hist, np.arange(-dim, 0)) tf_x_hist_norm = tf.Variable(tf_x_hist_ex_init, dtype=tf.float32) tf_get_hist_min = tf.assign( tf_x_hist_min, tf.reduce_min(tf_x_hist, np.arange(-dim, 0))) tf_get_hist_norm = tf.assign( tf_x_hist_norm, tf.where(tf.equal(tf_x_hist_min, tf_x_hist_max), tf.ones_like(tf_x_hist_min), tf_x_hist_max - tf_x_hist_min)) tf_x_hist_scaled = (tf_x_hist - tf.reshape(tf_x_hist_min, hist_ex_shape))\ / tf.reshape(tf_x_hist_norm, hist_ex_shape) else: tf_x_hist_scaled = tf_x_hist tf_hist = tf.cast( tf_batch_histogram(tf_x_hist_scaled, [0., 1.], dim, nbins=n_bins), tf.float32) # Clip histogram tf_n_to_high = tf.reduce_sum( tf.nn.relu(tf_hist - np.prod(kernel_size) * clip_limit), -1, keepdims=True) tf_hist_clipped = tf.minimum( tf_hist, np.prod(kernel_size) * clip_limit) + tf_n_to_high / n_bins tf_cdf = tf.cumsum(tf_hist_clipped, -1) tf_cdf_slice_size = tf.constant(np.concatenate((n_blocks_hist, [1])), tf.int32) tf_cdf_min = tf.slice(tf_cdf, tf.constant([0] * (dim + 1), dtype=tf.int32), tf_cdf_slice_size) tf_cdf_max = tf.slice( tf_cdf, tf.constant([0] * dim + [n_bins - 1], dtype=tf.int32), tf_cdf_slice_size) tf_cdf_norm = tf.where(tf.equal(tf_cdf_min, tf_cdf_max), tf.ones_like(tf_cdf_max), tf_cdf_max - tf_cdf_min) tf_mapping = (tf_cdf - tf_cdf_min) / tf_cdf_norm map_shape = np.concatenate((n_blocks_hist, [n_bins])) tf_map_init = tf.placeholder(tf.float32, shape=map_shape) tf_map = tf.Variable(tf_map_init, dtype=tf.float32) tf_get_map = tf.assign(tf_map, tf_mapping) # Prepare initializer tf_x_block_init = tf.placeholder(tf.float32, shape=shape_x_block) # Set up slice of data and map tf_slice_begin = tf.placeholder(tf.int32, shape=(dim, )) tf_map_slice_begin = tf.concat([tf_slice_begin, [0]], 0) tf_map_slice_size = tf.constant(np.concatenate((n_blocks, [n_bins])), dtype=tf.int32) tf_map_slice = tf.slice(tf_map, tf_map_slice_begin, tf_map_slice_size) # Get bins if adaptive_hist_range: # Local bins tf_hist_norm_slice_shape = np.concatenate((n_blocks, [1] * dim)) tf_x_hist_min_sub = tf.slice(tf_x_hist_min, tf_slice_begin, n_blocks) tf_x_hist_norm_sub = tf.slice(tf_x_hist_norm, tf_slice_begin, n_blocks) tf_x_block_scaled = (tf_x_block - tf.reshape(tf_x_hist_min_sub, tf_hist_norm_slice_shape))\ / tf.reshape(tf_x_hist_norm_sub, tf_hist_norm_slice_shape) tf_bin = tf.histogram_fixed_width_bins(tf_x_block_scaled, [0., 1.], nbins=n_bins) else: # Global bins tf_bin = tf.Variable(tf.cast(tf_x_block_init, tf.int32), dtype=tf.int32) tf_get_bin = tf.assign( tf_bin, tf.histogram_fixed_width_bins(tf_x_block, [0., 1.], nbins=n_bins)) # Apply map tf_mapped_sub = tf_batch_gather(tf_map_slice, tf_bin, dim) # Apply coefficients tf_coeff = tf.placeholder(tf.float32) tf_res_sub = tf.Variable(tf_x_block_init, dtype=tf.float32) tf_apply_map = tf.assign(tf_res_sub, tf_mapped_sub) tf_apply_coeff = tf.assign(tf_res_sub, tf_coeff * tf_res_sub) # Update results tf_res = tf.Variable(tf_x_block_init, dtype=tf.float32) tf_update_res = tf.assign_add(tf_res, tf_res_sub) # Rescaling tf_res_min, tf_res_max = (tf.reduce_min(tf_res), tf.reduce_max(tf_res)) tf_res_norm = (tf_res - tf_res_min) / (tf_res_max - tf_res_min) tf_rescale = tf.assign(tf_res, tf_res_norm) # Reshape result new_shape = tuple((axis, axis + dim) for axis in range(dim)) new_shape = tuple(j for i in new_shape for j in i) tf_res_transposed = tf.transpose(tf_res, new_shape) tf_res_reshaped = tf.reshape( tf_res_transposed, tuple(n_blocks[axis] * kernel_size[axis] for axis in range(dim))) # Recover original size tf_res_cropped = tf.slice(tf_res_reshaped, padding_x[:, 0], x.shape) # Setting up tf session if use_gpu: config = None else: config = tf.ConfigProto(device_count={'GPU': 0}) with tf.Session(config=config) as sess: map_init = np.zeros(map_shape, dtype=np.float32) x_block_init = np.zeros(shape_x_block, dtype=np.float32) # Initialize vars for local hist range if needed if adaptive_hist_range: x_hist_ex_init = np.zeros(n_blocks_hist, dtype=np.float32) tf_var_init = tf.initializers.variables([ tf_x_hist_padded, tf_map, tf_res, tf_res_sub, tf_x_hist_min, tf_x_hist_norm ]) sess.run(tf_var_init, feed_dict={ tf_x_hist_padded_init: x_hist_padded, tf_map_init: map_init, tf_x_block_init: x_block_init, tf_x_hist_ex_init: x_hist_ex_init }) else: tf_var_init = tf.initializers.variables( [tf_x_hist_padded, tf_map, tf_bin, tf_res, tf_res_sub]) sess.run(tf_var_init, feed_dict={ tf_x_hist_padded_init: x_hist_padded, tf_map_init: map_init, tf_x_block_init: x_block_init }) # Run calculations # Normalize histogram data if needed if adaptive_hist_range: sess.run(tf_get_hist_min) sess.run(tf_get_hist_norm) sess.run(tf_get_map) # Get global hist bins if needed if not adaptive_hist_range: sess.run(tf_get_bin) # Loop over maps inds = [list(i) for i in product([0, 1], repeat=dim)] for ind_map in inds: sess.run(tf_apply_map, feed_dict={tf_slice_begin: ind_map}) # Calculate and apply coefficients for axis in range(dim): coeff = np.arange(kernel_size[axis], dtype=np.float32) / kernel_size[axis] if kernel_size[axis] % 2 == 0: coeff = 0.5 / kernel_size[axis] + coeff if ind_map[axis] == 0: coeff = 1. - coeff new_shape = [1] * (dim + axis) + [ kernel_size[axis] ] + [1] * (dim - 1 - axis) coeff = np.reshape(coeff, new_shape) sess.run(tf_apply_coeff, feed_dict={tf_coeff: coeff}) # Update results sess.run(tf_update_res) # Rescaling sess.run(tf_rescale) # Get result result = sess.run(tf_res_cropped) return result
def sft_generator(img_shape, hu_min, hu_max, spectr_norm=False, gen_out=None): input_layer = Input(shape=img_shape) # Part 1. Feature Extraction Network filter_outputs = [ 64, 54, 48, 43, 39, 35, 31, 28, 25, 22, 18, 16, 24, 8, 8, 32, 16 ] fe_layers = [] for i in range(12): if i == 0: # segmentation map indices = tf.histogram_fixed_width_bins( input_layer, [float(hu_min), float(hu_max)], 10) seg_map = tf.one_hot(indices, 10) seg_map = tf.squeeze(seg_map, axis=3) sm = condition()(seg_map) # feature map fe = conv2d(input_layer, filters=filter_outputs[i], kernel_size=3, stride=2, padding='same', sn=spectr_norm) fe = LeakyReLU(0.1)(fe) fe = Dropout(0.2)(fe) else: fe = sft(units=[32, fe.shape[-1]])([fe, sm]) fe = conv2d(fe, filters=filter_outputs[i], kernel_size=3, stride=1, padding='same', sn=spectr_norm) fe = LeakyReLU(0.1)(fe) fe = Dropout(0.2)(fe) fe_layers.append(fe) fe_final_layer = Concatenate()(fe_layers) # Part 2.1 Reconstruction Network a1 = sft(units=[32, fe_final_layer.shape[-1]])([fe_final_layer, sm]) a1 = conv2d(a1, filters=filter_outputs[12], kernel_size=1, stride=1, padding='same', sn=spectr_norm) a1 = LeakyReLU(0.1)(a1) a1 = Dropout(0.2)(a1) b1 = sft(units=[32, fe_final_layer.shape[-1]])([fe_final_layer, sm]) b1 = conv2d(fe_final_layer, filters=filter_outputs[13], kernel_size=1, stride=1, padding='same', sn=spectr_norm) b1 = LeakyReLU(0.1)(b1) b1 = Dropout(0.2)(b1) b2 = sft(units=[32, b1.shape[-1]])([b1, sm]) b2 = conv2d(b1, filters=filter_outputs[14], kernel_size=3, stride=1, padding='same', sn=spectr_norm) b2 = LeakyReLU(0.1)(b2) b2 = Dropout(0.2)(b2) reconstructed = Concatenate()([a1, b2]) # Part 2.2 Upsampling c1 = conv2d(reconstructed, filters=filter_outputs[15], kernel_size=3, stride=1, padding='same', sn=spectr_norm) c1 = LeakyReLU(0.1)(c1) c2 = upsample(c1, filters=filter_outputs[16], kernel_size=4, stride=2, padding='same') c2 = LeakyReLU(0.1)(c2) output = conv2d(c2, filters=1, kernel_size=3, stride=1, padding='same', bias=False, activation=gen_out) return Model(input_layer, output)