def _should_continue(a, b, f_a, f_b, t, num_iterations, converged): del a, b, f_a, f_b, t # Unused. all_converged = stopping_policy_fn( tf.logical_or(converged, num_iterations >= max_iterations)) return ~all_converged
def add_or_or(x1, x2): if x1.dtype == tf.bool: assert x2.dtype == tf.bool return tf.logical_or(x1, x2) return tf.add(x1, x2)
def max_or_or(x1, x2): if x1.dtype == tf.bool: assert x2.dtype == tf.bool return tf.logical_or(x1, x2) return tf.math.maximum(x1, x2)
def _calculate_spline_coeffs(x_data, y_data): """Calculates the coefficients for the spline interpolation. These are the values of the second derivative of the spline at `x_data`. See p.548 of [1]. Below is an outline of the function when number of observations if equal to 7. The coefficients are obtained by building and solving a tridiagonal linear system of equations with symmetric matrix w2, dx2, 0, 0, 0 dx2, w3, dx3, 0, 0 0, dx3, w4, dx4, 0 0, 0, dx4, w5, dx5 0, 0, 0, dx5, w6 where: wn = 2 * (x_data[n-2] + x_data[n-1]) dxn = x_data[n-1] - x_data[n-2] and the right hand side of the equation is: [[3*( (d2-d1)/X1 - (d1-d0)/x0], [3*( (d3-d2)/X2 - (d2-d1)/x1], ... ] with di = y_data[..., i] Solve for `spline_coeffs`, so that matrix * spline_coeffs = rhs the solution is the `spline_coeffs` parameter of the spline equation: y_pred = a(spline_coeffs) * t^3 + b(spline_coeffs) * t^2 + c(spline_coeffs) * t + d(spline_coeffs) with t being the proportion of the difference between the x value of the spline used and the nx_value of the next spline: t = (x_values - x_data[:,n]) / (x_data[:,n+1]-x_data[:,n]) and `a`, `b`, `c`, and `d` are functions of `spline_coeffs` and `x_data` and are provided in the `interpolate` function. ## References: [1]: R. Sedgewick, Algorithms in C, 1990, p. 545-550. Link: http://index-of.co.uk/Algorithms/Algorithms%20in%20C.pdf Args: x_data: A real `Tensor` of shape `[..., num_points]` containing X-coordinates of points to fit the splines to. The values have to be monotonically non-decreasing along the last dimension. y_data: A `Tensor` of the same shape and `dtype` as `x_data` containing Y-coordinates of points to fit the splines to. Returns: A `Tensor` of the same shape and `dtype` as `x_data`. Represents the spline coefficients for the cubic spline interpolation. """ # `dx` is the distances between the x points. It is 1 element shorter than # `x_data` dx = x_data[..., 1:] - x_data[..., :-1] # `diag_values` are the diagonal values 2 * (x_data[i+1] - x_data[i-1]) # its length 2 shorter diag_values = 2.0 * (x_data[..., 2:] - x_data[..., :-2]) superdiag = dx[..., 1:] subdiag = dx[..., :-1] corr_term = tf.logical_or(tf.equal(superdiag, 0), tf.equal(subdiag, 0)) diag_values_corr = tf.where(corr_term, tf.ones_like(diag_values), diag_values) superdiag_corr = tf.where(tf.equal(subdiag, 0), tf.zeros_like(superdiag), superdiag) subdiag_corr = tf.where(tf.equal(superdiag, 0), tf.zeros_like(subdiag), subdiag) diagonals = tf.stack([superdiag_corr, diag_values_corr, subdiag_corr], axis=-2) # determine the rhs of the equation dd = (y_data[..., 1:] - y_data[..., :-1]) / dx dd = tf.where(tf.equal(dx, 0), tf.zeros_like(dd), dd) # rhs is a column vector: # [[-3((y1-y0)/dx0 - (y2-y1)/dx0], ...] rhs = -3 * (dd[..., :-1] - dd[..., 1:]) rhs = tf.where(corr_term, tf.zeros_like(rhs), rhs) # Partial pivoting is unnecessary since the matrix is diagonally dominant. spline_coeffs = tf.linalg.tridiagonal_solve(diagonals, rhs, partial_pivoting=False) # Reshape `spline_coeffs` zero = tf.zeros_like(dx[..., :1], dtype=x_data.dtype) spline_coeffs = tf.concat([zero, spline_coeffs, zero], axis=-1) return spline_coeffs
def _maybe_validate_shape_override(self, override_shape, base_is_scalar_fn, static_base_shape, is_init): """Helper which ensures override batch/event_shape are valid.""" assertions = [] concretized_shape = None # Check valid dtype if is_init: # No xor check because `dtype` cannot change. dtype_ = override_shape.dtype if dtype_ is None: if concretized_shape is None: concretized_shape = tf.convert_to_tensor(override_shape) dtype_ = concretized_shape.dtype if dtype_util.base_dtype(dtype_) not in {tf.int32, tf.int64}: raise TypeError('Shape override must be integer type; ' 'saw {}.'.format(dtype_util.name(dtype_))) # Check non-negative elements if is_init != tensor_util.is_ref(override_shape): override_shape_ = tf.get_static_value(override_shape) msg = 'Shape override must have non-negative elements.' if override_shape_ is not None: if np.any(np.array(override_shape_) < 0): raise ValueError('{} Saw: {}'.format(msg, override_shape_)) elif self.validate_args: if concretized_shape is None: concretized_shape = tf.convert_to_tensor(override_shape) assertions.append( assert_util.assert_non_negative(concretized_shape, message=msg)) # Check valid shape override_ndims_ = tensorshape_util.rank(override_shape.shape) if is_init != (override_ndims_ is None): msg = 'Shape override must be a vector.' if override_ndims_ is not None: if override_ndims_ != 1: raise ValueError(msg) elif self.validate_args: if concretized_shape is None: concretized_shape = tf.convert_to_tensor(override_shape) override_rank = tf.rank(concretized_shape) assertions.append( assert_util.assert_equal(override_rank, 1, message=msg)) static_base_rank = tensorshape_util.rank(static_base_shape) # Determine if the override shape is `[]` (static_override_dims == [0]), # in which case the base distribution may be nonscalar. static_override_dims = tensorshape_util.dims(override_shape.shape) if is_init != (static_base_rank is None or static_override_dims is None): msg = 'Base distribution is not scalar.' if static_base_rank is not None and static_override_dims is not None: if static_base_rank != 0 and static_override_dims != [0]: raise ValueError(msg) elif self.validate_args: if concretized_shape is None: concretized_shape = tf.convert_to_tensor(override_shape) override_is_empty = tf.logical_not( self._has_nonzero_rank(concretized_shape)) assertions.append( assert_util.assert_equal(tf.logical_or( base_is_scalar_fn(), override_is_empty), True, message=msg)) return assertions
def assign_and_sample_proposals(proposed_boxes, gt_boxes, gt_classes, num_samples_per_image=512, mix_gt_boxes=True, fg_fraction=0.25, fg_iou_thresh=0.5, bg_iou_thresh_hi=0.5, bg_iou_thresh_lo=0.0): """Assigns the proposals with groundtruth classes and performs subsmpling. Given `proposed_boxes`, `gt_boxes`, and `gt_classes`, the function uses the following algorithm to generate the final `num_samples_per_image` RoIs. 1. Calculates the IoU between each proposal box and each gt_boxes. 2. Assigns each proposed box with a groundtruth class and box by choosing the largest IoU overlap. 3. Samples `num_samples_per_image` boxes from all proposed boxes, and returns box_targets, class_targets, and RoIs. Args: proposed_boxes: a tensor of shape of [batch_size, N, 4]. N is the number of proposals before groundtruth assignment. The last dimension is the box coordinates w.r.t. the scaled images in [ymin, xmin, ymax, xmax] format. gt_boxes: a tensor of shape of [batch_size, MAX_NUM_INSTANCES, 4]. The coordinates of gt_boxes are in the pixel coordinates of the scaled image. This tensor might have padding of values -1 indicating the invalid box coordinates. gt_classes: a tensor with a shape of [batch_size, MAX_NUM_INSTANCES]. This tensor might have paddings with values of -1 indicating the invalid classes. num_samples_per_image: a integer represents RoI minibatch size per image. mix_gt_boxes: a bool indicating whether to mix the groundtruth boxes before sampling proposals. fg_fraction: a float represents the target fraction of RoI minibatch that is labeled foreground (i.e., class > 0). fg_iou_thresh: a float represents the IoU overlap threshold for an RoI to be considered foreground (if >= fg_iou_thresh). bg_iou_thresh_hi: a float represents the IoU overlap threshold for an RoI to be considered background (class = 0 if overlap in [LO, HI)). bg_iou_thresh_lo: a float represents the IoU overlap threshold for an RoI to be considered background (class = 0 if overlap in [LO, HI)). Returns: sampled_rois: a tensor of shape of [batch_size, K, 4], representing the coordinates of the sampled RoIs, where K is the number of the sampled RoIs, i.e. K = num_samples_per_image. sampled_gt_boxes: a tensor of shape of [batch_size, K, 4], storing the box coordinates of the matched groundtruth boxes of the samples RoIs. sampled_gt_classes: a tensor of shape of [batch_size, K], storing the classes of the matched groundtruth boxes of the sampled RoIs. sampled_gt_indices: a tensor of shape of [batch_size, K], storing the indices of the sampled groudntruth boxes in the original `gt_boxes` tensor, i.e. gt_boxes[sampled_gt_indices[:, i]] = sampled_gt_boxes[:, i]. """ with tf.name_scope('sample_proposals'): if mix_gt_boxes: boxes = tf.concat([proposed_boxes, gt_boxes], axis=1) else: boxes = proposed_boxes (matched_gt_boxes, matched_gt_classes, matched_gt_indices, matched_iou, _) = box_matching(boxes, gt_boxes, gt_classes) positive_match = tf.greater(matched_iou, fg_iou_thresh) negative_match = tf.logical_and( tf.greater_equal(matched_iou, bg_iou_thresh_lo), tf.less(matched_iou, bg_iou_thresh_hi)) ignored_match = tf.less(matched_iou, 0.0) # re-assign negatively matched boxes to the background class. matched_gt_classes = tf.where(negative_match, tf.zeros_like(matched_gt_classes), matched_gt_classes) matched_gt_indices = tf.where(negative_match, tf.zeros_like(matched_gt_indices), matched_gt_indices) sample_candidates = tf.logical_and( tf.logical_or(positive_match, negative_match), tf.logical_not(ignored_match)) sampler = ( balanced_positive_negative_sampler.BalancedPositiveNegativeSampler( positive_fraction=fg_fraction, is_static=True)) batch_size, _ = sample_candidates.get_shape().as_list() sampled_indicators = [] for i in range(batch_size): sampled_indicator = sampler.subsample(sample_candidates[i], num_samples_per_image, positive_match[i]) sampled_indicators.append(sampled_indicator) sampled_indicators = tf.stack(sampled_indicators) _, sampled_indices = tf.nn.top_k(tf.cast(sampled_indicators, dtype=tf.int32), k=num_samples_per_image, sorted=True) sampled_indices_shape = tf.shape(sampled_indices) batch_indices = ( tf.expand_dims(tf.range(sampled_indices_shape[0]), axis=-1) * tf.ones([1, sampled_indices_shape[-1]], dtype=tf.int32)) gather_nd_indices = tf.stack([batch_indices, sampled_indices], axis=-1) sampled_rois = tf.gather_nd(boxes, gather_nd_indices) sampled_gt_boxes = tf.gather_nd(matched_gt_boxes, gather_nd_indices) sampled_gt_classes = tf.gather_nd(matched_gt_classes, gather_nd_indices) sampled_gt_indices = tf.gather_nd(matched_gt_indices, gather_nd_indices) return (sampled_rois, sampled_gt_boxes, sampled_gt_classes, sampled_gt_indices)