def __init__( self, features: torch.Tensor, coordinates: torch.Tensor = None, inverse_mapping: torch.Tensor = None, # optional coordinate related arguments tensor_stride: StrideType = 1, coordinate_map_key: CoordinateMapKey = None, coordinate_field_map_key: CoordinateMapKey = None, coordinate_manager: CoordinateManager = None, quantization_mode: SparseTensorQuantizationMode = SparseTensorQuantizationMode. UNWEIGHTED_AVERAGE, # optional manager related arguments allocator_type: GPUMemoryAllocatorType = None, minkowski_algorithm: MinkowskiAlgorithm = None, device=None, ): # To device if device is not None: features = features.to(device) coordinates = coordinates.to(device) assert quantization_mode in [ SparseTensorQuantizationMode.UNWEIGHTED_AVERAGE, SparseTensorQuantizationMode.UNWEIGHTED_SUM, SparseTensorQuantizationMode.RANDOM_SUBSAMPLE, ], "invalid quantization mode" # A tensor field is a shallow wrapper on a sparse tensor, but keeps the original data for element-wise operations Tensor.__init__( self, features, coordinates, tensor_stride, coordinate_map_key, coordinate_manager, SparseTensorQuantizationMode.NO_QUANTIZATION, allocator_type, minkowski_algorithm, device, ) # overwrite the current quantization mode self.quantization_mode = quantization_mode if inverse_mapping is not None: self.inverse_mapping = inverse_mapping self.coordinate_field_map_key = coordinate_field_map_key if coordinate_field_map_key is None: assert coordinates is not None self._CC = coordinates.float() self.coordinate_field_map_key = self._manager.insert_field( self._CC, *self.coordinate_map_key.get_key())
def __init__( self, features: torch.Tensor, coordinates: torch.Tensor = None, # optional coordinate related arguments tensor_stride: StrideType = 1, coordinate_field_map_key: CoordinateMapKey = None, coordinate_manager: CoordinateManager = None, quantization_mode: SparseTensorQuantizationMode = SparseTensorQuantizationMode. UNWEIGHTED_AVERAGE, # optional manager related arguments allocator_type: GPUMemoryAllocatorType = None, minkowski_algorithm: MinkowskiAlgorithm = None, requires_grad=None, device=None, ): r""" Args: :attr:`features` (:attr:`torch.FloatTensor`, :attr:`torch.DoubleTensor`, :attr:`torch.cuda.FloatTensor`, or :attr:`torch.cuda.DoubleTensor`): The features of a sparse tensor. :attr:`coordinates` (:attr:`torch.IntTensor`): The coordinates associated to the features. If not provided, :attr:`coordinate_map_key` must be provided. :attr:`tensor_stride` (:attr:`int`, :attr:`list`, :attr:`numpy.array`, or :attr:`tensor.Tensor`): The tensor stride of the current sparse tensor. By default, it is 1. :attr:`coordinate_field_map_key` (:attr:`MinkowskiEngine.CoordinateMapKey`): When the coordinates are already cached in the MinkowskiEngine, we could reuse the same coordinate map by simply providing the coordinate map key. In most case, this process is done automatically. When you provide a `coordinate_field_map_key`, `coordinates` will be be ignored. :attr:`coordinate_manager` (:attr:`MinkowskiEngine.CoordinateManager`): The MinkowskiEngine manages all coordinate maps using the `_C.CoordinateMapManager`. If not provided, the MinkowskiEngine will create a new computation graph. In most cases, this process is handled automatically and you do not need to use this. :attr:`quantization_mode` (:attr:`MinkowskiEngine.SparseTensorQuantizationMode`): Defines how continuous coordinates will be quantized to define a sparse tensor. Please refer to :attr:`SparseTensorQuantizationMode` for details. :attr:`allocator_type` (:attr:`MinkowskiEngine.GPUMemoryAllocatorType`): Defines the GPU memory allocator type. By default, it uses the c10 allocator. :attr:`minkowski_algorithm` (:attr:`MinkowskiEngine.MinkowskiAlgorithm`): Controls the mode the minkowski engine runs, Use :attr:`MinkowskiAlgorithm.MEMORY_EFFICIENT` if you want to reduce the memory footprint. Or use :attr:`MinkowskiAlgorithm.SPEED_OPTIMIZED` if you want to make it run fasterat the cost of more memory. :attr:`requires_grad` (:attr:`bool`): Set the requires_grad flag. :attr:`device` (:attr:`torch.device`): Set the device the sparse tensor is defined. """ # Type checks assert isinstance(features, torch.Tensor), "Features must be a torch.Tensor" assert ( features.ndim == 2 ), f"The feature should be a matrix, The input feature is an order-{features.ndim} tensor." assert isinstance(quantization_mode, SparseTensorQuantizationMode) assert quantization_mode in [ SparseTensorQuantizationMode.UNWEIGHTED_AVERAGE, SparseTensorQuantizationMode.UNWEIGHTED_SUM, SparseTensorQuantizationMode.RANDOM_SUBSAMPLE, SparseTensorQuantizationMode.MAX_POOL, ], "invalid quantization mode" self.quantization_mode = quantization_mode if coordinates is not None: assert isinstance(coordinates, torch.Tensor) if coordinate_field_map_key is not None: assert isinstance(coordinate_field_map_key, CoordinateMapKey) if coordinate_manager is not None: assert isinstance(coordinate_manager, CoordinateManager) if coordinates is None and (coordinate_field_map_key is None or coordinate_manager is None): raise ValueError( "Either coordinates or (coordinate_field_map_key, coordinate_manager) pair must be provided." ) Tensor.__init__(self) # To device if device is not None: features = features.to(device) if coordinates is not None: # assertion check for the map key done later coordinates = coordinates.to(device) self._D = (coordinates.size(1) - 1 if coordinates is not None else coordinate_manager.D) ########################## # Setup CoordsManager ########################## if coordinate_manager is None: # If set to share the coords man, use the global coords man if (sparse_tensor_operation_mode() == SparseTensorOperationMode.SHARE_COORDINATE_MANAGER): coordinate_manager = global_coordinate_manager() if coordinate_manager is None: coordinate_manager = CoordinateManager( D=self._D, coordinate_map_type=CoordinateMapType.CUDA if coordinates.is_cuda else CoordinateMapType.CPU, allocator_type=allocator_type, minkowski_algorithm=minkowski_algorithm, ) set_global_coordinate_manager(coordinate_manager) else: coordinate_manager = CoordinateManager( D=coordinates.size(1) - 1, coordinate_map_type=CoordinateMapType.CUDA if coordinates.is_cuda else CoordinateMapType.CPU, allocator_type=allocator_type, minkowski_algorithm=minkowski_algorithm, ) self._manager = coordinate_manager ########################## # Initialize coords ########################## # Coordinate Management if coordinates is not None: assert ( features.shape[0] == coordinates.shape[0] ), "The number of rows in features and coordinates must match." assert (features.is_cuda == coordinates.is_cuda ), "Features and coordinates must have the same backend." coordinate_field_map_key = CoordinateMapKey( convert_to_int_list(tensor_stride, self._D), "") coordinate_field_map_key = self._manager.insert_field( coordinates.float(), convert_to_int_list(tensor_stride, self._D), "") else: assert (coordinate_field_map_key.is_key_set() ), "The coordinate field map key must be valid." if requires_grad is not None: features.requires_grad_(requires_grad) self._F = features self._C = coordinates self.coordinate_field_map_key = coordinate_field_map_key self._batch_rows = None self._inverse_mapping = {}