def __call__(self, features, point_cloud, return_sorted=False, return_padded=False): """ Computes the 1x1 convolution on a point cloud. Note: In the following, `A1` to `An` are optional batch dimensions. `C_in` is the number of input features. `C_out` is the number of output features. Args: features: A `float` `Tensor` of shape `[N_in, C_in]` or `[A1, ..., An, V, C_in]`. point_cloud: A 'PointCloud' instance, on which the features are defined. return_sorted: A `boolean`, if `True` the output tensor is sorted according to the batch_ids. (optional) return_padded: A `bool`, if 'True' the output tensor is sorted and zero padded. (optional) Returns: A `float` `Tensor` of shape `[N_out, C_out]`, if `return_padded` is `False` or `[A1, ..., An, V_out, C_out]`, if `return_padded` is `True`. """ features = tf.cast(tf.convert_to_tensor(value=features), dtype=tf.float32) features = _flatten_features(features, point_cloud) features = tf.matmul(features, self._weights_tf) + self._bias_tf return _format_output(features, point_cloud, return_sorted, return_padded)
def __call__(self, features, point_cloud: PointCloud, return_padded=False, name=None): """ Performs a global average pooling on a point cloud Note: In the following, `A1` to `An` are optional batch dimensions. Args: features: A tensor of shape `[N, C]` or `[A1, ..., An, V, C]`. point_cloud: A `PointCloud` instance. return_padded: A `bool`, if `True` reshapes the output to match the batch shape of `point_cloud`. Returns: A tensor of same type as `features` and of shape `[B, C]`, if not `return_padded` or `[A1 ,..., An, C]`, if `return_padded` """ features = tf.convert_to_tensor(value=features) features = _flatten_features(features, point_cloud) features = tf.math.unsorted_segment_mean( features, segment_ids=point_cloud._batch_ids, num_segments=point_cloud._batch_size) if return_padded: shape = tf.concat((point_cloud._batch_shape, [-1]), axis=0) features = tf.reshape(features, shape) return features
def __call__(self, pool_op, features, point_cloud_in: PointCloud, point_cloud_out: PointCloud, pooling_radius, return_sorted=False, return_padded=False, name=None, default_name="custom pooling"): """ Computes a local pooling between two point clouds specified by `pool_op`. Note: In the following, `A1` to `An` are optional batch dimensions. Args: pool_op: A function of type `tf.math.unsorted_segmented_*`. features: A `float` `Tensor` of shape `[N_in, C]` or `[A1, ..., An, V_in, C]`. point_cloud_in: A `PointCloud` instance on which the features are defined. point_cloud_out: A `PointCloud` instance, on which the output features are defined. pooling_radius: A `float` or a `float` `Tensor` of shape `[D]`. return_sorted: A `bool`, if 'True' the output tensor is sorted according to the sorted batch ids of `point_cloud_out`. return_padded: A `bool`, if 'True' the output tensor is sorted and zero padded. Returns: A `float` `Tensor` of shape `[N_out, C]`, if `return_padded` is `False` or `[A1, ..., An, V_out, C]`, if `return_padded` is `True`. """ features = tf.convert_to_tensor(value=features) features = _flatten_features(features, point_cloud_in) pooling_radius = tf.convert_to_tensor(value=pooling_radius, dtype=tf.float32) if pooling_radius.shape[0] == 1: pooling_radius = tf.repeat(pooling_radius, point_cloud_in._dimension) # Compute the grid. grid_in = Grid(point_cloud_in, pooling_radius) # Compute the neighborhood keys. neigh = Neighborhood(grid_in, pooling_radius, point_cloud_out) features_on_neighbors = tf.gather(features, neigh._original_neigh_ids[:, 0]) # Pool the features in the neighborhoods features_out = pool_op(data=features_on_neighbors, segment_ids=neigh._original_neigh_ids[:, 1], num_segments=tf.shape( point_cloud_out._points)[0]) return _format_output(features_out, point_cloud_out, return_sorted, return_padded)
def __call__(self, features, point_cloud_in: PointCloud, point_cloud_out: PointCloud, radius, neighborhood=None, bandwidth=0.2, return_sorted=False, return_padded=False, name=None): """ Computes the Monte-Carlo Convolution between two point clouds. Note: In the following, `A1` to `An` are optional batch dimensions. `C_in` is the number of input features. `C_out` is the number of output features. Args: features: A `float` `Tensor` of shape `[N_in, C_in]` or `[A1, ..., An,V, C_in]`. point_cloud_in: A 'PointCloud' instance, on which the features are defined. point_cloud_out: A `PointCloud` instance, on which the output features are defined. radius: A `float`, the convolution radius. neighborhood: A `Neighborhood` instance, defining the neighborhood with centers from `point_cloud_out` and neighbors in `point_cloud_in`. If `None` it is computed internally. (optional) bandwidth: A `float`, the bandwidth used in the kernel density estimation on the input point cloud. (optional) return_sorted: A `boolean`, if `True` the output tensor is sorted according to the batch_ids. (optional) return_padded: A `bool`, if 'True' the output tensor is sorted and zero padded. (optional) Returns: A `float` `Tensor` of shape `[N_out, C_out]`, if `return_padded` is `False` or `[A1, ..., An, V_out, C_out]`, if `return_padded` is `True`. """ features = tf.cast(tf.convert_to_tensor(value=features), dtype=tf.float32) tf.assert_equal(tf.shape(features)[-1], self._num_features_in) features = _flatten_features(features, point_cloud_in) #Create the radii tensor. radius = tf.reshape( tf.convert_to_tensor(value=radius, dtype=tf.float32), [1, 1]) radii_tensor = tf.repeat(radius, self._num_dims) #Create the bandwidth tensor. bwTensor = tf.repeat(bandwidth, self._num_dims) if neighborhood is None: #Compute the grid grid = Grid(point_cloud_in, radii_tensor) #Compute the neighborhoods neigh = Neighborhood(grid, radii_tensor, point_cloud_out) else: neigh = neighborhood pdf = neigh.get_pdf(bandwidth=bwTensor, mode=KDEMode.constant) #Compute kernel inputs. neigh_point_coords = tf.gather(point_cloud_in._points, neigh._original_neigh_ids[:, 0]) center_point_coords = tf.gather(point_cloud_out._points, neigh._original_neigh_ids[:, 1]) points_diff = (neigh_point_coords - center_point_coords) / \ tf.reshape(radii_tensor, [1, self._num_dims]) #Compute Monte-Carlo convolution convolution_result = self._monte_carlo_conv(points_diff, neigh, pdf, features, self._non_linearity_type) return _format_output(convolution_result, point_cloud_out, return_sorted, return_padded)
def __call__(self, features, point_cloud_in: PointCloud, point_cloud_out: PointCloud, conv_radius, neighborhood=None, kernel_influence_dist=None, return_sorted=False, return_padded=False, name=None): """ Computes the Kernel Point Convolution between two point clouds. Note: In the following, `A1` to `An` are optional batch dimensions. `C_in` is the number of input features. `C_out` is the number of output features. Args: features: A `float` `Tensor` of shape `[N1, C_in]` or `[A1, ..., An,V, C_in]`. point_cloud_in: A 'PointCloud' instance, on which the features are defined. point_cloud_out: A `PointCloud` instance, on which the output features are defined. conv_radius: A `float`, the convolution radius. neighborhood: A `Neighborhood` instance, defining the neighborhood with centers from `point_cloud_out` and neighbors in `point_cloud_in`. If `None` it is computed internally. (optional) kernel_influence_dist = A `float`, the influence distance of the kernel points. If `None` uses `conv_radius / 2.5`, as suggested in Section 3.3 of the paper. (optional) return_sorted: A `boolean`, if `True` the output tensor is sorted according to the batch_ids. (optional) return_padded: A `bool`, if 'True' the output tensor is sorted and zero padded. (optional) Returns: A `float` `Tensor` of shape `[N2, C_out]`, if `return_padded` is `False` or `[A1, ..., An, V_out, C_out]`, if `return_padded` is `True`. """ features = tf.cast(tf.convert_to_tensor(value=features), dtype=tf.float32) features = _flatten_features(features, point_cloud_in) self._num_output_points = point_cloud_out._points.shape[0] if kernel_influence_dist is None: # normalized self._sigma = tf.constant(1.0) else: self._sigma = tf.convert_to_tensor( value=kernel_influence_dist / conv_radius, dtype=tf.float32) #Create the radii tensor. conv_radius = tf.reshape(tf.convert_to_tensor(value=conv_radius, dtype=tf.float32), [1, 1]) radii_tensor = tf.repeat(conv_radius, self._num_dims) if neighborhood is None: #Compute the grid grid = Grid(point_cloud_in, radii_tensor) #Compute the neighborhoods neigh = Neighborhood(grid, radii_tensor, point_cloud_out) else: neigh = neighborhood #Compute kernel inputs. neigh_point_coords = tf.gather( point_cloud_in._points, neigh._original_neigh_ids[:, 0]) center_point_coords = tf.gather( point_cloud_out._points, neigh._original_neigh_ids[:, 1]) points_diff = (neigh_point_coords - center_point_coords) / \ tf.reshape(radii_tensor, [1, self._num_dims]) #Compute Monte-Carlo convolution convolution_result = self._kp_conv(points_diff, neigh, features) return _format_output(convolution_result, point_cloud_out, return_sorted, return_padded)