r""" Args: :attr:`X` (:attr:`MinkowskiEngine.SparseTensor`): a sparse tensor that discretized the original input. Returns: :attr:`tensor_field` (:attr:`MinkowskiEngine.TensorField`): the resulting tensor field contains the concatenation o
(self, X)
| 618 | ) |
| 619 | |
| 620 | def cat_slice(self, X): |
| 621 | r""" |
| 622 | |
| 623 | Args: |
| 624 | :attr:`X` (:attr:`MinkowskiEngine.SparseTensor`): a sparse tensor |
| 625 | that discretized the original input. |
| 626 | |
| 627 | Returns: |
| 628 | :attr:`tensor_field` (:attr:`MinkowskiEngine.TensorField`): the |
| 629 | resulting tensor field contains the concatenation of features on the |
| 630 | original continuous coordinates that generated the input X and the |
| 631 | self. |
| 632 | |
| 633 | Example:: |
| 634 | |
| 635 | >>> # coords, feats from a data loader |
| 636 | >>> print(len(coords)) # 227742 |
| 637 | >>> sinput = ME.SparseTensor(coordinates=coords, features=feats, quantization_mode=SparseTensorQuantizationMode.UNWEIGHTED_AVERAGE) |
| 638 | >>> print(len(sinput)) # 161890 quantization results in fewer voxels |
| 639 | >>> soutput = network(sinput) |
| 640 | >>> print(len(soutput)) # 161890 Output with the same resolution |
| 641 | >>> ofield = soutput.cat_slice(sinput) |
| 642 | >>> assert soutput.F.size(1) + sinput.F.size(1) == ofield.F.size(1) # concatenation of features |
| 643 | """ |
| 644 | # Currently only supports unweighted slice. |
| 645 | assert X.quantization_mode in [ |
| 646 | SparseTensorQuantizationMode.RANDOM_SUBSAMPLE, |
| 647 | SparseTensorQuantizationMode.UNWEIGHTED_AVERAGE, |
| 648 | ], "slice only available for sparse tensors with quantization RANDOM_SUBSAMPLE or UNWEIGHTED_AVERAGE" |
| 649 | |
| 650 | from MinkowskiTensorField import TensorField |
| 651 | |
| 652 | inv_map = X.inverse_mapping(self.coordinate_map_key) |
| 653 | features = torch.cat((self.F[inv_map], X.F), dim=1) |
| 654 | if isinstance(X, TensorField): |
| 655 | return TensorField( |
| 656 | features, |
| 657 | coordinate_field_map_key=X.coordinate_field_map_key, |
| 658 | coordinate_manager=X.coordinate_manager, |
| 659 | quantization_mode=X.quantization_mode, |
| 660 | ) |
| 661 | elif isinstance(X, SparseTensor): |
| 662 | assert ( |
| 663 | X.coordinate_map_key == self.coordinate_map_key |
| 664 | ), "Slice can only be applied on the same coordinates (coordinate_map_key)" |
| 665 | return TensorField( |
| 666 | features, |
| 667 | coordinates=self.C[inv_map], |
| 668 | coordinate_manager=self.coordinate_manager, |
| 669 | quantization_mode=self.quantization_mode, |
| 670 | ) |
| 671 | else: |
| 672 | raise ValueError( |
| 673 | "Invalid input. The input must be an instance of TensorField or SparseTensor." |
| 674 | ) |
| 675 | |
| 676 | def features_at_coordinates(self, query_coordinates: torch.Tensor): |
| 677 | r"""Extract features at the specified continuous coordinate matrix. |
no test coverage detected