├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── MANIFEST.in ├── Makefile ├── MinkowskiEngine ├── MinkowskiBroadcast.py ├── MinkowskiChannelwiseConvolution.py ├── MinkowskiCommon.py ├── MinkowskiConvolution.py ├── MinkowskiCoordinateManager.py ├── MinkowskiFunctional.py ├── MinkowskiInterpolation.py ├── MinkowskiKernelGenerator.py ├── MinkowskiNetwork.py ├── MinkowskiNonlinearity.py ├── MinkowskiNormalization.py ├── MinkowskiOps.py ├── MinkowskiPooling.py ├── MinkowskiPruning.py ├── MinkowskiSparseTensor.py ├── MinkowskiTensor.py ├── MinkowskiTensorField.py ├── MinkowskiUnion.py ├── __init__.py ├── diagnostics.py ├── modules │ ├── __init__.py │ ├── resnet_block.py │ └── senet_block.py ├── sparse_matrix_functions.py └── utils │ ├── __init__.py │ ├── collation.py │ ├── coords.py │ ├── gradcheck.py │ ├── init.py │ ├── quantization.py │ └── summary.py ├── README.md ├── docker └── Dockerfile ├── docs ├── .gitignore ├── Makefile ├── README.md ├── _templates │ └── layout.html ├── benchmark.md ├── broadcast.rst ├── common.rst ├── conf.py ├── convolution.rst ├── coords.rst ├── demo │ ├── interop.rst │ ├── modelnet40_classification.rst │ ├── multigpu.md │ ├── pointnet.md │ ├── segmentation.rst │ ├── sparse_tensor_reconstruction.rst │ └── training.rst ├── guides.md ├── images │ ├── classification_3d_net.png │ ├── conv_dense.gif │ ├── conv_generalized.gif │ ├── conv_sparse.gif │ ├── conv_sparse_conv.gif │ ├── demo_reconstruction.png │ ├── detection_3d_net.png │ ├── generative_3d_net.png │ ├── generative_3d_results.gif │ ├── kernel_map.gif │ ├── segmentation.png │ └── segmentation_3d_net.png ├── index.rst ├── interp.rst ├── issues.md ├── migration_05.md ├── misc.rst ├── nonlinearity.rst ├── normalization.rst ├── pooling.rst ├── pruning.rst ├── quick_start.md ├── sparse_tensor.rst ├── sparse_tensor_network.rst ├── terminology.rst ├── tutorial │ ├── convolution_basic.rst │ └── sparse_tensor_basic.rst ├── union.rst └── utils.rst ├── examples ├── README.md ├── __init__.py ├── classification_modelnet40.py ├── common.py ├── completion.py ├── convolution.py ├── download_modelnet40.sh ├── example.py ├── indoor.py ├── minkunet.py ├── multigpu.py ├── multigpu_ddp.py ├── multigpu_lightning.py ├── pointnet.py ├── reconstruction.py ├── resnet.py ├── sparse_tensor_basic.py ├── stack_unet.py ├── training.py ├── unet.py └── vae.py ├── pybind ├── extern.hpp ├── minkowski.cpp └── minkowski.cu ├── requirements.txt ├── setup.py ├── src ├── 3rdparty │ ├── concurrent_unordered_map.cuh │ ├── cudf │ │ ├── detail │ │ │ ├── nvtx │ │ │ │ ├── nvtx3.hpp │ │ │ │ └── ranges.hpp │ │ │ └── utilities │ │ │ │ ├── device_atomics.cuh │ │ │ │ ├── device_operators.cuh │ │ │ │ └── hash_functions.cuh │ │ ├── types.h │ │ ├── types.hpp │ │ └── utilities │ │ │ ├── error.hpp │ │ │ └── legacy │ │ │ └── wrapper_types.hpp │ ├── hash │ │ ├── hash_allocator.cuh │ │ ├── helper_functions.cuh │ │ └── managed.cuh │ └── robin_hood.h ├── allocators.cuh ├── broadcast_cpu.cpp ├── broadcast_gpu.cu ├── broadcast_kernel.cu ├── broadcast_kernel.cuh ├── broadcast_kernel.hpp ├── common.hpp ├── convolution_cpu.cpp ├── convolution_gpu.cu ├── convolution_kernel.cu ├── convolution_kernel.cuh ├── convolution_kernel.hpp ├── convolution_transpose_cpu.cpp ├── convolution_transpose_gpu.cu ├── coordinate.hpp ├── coordinate_map.hpp ├── coordinate_map_cpu.hpp ├── coordinate_map_functors.cuh ├── coordinate_map_gpu.cu ├── coordinate_map_gpu.cuh ├── coordinate_map_key.hpp ├── coordinate_map_manager.cpp ├── coordinate_map_manager.cu ├── coordinate_map_manager.hpp ├── direct_max_pool.cpp ├── dispatcher.hpp ├── errors.hpp ├── global_pooling_cpu.cpp ├── global_pooling_gpu.cu ├── gpu.cu ├── gpu.cuh ├── interpolation_cpu.cpp ├── interpolation_gpu.cu ├── interpolation_kernel.hpp ├── kernel_map.cuh ├── kernel_map.hpp ├── kernel_region.hpp ├── local_pooling_cpu.cpp ├── local_pooling_gpu.cu ├── local_pooling_transpose_cpu.cpp ├── local_pooling_transpose_gpu.cu ├── math_functions.cuh ├── math_functions.hpp ├── math_functions_cpu.cpp ├── math_functions_gpu.cu ├── mkl_alternate.hpp ├── pooling_avg_kernel.cu ├── pooling_avg_kernel.cuh ├── pooling_avg_kernel.hpp ├── pooling_max_kernel.cu ├── pooling_max_kernel.cuh ├── pooling_max_kernel.hpp ├── primitives │ └── small_vector.hpp ├── pruning.hpp ├── pruning_cpu.cpp ├── pruning_gpu.cu ├── quantization.cpp ├── sharedmem.cuh ├── spmm.cu ├── spmm.cuh ├── storage.cuh ├── types.hpp └── utils.hpp └── tests ├── cpp ├── README.md ├── __init__.py ├── convolution_cpu.py ├── convolution_cpu_test.py ├── convolution_gpu_test.py ├── convolution_test.cpp ├── convolution_test.cu ├── coordinate_map_cpu_test.cpp ├── coordinate_map_cpu_test.py ├── coordinate_map_gpu_test.cu ├── coordinate_map_gpu_test.py ├── coordinate_map_key_test.cpp ├── coordinate_map_key_test.py ├── coordinate_map_manager_cpu_test.cpp ├── coordinate_map_manager_cpu_test.py ├── coordinate_map_manager_gpu_test.cu ├── coordinate_map_manager_gpu_test.py ├── coordinate_test.cpp ├── coordinate_test.py ├── kernel_region_cpu_test.cpp ├── kernel_region_cpu_test.py ├── kernel_region_gpu_test.cu ├── kernel_region_gpu_test.py ├── setup.py ├── test_all.sh ├── type_test.cpp ├── type_test.py └── utils.py ├── python ├── __init__.py ├── broadcast.py ├── chwise_conv.py ├── common.py ├── conv_on_coords.py ├── convolution.py ├── coordinate_manager.py ├── dense.py ├── direct_pool.py ├── global.py ├── interpolation.py ├── kernel_map.py ├── network_speed.py ├── norm.py ├── pool.py ├── pruning.py ├── quantization.py ├── sparse_tensor.py ├── spmm.py ├── stack.py ├── strided_conv.py ├── summary.py ├── tensor_field.py ├── union.py └── utility_functions.py └── run_test.py /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | - Please complete all sections of this template if applicable. For installation, you must report the environment. Otherwise, your issue will be closed automatically. 14 | 15 | 16 | 17 | ************************************************************************************ 18 | **To Reproduce** 19 | Steps to reproduce the behavior. If the code is not attached and cannot be reproduced easily, the bug report will be closed without any comments. 20 | 21 | - a minimally reproducible code. 22 | 23 | 24 | 25 | ************************************************************************************ 26 | **Expected behavior** 27 | A clear and concise description of what you expected to happen. 28 | 29 | 30 | 31 | ************************************************************************************ 32 | **Desktop (please complete the following information):** 33 | 34 | - OS: [e.g. Ubuntu 18.04] 35 | - Python version: [e.g. 3.8.5] 36 | - Pytorch version: [e.g. 1.7.1] 37 | - CUDA version: [e.g. 11.1] 38 | - NVIDIA Driver version: [e.g. 450.11] 39 | - Minkowski Engine version [e.g. 0.5.0] 40 | - Output of the following command. (If you installed the latest MinkowskiEngine, paste the output of `python -c "import MinkowskiEngine as ME; ME.print_diagnostics()"`. Otherwise, paste the output of the following command.) 41 | 42 | ``` 43 | wget -q https://raw.githubusercontent.com/NVIDIA/MinkowskiEngine/master/MinkowskiEngine/diagnostics.py ; python diagnostics.py 44 | ``` 45 | 46 | 47 | ************************************************************************************ 48 | **Additional context** 49 | Add any other context about the problem here. 50 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.so 2 | *.[o,d,a] 3 | *.swo 4 | *.swp 5 | *.swn 6 | *.pyc 7 | 8 | build/ 9 | objs/ 10 | dist/ 11 | MinkowskiEngine.egg-info/ 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 NVIDIA CORPORATION. 4 | Copyright (c) 2018-2020 Chris Choy (chrischoy@ai.stanford.edu) 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | this software and associated documentation files (the "Software"), to deal in 8 | the Software without restriction, including without limitation the rights to 9 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 10 | of the Software, and to permit persons to whom the Software is furnished to do 11 | so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural 25 | Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part 26 | of the code. 27 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include Makefile 2 | recursive-include src *.hpp *.cpp *.cu *.cuh *.h 3 | recursive-include pybind *.hpp *.cpp 4 | -------------------------------------------------------------------------------- /MinkowskiEngine/MinkowskiCommon.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020 NVIDIA CORPORATION. 2 | # Copyright (c) 2018-2020 Chris Choy (chrischoy@ai.stanford.edu). 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | # this software and associated documentation files (the "Software"), to deal in 6 | # the Software without restriction, including without limitation the rights to 7 | # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 8 | # of the Software, and to permit persons to whom the Software is furnished to do 9 | # so, subject to the following conditions: 10 | # 11 | # The above copyright notice and this permission notice shall be included in all 12 | # copies or substantial portions of the Software. 13 | # 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | # SOFTWARE. 21 | # 22 | # Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural 23 | # Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part 24 | # of the code. 25 | from collections.abc import Sequence 26 | import numpy as np 27 | from typing import Union 28 | 29 | import torch 30 | 31 | from torch.nn import Module 32 | 33 | import MinkowskiEngineBackend._C as MEB 34 | 35 | 36 | StrideType = Union[int, Sequence, np.ndarray, torch.IntTensor] 37 | 38 | 39 | def convert_to_int_list( 40 | arg: Union[int, Sequence, np.ndarray, torch.Tensor], dimension: int 41 | ): 42 | if isinstance(arg, list): 43 | assert len(arg) == dimension 44 | return arg 45 | 46 | if isinstance(arg, (Sequence, np.ndarray, torch.Tensor)): 47 | tmp = [i for i in arg] 48 | assert len(tmp) == dimension 49 | elif np.isscalar(arg): # Assume that it is a scalar 50 | tmp = [int(arg) for i in range(dimension)] 51 | else: 52 | raise ValueError("Input must be a scalar or a sequence") 53 | 54 | return tmp 55 | 56 | 57 | def convert_to_int_tensor( 58 | arg: Union[int, Sequence, np.ndarray, torch.IntTensor], dimension: int 59 | ): 60 | if isinstance(arg, torch.IntTensor): 61 | assert arg.numel() == dimension 62 | return arg 63 | 64 | if isinstance(arg, (Sequence, np.ndarray)): 65 | tmp = torch.IntTensor([i for i in arg]) 66 | assert tmp.numel() == dimension 67 | elif np.isscalar(arg): # Assume that it is a scalar 68 | tmp = torch.IntTensor([int(arg) for i in range(dimension)]) 69 | else: 70 | raise ValueError("Input must be a scalar or a sequence") 71 | 72 | return tmp 73 | 74 | 75 | def prep_args( 76 | tensor_stride: Union[int, Sequence, np.ndarray, torch.IntTensor], 77 | stride: Union[int, Sequence, np.ndarray, torch.IntTensor], 78 | kernel_size: Union[int, Sequence, np.ndarray, torch.IntTensor], 79 | dilation: Union[int, Sequence, np.ndarray, torch.IntTensor], 80 | region_type: Union[int, MEB.RegionType], 81 | D=-1, 82 | ): 83 | assert torch.prod( 84 | kernel_size > 0 85 | ), f"kernel_size must be a positive integer, provided {kernel_size}" 86 | assert D > 0, f"dimension must be a positive integer, {D}" 87 | tensor_stride = convert_to_int_tensor(tensor_stride, D) 88 | stride = convert_to_int_tensor(stride, D) 89 | kernel_size = convert_to_int_tensor(kernel_size, D) 90 | dilation = convert_to_int_tensor(dilation, D) 91 | region_type = int(region_type) 92 | return ( 93 | tensor_stride, 94 | stride, 95 | kernel_size, 96 | dilation, 97 | region_type, 98 | ) 99 | 100 | 101 | def get_postfix(tensor: torch.Tensor): 102 | postfix = "GPU" if tensor.is_cuda else "CPU" 103 | return postfix 104 | 105 | 106 | class MinkowskiModuleBase(Module): 107 | pass 108 | 109 | 110 | def get_minkowski_function(name, variable): 111 | fn_name = name + get_postfix(variable) 112 | if hasattr(MEB, fn_name): 113 | return getattr(MEB, fn_name) 114 | else: 115 | if variable.is_cuda: 116 | raise ValueError( 117 | f"Function {fn_name} not available. Please compile MinkowskiEngine with `torch.cuda.is_available()` is `True`." 118 | ) 119 | else: 120 | raise ValueError(f"Function {fn_name} not available.") 121 | -------------------------------------------------------------------------------- /MinkowskiEngine/MinkowskiNetwork.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Chris Choy (chrischoy@ai.stanford.edu). 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | # this software and associated documentation files (the "Software"), to deal in 5 | # the Software without restriction, including without limitation the rights to 6 | # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | # of the Software, and to permit persons to whom the Software is furnished to do 8 | # so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in all 11 | # copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | # 21 | # Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural 22 | # Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part 23 | # of the code. 24 | from abc import ABC, abstractmethod 25 | 26 | import torch.nn as nn 27 | 28 | from MinkowskiSparseTensor import SparseTensor 29 | 30 | 31 | class MinkowskiNetwork(nn.Module, ABC): 32 | """ 33 | MinkowskiNetwork: an abstract class for sparse convnets. 34 | 35 | Note: All modules that use the same coordinates must use the same net_metadata 36 | """ 37 | 38 | def __init__(self, D): 39 | super(MinkowskiNetwork, self).__init__() 40 | self.D = D 41 | 42 | @abstractmethod 43 | def forward(self, x): 44 | pass 45 | 46 | def init(self, x): 47 | """ 48 | Initialize coordinates if it does not exist 49 | """ 50 | nrows = self.get_nrows(1) 51 | if nrows < 0: 52 | if isinstance(x, SparseTensor): 53 | self.initialize_coords(x.coords_man) 54 | else: 55 | raise ValueError('Initialize input coordinates') 56 | elif nrows != x.F.size(0): 57 | raise ValueError('Input size does not match the coordinate size') 58 | -------------------------------------------------------------------------------- /MinkowskiEngine/diagnostics.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | import platform 4 | import subprocess 5 | 6 | 7 | def parse_nvidia_smi(): 8 | sp = subprocess.Popen( 9 | ["nvidia-smi", "-q"], stdout=subprocess.PIPE, stderr=subprocess.PIPE 10 | ) 11 | out_dict = dict() 12 | for item in sp.communicate()[0].decode("utf-8").split("\n"): 13 | if item.count(":") == 1: 14 | key, val = [i.strip() for i in item.split(":")] 15 | out_dict[key] = val 16 | return out_dict 17 | 18 | 19 | def print_diagnostics(): 20 | print("==========System==========") 21 | print(platform.platform()) 22 | os.system("cat /etc/lsb-release") 23 | print(sys.version) 24 | 25 | print("==========Pytorch==========") 26 | try: 27 | import torch 28 | 29 | print(torch.__version__) 30 | print(f"torch.cuda.is_available(): {torch.cuda.is_available()}") 31 | except ImportError: 32 | print("torch not installed") 33 | 34 | print("==========NVIDIA-SMI==========") 35 | os.system("which nvidia-smi") 36 | for k, v in parse_nvidia_smi().items(): 37 | if "version" in k.lower(): 38 | print(k, v) 39 | 40 | print("==========NVCC==========") 41 | os.system("which nvcc") 42 | os.system("nvcc --version") 43 | 44 | print("==========CC==========") 45 | CC = "c++" 46 | if "CC" in os.environ or "CXX" in os.environ: 47 | # distutils only checks CC not CXX 48 | if "CXX" in os.environ: 49 | os.environ["CC"] = os.environ["CXX"] 50 | CC = os.environ["CXX"] 51 | else: 52 | CC = os.environ["CC"] 53 | print(f"CC={CC}") 54 | os.system(f"which {CC}") 55 | os.system(f"{CC} --version") 56 | 57 | print("==========MinkowskiEngine==========") 58 | try: 59 | import MinkowskiEngine as ME 60 | 61 | print(ME.__version__) 62 | print(f"MinkowskiEngine compiled with CUDA Support: {ME.is_cuda_available()}") 63 | print(f"NVCC version MinkowskiEngine is compiled: {ME.cuda_version()}") 64 | print(f"CUDART version MinkowskiEngine is compiled: {ME.cudart_version()}") 65 | except ImportError: 66 | print("MinkowskiEngine not installed") 67 | 68 | 69 | if __name__ == "__main__": 70 | print_diagnostics() 71 | -------------------------------------------------------------------------------- /MinkowskiEngine/modules/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Chris Choy (chrischoy@ai.stanford.edu). 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | # this software and associated documentation files (the "Software"), to deal in 5 | # the Software without restriction, including without limitation the rights to 6 | # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | # of the Software, and to permit persons to whom the Software is furnished to do 8 | # so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in all 11 | # copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | # 21 | # Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural 22 | # Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part 23 | # of the code. 24 | -------------------------------------------------------------------------------- /MinkowskiEngine/modules/resnet_block.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Chris Choy (chrischoy@ai.stanford.edu). 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | # this software and associated documentation files (the "Software"), to deal in 5 | # the Software without restriction, including without limitation the rights to 6 | # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | # of the Software, and to permit persons to whom the Software is furnished to do 8 | # so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in all 11 | # copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | # 21 | # Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural 22 | # Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part 23 | # of the code. 24 | import torch.nn as nn 25 | 26 | import MinkowskiEngine as ME 27 | 28 | 29 | class BasicBlock(nn.Module): 30 | expansion = 1 31 | 32 | def __init__(self, 33 | inplanes, 34 | planes, 35 | stride=1, 36 | dilation=1, 37 | downsample=None, 38 | bn_momentum=0.1, 39 | dimension=-1): 40 | super(BasicBlock, self).__init__() 41 | assert dimension > 0 42 | 43 | self.conv1 = ME.MinkowskiConvolution( 44 | inplanes, planes, kernel_size=3, stride=stride, dilation=dilation, dimension=dimension) 45 | self.norm1 = ME.MinkowskiBatchNorm(planes, momentum=bn_momentum) 46 | self.conv2 = ME.MinkowskiConvolution( 47 | planes, planes, kernel_size=3, stride=1, dilation=dilation, dimension=dimension) 48 | self.norm2 = ME.MinkowskiBatchNorm(planes, momentum=bn_momentum) 49 | self.relu = ME.MinkowskiReLU(inplace=True) 50 | self.downsample = downsample 51 | 52 | def forward(self, x): 53 | residual = x 54 | 55 | out = self.conv1(x) 56 | out = self.norm1(out) 57 | out = self.relu(out) 58 | 59 | out = self.conv2(out) 60 | out = self.norm2(out) 61 | 62 | if self.downsample is not None: 63 | residual = self.downsample(x) 64 | 65 | out += residual 66 | out = self.relu(out) 67 | 68 | return out 69 | 70 | 71 | class Bottleneck(nn.Module): 72 | expansion = 4 73 | 74 | def __init__(self, 75 | inplanes, 76 | planes, 77 | stride=1, 78 | dilation=1, 79 | downsample=None, 80 | bn_momentum=0.1, 81 | dimension=-1): 82 | super(Bottleneck, self).__init__() 83 | assert dimension > 0 84 | 85 | self.conv1 = ME.MinkowskiConvolution( 86 | inplanes, planes, kernel_size=1, dimension=dimension) 87 | self.norm1 = ME.MinkowskiBatchNorm(planes, momentum=bn_momentum) 88 | 89 | self.conv2 = ME.MinkowskiConvolution( 90 | planes, planes, kernel_size=3, stride=stride, dilation=dilation, dimension=dimension) 91 | self.norm2 = ME.MinkowskiBatchNorm(planes, momentum=bn_momentum) 92 | 93 | self.conv3 = ME.MinkowskiConvolution( 94 | planes, planes * self.expansion, kernel_size=1, dimension=dimension) 95 | self.norm3 = ME.MinkowskiBatchNorm( 96 | planes * self.expansion, momentum=bn_momentum) 97 | 98 | self.relu = ME.MinkowskiReLU(inplace=True) 99 | self.downsample = downsample 100 | 101 | def forward(self, x): 102 | residual = x 103 | 104 | out = self.conv1(x) 105 | out = self.norm1(out) 106 | out = self.relu(out) 107 | 108 | out = self.conv2(out) 109 | out = self.norm2(out) 110 | out = self.relu(out) 111 | 112 | out = self.conv3(out) 113 | out = self.norm3(out) 114 | 115 | if self.downsample is not None: 116 | residual = self.downsample(x) 117 | 118 | out += residual 119 | out = self.relu(out) 120 | 121 | return out 122 | -------------------------------------------------------------------------------- /MinkowskiEngine/modules/senet_block.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Chris Choy (chrischoy@ai.stanford.edu). 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | # this software and associated documentation files (the "Software"), to deal in 5 | # the Software without restriction, including without limitation the rights to 6 | # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | # of the Software, and to permit persons to whom the Software is furnished to do 8 | # so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in all 11 | # copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | # 21 | # Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural 22 | # Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part 23 | # of the code. 24 | import torch.nn as nn 25 | 26 | import MinkowskiEngine as ME 27 | 28 | from MinkowskiEngine.modules.resnet_block import BasicBlock, Bottleneck 29 | 30 | 31 | class SELayer(nn.Module): 32 | 33 | def __init__(self, channel, reduction=16, D=-1): 34 | # Global coords does not require coords_key 35 | super(SELayer, self).__init__() 36 | self.fc = nn.Sequential( 37 | ME.MinkowskiLinear(channel, channel // reduction), 38 | ME.MinkowskiReLU(inplace=True), 39 | ME.MinkowskiLinear(channel // reduction, channel), 40 | ME.MinkowskiSigmoid()) 41 | self.pooling = ME.MinkowskiGlobalPooling() 42 | self.broadcast_mul = ME.MinkowskiBroadcastMultiplication() 43 | 44 | def forward(self, x): 45 | y = self.pooling(x) 46 | y = self.fc(y) 47 | return self.broadcast_mul(x, y) 48 | 49 | 50 | class SEBasicBlock(BasicBlock): 51 | 52 | def __init__(self, 53 | inplanes, 54 | planes, 55 | stride=1, 56 | dilation=1, 57 | downsample=None, 58 | reduction=16, 59 | D=-1): 60 | super(SEBasicBlock, self).__init__( 61 | inplanes, 62 | planes, 63 | stride=stride, 64 | dilation=dilation, 65 | downsample=downsample, 66 | D=D) 67 | self.se = SELayer(planes, reduction=reduction, D=D) 68 | 69 | def forward(self, x): 70 | residual = x 71 | 72 | out = self.conv1(x) 73 | out = self.norm1(out) 74 | out = self.relu(out) 75 | 76 | out = self.conv2(out) 77 | out = self.norm2(out) 78 | out = self.se(out) 79 | 80 | if self.downsample is not None: 81 | residual = self.downsample(x) 82 | 83 | out += residual 84 | out = self.relu(out) 85 | 86 | return out 87 | 88 | 89 | class SEBottleneck(Bottleneck): 90 | 91 | def __init__(self, 92 | inplanes, 93 | planes, 94 | stride=1, 95 | dilation=1, 96 | downsample=None, 97 | D=3, 98 | reduction=16): 99 | super(SEBottleneck, self).__init__( 100 | inplanes, 101 | planes, 102 | stride=stride, 103 | dilation=dilation, 104 | downsample=downsample, 105 | D=D) 106 | self.se = SELayer(planes * self.expansion, reduction=reduction, D=D) 107 | 108 | def forward(self, x): 109 | residual = x 110 | 111 | out = self.conv1(x) 112 | out = self.norm1(out) 113 | out = self.relu(out) 114 | 115 | out = self.conv2(out) 116 | out = self.norm2(out) 117 | out = self.relu(out) 118 | 119 | out = self.conv3(out) 120 | out = self.norm3(out) 121 | out = self.se(out) 122 | 123 | if self.downsample is not None: 124 | residual = self.downsample(x) 125 | 126 | out += residual 127 | out = self.relu(out) 128 | 129 | return out 130 | -------------------------------------------------------------------------------- /MinkowskiEngine/utils/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Chris Choy (chrischoy@ai.stanford.edu). 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | # this software and associated documentation files (the "Software"), to deal in 5 | # the Software without restriction, including without limitation the rights to 6 | # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | # of the Software, and to permit persons to whom the Software is furnished to do 8 | # so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in all 11 | # copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | # 21 | # Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural 22 | # Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part 23 | # of the code. 24 | from .quantization import sparse_quantize, ravel_hash_vec, fnv_hash_vec, unique_coordinate_map 25 | from .collation import SparseCollation, batched_coordinates, sparse_collate, batch_sparse_collate 26 | # from .coords import get_coords_map 27 | from .init import kaiming_normal_ 28 | from .summary import summary -------------------------------------------------------------------------------- /MinkowskiEngine/utils/coords.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Chris Choy (chrischoy@ai.stanford.edu). 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | # this software and associated documentation files (the "Software"), to deal in 5 | # the Software without restriction, including without limitation the rights to 6 | # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | # of the Software, and to permit persons to whom the Software is furnished to do 8 | # so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in all 11 | # copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | # 21 | # Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural 22 | # Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part 23 | # of the code. 24 | import torch 25 | 26 | from MinkowskiSparseTensor import SparseTensor 27 | 28 | 29 | def get_coords_map(x, y): 30 | r"""Get mapping between sparse tensor 1 and sparse tensor 2. 31 | 32 | Args: 33 | :attr:`x` (:attr:`MinkowskiEngine.SparseTensor`): a sparse tensor with 34 | `x.tensor_stride` <= `y.tensor_stride`. 35 | 36 | :attr:`y` (:attr:`MinkowskiEngine.SparseTensor`): a sparse tensor with 37 | `x.tensor_stride` <= `y.tensor_stride`. 38 | 39 | Returns: 40 | :attr:`x_indices` (:attr:`torch.LongTensor`): the indices of x that 41 | corresponds to the returned indices of y. 42 | 43 | :attr:`x_indices` (:attr:`torch.LongTensor`): the indices of y that 44 | corresponds to the returned indices of x. 45 | 46 | Example:: 47 | 48 | .. code-block:: python 49 | 50 | sp_tensor = ME.SparseTensor(features, coordinates=coordinates) 51 | out_sp_tensor = stride_2_conv(sp_tensor) 52 | 53 | ins, outs = get_coords_map(sp_tensor, out_sp_tensor) 54 | for i, o in zip(ins, outs): 55 | print(f"{i} -> {o}") 56 | 57 | """ 58 | assert isinstance(x, SparseTensor) 59 | assert isinstance(y, SparseTensor) 60 | assert ( 61 | x.coords_man == y.coords_man 62 | ), "X and Y are using different CoordinateManagers. Y must be derived from X through strided conv/pool/etc." 63 | return x.coords_man.get_coords_map(x.coords_key, y.coords_key) 64 | -------------------------------------------------------------------------------- /MinkowskiEngine/utils/gradcheck.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Chris Choy (chrischoy@ai.stanford.edu). 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | # this software and associated documentation files (the "Software"), to deal in 5 | # the Software without restriction, including without limitation the rights to 6 | # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | # of the Software, and to permit persons to whom the Software is furnished to do 8 | # so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in all 11 | # copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | # 21 | # Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural 22 | # Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part 23 | # of the code. 24 | import torch 25 | 26 | assert torch.__version__ >= "1.7.0", "Gradcheck requires pytorch 1.7 or higher" 27 | 28 | from torch.types import _TensorOrTensors 29 | from typing import Callable, Union, Optional 30 | 31 | from torch.autograd.gradcheck import gradcheck as _gradcheck 32 | 33 | 34 | def gradcheck( 35 | func: Callable[..., Union[_TensorOrTensors]], # See Note [VarArg of Tensors] 36 | inputs: _TensorOrTensors, 37 | eps: float = 1e-6, 38 | atol: float = 1e-5, 39 | rtol: float = 1e-3, 40 | raise_exception: bool = True, 41 | check_sparse_nnz: bool = False, 42 | nondet_tol: float = 0.0, 43 | check_undefined_grad: bool = True, 44 | check_grad_dtypes: bool = False, 45 | ) -> bool: 46 | return _gradcheck( 47 | lambda *x: func.apply(*x), 48 | inputs, 49 | eps=eps, 50 | atol=atol, 51 | rtol=rtol, 52 | raise_exception=raise_exception, 53 | check_sparse_nnz=check_sparse_nnz, 54 | nondet_tol=nondet_tol, 55 | check_undefined_grad=check_undefined_grad, 56 | check_grad_dtypes=check_grad_dtypes, 57 | ) 58 | -------------------------------------------------------------------------------- /MinkowskiEngine/utils/init.py: -------------------------------------------------------------------------------- 1 | import math 2 | import torch 3 | 4 | 5 | def _calculate_fan_in_and_fan_out(tensor): 6 | dimensions = tensor.dim() 7 | if dimensions < 2: 8 | raise ValueError( 9 | "Fan in and fan out can not be computed for tensor with fewer than 2 dimensions" 10 | ) 11 | 12 | if dimensions == 2: # Linear 13 | fan_in = tensor.size(1) 14 | fan_out = tensor.size(0) 15 | else: 16 | num_input_fmaps = tensor.size(1) 17 | num_output_fmaps = tensor.size(2) 18 | receptive_field_size = tensor.size(0) 19 | fan_in = num_input_fmaps * receptive_field_size 20 | fan_out = num_output_fmaps * receptive_field_size 21 | 22 | return fan_in, fan_out 23 | 24 | 25 | def _calculate_correct_fan(tensor, mode): 26 | mode = mode.lower() 27 | valid_modes = ['fan_in', 'fan_out'] 28 | if mode not in valid_modes: 29 | raise ValueError("Mode {} not supported, please use one of {}".format( 30 | mode, valid_modes)) 31 | 32 | fan_in, fan_out = _calculate_fan_in_and_fan_out(tensor) 33 | return fan_in if mode == 'fan_in' else fan_out 34 | 35 | 36 | def kaiming_normal_(tensor, a=0, mode='fan_in', nonlinearity='leaky_relu'): 37 | fan = _calculate_correct_fan(tensor, mode) 38 | gain = torch.nn.init.calculate_gain(nonlinearity, a) 39 | std = gain / math.sqrt(fan) 40 | with torch.no_grad(): 41 | return tensor.normal_(0, std) 42 | -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | # Use use previous versions, modify these variables 2 | # ARG PYTORCH="1.9.0" 3 | # ARG CUDA="11.1" 4 | 5 | ARG PYTORCH="1.12.0" 6 | ARG CUDA="11.3" 7 | ARG CUDNN="8" 8 | 9 | FROM pytorch/pytorch:${PYTORCH}-cuda${CUDA}-cudnn${CUDNN}-devel 10 | 11 | ############################################## 12 | # You should modify this to match your GPU compute capability 13 | # ENV TORCH_CUDA_ARCH_LIST="6.0 6.1 7.0+PTX" 14 | ENV TORCH_CUDA_ARCH_LIST="6.0 6.1 6.2 7.0 7.2 7.5 8.0 8.6" 15 | ############################################## 16 | 17 | ENV TORCH_NVCC_FLAGS="-Xfatbin -compress-all" 18 | 19 | # Install dependencies 20 | RUN apt-get update 21 | RUN apt-get install -y git ninja-build cmake build-essential libopenblas-dev \ 22 | xterm xauth openssh-server tmux wget mate-desktop-environment-core 23 | 24 | RUN apt-get clean 25 | RUN rm -rf /var/lib/apt/lists/* 26 | 27 | # For faster build, use more jobs. 28 | ENV MAX_JOBS=4 29 | RUN git clone --recursive "https://github.com/NVIDIA/MinkowskiEngine" 30 | RUN cd MinkowskiEngine; python setup.py install --force_cuda --blas=openblas 31 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | source 2 | _build 3 | _static 4 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SOURCEDIR = . 8 | BUILDDIR = _build 9 | 10 | # Put it first so that "make" without argument is like "make help". 11 | help: 12 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 13 | 14 | .PHONY: help Makefile 15 | 16 | # Catch-all target: route all unknown targets to Sphinx using the new 17 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 18 | %: Makefile 19 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Documentation with Sphinx 2 | 3 | ## Install dependencies 4 | `pip install -U recommonmark sphinx sphinx_rtd_theme sphinx_markdown_tables` 5 | 6 | ## Generate curated lists only 7 | ## Automatically generate module documentations 8 | `rm -rf source && sphinx-apidoc -o source/ ../` 9 | 10 | ## Customize documentation contents 11 | Write or modify each documentation page as a markdown file. 12 | Include the markdown file in `index.rst` `toctree`. 13 | You may modify the landing page `index.rst` itself in reStructuredText format. 14 | 15 | ## Generate HTML documentation website 16 | `cp ../README.md overview.md; make html` 17 | You may ignore the consistency warning that README.md is not included in toctree. README.md is this file, the instruction to generate documentation website. 18 | The website is generated in `_build/html` 19 | -------------------------------------------------------------------------------- /docs/_templates/layout.html: -------------------------------------------------------------------------------- 1 | {% extends '!layout.html' %} 2 | {% block document %} 3 | {{super()}} 4 | 5 | Fork me on GitHub 6 | 7 | 8 | 9 | 16 | 17 | {% endblock %} 18 | -------------------------------------------------------------------------------- /docs/benchmark.md: -------------------------------------------------------------------------------- 1 | # Benchmark 2 | 3 | We report the feed forward and backward pass time of a convolution layer, and a small U-network for v0.4.3. Note that the kernel map can be reused for other layers with the same tensor-stride, stride, and kernel offsets, thus the time reported in this page can be amortized across all layers used in a large nueral network. 4 | 5 | We use a Titan X for the experiments. 6 | 7 | ## Experiment setup 8 | 9 | 10 | For a single-convolution-layer experiment, we use the following setup. 11 | 12 | 13 | ```python 14 | import MinkowskiEngine as ME 15 | 16 | conv = ME.MinkowskiConvolution( 17 | in_channels=3, 18 | out_channels=32, 19 | kernel_size=7, 20 | stride=1, 21 | dilation=1, 22 | bias=False, 23 | dimension=3) 24 | ``` 25 | 26 | We used ScanNet test set with voxel size 5cm for the experiments. As the SparseConvNet and the MinkowskiEngine use different voxelization algorithms, the number of points processed by each engine differs as well. On average, the SparseConvNet generated 25757.01 points whereas the MinkowskiEngine generated 26097.58 points over 100 ScanNet test rooms. 27 | 28 | 29 | ## Single Convolution Layer 30 | 31 | We tested the same single convolution layer with various kernel size as well. We report the average time in second each algorithm takes to process on average 25757.011 points for SparseConvNet and 26097.58 for MinkowskiEngine. 32 | 33 | | kernel size | SparseConvNet Forward | MinkowskiEngine Forward | 34 | |-------------|-----------------------|-------------------------| 35 | | 3 | 0.174 s | 0.093 s | 36 | | 5 | 0.301 s | 0.121 s | 37 | | 7 | 0.583 s | 0.165 s | 38 | 39 | | kernel size | SparseConvNet Backward | MinkowskiEngine Backward | 40 | |-------------|------------------------|--------------------------| 41 | | 3 | 0.0118 s | 0.0056 s | 42 | | 5 | 0.0287 s | 0.0149 s | 43 | | 7 | 0.0537 s | 0.0312 s | 44 | 45 | 46 | ## Simple UNet 47 | 48 | ```python 49 | net = nn.Sequential( 50 | ME.MinkowskiConvolution( 51 | in_channels=3, 52 | out_channels=32, 53 | kernel_size=5, 54 | stride=1, 55 | dilation=1, 56 | bias=False, 57 | dimension=3), 58 | ME.MinkowskiConvolution( 59 | in_channels=32, 60 | out_channels=32, 61 | kernel_size=2, 62 | stride=2, 63 | dilation=1, 64 | bias=False, 65 | dimension=3), 66 | ME.MinkowskiConvolutionTranspose 67 | in_channels=32, 68 | out_channels=32, 69 | kernel_size=2, 70 | stride=2, 71 | dilation=1, 72 | bias=False, 73 | dimension=3)) 74 | ``` 75 | 76 | 77 | For this experiment, we only change the kernel size of the first convolution layer. 78 | 79 | | kernel size | SparseConvNet Forward | MinkowskiEngine Forward | 80 | |-------------|-----------------------|-------------------------| 81 | | 3 | 0.1806 s | 0.1238 s | 82 | | 5 | 0.3104 s | 0.1440 s | 83 | 84 | | kernel size | SparseConvNet Backward | MinkowskiEngine Backward | 85 | |-------------|------------------------|--------------------------| 86 | | 3 | 0.0130 s | 0.0074 s | 87 | | 5 | 0.0295 s | 0.0170 s | 88 | -------------------------------------------------------------------------------- /docs/broadcast.rst: -------------------------------------------------------------------------------- 1 | MinkowskiBroadcast 2 | ================== 3 | 4 | MinkowskiBroadcastAddition 5 | -------------------------- 6 | 7 | .. autoclass:: MinkowskiEngine.MinkowskiBroadcastAddition 8 | :members: forward 9 | :undoc-members: 10 | :exclude-members: 11 | 12 | .. automethod:: __init__ 13 | 14 | 15 | MinkowskiBroadcastMultiplication 16 | -------------------------------- 17 | 18 | .. autoclass:: MinkowskiEngine.MinkowskiBroadcastMultiplication 19 | :members: forward 20 | :undoc-members: 21 | :exclude-members: 22 | 23 | .. automethod:: __init__ 24 | 25 | 26 | MinkowskiBroadcastConcatenation 27 | ------------------------------- 28 | 29 | .. autoclass:: MinkowskiEngine.MinkowskiBroadcastConcatenation 30 | :members: forward 31 | :undoc-members: 32 | :exclude-members: 33 | 34 | .. automethod:: __init__ 35 | 36 | 37 | MinkowskiBroadcast 38 | ------------------ 39 | 40 | .. autoclass:: MinkowskiEngine.MinkowskiBroadcast 41 | :members: forward 42 | :undoc-members: 43 | :exclude-members: 44 | 45 | .. automethod:: __init__ 46 | -------------------------------------------------------------------------------- /docs/common.rst: -------------------------------------------------------------------------------- 1 | Miscellaneous Classes 2 | ===================== 3 | 4 | Kernel Generator 5 | ---------------- 6 | 7 | .. autoclass:: MinkowskiEngine.KernelGenerator 8 | :members: 9 | :undoc-members: 10 | 11 | .. automethod:: __init__ 12 | 13 | 14 | RegionType 15 | ---------- 16 | 17 | .. autoclass:: MinkowskiEngine.RegionType 18 | :members: 19 | :undoc-members: 20 | -------------------------------------------------------------------------------- /docs/convolution.rst: -------------------------------------------------------------------------------- 1 | MinkowskiConvolution 2 | ==================== 3 | 4 | All classes defined in this class does not require :attr:`region_type`, :attr:`region_offset`, :attr:`out_coords_key`, and :attr:`axis_types`. If you provide those to the class initialization, make sure that you are providing valid arguments. 5 | 6 | 7 | MinkowskiConvolution 8 | -------------------- 9 | 10 | .. autoclass:: MinkowskiEngine.MinkowskiConvolution 11 | :members: cpu, cuda, double, float, to, type, forward 12 | :undoc-members: 13 | 14 | .. automethod:: __init__ 15 | 16 | 17 | MinkowskiChannelwiseConvolution 18 | ------------------------------- 19 | 20 | .. autoclass:: MinkowskiEngine.MinkowskiChannelwiseConvolution 21 | :members: cpu, cuda, double, float, to, type, forward 22 | :undoc-members: 23 | 24 | .. automethod:: __init__ 25 | 26 | 27 | MinkowskiConvolutionTranspose 28 | ----------------------------- 29 | 30 | .. autoclass:: MinkowskiEngine.MinkowskiConvolutionTranspose 31 | :members: cpu, cuda, double, float, to, type, forward 32 | :undoc-members: 33 | 34 | .. automethod:: __init__ 35 | 36 | 37 | MinkowskiGenerativeConvolutionTranspose 38 | --------------------------------------- 39 | 40 | .. autoclass:: MinkowskiEngine.MinkowskiGenerativeConvolutionTranspose 41 | :members: cpu, cuda, double, float, to, type, forward 42 | :undoc-members: 43 | 44 | .. automethod:: __init__ 45 | -------------------------------------------------------------------------------- /docs/coords.rst: -------------------------------------------------------------------------------- 1 | Coordinate Management 2 | ===================== 3 | 4 | CoordinateMapKey 5 | ---------------- 6 | 7 | .. autoclass:: MinkowskiEngine.CoordinateMapKey 8 | :members: 9 | :undoc-members: 10 | :exclude-members: __repr__ 11 | 12 | .. automethod:: __init__ 13 | 14 | 15 | CoordinateManager 16 | ----------------- 17 | 18 | .. autoclass:: MinkowskiEngine.CoordinateManager 19 | :members: 20 | :undoc-members: 21 | :exclude-members: __repr__ 22 | 23 | .. automethod:: __init__ 24 | 25 | 26 | GPU Memory Allocator 27 | -------------------- 28 | 29 | .. autoclass:: MinkowskiEngine.GPUMemoryAllocatorType 30 | :members: 31 | 32 | .. autofunction:: MinkowskiEngine.set_gpu_allocator 33 | -------------------------------------------------------------------------------- /docs/demo/interop.rst: -------------------------------------------------------------------------------- 1 | Working with Pytorch Layers 2 | =========================== 3 | 4 | The :attr:`MinkowskiEngine.SparseTensor` is a shallow wrapper of the 5 | :attr:`torch.Tensor`. Thus, it very easy to convert a sparse tensor to a 6 | pytorch tensor and vice versa. 7 | 8 | 9 | Example: Features for Classification 10 | ------------------------------------ 11 | 12 | In this example, we show how to extract features from a 13 | :attr:`MinkowskiEngine.SparseTensor` and using the features with a pytorch 14 | layer. 15 | 16 | First, let's create a network that generate a feature vector for each input in 17 | a min-batch. 18 | 19 | .. code-block:: python 20 | 21 | import torch.nn as nn 22 | import MinkowskiEngine as ME 23 | 24 | 25 | class ExampleNetwork(nn.Module): 26 | 27 | def __init__(self, in_feat, out_feat, D): 28 | self.net = nn.Sequential( 29 | ME.MinkowskiConvolution( 30 | in_channels=in_feat, 31 | out_channels=64, 32 | kernel_size=3, 33 | stride=2, 34 | dilation=1, 35 | bias=False, 36 | dimension=D), ME.MinkowskiBatchNorm(64), ME.MinkowskiReLU(), 37 | ME.MinkowskiConvolution( 38 | in_channels=64, 39 | out_channels=128, 40 | kernel_size=3, 41 | stride=2, 42 | dimension=D), ME.MinkowskiBatchNorm(128), ME.MinkowskiReLU(), 43 | ME.MinkowskiGlobalPooling(), 44 | ME.MinkowskiLinear(128, out_feat)) 45 | 46 | def forward(self, x): 47 | return self.net(x) 48 | 49 | 50 | Note that the above :attr:`MinkowskiEngine.MinkowskiGlobalPooling` layer 51 | averages all features in the input sparse tensor and generate :math:`B \times 52 | D_F` when :math:`B` is the batch size (adaptively changes accordingly) and 53 | :math:`D_F` is the feature dimension of the input sparse tensor. 54 | 55 | Then, during the training, we could us the `torch.nn.CrossEntropyLoss` layer by 56 | accessing the features of the sparse tensor 57 | :attr:`MinkowskiEngine.SparseTensor.F` or 58 | :attr:`MinkowskiEngine.SparseTensor.feats`. 59 | 60 | .. code-block:: python 61 | 62 | criterion = nn.CrossEntropyLoss() 63 | 64 | for i in range(10): 65 | optimizer.zero_grad() 66 | 67 | # Get new data 68 | coords, feat, label = data_loader() 69 | input = ME.SparseTensor(features=feat, coordinates=coords, device=device) 70 | label = label.to(device) 71 | 72 | # Forward 73 | output = net(input) 74 | 75 | # Loss 76 | out_feats = output.F 77 | loss = criterion(out_feats, label) 78 | 79 | Please refer to `examples/example.py 80 | `_ 81 | for the complete demo. 82 | -------------------------------------------------------------------------------- /docs/demo/pointnet.md: -------------------------------------------------------------------------------- 1 | PointNet 2 | ======== 3 | 4 | A PointNet uses a series of multi-layered perceptrons (linear layers) with 5 | spatial transformers and global pooling layers. 6 | 7 | However, you can think of a PointNet as a specialization of a convolutional 8 | neural network consisting of a series of convolution layers and global poolings. 9 | In this network, all convolution layers have kernel size 1, and stride 1. Also, 10 | the input is a sparse tensor where features are normalized coordinates. 11 | 12 | This generalization allows the network to process an arbitrary number of 13 | points, but allows you to think of linear layers as a specialization of 14 | convolution. 15 | 16 | In addition to being able to process arbitrary number of points, it allows you 17 | to define 18 | 19 | 1. Features as arbitrary generic features such as color. 20 | 2. Convolutions with kernel size > 1. 21 | 3. Convolutions with stride > 1. 22 | 23 | Please refer to the [complete pointnet example](https://github.com/NVIDIA/MinkowskiEngine/blob/master/examples/pointnet.py) for more detail. 24 | -------------------------------------------------------------------------------- /docs/demo/segmentation.rst: -------------------------------------------------------------------------------- 1 | Semantic Segmentation 2 | ===================== 3 | 4 | To run the example, please install `Open3D `_ with `pip 5 | install open3d-python`. 6 | 7 | .. code-block:: shell 8 | 9 | cd /path/to/MinkowskiEngine 10 | python -m examples.indoor 11 | 12 | 13 | Segmentation of a hotel room 14 | ---------------------------- 15 | 16 | When you run the example, you will see a hotel room and semantic segmentation 17 | of the room. You can interactively rotate the visualization when you run the 18 | example. First, we load the data. 19 | 20 | .. code-block:: python 21 | 22 | def load_file(file_name): 23 | pcd = o3d.read_point_cloud(file_name) 24 | coords = np.array(pcd.points) 25 | colors = np.array(pcd.colors) 26 | return coords, colors, pcd 27 | 28 | You can provide a quantized coordinates that ensures there would be only one point per voxel, or you can use the new :attr:`MinkowskiEngine.TensorField` that does not require quantized coordinates to process point clouds. However, since it does the quanization in the main training process instead of delegating the quantization to the data loading processes, it could slow down the training. 29 | Next, you should create a batched coordinates by calling :attr:`MinkowskiEngine.utils.batched_coordinates`. 30 | 31 | .. code-block:: python 32 | 33 | # Create a batch, this process is done in a data loader during training in parallel. 34 | in_field = ME.TensorField( 35 | features=torch.from_numpy(colors).float(), 36 | coordinates=ME.utils.batched_coordinates([coords / voxel_size], dtype=torch.float32), 37 | quantization_mode=ME.SparseTensorQuantizationMode.UNWEIGHTED_AVERAGE, 38 | minkowski_algorithm=ME.MinkowskiAlgorithm.SPEED_OPTIMIZED, 39 | device=device, 40 | ) 41 | 42 | 43 | Finally, we feed-forward the sparse tensor into the network and get the predictions. 44 | 45 | 46 | .. code-block:: python 47 | 48 | # Convert to a sparse tensor 49 | sinput = in_field.sparse() 50 | # Output sparse tensor 51 | soutput = model(sinput) 52 | # get the prediction on the input tensor field 53 | out_field = soutput.slice(in_field) 54 | 55 | 56 | After doing some post-processing. We can color the labels and visualize the 57 | input and the prediction side-by-side. 58 | 59 | .. image:: ../images/segmentation.png 60 | 61 | 62 | The weights are downloaded automatically once you run the example and the 63 | weights are currently the top-ranking algorithm on the `Scannet 3D segmentation 64 | benchmark `_. 65 | 66 | Please refer to the `complete indoor segmentation example 67 | `_ 68 | for more detail. 69 | -------------------------------------------------------------------------------- /docs/demo/sparse_tensor_reconstruction.rst: -------------------------------------------------------------------------------- 1 | 3D Sparsity Pattern Reconstruction 2 | ================================== 3 | 4 | In this page, we will go over a simple demo example that trains a 3D 5 | convolutional neural network that reconstructs a 3D sparsity pattern from an 6 | one-hot vector. This is similar to the `Octree Generating Networks, ICCV'17 7 | `_. The input one-hot vector indicates a 3D 8 | Computer Aided Design (CAD) chair index from the ModelNet40 dataset. 9 | 10 | We use :attr:`MinkowskiEngine.MinkowskiConvolutionTranspose` along with 11 | :attr:`MinkowskiEngine.MinkowskiPruning` to sequentially upsample a voxel by a 12 | factor of 2 and then remove some of the upsampled voxels to generate target 13 | shapes. The general network architecture looks similar to the following 14 | diagram, but the details might differ. 15 | 16 | .. image:: ../images/generative_3d_net.png 17 | 18 | 19 | Before we proceed, please go over `the training and data loading tutorial 20 | `_ first. 21 | 22 | 23 | Making a Sparsity Pattern Reconstruction Network 24 | ------------------------------------------------ 25 | 26 | To create a sparse tensor defined in a 3D grid world from a vector, we need to upsample sequentially from a :math:`1 \times 1 \times 1` resolution voxel. Here, we use a block that consists of :attr:`MinkowskiEngine.MinkowskiConvolutionTranspose`, :attr:`MinkowskiEngine.MinkowskiConvolution`, and :attr:`MinkowskiEngine.MinkowskiPruning`. 27 | 28 | During a forward pass, we create two paths for 1) the main features and 2) a sparse voxel classification to remove unnecessary voxels. 29 | 30 | .. code-block:: python 31 | 32 | out = upsample_block(z) 33 | out_cls = classification(out).F 34 | out = pruning(out, out_cls > 0) 35 | 36 | 37 | Until the input sparse tensor reaches the target resolution, the network repeats a series of upsampling and pruning that removes out unnecessary voxels. We visualize the results on the following figure. Note that the final reconstruction captures the target geometry very accurately. We also visualized the hierarchical reconstruction process of upsampling and pruning. 38 | 39 | .. image:: ../images/generative_3d_results.gif 40 | 41 | 42 | Running the Example 43 | ------------------- 44 | 45 | To train a network, go to the Minkowski Engine root directory, and type: 46 | 47 | 48 | .. code-block:: 49 | 50 | python -m examples.reconstruction --train 51 | 52 | 53 | To visualize network predictions, or to try out a pretrained model, type: 54 | 55 | .. code-block:: 56 | 57 | python -m examples.reconstruction 58 | 59 | 60 | .. image:: ../images/demo_reconstruction.png 61 | 62 | The program will visualize two 3D shapes. One on the left is the target 3D 63 | shape, one on the right is the reconstructed network prediction. 64 | 65 | The entire code can be found at `example/reconstruction.py 66 | `_. 67 | -------------------------------------------------------------------------------- /docs/guides.md: -------------------------------------------------------------------------------- 1 | # Guidelines for Faster Networks 2 | 3 | The Minkowski Engine requires two main components for convolution on a sparse tensor: efficient kernel mapping management and operations on the features. A kernel map refers to a mapping that defines which row in an input feature maps to which row in an output feature. 4 | 5 | In Minkowski Engine, we use an unordered map whose key is a non-zero index and the corresponding row index as the value. Given two unordered maps that define input and output tensors, we can find which row maps in the input feature to which row in the output feature. 6 | 7 | However, in many cases, a convolutional network consists of repeated blocks of operations. e.g. a residual block that consists of convolutions with the same kernel size. Thus, we end up re-using a lot of kernel map and instead of re-computing every time, we cache all the kernel maps. 8 | 9 | 10 | ## Reusing the cached kernel maps 11 | 12 | As we mentioned in the previous section, the Minkowski Engine caches all kernel maps. If a network has a lot of repeated layers, such as convolutions, the network will reuse the cached kernel maps. 13 | 14 | 15 | ## Reusing the cached kernel maps for transposed layers 16 | 17 | The Minkowski Engine can reuse cached kernel maps for transposed layers by swapping the input and output of the kernel maps. For instance, if a stride-2 convolution was used on the sparse tensor with the tensor stride 2, a transposed convolution layer on the tensor stride 4 with stride 2 can reuse the same kernel map generated on the previous stride-2 convolution. Reuse as many repeated network structure as possible. 18 | 19 | 20 | ## High-dimensional convolution with cross-shaped or custom kernels 21 | 22 | As the dimension or the kernel size increases, it becomes computationally inefficient very quickly if we use hyper-cubic kernels (volumetric kernels). Try to use cross shaped kernel or other custom kernels to reduce the load. In the following snippet, we create a cross-shaped kernel for convolution. 23 | 24 | ```python 25 | import MinkowskiEngine as ME 26 | 27 | ... 28 | 29 | kernel_generator = ME.KernelGenerator( 30 | kernel_size, 31 | stride, 32 | dilation, 33 | region_type=ME.RegionType.HYPERCROSS, 34 | dimension=dimension) 35 | 36 | conv = ME.MinkowskiConvolution( 37 | in_channels=in_channels, 38 | out_channels=out_channels, 39 | kernel_size=kernel_size, 40 | stride=stride, 41 | dilation=dilation, 42 | bias=bias, 43 | kernel_generator=kernel_generator, 44 | dimension=dimension) 45 | ``` 46 | 47 | 48 | ## Strided pooling layers for high-dimensional spaces 49 | 50 | In extremely high-dimensional spaces, it is very expensive to use strided convolution. Using a cross-shaped kernel is not a good solution for hierarchical maps as everything is very sparse in high-dimensional spaces and cross shaped kernel will end up being empty. Instead, use a pooling layer to create kernel map efficiently and fast. 51 | 52 | If you use a pooling layer with kernel size == strides, the MinkowskiEngine will generate kernel map very efficiently as the mapping becomes trivial. 53 | -------------------------------------------------------------------------------- /docs/images/classification_3d_net.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NVIDIA/MinkowskiEngine/02fc608bea4c0549b0a7b00ca1bf15dee4a0b228/docs/images/classification_3d_net.png -------------------------------------------------------------------------------- /docs/images/conv_dense.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NVIDIA/MinkowskiEngine/02fc608bea4c0549b0a7b00ca1bf15dee4a0b228/docs/images/conv_dense.gif -------------------------------------------------------------------------------- /docs/images/conv_generalized.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NVIDIA/MinkowskiEngine/02fc608bea4c0549b0a7b00ca1bf15dee4a0b228/docs/images/conv_generalized.gif -------------------------------------------------------------------------------- /docs/images/conv_sparse.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NVIDIA/MinkowskiEngine/02fc608bea4c0549b0a7b00ca1bf15dee4a0b228/docs/images/conv_sparse.gif -------------------------------------------------------------------------------- /docs/images/conv_sparse_conv.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NVIDIA/MinkowskiEngine/02fc608bea4c0549b0a7b00ca1bf15dee4a0b228/docs/images/conv_sparse_conv.gif -------------------------------------------------------------------------------- /docs/images/demo_reconstruction.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NVIDIA/MinkowskiEngine/02fc608bea4c0549b0a7b00ca1bf15dee4a0b228/docs/images/demo_reconstruction.png -------------------------------------------------------------------------------- /docs/images/detection_3d_net.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NVIDIA/MinkowskiEngine/02fc608bea4c0549b0a7b00ca1bf15dee4a0b228/docs/images/detection_3d_net.png -------------------------------------------------------------------------------- /docs/images/generative_3d_net.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NVIDIA/MinkowskiEngine/02fc608bea4c0549b0a7b00ca1bf15dee4a0b228/docs/images/generative_3d_net.png -------------------------------------------------------------------------------- /docs/images/generative_3d_results.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NVIDIA/MinkowskiEngine/02fc608bea4c0549b0a7b00ca1bf15dee4a0b228/docs/images/generative_3d_results.gif -------------------------------------------------------------------------------- /docs/images/kernel_map.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NVIDIA/MinkowskiEngine/02fc608bea4c0549b0a7b00ca1bf15dee4a0b228/docs/images/kernel_map.gif -------------------------------------------------------------------------------- /docs/images/segmentation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NVIDIA/MinkowskiEngine/02fc608bea4c0549b0a7b00ca1bf15dee4a0b228/docs/images/segmentation.png -------------------------------------------------------------------------------- /docs/images/segmentation_3d_net.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NVIDIA/MinkowskiEngine/02fc608bea4c0549b0a7b00ca1bf15dee4a0b228/docs/images/segmentation_3d_net.png -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | Welcome to MinkowskiEngine's documentation! 2 | =========================================== 3 | 4 | The MinkowskiEngine is an auto-differentiation library for sparse tensors. 5 | 6 | Table of Contents 7 | ================= 8 | 9 | .. toctree:: 10 | :maxdepth: 1 11 | :caption: Introduction 12 | 13 | overview 14 | sparse_tensor_network 15 | quick_start 16 | terminology 17 | 18 | .. toctree:: 19 | :maxdepth: 2 20 | :caption: Tutorials 21 | 22 | tutorial/sparse_tensor_basic 23 | 24 | .. toctree:: 25 | :maxdepth: 2 26 | :caption: Demos 27 | 28 | demo/training 29 | demo/modelnet40_classification 30 | demo/segmentation 31 | demo/sparse_tensor_reconstruction 32 | demo/interop 33 | demo/multigpu 34 | demo/pointnet 35 | 36 | .. toctree:: 37 | :maxdepth: 2 38 | :caption: API 39 | 40 | sparse_tensor 41 | convolution 42 | pooling 43 | broadcast 44 | normalization 45 | nonlinearity 46 | pruning 47 | interp 48 | union 49 | coords 50 | utils 51 | common 52 | misc 53 | 54 | .. toctree:: 55 | :maxdepth: 1 56 | :caption: Miscellanea 57 | 58 | issues 59 | guides 60 | migration_05 61 | benchmark 62 | 63 | 64 | Indices and tables 65 | ================== 66 | 67 | * :ref:`genindex` 68 | * :ref:`search` 69 | -------------------------------------------------------------------------------- /docs/interp.rst: -------------------------------------------------------------------------------- 1 | MinkowskiInterpolation 2 | ====================== 3 | 4 | 5 | MinkowskiInterpolation 6 | ---------------------- 7 | 8 | .. autoclass:: MinkowskiEngine.MinkowskiInterpolation 9 | :members: cpu, cuda, double, float, to, type, forward 10 | :undoc-members: 11 | 12 | .. automethod:: __init__ 13 | -------------------------------------------------------------------------------- /docs/migration_05.md: -------------------------------------------------------------------------------- 1 | # Migration Guide from v0.4.x to v0.5.0 2 | 3 | ## Summary 4 | 5 | ```python 6 | # 0.4 7 | ME.SparseTensor(feats=feats, coords=coords, D=3) 8 | # 0.5 9 | ME.SparseTensor(feats=feats, coords=coords, D=3) 10 | ``` 11 | 12 | 13 | ``` 14 | # 0.4 15 | ME.MinkowskiConvolution(..., has_bias=True) 16 | # 0.5 17 | ME.MinkowskiConvolution(..., bias=True) 18 | ``` 19 | 20 | 21 | ``` 22 | # 0.4 23 | RegionType.HYPERCUBE 24 | # 0.5 25 | RegionType.HYPER_CUBE 26 | ``` 27 | 28 | 29 | ## Definitions 30 | 31 | ### `CoordinateMap` 32 | 33 | A coordinate map refers to a map object that converts a D-dimensional 34 | coordinate into a row index for a feature matrix where the corresponding 35 | feature for the coordinate is located. This can be implemented using 36 | `std::map`, `std::unordered_map` or a hash-table with the right hash function 37 | and the equality function. 38 | 39 | ### `CoordinateKey` 40 | 41 | A `CoordinateKey` or `CoordinateMapKey` refers to a unique identifier that can 42 | be used to retrieve a `CoordinateMap`. 43 | 44 | ### `tensor_stride` 45 | 46 | A tensor stride is a minimum distance between non-zero elements in a sparse 47 | tensor. If we take a stride-2 convolution on a sparse tensor with tensor 48 | stride 1, the resulting sparse tensor will have tensor stride 2. If we apply 49 | two stride-2 convolutions on a sparse tensor with tensor stride 3, the 50 | resulting sparse tensor will have the tensor stride 2 x 2 x 3 = 12. 51 | 52 | ## From CoordsKey to CoordinateMapKey 53 | 54 | CoordsKey should not be called in most cases, but in rare cases where you used 55 | it. Please review this section to update your code. 56 | 57 | One of the major difference is that we expose the pybind11 object directly to 58 | the python side to remove the redundant abstraction layer. 59 | 60 | In v0.4, Minkowski Engine uses a `uint64_t` hash key to identify a 61 | `CoordinateMap`, but from v0.5, we use a tensor stride 62 | 63 | 64 | ## From CoordsManager to CoordinateManager 65 | 66 | CoordinateManager should not be called in most cases, but if you do please re 67 | 68 | 69 | ### Initialization 70 | 71 | ```python 72 | # 0.4.x 73 | manager = CoordsManager(D=3) 74 | # 0.5.x 75 | manager = CoordinateManager(D=3) 76 | ``` 77 | 78 | ## Initializing a new CoordinateMap 79 | 80 | ```python 81 | # 0.4.x 82 | manager = CoordsManager(D = 3) 83 | manager.initialize(torch.IntTens 84 | def initialize(self, 85 | coords: torch.IntTensor, 86 | coords_key: CoordsKey, 87 | force_creation: bool = False, 88 | force_remap: bool = False, 89 | allow_duplicate_coords: bool = False, 90 | return_inverse: bool = False) -> torch.LongTensor: 91 | ``` 92 | 93 | 94 | ## Consistent Layer Arguments 95 | -------------------------------------------------------------------------------- /docs/misc.rst: -------------------------------------------------------------------------------- 1 | Miscellanea 2 | =========== 3 | 4 | Controlling the number of threads 5 | --------------------------------- 6 | 7 | The kernel map `[1] `_ defines which row of an input feature matrix to which row of the output feature matrix. This however is an expensive operation as the dimension increases. Fortunately, some part of the operation can be parallelized and we provide a multi-threaded function to speed up this process. 8 | 9 | By default, we use all CPU threads available in the system. However, this might not be desirable in some cases. Simply define an environmental variable ``OMP_NUM_THREADS`` to control the number of threads you want to use. For example, ``export OMP_NUM_THREADS=8; python your_program.py``. If you use SLURM, the environment variable ``OMP_NUM_THREADS`` will be automatically set. 10 | 11 | 12 | 13 | is_cuda_available 14 | ----------------- 15 | 16 | .. autofunction:: MinkowskiEngine.is_cuda_available 17 | 18 | 19 | cuda_version 20 | ------------ 21 | 22 | .. autofunction:: MinkowskiEngine.cuda_version 23 | 24 | 25 | get_gpu_memory_info 26 | ------------------- 27 | 28 | .. autofunction:: MinkowskiEngine.get_gpu_memory_info 29 | 30 | 31 | set_memory_manager_backend 32 | -------------------------- 33 | 34 | .. autofunction:: MinkowskiEngine.set_memory_manager_backend 35 | 36 | 37 | 38 | 39 | References 40 | ---------- 41 | 42 | - `[1] 4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural Networks, CVPR'19 `_ 43 | -------------------------------------------------------------------------------- /docs/nonlinearity.rst: -------------------------------------------------------------------------------- 1 | MinkowskiNonlinearities 2 | ======================= 3 | 4 | 5 | MinkowskiReLU 6 | ------------- 7 | 8 | .. autoclass:: MinkowskiEngine.MinkowskiReLU 9 | :members: 10 | :undoc-members: 11 | :exclude-members: forward 12 | 13 | .. automethod:: __init__ 14 | 15 | 16 | MinkowskiPReLU 17 | -------------- 18 | 19 | .. autoclass:: MinkowskiEngine.MinkowskiPReLU 20 | :members: 21 | :undoc-members: 22 | :exclude-members: forward 23 | 24 | .. automethod:: __init__ 25 | 26 | 27 | MinkowskiSELU 28 | ------------- 29 | 30 | .. autoclass:: MinkowskiEngine.MinkowskiSELU 31 | :members: 32 | :undoc-members: 33 | :exclude-members: forward 34 | 35 | .. automethod:: __init__ 36 | 37 | 38 | MinkowskiSELU 39 | ------------- 40 | 41 | .. autoclass:: MinkowskiEngine.MinkowskiSELU 42 | :members: 43 | :undoc-members: 44 | :exclude-members: forward 45 | 46 | .. automethod:: __init__ 47 | 48 | 49 | MinkowskiCELU 50 | ------------- 51 | 52 | .. autoclass:: MinkowskiEngine.MinkowskiCELU 53 | :members: 54 | :undoc-members: 55 | :exclude-members: forward 56 | 57 | .. automethod:: __init__ 58 | 59 | 60 | MinkowskiDropout 61 | ---------------- 62 | 63 | .. autoclass:: MinkowskiEngine.MinkowskiDropout 64 | :members: 65 | :undoc-members: 66 | :exclude-members: forward 67 | 68 | .. automethod:: __init__ 69 | 70 | 71 | MinkowskiThreshold 72 | ------------------ 73 | 74 | .. autoclass:: MinkowskiEngine.MinkowskiThreshold 75 | :members: 76 | :undoc-members: 77 | :exclude-members: forward 78 | 79 | .. automethod:: __init__ 80 | 81 | 82 | MinkowskiSigmoid 83 | ----------------- 84 | 85 | .. autoclass:: MinkowskiEngine.MinkowskiSigmoid 86 | :members: 87 | :undoc-members: 88 | :exclude-members: forward 89 | 90 | .. automethod:: __init__ 91 | 92 | 93 | MinkowskiTanh 94 | ------------- 95 | 96 | .. autoclass:: MinkowskiEngine.MinkowskiTanh 97 | :members: 98 | :undoc-members: 99 | :exclude-members: forward 100 | 101 | .. automethod:: __init__ 102 | 103 | 104 | MinkowskiSoftmax 105 | ---------------- 106 | 107 | .. autoclass:: MinkowskiEngine.MinkowskiSoftmax 108 | :members: 109 | :undoc-members: 110 | :exclude-members: forward 111 | 112 | .. automethod:: __init__ 113 | -------------------------------------------------------------------------------- /docs/normalization.rst: -------------------------------------------------------------------------------- 1 | MinkowskiNormalization 2 | ====================== 3 | 4 | 5 | MinkowskiBatchNorm 6 | ------------------ 7 | 8 | .. autoclass:: MinkowskiEngine.MinkowskiBatchNorm 9 | :members: cpu, cuda, double, float, to, type, forward 10 | :undoc-members: 11 | :exclude-members: 12 | 13 | .. automethod:: __init__ 14 | 15 | 16 | MinkowskiSyncBatchNorm 17 | ---------------------- 18 | 19 | .. autoclass:: MinkowskiEngine.MinkowskiSyncBatchNorm 20 | :members: cpu, cuda, double, float, to, type, forward 21 | :undoc-members: 22 | :exclude-members: 23 | 24 | .. automethod:: __init__ 25 | 26 | 27 | 28 | MinkowskiInstanceNorm 29 | --------------------- 30 | 31 | .. autoclass:: MinkowskiEngine.MinkowskiInstanceNorm 32 | :members: cpu, cuda, double, float, to, type, forward 33 | :undoc-members: 34 | :exclude-members: 35 | 36 | .. automethod:: __init__ 37 | -------------------------------------------------------------------------------- /docs/pooling.rst: -------------------------------------------------------------------------------- 1 | MinkowskiPooling 2 | ================ 3 | 4 | MinkowskiMaxPooling 5 | ------------------- 6 | 7 | .. autoclass:: MinkowskiEngine.MinkowskiMaxPooling 8 | :members: cpu, cuda, double, float, to, type, forward 9 | :undoc-members: 10 | :exclude-members: 11 | 12 | .. automethod:: __init__ 13 | 14 | 15 | MinkowskiAvgPooling 16 | ------------------- 17 | 18 | .. autoclass:: MinkowskiEngine.MinkowskiAvgPooling 19 | :members: cpu, cuda, double, float, to, type, forward 20 | :undoc-members: 21 | :exclude-members: 22 | 23 | .. automethod:: __init__ 24 | 25 | 26 | MinkowskiSumPooling 27 | ------------------- 28 | 29 | .. autoclass:: MinkowskiEngine.MinkowskiSumPooling 30 | :members: cpu, cuda, double, float, to, type, forward 31 | :undoc-members: 32 | :exclude-members: 33 | 34 | .. automethod:: __init__ 35 | 36 | 37 | MinkowskiPoolingTranspose 38 | ------------------------- 39 | 40 | .. autoclass:: MinkowskiEngine.MinkowskiPoolingTranspose 41 | :members: cpu, cuda, double, float, to, type, forward 42 | :undoc-members: 43 | :exclude-members: 44 | 45 | .. automethod:: __init__ 46 | 47 | 48 | MinkowskiGlobalMaxPooling 49 | ------------------------- 50 | 51 | .. autoclass:: MinkowskiEngine.MinkowskiGlobalMaxPooling 52 | :members: cpu, cuda, double, float, to, type, forward 53 | :undoc-members: 54 | :exclude-members: 55 | 56 | .. automethod:: __init__ 57 | 58 | 59 | MinkowskiGlobalAvgPooling 60 | ------------------------- 61 | 62 | .. autoclass:: MinkowskiEngine.MinkowskiGlobalAvgPooling 63 | :members: cpu, cuda, double, float, to, type, forward 64 | :undoc-members: 65 | :exclude-members: 66 | 67 | .. automethod:: __init__ 68 | 69 | 70 | MinkowskiGlobalSumPooling 71 | ------------------------- 72 | 73 | .. autoclass:: MinkowskiEngine.MinkowskiGlobalSumPooling 74 | :members: cpu, cuda, double, float, to, type, forward 75 | :undoc-members: 76 | :exclude-members: 77 | 78 | .. automethod:: __init__ 79 | -------------------------------------------------------------------------------- /docs/pruning.rst: -------------------------------------------------------------------------------- 1 | MinkowskiPruning 2 | ================ 3 | 4 | MinkowskiPruning 5 | ---------------- 6 | 7 | .. autoclass:: MinkowskiEngine.MinkowskiPruning 8 | :members: 9 | :undoc-members: 10 | 11 | .. automethod:: __init__ 12 | -------------------------------------------------------------------------------- /docs/quick_start.md: -------------------------------------------------------------------------------- 1 | # Quick Start 2 | 3 | ## Installation 4 | 5 | The MinkowskiEngine can be installed via `pip` or using conda. Currently, the installation requirements are: 6 | 7 | - Ubuntu 14.04 or higher 8 | - CUDA 10.1 or higher if you want CUDA acceleration 9 | - pytorch 1.3 or higher 10 | - python 3.6 or higher 11 | - GCC 6 or higher 12 | 13 | 14 | ## System requirements 15 | 16 | MinkowskiEngine requires `openblas`, `python3-dev` and `torch`, `numpy` python packages. Using anaconda is highly recommended and the following instructions will install all the requirements. 17 | 18 | ## Installation 19 | 20 | The MinkowskiEngine is distributed via [PyPI MinkowskiEngine](https://pypi.org/project/MinkowskiEngine/) which can be installed simply with `pip`. 21 | 22 | ``` 23 | pip3 install -U MinkowskiEngine 24 | ``` 25 | 26 | To install the latest version, use `pip3 install -U git+https://github.com/NVIDIA/MinkowskiEngine`. 27 | 28 | 29 | ## Running a segmentation network 30 | 31 | Download the MinkowskiEngine and run the example code. 32 | 33 | ``` 34 | git clone https://github.com/NVIDIA/MinkowskiEngine.git 35 | cd MinkowskiEngine 36 | python -m examples.indoor 37 | ``` 38 | 39 | When you run the above example, it will download pretrained weights of a 40 | Minkowski network and will visualize the semantic segmentation results of a 3D scene. 41 | 42 | 43 | ## CPU only compilation 44 | 45 | 46 | ``` 47 | git clone https://github.com/NVIDIA/MinkowskiEngine.git 48 | cd MinkowskiEngine 49 | python setup.py install --cpu_only 50 | ``` 51 | 52 | ## Other BLAS and MKL support 53 | 54 | On intel CPU devices, `conda` installs `numpy` with `Intel Math Kernel Library` or `MKL`. The Minkowski Engine will automatically detect the MKL using `numpy` and use `MKL` instead of `openblas` or `atlas`. 55 | 56 | In many cases, this will be done automatically. However, if the numpy is not using MKL, but you have an Intel CPU, use conda to install MKL. 57 | 58 | ``` 59 | conda install -c intel mkl mkl-include 60 | python setup.py install --blas=mkl 61 | ``` 62 | 63 | If you want to use a specific BLAS among MKL, ATLAS, OpenBLAS, and the system BLAS, provide the blas name as follows: 64 | 65 | ``` 66 | cd MinkowskiEngine 67 | python setup.py install --blas=openblas 68 | ``` 69 | -------------------------------------------------------------------------------- /docs/sparse_tensor.rst: -------------------------------------------------------------------------------- 1 | SparseTensor and TensorField 2 | ============================ 3 | 4 | SparseTensor 5 | ------------ 6 | 7 | .. autoclass:: MinkowskiEngine.MinkowskiSparseTensor.SparseTensor 8 | :members: 9 | :undoc-members: 10 | 11 | .. automethod:: __init__ 12 | 13 | 14 | TensorField 15 | ----------- 16 | 17 | .. autoclass:: MinkowskiEngine.MinkowskiTensorField.TensorField 18 | :members: 19 | :undoc-members: 20 | 21 | .. automethod:: __init__ 22 | 23 | 24 | SparseTensorOperationMode 25 | ------------------------- 26 | 27 | .. autoclass:: MinkowskiEngine.MinkowskiTensor.SparseTensorOperationMode 28 | :members: 29 | 30 | SparseTensorQuantizationMode 31 | ---------------------------- 32 | 33 | .. autoclass:: MinkowskiEngine.MinkowskiTensor.SparseTensorQuantizationMode 34 | :members: 35 | 36 | set_sparse_tensor_operation_mode 37 | -------------------------------- 38 | 39 | .. autofunction:: MinkowskiEngine.MinkowskiTensor.set_sparse_tensor_operation_mode 40 | 41 | sparse_tensor_operation_mode 42 | ---------------------------- 43 | 44 | .. autofunction:: MinkowskiEngine.MinkowskiTensor.sparse_tensor_operation_mode 45 | 46 | global_coordinate_manager 47 | ------------------------- 48 | 49 | .. autofunction:: MinkowskiEngine.MinkowskiTensor.global_coordinate_manager 50 | 51 | set_global_coordinate_manager 52 | ----------------------------- 53 | 54 | .. autofunction:: MinkowskiEngine.MinkowskiTensor.set_global_coordinate_manager 55 | 56 | clear_global_coordinate_manager 57 | ------------------------------- 58 | 59 | .. autofunction:: MinkowskiEngine.MinkowskiTensor.clear_global_coordinate_manager 60 | -------------------------------------------------------------------------------- /docs/tutorial/convolution_basic.rst: -------------------------------------------------------------------------------- 1 | Convolution Basics 2 | ================== 3 | 4 | In this tutorial, we will cover how to use a convolution layer and 5 | 6 | Must be a positive integer or a list of positive integers. 7 | 8 | `examples/convolution.py` 9 | -------------------------------------------------------------------------------- /docs/union.rst: -------------------------------------------------------------------------------- 1 | MinkowskiUnion 2 | ============== 3 | 4 | MinkowskiUnion 5 | -------------- 6 | 7 | .. autoclass:: MinkowskiEngine.MinkowskiUnion 8 | :members: forward 9 | :undoc-members: 10 | 11 | .. automethod:: __init__ 12 | -------------------------------------------------------------------------------- /docs/utils.rst: -------------------------------------------------------------------------------- 1 | Utility Functions and Classes 2 | ============================= 3 | 4 | 5 | sparse_quantize 6 | --------------- 7 | 8 | .. autofunction:: MinkowskiEngine.utils.sparse_quantize 9 | 10 | 11 | batched_coordinates 12 | ------------------- 13 | 14 | .. autofunction:: MinkowskiEngine.utils.batched_coordinates 15 | 16 | 17 | sparse_collate 18 | -------------- 19 | 20 | .. autofunction:: MinkowskiEngine.utils.sparse_collate 21 | 22 | 23 | batch_sparse_collate 24 | -------------------- 25 | 26 | .. autofunction:: MinkowskiEngine.utils.batch_sparse_collate 27 | 28 | 29 | cat 30 | --- 31 | 32 | .. autofunction:: MinkowskiEngine.cat 33 | 34 | 35 | to_sparse 36 | --------- 37 | 38 | .. autofunction:: MinkowskiEngine.to_sparse 39 | 40 | 41 | to_sparse_all 42 | ------------- 43 | 44 | .. autofunction:: MinkowskiEngine.to_sparse_all 45 | 46 | 47 | SparseCollation 48 | --------------- 49 | 50 | .. autoclass:: MinkowskiEngine.utils.SparseCollation 51 | :members: 52 | :undoc-members: 53 | 54 | .. automethod:: __init__ 55 | 56 | 57 | MinkowskiToSparseTensor 58 | ----------------------- 59 | 60 | .. autoclass:: MinkowskiEngine.MinkowskiToSparseTensor 61 | 62 | .. automethod:: __init__ 63 | 64 | 65 | MinkowskiToDenseTensor 66 | ----------------------- 67 | 68 | .. autoclass:: MinkowskiEngine.MinkowskiToDenseTensor 69 | 70 | .. automethod:: __init__ 71 | 72 | 73 | MinkowskiToFeature 74 | ------------------ 75 | 76 | .. autoclass:: MinkowskiEngine.MinkowskiToFeature 77 | 78 | .. automethod:: __init__ 79 | 80 | 81 | MinkowskiStackCat 82 | ----------------- 83 | 84 | .. autoclass:: MinkowskiEngine.MinkowskiStackCat 85 | :members: forward 86 | :undoc-members: 87 | 88 | .. automethod:: __init__ 89 | 90 | 91 | MinkowskiStackSum 92 | ----------------- 93 | 94 | .. autoclass:: MinkowskiEngine.MinkowskiStackSum 95 | :members: forward 96 | :undoc-members: 97 | 98 | .. automethod:: __init__ 99 | 100 | 101 | MinkowskiStackMean 102 | ------------------ 103 | 104 | .. autoclass:: MinkowskiEngine.MinkowskiStackMean 105 | :members: forward 106 | :undoc-members: 107 | 108 | .. automethod:: __init__ 109 | 110 | 111 | MinkowskiStackVar 112 | ----------------- 113 | 114 | .. autoclass:: MinkowskiEngine.MinkowskiStackVar 115 | :members: forward 116 | :undoc-members: 117 | 118 | .. automethod:: __init__ -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Minkowski Engine Examples 2 | 3 | 4 | ## ModelNet40 Classification 5 | 6 | ``` 7 | python -m examples.classification_modelnet40 --network pointnet # torch PointNet 8 | python -m examples.classification_modelnet40 --network minkpointnet # MinkowskiEngine PointNet 9 | python -m examples.classification_modelnet40 --network minkfcnn # MinkowskiEngine FCNN 10 | ``` 11 | 12 | ### Training Logs 13 | 14 | - training log for MinkowskiFCNN: [https://pastebin.pl/view/30f0a0c8](https://pastebin.pl/view/30f0a0c8) 15 | 16 | ## ScanNet Semantic Segmentation 17 | 18 | ``` 19 | python -m examples.indoor 20 | ``` 21 | -------------------------------------------------------------------------------- /examples/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NVIDIA/MinkowskiEngine/02fc608bea4c0549b0a7b00ca1bf15dee4a0b228/examples/__init__.py -------------------------------------------------------------------------------- /examples/common.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Chris Choy (chrischoy@ai.stanford.edu). 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | # this software and associated documentation files (the "Software"), to deal in 5 | # the Software without restriction, including without limitation the rights to 6 | # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | # of the Software, and to permit persons to whom the Software is furnished to do 8 | # so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in all 11 | # copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | # 21 | # Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural 22 | # Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part 23 | # of the code. 24 | import numpy as np 25 | import random 26 | import time 27 | 28 | import torch 29 | from torch.utils.data.sampler import Sampler 30 | 31 | 32 | class Timer(object): 33 | """A simple timer.""" 34 | 35 | def __init__(self): 36 | self.reset() 37 | 38 | def reset(self): 39 | self.total_time = 0 40 | self.calls = 0 41 | self.start_time = 0 42 | self.diff = 0 43 | self.averate_time = 0 44 | self.min_time = np.Inf 45 | 46 | def tic(self): 47 | # using time.time instead of time.clock because time time.clock 48 | # does not normalize for multithreading 49 | self.start_time = time.time() 50 | 51 | def toc(self, average=False): 52 | self.diff = time.time() - self.start_time 53 | self.total_time += self.diff 54 | self.calls += 1 55 | self.average_time = self.total_time / self.calls 56 | if self.diff < self.min_time: 57 | self.min_time = self.diff 58 | if average: 59 | return self.average_time 60 | else: 61 | return self.diff 62 | 63 | 64 | class InfSampler(Sampler): 65 | """Samples elements randomly, without replacement. 66 | 67 | Arguments: 68 | data_source (Dataset): dataset to sample from 69 | """ 70 | 71 | def __init__(self, data_source, shuffle=False): 72 | self.data_source = data_source 73 | self.shuffle = shuffle 74 | self.reset_permutation() 75 | 76 | def reset_permutation(self): 77 | perm = len(self.data_source) 78 | if self.shuffle: 79 | perm = torch.randperm(perm) 80 | else: 81 | perm = torch.arange(perm) 82 | self._perm = perm.tolist() 83 | 84 | def __iter__(self): 85 | return self 86 | 87 | def __next__(self): 88 | if len(self._perm) == 0: 89 | self.reset_permutation() 90 | return self._perm.pop() 91 | 92 | def __len__(self): 93 | return len(self.data_source) 94 | 95 | 96 | def seed_all(random_seed): 97 | torch.manual_seed(random_seed) 98 | torch.cuda.manual_seed(random_seed) 99 | torch.cuda.manual_seed_all(random_seed) 100 | # torch.backends.cudnn.deterministic = True 101 | # torch.backends.cudnn.benchmark = False 102 | np.random.seed(random_seed) 103 | random.seed(random_seed) 104 | -------------------------------------------------------------------------------- /examples/download_modelnet40.sh: -------------------------------------------------------------------------------- 1 | export BASE_URL=http://cvgl.stanford.edu/data2/ModelNet40/ 2 | 3 | # set progress option accordingly 4 | wget --help | grep -q '\--show-progress' && \ 5 | _PROGRESS_OPT="-q --show-progress" || _PROGRESS_OPT="" 6 | 7 | wget $_PROGRESS_OPT ${BASE_URL}/ModelNet40.tgz 8 | tar -xzf ModelNet40.tgz 9 | cd ModelNet40 10 | wget ${BASE_URL}/train_modelnet40.txt 11 | wget ${BASE_URL}/val_modelnet40.txt 12 | wget ${BASE_URL}/test_modelnet40.txt -------------------------------------------------------------------------------- /examples/example.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Chris Choy (chrischoy@ai.stanford.edu). 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | # this software and associated documentation files (the "Software"), to deal in 5 | # the Software without restriction, including without limitation the rights to 6 | # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | # of the Software, and to permit persons to whom the Software is furnished to do 8 | # so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in all 11 | # copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | # 21 | # Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural 22 | # Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part 23 | # of the code. 24 | import torch 25 | import torch.nn as nn 26 | from torch.optim import SGD 27 | 28 | import MinkowskiEngine as ME 29 | 30 | from tests.python.common import data_loader 31 | 32 | 33 | class ExampleNetwork(ME.MinkowskiNetwork): 34 | 35 | def __init__(self, in_feat, out_feat, D): 36 | super(ExampleNetwork, self).__init__(D) 37 | self.net = nn.Sequential( 38 | ME.MinkowskiConvolution( 39 | in_channels=in_feat, 40 | out_channels=64, 41 | kernel_size=3, 42 | stride=2, 43 | dilation=1, 44 | bias=False, 45 | dimension=D), ME.MinkowskiBatchNorm(64), ME.MinkowskiReLU(), 46 | ME.MinkowskiConvolution( 47 | in_channels=64, 48 | out_channels=128, 49 | kernel_size=3, 50 | stride=2, 51 | dimension=D), ME.MinkowskiBatchNorm(128), ME.MinkowskiReLU(), 52 | ME.MinkowskiGlobalPooling(), 53 | ME.MinkowskiLinear(128, out_feat)) 54 | 55 | def forward(self, x): 56 | return self.net(x) 57 | 58 | 59 | if __name__ == '__main__': 60 | # loss and network 61 | criterion = nn.CrossEntropyLoss() 62 | net = ExampleNetwork(in_feat=3, out_feat=5, D=2) 63 | print(net) 64 | 65 | # a data loader must return a tuple of coords, features, and labels. 66 | device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') 67 | 68 | net = net.to(device) 69 | optimizer = SGD(net.parameters(), lr=1e-1) 70 | 71 | for i in range(10): 72 | optimizer.zero_grad() 73 | 74 | # Get new data 75 | coords, feat, label = data_loader() 76 | input = ME.SparseTensor(feat, coords, device=device) 77 | label = label.to(device) 78 | 79 | # Forward 80 | output = net(input) 81 | 82 | # Loss 83 | loss = criterion(output.F, label) 84 | print('Iteration: ', i, ', Loss: ', loss.item()) 85 | 86 | # Gradient 87 | loss.backward() 88 | optimizer.step() 89 | 90 | # Saving and loading a network 91 | torch.save(net.state_dict(), 'test.pth') 92 | net.load_state_dict(torch.load('test.pth')) 93 | -------------------------------------------------------------------------------- /examples/multigpu_ddp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | File Name : MinkowskiEngine-multigpu_ddp 4 | date : 16/12/2019 5 | Author : wenbo 6 | Email : huwenbodut@gmail.com 7 | Description : 8 | _ _ 9 | ( |---/ ) 10 | ) . . ( 11 | ________________________,--._(___Y___)_,--._______________________ 12 | `--' `--' 13 | """ 14 | 15 | import os 16 | import argparse 17 | import numpy as np 18 | from time import time 19 | from urllib.request import urlretrieve 20 | import open3d as o3d 21 | import torch 22 | import torch.nn as nn 23 | from torch.optim import SGD 24 | import torch.multiprocessing as mp 25 | import torch.distributed as dist 26 | 27 | import MinkowskiEngine as ME 28 | from examples.minkunet import MinkUNet34C 29 | 30 | 31 | if not os.path.isfile("weights.pth"): 32 | urlretrieve("http://cvgl.stanford.edu/data2/minkowskiengine/1.ply", "1.ply") 33 | 34 | parser = argparse.ArgumentParser() 35 | parser.add_argument("--file_name", type=str, default="1.ply") 36 | parser.add_argument("--batch_size", type=int, default=4) 37 | parser.add_argument("--max_ngpu", type=int, default=2) 38 | 39 | cache = {} 40 | min_time = np.inf 41 | 42 | 43 | def load_file(file_name, voxel_size): 44 | if file_name not in cache: 45 | pcd = o3d.io.read_point_cloud(file_name) 46 | cache[file_name] = pcd 47 | 48 | pcd = cache[file_name] 49 | quantized_coords, feats = ME.utils.sparse_quantize( 50 | np.array(pcd.points, dtype=np.float32), 51 | np.array(pcd.colors, dtype=np.float32), 52 | quantization_size=voxel_size, 53 | ) 54 | random_labels = torch.zeros(len(feats)) 55 | 56 | return quantized_coords, feats, random_labels 57 | 58 | 59 | def main(): 60 | # loss and network 61 | config = parser.parse_args() 62 | num_devices = torch.cuda.device_count() 63 | num_devices = min(config.max_ngpu, num_devices) 64 | print( 65 | "Testing ", 66 | num_devices, 67 | " GPUs. Total batch size: ", 68 | num_devices * config.batch_size, 69 | ) 70 | 71 | config.world_size = num_devices 72 | mp.spawn(main_worker, nprocs=num_devices, args=(num_devices, config)) 73 | 74 | 75 | def main_worker(gpu, ngpus_per_node, args): 76 | global min_time 77 | args.gpu = gpu 78 | if args.gpu is not None: 79 | print("Use GPU: {} for training".format(args.gpu)) 80 | args.rank = 0 * ngpus_per_node + gpu 81 | dist.init_process_group( 82 | backend="nccl", 83 | init_method="tcp://127.0.0.1:23456", 84 | world_size=args.world_size, 85 | rank=args.rank, 86 | ) 87 | # create model 88 | model = MinkUNet34C(3, 20, D=3) 89 | torch.cuda.set_device(args.gpu) 90 | model.cuda(args.gpu) 91 | model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.gpu]) 92 | # define loss function (criterion) and optimizer 93 | criterion = nn.CrossEntropyLoss().cuda(args.gpu) 94 | # Synchronized batch norm 95 | net = ME.MinkowskiSyncBatchNorm.convert_sync_batchnorm(model) 96 | optimizer = SGD(net.parameters(), lr=1e-1) 97 | 98 | for iteration in range(10): 99 | optimizer.zero_grad() 100 | 101 | # Get new data 102 | # inputs, labels = [], [] 103 | batch = [load_file(args.file_name, 0.05) for _ in range(args.batch_size)] 104 | coordinates_, featrues_, random_labels = list(zip(*batch)) 105 | coordinates, features = ME.utils.sparse_collate(coordinates_, featrues_) 106 | inputs = ME.SparseTensor(features, coordinates, device=args.gpu) 107 | labels = torch.cat(random_labels).long().to(args.gpu) 108 | # The raw version of the parallel_apply 109 | st = time() 110 | outputs = net(inputs) 111 | # Extract features from the sparse tensors to use a pytorch criterion 112 | out_features = outputs.F 113 | loss = criterion(out_features, labels) 114 | # Gradient 115 | loss.backward() 116 | optimizer.step() 117 | 118 | t = torch.tensor(time() - st, dtype=torch.float).cuda(args.gpu) 119 | dist.all_reduce(t) 120 | min_time = min(t.detach().cpu().numpy() / ngpus_per_node, min_time) 121 | print( 122 | f"Iteration: {iteration}, Loss: {loss.item()}, Time: {t.detach().item()}, Min time: {min_time}" 123 | ) 124 | 125 | # Must clear cache at regular interval 126 | if iteration % 10 == 0: 127 | torch.cuda.empty_cache() 128 | 129 | 130 | if __name__ == "__main__": 131 | main() 132 | -------------------------------------------------------------------------------- /examples/stack_unet.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Chris Choy (chrischoy@ai.stanford.edu). 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | # this software and associated documentation files (the "Software"), to deal in 5 | # the Software without restriction, including without limitation the rights to 6 | # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | # of the Software, and to permit persons to whom the Software is furnished to do 8 | # so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in all 11 | # copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | # 21 | # Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural 22 | # Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part 23 | # of the code. 24 | import torch 25 | import torch.nn as nn 26 | 27 | import MinkowskiEngine as ME 28 | import MinkowskiEngine.MinkowskiFunctional as MF 29 | 30 | from tests.python.common import data_loader 31 | 32 | 33 | class StackUNet(ME.MinkowskiNetwork): 34 | def __init__(self, in_nchannel, out_nchannel, D): 35 | ME.MinkowskiNetwork.__init__(self, D) 36 | channels = [in_nchannel, 16, 32] 37 | self.net = nn.Sequential( 38 | ME.MinkowskiStackSum( 39 | ME.MinkowskiConvolution( 40 | channels[0], 41 | channels[1], 42 | kernel_size=3, 43 | stride=1, 44 | dimension=D, 45 | ), 46 | nn.Sequential( 47 | ME.MinkowskiConvolution( 48 | channels[0], 49 | channels[1], 50 | kernel_size=3, 51 | stride=2, 52 | dimension=D, 53 | ), 54 | ME.MinkowskiStackSum( 55 | nn.Identity(), 56 | nn.Sequential( 57 | ME.MinkowskiConvolution( 58 | channels[1], 59 | channels[2], 60 | kernel_size=3, 61 | stride=2, 62 | dimension=D, 63 | ), 64 | ME.MinkowskiConvolutionTranspose( 65 | channels[2], 66 | channels[1], 67 | kernel_size=3, 68 | stride=1, 69 | dimension=D, 70 | ), 71 | ME.MinkowskiPoolingTranspose( 72 | kernel_size=2, stride=2, dimension=D 73 | ), 74 | ), 75 | ), 76 | ME.MinkowskiPoolingTranspose(kernel_size=2, stride=2, dimension=D), 77 | ), 78 | ), 79 | ME.MinkowskiToFeature(), 80 | nn.Linear(channels[1], out_nchannel, bias=True), 81 | ) 82 | 83 | def forward(self, x): 84 | return self.net(x) 85 | 86 | 87 | if __name__ == "__main__": 88 | # loss and network 89 | net = StackUNet(3, 5, D=2) 90 | print(net) 91 | 92 | # a data loader must return a tuple of coords, features, and labels. 93 | coords, feat, label = data_loader() 94 | device = torch.device("cuda" if torch.cuda.is_available() else "cpu") 95 | 96 | net = net.to(device) 97 | input = ME.SparseTensor(feat, coords, device=device) 98 | 99 | # Forward 100 | output = net(input) 101 | -------------------------------------------------------------------------------- /examples/unet.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Chris Choy (chrischoy@ai.stanford.edu). 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | # this software and associated documentation files (the "Software"), to deal in 5 | # the Software without restriction, including without limitation the rights to 6 | # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | # of the Software, and to permit persons to whom the Software is furnished to do 8 | # so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in all 11 | # copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | # 21 | # Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural 22 | # Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part 23 | # of the code. 24 | import torch 25 | 26 | import MinkowskiEngine as ME 27 | import MinkowskiEngine.MinkowskiFunctional as MF 28 | 29 | from tests.python.common import data_loader 30 | 31 | 32 | class UNet(ME.MinkowskiNetwork): 33 | 34 | def __init__(self, in_nchannel, out_nchannel, D): 35 | super(UNet, self).__init__(D) 36 | self.block1 = torch.nn.Sequential( 37 | ME.MinkowskiConvolution( 38 | in_channels=in_nchannel, 39 | out_channels=8, 40 | kernel_size=3, 41 | stride=1, 42 | dimension=D), 43 | ME.MinkowskiBatchNorm(8)) 44 | 45 | self.block2 = torch.nn.Sequential( 46 | ME.MinkowskiConvolution( 47 | in_channels=8, 48 | out_channels=16, 49 | kernel_size=3, 50 | stride=2, 51 | dimension=D), 52 | ME.MinkowskiBatchNorm(16), 53 | ) 54 | 55 | self.block3 = torch.nn.Sequential( 56 | ME.MinkowskiConvolution( 57 | in_channels=16, 58 | out_channels=32, 59 | kernel_size=3, 60 | stride=2, 61 | dimension=D), 62 | ME.MinkowskiBatchNorm(32)) 63 | 64 | self.block3_tr = torch.nn.Sequential( 65 | ME.MinkowskiConvolutionTranspose( 66 | in_channels=32, 67 | out_channels=16, 68 | kernel_size=3, 69 | stride=2, 70 | dimension=D), 71 | ME.MinkowskiBatchNorm(16)) 72 | 73 | self.block2_tr = torch.nn.Sequential( 74 | ME.MinkowskiConvolutionTranspose( 75 | in_channels=32, 76 | out_channels=16, 77 | kernel_size=3, 78 | stride=2, 79 | dimension=D), 80 | ME.MinkowskiBatchNorm(16)) 81 | 82 | self.conv1_tr = ME.MinkowskiConvolution( 83 | in_channels=24, 84 | out_channels=out_nchannel, 85 | kernel_size=1, 86 | stride=1, 87 | dimension=D) 88 | 89 | def forward(self, x): 90 | out_s1 = self.block1(x) 91 | out = MF.relu(out_s1) 92 | 93 | out_s2 = self.block2(out) 94 | out = MF.relu(out_s2) 95 | 96 | out_s4 = self.block3(out) 97 | out = MF.relu(out_s4) 98 | 99 | out = MF.relu(self.block3_tr(out)) 100 | out = ME.cat(out, out_s2) 101 | 102 | out = MF.relu(self.block2_tr(out)) 103 | out = ME.cat(out, out_s1) 104 | 105 | return self.conv1_tr(out) 106 | 107 | 108 | if __name__ == '__main__': 109 | # loss and network 110 | net = UNet(3, 5, D=2) 111 | print(net) 112 | 113 | # a data loader must return a tuple of coords, features, and labels. 114 | coords, feat, label = data_loader() 115 | device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') 116 | 117 | net = net.to(device) 118 | input = ME.SparseTensor(feat, coords, device=device) 119 | 120 | # Forward 121 | output = net(input) 122 | -------------------------------------------------------------------------------- /pybind/minkowski.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 NVIDIA Corporation. 3 | * Copyright (c) 2018-2020 Chris Choy (chrischoy@ai.stanford.edu). 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 | * IN THE SOFTWARE. 22 | * 23 | * Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural 24 | * Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part 25 | * of the code. 26 | */ 27 | #include 28 | 29 | #include 30 | 31 | #include 32 | #include 33 | 34 | #include "extern.hpp" 35 | 36 | PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { 37 | // Constant function 38 | m.def("is_cuda_available", &is_cuda_available); 39 | m.def("cuda_version", &cuda_version); 40 | m.def("cudart_version", &cudart_version); 41 | m.def("get_gpu_memory_info", &get_gpu_memory_info); 42 | 43 | initialize_non_templated_classes(m); 44 | 45 | // Manager 46 | instantiate_manager>(m, 47 | std::string("CPU")); 48 | #ifndef CPU_ONLY 49 | instantiate_manager>( 50 | m, std::string("GPU_default")); 51 | instantiate_manager>( 52 | m, std::string("GPU_c10")); 53 | #endif 54 | 55 | // Functions 56 | non_templated_cpu_func(m); 57 | instantiate_cpu_func(m, ""); 58 | 59 | #ifndef CPU_ONLY 60 | instantiate_gpu_func( 61 | m, std::string("")); 62 | 63 | instantiate_gpu_func( 64 | m, std::string("")); 65 | 66 | non_templated_gpu_func(m); 67 | #endif 68 | } 69 | -------------------------------------------------------------------------------- /pybind/minkowski.cu: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 NVIDIA Corporation. 3 | * Copyright (c) 2018-2020 Chris Choy (chrischoy@ai.stanford.edu). 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 | * IN THE SOFTWARE. 22 | * 23 | * Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural 24 | * Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part 25 | * of the code. 26 | */ 27 | #include "extern.hpp" 28 | 29 | #include 30 | 31 | #include 32 | 33 | #include 34 | #include 35 | 36 | PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { 37 | // Constant function 38 | m.def("is_cuda_available", &is_cuda_available); 39 | m.def("cuda_version", &cuda_version); 40 | m.def("cudart_version", &cudart_version); 41 | m.def("get_gpu_memory_info", &get_gpu_memory_info); 42 | 43 | initialize_non_templated_classes(m); 44 | 45 | // Manager 46 | instantiate_manager>(m, 47 | std::string("CPU")); 48 | #ifndef CPU_ONLY 49 | instantiate_manager>( 50 | m, std::string("GPU_default")); 51 | instantiate_manager>( 52 | m, std::string("GPU_c10")); 53 | #endif 54 | 55 | // Functions 56 | non_templated_cpu_func(m); 57 | instantiate_cpu_func(m, ""); 58 | 59 | #ifndef CPU_ONLY 60 | instantiate_gpu_func( 61 | m, std::string("")); 62 | 63 | instantiate_gpu_func( 64 | m, std::string("")); 65 | 66 | non_templated_gpu_func(m); 67 | #endif 68 | } 69 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | numpy 2 | torch>=1.4,<1.7 3 | -------------------------------------------------------------------------------- /src/3rdparty/cudf/detail/nvtx/ranges.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, NVIDIA CORPORATION. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include "nvtx3.hpp" 20 | 21 | namespace cudf { 22 | /** 23 | * @brief Tag type for libcudf's NVTX domain. 24 | * 25 | */ 26 | struct libcudf_domain { 27 | static constexpr char const* name{"libcudf"}; ///< Name of the libcudf domain 28 | }; 29 | 30 | /** 31 | * @brief Alias for an NVTX range in the libcudf domain. 32 | * 33 | */ 34 | using thread_range = ::nvtx3::domain_thread_range; 35 | 36 | } // namespace cudf 37 | 38 | /** 39 | * @brief Convenience macro for generating an NVTX range in the `libcudf` domain 40 | * from the lifetime of a function. 41 | * 42 | * Uses the name of the immediately enclosing function returned by `__func__` to 43 | * name the range. 44 | * 45 | * Example: 46 | * ``` 47 | * void some_function(){ 48 | * CUDF_FUNC_RANGE(); 49 | * ... 50 | * } 51 | * ``` 52 | * 53 | */ 54 | #define CUDF_FUNC_RANGE() NVTX3_FUNC_RANGE_IN(cudf::libcudf_domain) 55 | -------------------------------------------------------------------------------- /src/3rdparty/cudf/detail/utilities/device_operators.cuh: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019, NVIDIA CORPORATION. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef DEVICE_OPERATORS_CUH 18 | #define DEVICE_OPERATORS_CUH 19 | 20 | /** ---------------------------------------------------------------------------* 21 | * @brief definition of the device operators 22 | * @file device_operators.cuh 23 | * 24 | * ---------------------------------------------------------------------------**/ 25 | 26 | #include 27 | #include 28 | 29 | namespace cudf { 30 | // ------------------------------------------------------------------------ 31 | // Binary operators 32 | /* @brief binary `sum` operator */ 33 | struct DeviceSum { 34 | template 35 | CUDA_HOST_DEVICE_CALLABLE T operator()(const T& lhs, const T& rhs) 36 | { 37 | return lhs + rhs; 38 | } 39 | 40 | template 41 | static constexpr T identity() 42 | { 43 | return T{0}; 44 | } 45 | }; 46 | 47 | /* @brief `count` operator - used in rolling windows */ 48 | struct DeviceCount { 49 | template 50 | CUDA_HOST_DEVICE_CALLABLE T operator()(const T&, const T& rhs) 51 | { 52 | return rhs + T{1}; 53 | } 54 | 55 | template 56 | static constexpr T identity() 57 | { 58 | return T{0}; 59 | } 60 | }; 61 | 62 | /** 63 | * @brief string value for sentinel which is used in min, max reduction 64 | * operators 65 | * This sentinel string value is the highest possible valid UTF-8 encoded 66 | * character. This serves as identity value for maximum operator on string 67 | * values. Also, this char pointer serves as valid device pointer of identity 68 | * value for minimum operator on string values. 69 | * 70 | */ 71 | __constant__ char max_string_sentinel[5]{"\xF7\xBF\xBF\xBF"}; 72 | 73 | /* @brief binary `min` operator */ 74 | struct DeviceMin { 75 | template 76 | CUDA_HOST_DEVICE_CALLABLE T operator()(const T& lhs, const T& rhs) 77 | { 78 | return std::min(lhs, rhs); 79 | } 80 | 81 | template 82 | static constexpr T identity() 83 | { 84 | return std::numeric_limits::max(); 85 | } 86 | }; 87 | 88 | /* @brief binary `max` operator */ 89 | struct DeviceMax { 90 | template 91 | CUDA_HOST_DEVICE_CALLABLE T operator()(const T& lhs, const T& rhs) 92 | { 93 | return std::max(lhs, rhs); 94 | } 95 | 96 | template 97 | static constexpr T identity() 98 | { 99 | return std::numeric_limits::lowest(); 100 | } 101 | }; 102 | 103 | /* @brief binary `product` operator */ 104 | struct DeviceProduct { 105 | template 106 | CUDA_HOST_DEVICE_CALLABLE T operator()(const T& lhs, const T& rhs) 107 | { 108 | return lhs * rhs; 109 | } 110 | 111 | template 112 | static constexpr T identity() 113 | { 114 | return T{1}; 115 | } 116 | }; 117 | 118 | /* @brief binary `and` operator */ 119 | struct DeviceAnd { 120 | template ::value>* = nullptr> 121 | CUDA_HOST_DEVICE_CALLABLE T operator()(const T& lhs, const T& rhs) 122 | { 123 | return (lhs & rhs); 124 | } 125 | }; 126 | 127 | /* @brief binary `or` operator */ 128 | struct DeviceOr { 129 | template ::value>* = nullptr> 130 | CUDA_HOST_DEVICE_CALLABLE T operator()(const T& lhs, const T& rhs) 131 | { 132 | return (lhs | rhs); 133 | } 134 | }; 135 | 136 | /* @brief binary `xor` operator */ 137 | struct DeviceXor { 138 | template ::value>* = nullptr> 139 | CUDA_HOST_DEVICE_CALLABLE T operator()(const T& lhs, const T& rhs) 140 | { 141 | return (lhs ^ rhs); 142 | } 143 | }; 144 | 145 | } // namespace cudf 146 | 147 | #endif 148 | -------------------------------------------------------------------------------- /src/3rdparty/hash/hash_allocator.cuh: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017, NVIDIA CORPORATION. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef HASH_ALLOCATOR_CUH 18 | #define HASH_ALLOCATOR_CUH 19 | 20 | #include 21 | #include 22 | 23 | template 24 | struct managed_allocator { 25 | typedef T value_type; 26 | // rmm::mr::device_memory_resource* mr = new rmm::mr::managed_memory_resource; 27 | 28 | managed_allocator() = default; 29 | 30 | template 31 | constexpr managed_allocator(const managed_allocator&) noexcept 32 | { 33 | } 34 | 35 | T* allocate(std::size_t n, cudaStream_t stream = 0) const 36 | { 37 | T* d_tmp; 38 | cudaError_t error = cudaMalloc((void**) &d_tmp, n * sizeof(T)); 39 | if (error != cudaSuccess) { 40 | cudaGetLastError(); // clear CUDA error 41 | std::runtime_error("cudaMalloc failed in the hash_allocator.cuh:managed_allocator."); 42 | } 43 | return d_tmp; 44 | // return static_cast(mr->allocate(n * sizeof(T), stream)); 45 | } 46 | 47 | void deallocate(T* p, std::size_t n, cudaStream_t stream = 0) const 48 | { 49 | cudaFree(p); 50 | //mr->deallocate(p, n * sizeof(T), stream); 51 | } 52 | }; 53 | 54 | template 55 | bool operator==(const managed_allocator&, const managed_allocator&) 56 | { 57 | return true; 58 | } 59 | template 60 | bool operator!=(const managed_allocator&, const managed_allocator&) 61 | { 62 | return false; 63 | } 64 | 65 | template 66 | struct default_allocator { 67 | typedef T value_type; 68 | // rmm::mr::device_memory_resource* mr = rmm::mr::get_default_resource(); 69 | 70 | default_allocator() = default; 71 | 72 | template 73 | constexpr default_allocator(const default_allocator&) noexcept 74 | { 75 | } 76 | 77 | T* allocate(std::size_t n, cudaStream_t stream = 0) const 78 | { 79 | T* d_tmp; 80 | cudaError_t error = cudaMalloc((void**) &d_tmp, n * sizeof(T)); 81 | if (error != cudaSuccess) { 82 | cudaGetLastError(); // clear CUDA error 83 | std::runtime_error("cudaMalloc failed in the hash_allocator.cuh:default_allocator."); 84 | } 85 | 86 | return d_tmp; 87 | // return static_cast(mr->allocate(n * sizeof(T), stream)); 88 | } 89 | 90 | void deallocate(T* p, std::size_t n, cudaStream_t stream = 0) const 91 | { 92 | cudaFree(p); 93 | // mr->deallocate(p, n * sizeof(T), stream); 94 | } 95 | }; 96 | 97 | template 98 | bool operator==(const default_allocator&, const default_allocator&) 99 | { 100 | return true; 101 | } 102 | template 103 | bool operator!=(const default_allocator&, const default_allocator&) 104 | { 105 | return false; 106 | } 107 | 108 | #endif 109 | -------------------------------------------------------------------------------- /src/3rdparty/hash/managed.cuh: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017, NVIDIA CORPORATION. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef MANAGED_CUH 18 | #define MANAGED_CUH 19 | 20 | #include 21 | #include 22 | 23 | struct managed { 24 | static void *operator new(size_t n) 25 | { 26 | void *ptr = 0; 27 | cudaError_t result = cudaMallocManaged(&ptr, n); 28 | if (cudaSuccess != result || 0 == ptr) throw std::bad_alloc(); 29 | return ptr; 30 | } 31 | 32 | static void operator delete(void *ptr) noexcept 33 | { 34 | auto const free_result = cudaFree(ptr); 35 | assert(free_result == cudaSuccess); 36 | } 37 | }; 38 | 39 | inline bool isPtrManaged(cudaPointerAttributes attr) 40 | { 41 | #if CUDART_VERSION >= 10000 42 | return (attr.type == cudaMemoryTypeManaged); 43 | #else 44 | return attr.isManaged; 45 | #endif 46 | } 47 | 48 | #endif // MANAGED_CUH 49 | -------------------------------------------------------------------------------- /src/broadcast_kernel.cuh: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Chris Choy (chrischoy@ai.stanford.edu). 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in 11 | * all copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | * IN THE SOFTWARE. 20 | * 21 | * Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural 22 | * Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part 23 | * of the code. 24 | */ 25 | #ifndef BROADCAST_CUH 26 | #define BROADCAST_CUH 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | #include "gpu.cuh" 33 | #include "kernel_map.cuh" 34 | #include "math_functions.cuh" 35 | #include "types.hpp" 36 | 37 | namespace minkowski { 38 | 39 | template 40 | void BroadcastForwardKernelGPU( 41 | const Dtype *d_in_feat, int in_nrows, const Dtype *d_in_feat_global, 42 | int in_nrows_global, Dtype *d_out_feat, int nchannel, 43 | BroadcastMode::Type const op, 44 | gpu_kernel_map const &kernel_map, 45 | cusparseHandle_t cushandle, cudaStream_t stream); 46 | 47 | template 48 | void BroadcastBackwardKernelGPU( 49 | const Dtype *d_in_feat, Dtype *d_grad_in_feat, int in_nrows, 50 | const Dtype *d_in_feat_global, Dtype *d_grad_in_feat_global, 51 | int in_nrows_global, const Dtype *d_grad_out_feat, int nchannel, 52 | BroadcastMode::Type const op, 53 | gpu_kernel_map const &kernel_map, 54 | cusparseHandle_t cushandle, cudaStream_t stream); 55 | 56 | } // namespace minkowski 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /src/common.hpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Chris Choy (chrischoy@ai.stanford.edu). 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in 11 | * all copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | * IN THE SOFTWARE. 20 | * 21 | * Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural 22 | * Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part 23 | * of the code. 24 | */ 25 | #ifndef COMMON 26 | #define COMMON 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include 33 | 34 | #include "types.hpp" 35 | #include "utils.hpp" 36 | 37 | #include "coords_key.hpp" 38 | #include "coords_manager.hpp" 39 | 40 | #ifndef CPU_ONLY 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include // cuda driver types 47 | 48 | #include 49 | 50 | #include "gpu.cuh" 51 | #include "types.cuh" 52 | #include "gpu_memory_manager.hpp" 53 | #endif 54 | 55 | #endif // COMMON 56 | -------------------------------------------------------------------------------- /src/convolution_kernel.cuh: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Chris Choy (chrischoy@ai.stanford.edu). 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in 11 | * all copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | * IN THE SOFTWARE. 20 | * 21 | * Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural 22 | * Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part 23 | * of the code. 24 | */ 25 | #ifndef CONVOLUTION_CUH 26 | #define CONVOLUTION_CUH 27 | 28 | #include 29 | #include 30 | 31 | #include "gpu.cuh" 32 | #include "kernel_map.cuh" 33 | #include "math_functions.cuh" 34 | #include "types.hpp" 35 | 36 | namespace minkowski { 37 | 38 | template 39 | void ConvolutionForwardKernelGPU( 40 | Dtype const *d_in_feat, // 41 | default_types::size_type const in_nchannel, // 42 | Dtype *d_out_feat, // 43 | default_types::size_type const out_nchannel, // 44 | Dtype *d_kernel, gpu_kernel_map const &kernel_map, 45 | default_types::size_type const in_nrows, // 46 | default_types::size_type const out_nrows, // 47 | ByteAllocator &allocator, // 48 | MinkowskiAlgorithm::Mode const algo_index, // 49 | ConvolutionMode::Type const convolution_mode, // 50 | cublasHandle_t cuhandle, cudaStream_t stream); 51 | 52 | template 53 | void ConvolutionBackwardKernelGPU( 54 | Dtype const *d_in_feat, // 55 | Dtype *d_grad_in_feat, // 56 | default_types::size_type const in_nchannel, // 57 | Dtype const *d_grad_out_feat, // 58 | default_types::size_type const out_nchannel, // 59 | Dtype const *d_kernel, // 60 | Dtype *d_grad_kernel, // 61 | gpu_kernel_map const &kernel_map, 62 | default_types::size_type const in_nrows, // 63 | default_types::size_type const out_nrows, // 64 | ByteAllocator &allocator, // 65 | MinkowskiAlgorithm::Mode const algo_index, // 66 | ConvolutionMode::Type const convolution_mode, // 67 | cublasHandle_t cuhandle, cudaStream_t stream); 68 | } // end namespace minkowski 69 | 70 | #endif // end CONVOLUTION_CUH 71 | -------------------------------------------------------------------------------- /src/dispatcher.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace minkowski { 14 | 15 | #define MINK_PRIVATE_CASE_TYPE_USING_HINT(NAME, enum_type, type, HINT, ...) \ 16 | case enum_type: { \ 17 | using HINT = type; \ 18 | return __VA_ARGS__(); \ 19 | } 20 | 21 | #define MINK_PRIVATE_CASE_TYPE(NAME, enum_type, type, HINT, ...) \ 22 | MINK_PRIVATE_CASE_TYPE_USING_HINT(NAME, enum_type, type, HINT, __VA_ARGS__) 23 | 24 | #define MINK_DISPATCH_INTEGER_TYPES(TYPE, HINT, NAME, ...) \ 25 | [&] { \ 26 | const auto &the_type = TYPE; \ 27 | /* don't use TYPE again in case it is an expensive or side-effect op */ \ 28 | at::ScalarType _it = ::detail::scalar_type(the_type); \ 29 | switch (_it) { \ 30 | MINK_PRIVATE_CASE_TYPE(NAME, at::ScalarType::Int, int32_t, HINT, \ 31 | __VA_ARGS__) \ 32 | MINK_PRIVATE_CASE_TYPE(NAME, at::ScalarType::Long, int64_t, HINT, \ 33 | __VA_ARGS__) \ 34 | default: \ 35 | AT_ERROR(#NAME, " not implemented for '", toString(_it), "'"); \ 36 | } \ 37 | }() 38 | 39 | } // namespace minkowski 40 | -------------------------------------------------------------------------------- /src/errors.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 NVIDIA CORPORATION. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | * 22 | * Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural 23 | * Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part 24 | * of the code. 25 | */ 26 | #ifndef ERRORS_HPP 27 | #define ERRORS_HPP 28 | 29 | #include 30 | 31 | namespace minkowski { 32 | 33 | constexpr char const * const ERROR_MAP_NOT_FOUND = "CoordinateMap not found"; 34 | 35 | constexpr char const * const ERROR_NOT_IMPLEMENTED = "Not implemented"; 36 | 37 | constexpr char const * const ERROR_CPU_ONLY = "Compiled with only CPU backend."; 38 | 39 | } // end minkowski 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /src/gpu.cu: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 NVIDIA CORPORATION. 3 | * Copyright (c) Chris Choy (chrischoy@ai.stanford.edu). 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 | * IN THE SOFTWARE. 22 | * 23 | * Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural 24 | * Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part 25 | * of the code. 26 | */ 27 | #include 28 | #include 29 | #include 30 | 31 | #include "gpu.cuh" 32 | 33 | namespace minkowski { 34 | 35 | const char *cublasGetErrorString(cublasStatus_t error) { 36 | switch (error) { 37 | case CUBLAS_STATUS_SUCCESS: 38 | return "CUBLAS_STATUS_SUCCESS"; 39 | case CUBLAS_STATUS_NOT_INITIALIZED: 40 | return "CUBLAS_STATUS_NOT_INITIALIZED"; 41 | case CUBLAS_STATUS_ALLOC_FAILED: 42 | return "CUBLAS_STATUS_ALLOC_FAILED"; 43 | case CUBLAS_STATUS_INVALID_VALUE: 44 | return "CUBLAS_STATUS_INVALID_VALUE"; 45 | case CUBLAS_STATUS_ARCH_MISMATCH: 46 | return "CUBLAS_STATUS_ARCH_MISMATCH"; 47 | case CUBLAS_STATUS_MAPPING_ERROR: 48 | return "CUBLAS_STATUS_MAPPING_ERROR"; 49 | case CUBLAS_STATUS_EXECUTION_FAILED: 50 | return "CUBLAS_STATUS_EXECUTION_FAILED"; 51 | case CUBLAS_STATUS_INTERNAL_ERROR: 52 | return "CUBLAS_STATUS_INTERNAL_ERROR"; 53 | #if CUDA_VERSION >= 6000 54 | case CUBLAS_STATUS_NOT_SUPPORTED: 55 | return "CUBLAS_STATUS_NOT_SUPPORTED"; 56 | #endif 57 | #if CUDA_VERSION >= 6050 58 | case CUBLAS_STATUS_LICENSE_ERROR: 59 | return "CUBLAS_STATUS_LICENSE_ERROR"; 60 | #endif 61 | } 62 | return "Unknown cublas status"; 63 | } 64 | 65 | const char *cusparseGetErrorString(cusparseStatus_t error) { 66 | // Read more at: http://docs.nvidia.com/cuda/cusparse/index.html#ixzz3f79JxRar 67 | switch (error) { 68 | case CUSPARSE_STATUS_SUCCESS: 69 | return "The operation completed successfully."; 70 | case CUSPARSE_STATUS_NOT_INITIALIZED: 71 | return "CUSPARSE_STATUS_NOT_INITIALIZED"; 72 | 73 | case CUSPARSE_STATUS_ALLOC_FAILED: 74 | return "CUSPARSE_STATUS_ALLOC_FAILED"; 75 | 76 | case CUSPARSE_STATUS_INVALID_VALUE: 77 | return "CUSPARSE_STATUS_INVALID_VALUE"; 78 | 79 | case CUSPARSE_STATUS_ARCH_MISMATCH: 80 | return "CUSPARSE_STATUS_ARCH_MISMATCH"; 81 | 82 | case CUSPARSE_STATUS_MAPPING_ERROR: 83 | return "CUSPARSE_STATUS_MAPPING_ERROR"; 84 | 85 | case CUSPARSE_STATUS_EXECUTION_FAILED: 86 | return "CUSPARSE_STATUS_EXECUTION_FAILED"; 87 | 88 | case CUSPARSE_STATUS_INTERNAL_ERROR: 89 | return "CUSPARSE_STATUS_INTERNAL_ERROR"; 90 | 91 | case CUSPARSE_STATUS_MATRIX_TYPE_NOT_SUPPORTED: 92 | return "CUSPARSE_STATUS_MATRIX_TYPE_NOT_SUPPORTED"; 93 | } 94 | 95 | return ""; 96 | } 97 | 98 | cusparseHandle_t getCurrentCUDASparseHandle() { 99 | cusparseHandle_t handle; 100 | CUSPARSE_CHECK(cusparseCreate(&handle)); 101 | return handle; 102 | } 103 | 104 | static std::string format_size(uint64_t size) { 105 | std::ostringstream os; 106 | os.precision(2); 107 | os << std::fixed; 108 | if (size <= 1024) { 109 | os << size << " bytes"; 110 | } else if (size <= 1048576) { 111 | os << (size / 1024.0); 112 | os << " KiB"; 113 | } else if (size <= 1073741824ULL) { 114 | os << size / 1048576.0; 115 | os << " MiB"; 116 | } else { 117 | os << size / 1073741824.0; 118 | os << " GiB"; 119 | } 120 | return os.str(); 121 | } 122 | 123 | std::pair get_memory_info() { 124 | size_t device_free; 125 | size_t device_total; 126 | CUDA_CHECK(cudaMemGetInfo(&device_free, &device_total)); 127 | return std::make_pair(device_total, device_free); 128 | } 129 | 130 | } // end namespace minkowski 131 | -------------------------------------------------------------------------------- /src/kernel_map.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 NVIDIA Corporation. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | * 22 | * Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural 23 | * Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part 24 | * of the code. 25 | */ 26 | #ifndef KERNEL_MAP_HPP 27 | #define KERNEL_MAP_HPP 28 | 29 | #include "types.hpp" 30 | 31 | #include 32 | #include 33 | #include 34 | 35 | namespace minkowski { 36 | 37 | /* 38 | * Kernel map specific types 39 | */ 40 | using cpu_in_map = default_types::index_vector_type; 41 | using cpu_out_map = default_types::index_vector_type; 42 | 43 | // Input index to output index mapping for each spatial kernel 44 | using cpu_in_maps = std::vector; 45 | using cpu_out_maps = std::vector; 46 | struct cpu_kernel_map : std::pair { 47 | using index_type = default_types::index_type; 48 | using index_pair = 49 | std::pair; 50 | 51 | cpu_kernel_map() : std::pair() {} 52 | cpu_kernel_map(std::pair const &other) 53 | : std::pair(other) {} 54 | 55 | // origin map initialization. 56 | cpu_kernel_map(std::vector &in_out, 57 | std::vector const 58 | &unique_batch_indicies) { 59 | auto comp = [](std::pair const &l, 60 | std::pair const &r) { 61 | return l.second < r.second; 62 | }; 63 | std::sort(in_out.begin(), in_out.end(), comp); 64 | 65 | auto const kernel_volume = unique_batch_indicies.size(); 66 | this->first.resize(kernel_volume); 67 | this->second.resize(kernel_volume); 68 | 69 | for (index_type k = 0; k < unique_batch_indicies.size(); ++k) { 70 | auto const lb = std::lower_bound(in_out.begin(), in_out.end(), 71 | index_pair{0, k}, comp); 72 | auto const ub = std::upper_bound(in_out.begin(), in_out.end(), 73 | index_pair{0, k}, comp); 74 | auto const curr_size = ub - lb; 75 | default_types::index_type start_index = lb - in_out.begin(); 76 | LOG_DEBUG("batch row_index:", k, "curr_size:", curr_size, 77 | "start_index:", start_index); 78 | // resize 79 | auto &in_map = this->first[k]; 80 | auto &out_map = this->second[k]; 81 | in_map.resize(curr_size); 82 | out_map.resize(curr_size); 83 | // copy 84 | for (uint32_t i = 0; i < curr_size; ++i) { 85 | auto const &curr_pair = in_out[i + start_index]; 86 | in_map[i] = curr_pair.first; 87 | out_map[i] = curr_pair.second; 88 | } 89 | } 90 | } 91 | 92 | friend std::ostream &operator<<(std::ostream &out, 93 | cpu_kernel_map const &kernel_map) { 94 | uint32_t map_size = 0; 95 | for (auto const &v : kernel_map.first) { 96 | map_size += v.size(); 97 | } 98 | out << "cpu_kernel_map: number of unique maps:" << kernel_map.first.size() 99 | << ", kernel map size:" << map_size; 100 | return out; 101 | } 102 | }; 103 | 104 | using cpu_kernel_map_reference = std::pair; 105 | 106 | } // namespace minkowski 107 | 108 | #endif 109 | -------------------------------------------------------------------------------- /src/math_functions.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 NVIDIA Corporation. 3 | * Copyright (c) Chris Choy (chrischoy@ai.stanford.edu). 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 | * IN THE SOFTWARE. 22 | * 23 | * Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural 24 | * Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part 25 | * of the code. 26 | */ 27 | #ifndef MATH_FUNCTIONS_HPP 28 | #define MATH_FUNCTIONS_HPP 29 | 30 | #include "mkl_alternate.hpp" 31 | 32 | namespace minkowski { 33 | 34 | template 35 | void cpu_gemm(const CBLAS_ORDER Layout, const CBLAS_TRANSPOSE TransA, 36 | const CBLAS_TRANSPOSE TransB, const int M, const int N, 37 | const int K, const Dtype alpha, const Dtype *A, const Dtype *B, 38 | const Dtype beta, Dtype *C); 39 | 40 | template 41 | void cpu_add(const int N, const Dtype *a, const Dtype *b, Dtype *y); 42 | 43 | template 44 | void cpu_mul(const int N, const Dtype *a, const Dtype *b, Dtype *y); 45 | 46 | template 47 | void cpu_div(const int N, const Dtype *a, const Dtype *b, Dtype *y); 48 | 49 | template 50 | void cpu_axpy(const int N, const Dtype alpha, const Dtype *X, Dtype *Y); 51 | 52 | } // end namespace minkowski 53 | 54 | #endif // MATH_FUNCTIONS 55 | -------------------------------------------------------------------------------- /src/math_functions_cpu.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Chris Choy (chrischoy@ai.stanford.edu). 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in 11 | * all copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | * IN THE SOFTWARE. 20 | * 21 | * Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural 22 | * Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part 23 | * of the code. 24 | */ 25 | #include "math_functions.hpp" 26 | 27 | namespace minkowski { 28 | 29 | template <> 30 | void cpu_gemm(const CBLAS_ORDER Layout, const CBLAS_TRANSPOSE TransA, 31 | const CBLAS_TRANSPOSE TransB, const int M, const int N, 32 | const int K, const float alpha, const float *A, 33 | const float *B, const float beta, float *C) { 34 | int lda, ldb, ldc; 35 | if (Layout == CblasRowMajor) { 36 | lda = (TransA == CblasNoTrans) ? K : M; 37 | ldb = (TransB == CblasNoTrans) ? N : K; 38 | ldc = N; 39 | } else { 40 | lda = (TransA == CblasNoTrans) ? M : K; 41 | ldb = (TransB == CblasNoTrans) ? K : N; 42 | ldc = M; 43 | } 44 | cblas_sgemm(Layout, TransA, TransB, M, N, K, alpha, A, lda, B, ldb, beta, C, 45 | ldc); 46 | } 47 | 48 | template <> 49 | void cpu_gemm(const CBLAS_ORDER Layout, const CBLAS_TRANSPOSE TransA, 50 | const CBLAS_TRANSPOSE TransB, const int M, const int N, 51 | const int K, const double alpha, const double *A, 52 | const double *B, const double beta, double *C) { 53 | int lda, ldb, ldc; 54 | if (Layout == CblasRowMajor) { 55 | lda = (TransA == CblasNoTrans) ? K : M; 56 | ldb = (TransB == CblasNoTrans) ? N : K; 57 | ldc = N; 58 | } else { 59 | lda = (TransA == CblasNoTrans) ? M : K; 60 | ldb = (TransB == CblasNoTrans) ? K : N; 61 | ldc = M; 62 | } 63 | cblas_dgemm(Layout, TransA, TransB, M, N, K, alpha, A, lda, B, ldb, beta, C, 64 | ldc); 65 | } 66 | 67 | template <> 68 | void cpu_add(const int n, const float *a, const float *b, float *y) { 69 | vsAdd(n, a, b, y); 70 | } 71 | 72 | template <> 73 | void cpu_add(const int n, const double *a, const double *b, double *y) { 74 | vdAdd(n, a, b, y); 75 | } 76 | 77 | template <> 78 | void cpu_mul(const int n, const float *a, const float *b, float *y) { 79 | vsMul(n, a, b, y); 80 | } 81 | 82 | template <> 83 | void cpu_mul(const int n, const double *a, const double *b, double *y) { 84 | vdMul(n, a, b, y); 85 | } 86 | 87 | template <> 88 | void cpu_div(const int n, const float *a, const float *b, float *y) { 89 | vsDiv(n, a, b, y); 90 | } 91 | 92 | template <> 93 | void cpu_div(const int n, const double *a, const double *b, double *y) { 94 | vdMul(n, a, b, y); 95 | } 96 | 97 | template <> 98 | void cpu_axpy(const int N, const float alpha, const float *X, float *Y) { 99 | cblas_saxpy(N, alpha, X, 1, Y, 1); 100 | } 101 | 102 | template <> 103 | void cpu_axpy(const int N, const double alpha, const double *X, 104 | double *Y) { 105 | cblas_daxpy(N, alpha, X, 1, Y, 1); 106 | } 107 | 108 | } // end namespace minkowski 109 | -------------------------------------------------------------------------------- /src/mkl_alternate.hpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Chris Choy (chrischoy@ai.stanford.edu). 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | * this software and associated documentation files (the "Software"), to deal in 5 | * the Software without restriction, including without limitation the rights to 6 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | * of the Software, and to permit persons to whom the Software is furnished to do 8 | * so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all 11 | * copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | * SOFTWARE. 20 | * 21 | * Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural 22 | * Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part 23 | * of the code. 24 | */ 25 | #ifndef MKL_ALTERNATE_H_ 26 | #define MKL_ALTERNATE_H_ 27 | 28 | #ifdef USE_MKL 29 | 30 | #include 31 | 32 | #else // If use MKL, simply include the MKL header 33 | 34 | extern "C" { 35 | #include 36 | } 37 | #include 38 | 39 | 40 | // A simple way to define the vsl binary functions. The operation should 41 | // be in the form e.g. y[i] = a[i] + b[i] 42 | #define DEFINE_VSL_BINARY_FUNC(name, operation) \ 43 | template \ 44 | void v##name(const int n, const Dtype* a, const Dtype* b, Dtype* y) { \ 45 | for (int i = 0; i < n; ++i) { operation; } \ 46 | } \ 47 | inline void vs##name( \ 48 | const int n, const float* a, const float* b, float* y) { \ 49 | v##name(n, a, b, y); \ 50 | } \ 51 | inline void vd##name( \ 52 | const int n, const double* a, const double* b, double* y) { \ 53 | v##name(n, a, b, y); \ 54 | } 55 | 56 | DEFINE_VSL_BINARY_FUNC(Add, y[i] = a[i] + b[i]) 57 | DEFINE_VSL_BINARY_FUNC(Sub, y[i] = a[i] - b[i]) 58 | DEFINE_VSL_BINARY_FUNC(Mul, y[i] = a[i] * b[i]) 59 | DEFINE_VSL_BINARY_FUNC(Div, y[i] = a[i] / b[i]) 60 | 61 | #endif // USE_MKL 62 | #endif // MKL_ALTERNATE_H_ 63 | -------------------------------------------------------------------------------- /src/pooling_avg_kernel.cuh: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 NVIDIA Corporation. 3 | * Copyright (c) 2018-2020 Chris Choy (chrischoy@ai.stanford.edu). 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 | * IN THE SOFTWARE. 22 | * 23 | * Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural 24 | * Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part 25 | * of the code. 26 | */ 27 | #ifndef POOLING_AVG_CUH 28 | #define POOLING_AVG_CUH 29 | 30 | #include 31 | #include 32 | 33 | #include "gpu.cuh" 34 | #include "kernel_map.cuh" 35 | #include "math_functions.cuh" 36 | #include "types.hpp" 37 | 38 | namespace minkowski { 39 | 40 | template 41 | void NonzeroAvgPoolingForwardKernelGPU( 42 | Dtype const *d_in_feat, // 43 | default_types::size_type const in_nrows, // 44 | Dtype *d_out_feat, // 45 | default_types::size_type const out_nrows, // 46 | Dtype *d_num_nonzero, // 47 | default_types::size_type const nchannel, // 48 | gpu_kernel_map const &kernel_map, // 49 | bool const use_avg, 50 | ByteAllocator &allocator, // 51 | cusparseHandle_t cushandle, cudaStream_t stream); 52 | 53 | template 54 | void NonzeroAvgPoolingBackwardKernelGPU( 55 | Dtype *d_grad_in_feat, // 56 | default_types::size_type const in_nrows, // 57 | Dtype const *d_grad_out_feat, // 58 | default_types::size_type const out_nrows, // 59 | Dtype const *d_num_nonzero, // 60 | default_types::size_type const nchannel, // 61 | gpu_kernel_map const &kernel_map, bool const use_avg, 62 | cudaStream_t stream); 63 | 64 | } // end namespace minkowski 65 | 66 | #endif // POOLING_AVG_CUH 67 | -------------------------------------------------------------------------------- /src/pooling_max_kernel.cuh: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Chris Choy (chrischoy@ai.stanford.edu). 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in 11 | * all copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | * IN THE SOFTWARE. 20 | * 21 | * Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural 22 | * Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part 23 | * of the code. 24 | */ 25 | #ifndef POOLING_MAX_CUH 26 | #define POOLING_MAX_CUH 27 | 28 | #include 29 | #include 30 | 31 | #include "allocators.cuh" 32 | #include "gpu.cuh" 33 | #include "kernel_map.cuh" 34 | #include "math_functions.cuh" 35 | #include "types.hpp" 36 | 37 | namespace minkowski { 38 | 39 | template 40 | void max_pool_forward_pointer_kernel_gpu( 41 | MapItype *d_in_map, // this will be sorted 42 | MapItype *d_out_map, // this will be sorted 43 | size_t const nmap, // map size 44 | Dtype const *d_in_feat, // 45 | Dtype *d_out_feat, // 46 | size_t const out_nrows, // 47 | size_t const nchannel, // 48 | MaskItype *d_max_index, // 49 | bool const is_sorted // 50 | ); 51 | 52 | template 53 | void MaxPoolingForwardKernelGPU( 54 | const Dtype *d_in_feat, Dtype *d_out_feat, size_t const out_nrows, 55 | int *d_max_index, size_t const nchannel, 56 | gpu_kernel_map const &kernel_map, 57 | ByteAllocator &allocator, cudaStream_t stream); 58 | 59 | template 60 | void MaxPoolingBackwardKernelGPU(Dtype *d_grad_in_feat, size_t const in_nrows, 61 | const Dtype *d_grad_out_feat, 62 | size_t const out_nrows, 63 | const MaskItype *d_max_index, 64 | size_t const nchannel); 65 | 66 | } // end namespace minkowski 67 | 68 | #endif // end POOLING_MAX_CUH 69 | -------------------------------------------------------------------------------- /src/pruning.hpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Chris Choy (chrischoy@ai.stanford.edu). 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in 11 | * all copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | * IN THE SOFTWARE. 20 | * 21 | * Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural 22 | * Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part 23 | * of the code. 24 | */ 25 | #ifndef CPU_PRUNING 26 | #define CPU_PRUNING 27 | 28 | #include "types.hpp" 29 | 30 | namespace minkowski { 31 | 32 | template 33 | void PruningForwardKernelCPU(const Dtype *p_in_feat, Dtype *p_out_feat, 34 | int const nchannel, const cpu_in_maps &in_maps, 35 | const cpu_out_maps &out_maps) { 36 | const Dtype *p_curr_in; 37 | Dtype *p_curr_out; 38 | auto const &in_map = in_maps[0]; 39 | auto const &out_map = out_maps[0]; 40 | // Iterate through each spatial kernel out of filter_volume spatial kernels 41 | for (uint32_t row = 0; row < in_map.size(); row++) { 42 | // Define current pointers 43 | p_curr_in = p_in_feat + in_map[row] * nchannel; 44 | p_curr_out = p_out_feat + out_map[row] * nchannel; 45 | std::memcpy(p_curr_out, p_curr_in, nchannel * sizeof(Dtype)); 46 | } 47 | } 48 | 49 | template 50 | void PruningBackwardKernelCPU(Dtype *p_grad_in_feat, 51 | const Dtype *p_grad_out_feat, int const nchannel, 52 | const cpu_in_maps &in_maps, 53 | const cpu_out_maps &out_maps) { 54 | Dtype *p_curr_grad_in; 55 | const Dtype *p_curr_grad_out; 56 | auto const &in_map = in_maps[0]; 57 | auto const &out_map = out_maps[0]; 58 | 59 | for (uint32_t row = 0; row < in_map.size(); row++) { 60 | // Define current pointers 61 | p_curr_grad_in = p_grad_in_feat + in_map[row] * nchannel; 62 | p_curr_grad_out = p_grad_out_feat + out_map[row] * nchannel; 63 | std::memcpy(p_curr_grad_in, p_curr_grad_out, nchannel * sizeof(Dtype)); 64 | } 65 | } 66 | 67 | } // end namespace minkowski 68 | 69 | #endif // CPU_PRUNING 70 | -------------------------------------------------------------------------------- /src/sharedmem.cuh: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1993-2014 NVIDIA Corporation. All rights reserved. 3 | * 4 | * Please refer to the NVIDIA end user license agreement (EULA) associated 5 | * with this source code for terms and conditions that govern your use of 6 | * this software. Any use, reproduction, disclosure, or distribution of 7 | * this software and related documentation outside the terms of the EULA 8 | * is strictly prohibited. 9 | * 10 | */ 11 | 12 | #ifndef _SHAREDMEM_H_ 13 | #define _SHAREDMEM_H_ 14 | 15 | //**************************************************************************** 16 | // Because dynamically sized shared memory arrays are declared "extern", 17 | // we can't templatize them directly. To get around this, we declare a 18 | // simple wrapper struct that will declare the extern array with a different 19 | // name depending on the type. This avoids compiler errors about duplicate 20 | // definitions. 21 | // 22 | // To use dynamically allocated shared memory in a templatized __global__ or 23 | // __device__ function, just replace code like this: 24 | // 25 | // 26 | // template 27 | // __global__ void 28 | // foo( T* g_idata, T* g_odata) 29 | // { 30 | // // Shared mem size is determined by the host app at run time 31 | // extern __shared__ T sdata[]; 32 | // ... 33 | // doStuff(sdata); 34 | // ... 35 | // } 36 | // 37 | // With this 38 | // template 39 | // __global__ void 40 | // foo( T* g_idata, T* g_odata) 41 | // { 42 | // // Shared mem size is determined by the host app at run time 43 | // SharedMemory smem; 44 | // T* sdata = smem.getPointer(); 45 | // ... 46 | // doStuff(sdata); 47 | // ... 48 | // } 49 | //**************************************************************************** 50 | 51 | // This is the un-specialized struct. Note that we prevent instantiation of 52 | // this struct by putting an undefined symbol in the function body so it won't 53 | // compile. 54 | template struct SharedMemory { 55 | // Ensure that we won't compile any un-specialized types 56 | __device__ T *getPointer() { 57 | extern __device__ void error(void); 58 | error(); 59 | return NULL; 60 | } 61 | }; 62 | 63 | // Following are the specializations for the following types. 64 | // int, uint, char, uchar, short, ushort, long, ulong, bool, float, and double 65 | // One could also specialize it for user-defined types. 66 | 67 | template <> struct SharedMemory { 68 | __device__ int *getPointer() { 69 | extern __shared__ int s_int[]; 70 | return s_int; 71 | } 72 | }; 73 | 74 | template <> struct SharedMemory { 75 | __device__ unsigned int *getPointer() { 76 | extern __shared__ unsigned int s_uint[]; 77 | return s_uint; 78 | } 79 | }; 80 | 81 | template <> struct SharedMemory { 82 | __device__ char *getPointer() { 83 | extern __shared__ char s_char[]; 84 | return s_char; 85 | } 86 | }; 87 | 88 | template <> struct SharedMemory { 89 | __device__ unsigned char *getPointer() { 90 | extern __shared__ unsigned char s_uchar[]; 91 | return s_uchar; 92 | } 93 | }; 94 | 95 | template <> struct SharedMemory { 96 | __device__ short *getPointer() { 97 | extern __shared__ short s_short[]; 98 | return s_short; 99 | } 100 | }; 101 | 102 | template <> struct SharedMemory { 103 | __device__ unsigned short *getPointer() { 104 | extern __shared__ unsigned short s_ushort[]; 105 | return s_ushort; 106 | } 107 | }; 108 | 109 | template <> struct SharedMemory { 110 | __device__ long *getPointer() { 111 | extern __shared__ long s_long[]; 112 | return s_long; 113 | } 114 | }; 115 | 116 | template <> struct SharedMemory { 117 | __device__ unsigned long *getPointer() { 118 | extern __shared__ unsigned long s_ulong[]; 119 | return s_ulong; 120 | } 121 | }; 122 | 123 | template <> struct SharedMemory { 124 | __device__ bool *getPointer() { 125 | extern __shared__ bool s_bool[]; 126 | return s_bool; 127 | } 128 | }; 129 | 130 | template <> struct SharedMemory { 131 | __device__ float *getPointer() { 132 | extern __shared__ float s_float[]; 133 | return s_float; 134 | } 135 | }; 136 | 137 | template <> struct SharedMemory { 138 | __device__ double *getPointer() { 139 | extern __shared__ double s_double[]; 140 | return s_double; 141 | } 142 | }; 143 | 144 | #endif //_SHAREDMEM_H_ 145 | -------------------------------------------------------------------------------- /src/spmm.cuh: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 NVIDIA Corporation. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | * 22 | * Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural 23 | * Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part 24 | * of the code. 25 | */ 26 | #ifndef SPMM_CUH 27 | #define SPMM_CUH 28 | #include "gpu.cuh" 29 | 30 | #include 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | namespace minkowski { 39 | 40 | template 41 | torch::Tensor coo_spmm(torch::Tensor const &rows, torch::Tensor const &cols, 42 | torch::Tensor const &vals, int64_t const dim_i, 43 | int64_t const dim_j, torch::Tensor const &mat2, 44 | int64_t const spmm_algorithm_id, bool const is_sorted); 45 | 46 | template 47 | std::vector // output, sorted rows, sorted cols, sorted vals. 48 | coo_spmm_average(torch::Tensor const &rows, torch::Tensor const &cols, 49 | int64_t const dim_i, int64_t const dim_j, 50 | torch::Tensor const &mat2, int64_t const spmm_algorithm_id); 51 | } // namespace minkowski 52 | #endif 53 | -------------------------------------------------------------------------------- /tests/cpp/README.md: -------------------------------------------------------------------------------- 1 | # C++ Backend Unit Tests 2 | 3 | ## Installation 4 | 5 | ``` 6 | rm -rf build; CXX=g++; python setup.py install 7 | ``` 8 | 9 | ## Individual Test 10 | 11 | ``` 12 | python -m unittest 13 | python -m unittest --nodebug # to remove deub flags 14 | ``` 15 | 16 | e.g. 17 | 18 | ``` 19 | python -m unittest coordinate_map_key_test 20 | ``` 21 | -------------------------------------------------------------------------------- /tests/cpp/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NVIDIA/MinkowskiEngine/02fc608bea4c0549b0a7b00ca1bf15dee4a0b228/tests/cpp/__init__.py -------------------------------------------------------------------------------- /tests/cpp/convolution_cpu.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import unittest 3 | import time 4 | 5 | import torch 6 | import MinkowskiEngineTest._C as _C 7 | 8 | from utils import load_file, batched_coordinates 9 | 10 | 11 | class ConvolutionTestCase(unittest.TestCase): 12 | def test_stride(self): 13 | coordinates = torch.IntTensor([[0, 1], [1, 2], [2, 3], [2, 3]]) 14 | key, manager, map_inverse_map = _C.coordinate_map_manager_test(coordinates, "") 15 | unique_map, inverse_map = map_inverse_map 16 | stride = [2] 17 | key = _C.coordinate_map_manager_stride(manager, key, stride) 18 | print(key) 19 | 20 | def test_pcd(self): 21 | coords, colors, pcd = load_file("1.ply") 22 | kernel_size = torch.IntTensor([3, 3, 3]) 23 | for batch_size in [1, 5, 10, 20, 40]: 24 | for voxel_size in [0.05, 0.035, 0.02]: 25 | min_time = 100000 26 | dcoords = torch.from_numpy(np.floor(coords / voxel_size)).int() 27 | bcoords = batched_coordinates([dcoords for i in range(batch_size)]) 28 | for i in range(10): 29 | kernel_map, num, t = MinkowskiEngineTest._C.kernel_map_test( 30 | bcoords, bcoords, kernel_size 31 | ) 32 | min_time = min(t, min_time) 33 | 34 | num_kernels = np.sum([len(a) for a in kernel_map[0]]) 35 | print(f"{batch_size}\t{voxel_size}\t{num}\t{num_kernels}\t{min_time}") 36 | -------------------------------------------------------------------------------- /tests/cpp/coordinate_map_key_test.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2020 NVIDIA CORPORATION. 2 | * Copyright (c) 2018-2020 Chris Choy (chrischoy@ai.stanford.edu) 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | * 22 | * Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural 23 | * Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part 24 | * of the code. 25 | */ 26 | #include "coordinate_map_key.hpp" 27 | 28 | #include 29 | #include 30 | 31 | namespace minkowski { 32 | 33 | void coordinate_map_key_test() { 34 | // Check basic type compilation 35 | CoordinateMapKey key{3}; 36 | CoordinateMapKey key2{default_types::stride_type{2, 3, 4}}; 37 | } 38 | 39 | py::object coordinate_map_key_return(default_types::stride_type tensor_stride, 40 | std::string string_id) { 41 | return py::cast(new CoordinateMapKey(tensor_stride, string_id)); 42 | } 43 | 44 | void coordinate_map_key_update(CoordinateMapKey *map_key, 45 | default_types::stride_type tensor_stride, 46 | std::string string_id) { 47 | map_key->set_key(tensor_stride, string_id); 48 | } 49 | 50 | } // namespace minkowski 51 | 52 | PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { 53 | py::class_(m, "CoordinateMapKey") 54 | .def(py::init()) 55 | .def(py::init()) 56 | .def("__repr__", &minkowski::CoordinateMapKey::to_string) 57 | .def("get_coordinate_size", 58 | &minkowski::CoordinateMapKey::get_coordinate_size) 59 | .def("get_key", &minkowski::CoordinateMapKey::get_key) 60 | .def("set_key", (void (minkowski::CoordinateMapKey::*)( 61 | minkowski::default_types::stride_type, std::string)) & 62 | minkowski::CoordinateMapKey::set_key) 63 | .def("get_tensor_stride", 64 | &minkowski::CoordinateMapKey::get_tensor_stride); 65 | 66 | m.def("coordinate_map_key_return", &minkowski::coordinate_map_key_return, 67 | "Minkowski Engine coordinate map key return test"); 68 | 69 | m.def("coordinate_map_key_test", &minkowski::coordinate_map_key_test, 70 | "Minkowski Engine coordinate map key test"); 71 | 72 | m.def("coordinate_map_key_update", &minkowski::coordinate_map_key_update, 73 | "Minkowski Engine coordinate map key update test"); 74 | } 75 | -------------------------------------------------------------------------------- /tests/cpp/coordinate_map_key_test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import torch 3 | import MinkowskiEngineTest._C 4 | 5 | 6 | class CoordinateMapKeyTestCase(unittest.TestCase): 7 | def test(self): 8 | MinkowskiEngineTest._C.coordinate_map_key_test() 9 | key = MinkowskiEngineTest._C.CoordinateMapKey([3, 4, 5], "") 10 | print(key.__repr__()) 11 | self.assertEqual([3, 4, 5], key.get_tensor_stride()) 12 | self.assertEqual(4, key.get_coordinate_size()) 13 | self.assertEqual(([3, 4, 5], ''), key.get_key()) 14 | 15 | def test(self): 16 | MinkowskiEngineTest._C.coordinate_map_key_test() 17 | key = MinkowskiEngineTest._C.CoordinateMapKey(3) 18 | print(key.__repr__()) 19 | MinkowskiEngineTest._C.coordinate_map_key_update(key, [2, 3], "test") 20 | print(key.__repr__()) 21 | self.assertEqual(([2, 3], "test"), key.get_key()) 22 | with self.assertRaises(RuntimeError): 23 | MinkowskiEngineTest._C.coordinate_map_key_update(key, [2, 3, 4], "") 24 | -------------------------------------------------------------------------------- /tests/cpp/coordinate_map_manager_cpu_test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import torch 3 | import MinkowskiEngineTest._C as _C 4 | 5 | 6 | class CoordinateMapManagerTestCase(unittest.TestCase): 7 | def test(self): 8 | coordinates = torch.IntTensor([[0, 1], [1, 2], [2, 3], [2, 3]]) 9 | key, manager, map_inverse_map = _C.coordinate_map_manager_test(coordinates, "") 10 | unique_map, inverse_map = map_inverse_map 11 | self.assertTrue( 12 | torch.all(coordinates[unique_map.long()][inverse_map.long()] == coordinates) 13 | ) 14 | 15 | def test_stride(self): 16 | coordinates = torch.IntTensor([[0, 1], [1, 2], [2, 3], [2, 3]]) 17 | key, manager, map_inverse_map = _C.coordinate_map_manager_test(coordinates, "") 18 | unique_map, inverse_map = map_inverse_map 19 | stride = [2] 20 | key = _C.coordinate_map_manager_stride(manager, key, stride) 21 | print(key) 22 | 23 | def test_kernel_map(self): 24 | coordinates = torch.IntTensor([[0, 1], [0, 2], [1, 2], [1, 3]]) 25 | manager = _C.CoordinateMapManager() 26 | key, (unique_map, inverse_map) = manager.insert_and_map(coordinates, [1], "1") 27 | key2, (unique_map2, inverse_map2) = manager.insert_and_map( 28 | coordinates, [1], "2" 29 | ) 30 | print(key, key2) 31 | self.assertTrue( 32 | torch.all(coordinates[unique_map.long()][inverse_map.long()] == coordinates) 33 | ) 34 | in_maps, out_maps = _C.coordinate_map_manager_kernel_map( 35 | manager, key, key2, [3] 36 | ) 37 | 38 | print(in_maps) 39 | print(out_maps) 40 | -------------------------------------------------------------------------------- /tests/cpp/coordinate_map_manager_gpu_test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import torch 3 | import MinkowskiEngineTest._C as _C 4 | 5 | 6 | class CoordinateMapManagerTestCase(unittest.TestCase): 7 | def test(self): 8 | coordinates = torch.IntTensor([[0, 1], [1, 2], [2, 3], [2, 3]]).to(0) 9 | key, manager, map_inverse_map = _C.coordinate_map_manager_test(coordinates, "") 10 | unique_map, inverse_map = map_inverse_map 11 | self.assertTrue( 12 | torch.all(coordinates[unique_map.long()][inverse_map.long()] == coordinates) 13 | ) 14 | 15 | def test_stride(self): 16 | coordinates = torch.IntTensor([[0, 1], [1, 2], [2, 3], [2, 3]]).to(0) 17 | key, manager, map_inverse_map = _C.coordinate_map_manager_test(coordinates, "") 18 | unique_map, inverse_map = map_inverse_map 19 | stride = [2] 20 | key = _C.coordinate_map_manager_stride(manager, key, stride) 21 | print(key) 22 | 23 | def test_collision(self): 24 | coordinates = torch.IntTensor([[0, 1], [0, 1], [1, 2], [1, 2]]).to(0) 25 | manager = _C.CoordinateMapManager() 26 | key, (unique_map, inverse_map) = manager.insert_and_map(coordinates, [1], "1") 27 | key2, (unique_map2, inverse_map2) = manager.insert_and_map( 28 | coordinates, [1], "2" 29 | ) 30 | print(unique_map, inverse_map) 31 | in_maps, out_maps = _C.coordinate_map_manager_kernel_map( 32 | manager, key, key2, [3] 33 | ) 34 | 35 | print(in_maps) 36 | print(out_maps) 37 | 38 | def test_kernel_map(self): 39 | coordinates = torch.IntTensor([[0, 1], [0, 2], [1, 2], [1, 3]]).to(0) 40 | manager = _C.CoordinateMapManager() 41 | key, (unique_map, inverse_map) = manager.insert_and_map(coordinates, [1], "1") 42 | key2, (unique_map2, inverse_map2) = manager.insert_and_map( 43 | coordinates, [1], "2" 44 | ) 45 | print(key, key2) 46 | self.assertTrue( 47 | torch.all(coordinates[unique_map.long()][inverse_map.long()] == coordinates) 48 | ) 49 | in_maps, out_maps = _C.coordinate_map_manager_kernel_map( 50 | manager, key, key2, [3] 51 | ) 52 | 53 | print(in_maps) 54 | print(out_maps) 55 | -------------------------------------------------------------------------------- /tests/cpp/coordinate_test.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2020 NVIDIA CORPORATION. 2 | * Copyright (c) 2018-2020 Chris Choy (chrischoy@ai.stanford.edu) 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | * 22 | * Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural 23 | * Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part 24 | * of the code. 25 | */ 26 | #include "coordinate.hpp" 27 | #include "types.hpp" 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | namespace minkowski { 34 | 35 | using coordinate_type = int32_t; 36 | 37 | uint32_t coordinate_test(const torch::Tensor &coordinates) { 38 | // Create TensorArgs. These record the names and positions of each tensor as a 39 | // parameter. 40 | torch::TensorArg arg_coordinates(coordinates, "coordinates", 0); 41 | 42 | torch::CheckedFrom c = "coordinate_test"; 43 | torch::checkContiguous(c, arg_coordinates); 44 | // must match coordinate_type 45 | torch::checkScalarType(c, arg_coordinates, torch::kInt); 46 | torch::checkBackend(c, arg_coordinates.tensor, torch::Backend::CPU); 47 | torch::checkDim(c, arg_coordinates, 2); 48 | 49 | auto const N = (uint32_t)coordinates.size(0); 50 | auto const D = (uint32_t)coordinates.size(1); 51 | 52 | using map_type = 53 | std::unordered_map, default_types::index_type, 54 | detail::coordinate_murmur3, 55 | detail::coordinate_equal_to>; 56 | 57 | map_type map = map_type{N, detail::coordinate_murmur3{D}, 58 | detail::coordinate_equal_to{D}}; 59 | coordinate_type const * ptr = coordinates.data_ptr(); 60 | for (default_types::index_type i = 0; i < N; i++) { 61 | map[coordinate{ptr + D * i}] = i; 62 | } 63 | 64 | return map.size(); 65 | } 66 | 67 | } // namespace minkowski 68 | 69 | PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { 70 | m.def("coordinate_test", &minkowski::coordinate_test, 71 | "Minkowski Engine coordinate test"); 72 | } 73 | -------------------------------------------------------------------------------- /tests/cpp/coordinate_test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import torch 3 | import MinkowskiEngineTest._C 4 | 5 | 6 | class CoordinateTestCase(unittest.TestCase): 7 | def test_check(self): 8 | coordinates = torch.FloatTensor([2, 3]) 9 | with self.assertRaises(RuntimeError): 10 | MinkowskiEngineTest._C.coordinate_test(coordinates) 11 | 12 | coordinates = torch.IntTensor([2, 3]) 13 | with self.assertRaises(RuntimeError): 14 | MinkowskiEngineTest._C.coordinate_test(coordinates) 15 | 16 | def test(self): 17 | coordinates = torch.IntTensor([[0, 1], [1, 2], [2, 3], [2, 3]]) 18 | self.assertEqual(MinkowskiEngineTest._C.coordinate_test(coordinates), 3) 19 | -------------------------------------------------------------------------------- /tests/cpp/test_all.sh: -------------------------------------------------------------------------------- 1 | export CXX=g++-7; 2 | 3 | rm -rf build; python setup.py install --test=coordinate 4 | python -m unittest coordinate_test 5 | 6 | rm -rf build; python setup.py install --test=coordinate_map_key 7 | python -m unittest coordinate_map_key_test 8 | 9 | rm -rf build; python setup.py install --test=coordinate_map_cpu 10 | python -m unittest coordinate_map_cpu_test 11 | 12 | rm -rf build; python setup.py install --test=coordinate_map_gpu 13 | python -m unittest coordinate_map_gpu_test 14 | 15 | rm -rf build; python setup.py install --test=region_cpu 16 | python -m unittest kernel_region_cpu_test 17 | -------------------------------------------------------------------------------- /tests/cpp/type_test.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2020 NVIDIA Corporation. 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in 11 | * all copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | * IN THE SOFTWARE. 20 | * 21 | * Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural 22 | * Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part 23 | * of the code. 24 | */ 25 | #include "types.hpp" 26 | 27 | #include 28 | 29 | namespace minkowski { 30 | 31 | void type_test() { 32 | // Check basic type compilation 33 | constexpr default_types::tensor_order_type D = 3; 34 | constexpr default_types::dcoordinate_type a = 3; 35 | 36 | const cpuInMap in_map = std::vector{3, 4, 5}; 37 | const cpuOutMap out_map = std::vector{3, 4, 5}; 38 | const cpuInMaps in_maps = {in_map}; 39 | const cpuOutMaps out_maps = {out_map}; 40 | } 41 | 42 | } // namespace minkowski 43 | 44 | PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { 45 | m.def("type_test", &minkowski::type_test, "Minkowski Engine type test"); 46 | } 47 | -------------------------------------------------------------------------------- /tests/cpp/type_test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import torch 3 | import MinkowskiEngineTest._C 4 | 5 | 6 | class TypeTestCase(unittest.TestCase): 7 | 8 | def test(self): 9 | MinkowskiEngineTest._C.type_test() 10 | self.assertErtTrue(True) 11 | -------------------------------------------------------------------------------- /tests/cpp/utils.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020 NVIDIA CORPORATION. 2 | # Copyright (c) 2018-2020 Chris Choy (chrischoy@ai.stanford.edu). 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | # this software and associated documentation files (the "Software"), to deal in 6 | # the Software without restriction, including without limitation the rights to 7 | # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 8 | # of the Software, and to permit persons to whom the Software is furnished to do 9 | # so, subject to the following conditions: 10 | # 11 | # The above copyright notice and this permission notice shall be included in all 12 | # copies or substantial portions of the Software. 13 | # 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | # SOFTWARE. 21 | # 22 | # Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural 23 | # Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part 24 | # of the code. 25 | 26 | import os 27 | import numpy as np 28 | import collections 29 | from urllib.request import urlretrieve 30 | 31 | import torch 32 | 33 | try: 34 | import open3d as o3d 35 | except ImportError: 36 | raise ImportError("Please install open3d with `pip install open3d`.") 37 | 38 | if not os.path.isfile("1.ply"): 39 | urlretrieve("https://bit.ly/3c2iLhg", "1.ply") 40 | 41 | 42 | def load_file(file_name): 43 | pcd = o3d.io.read_point_cloud(file_name) 44 | coords = np.array(pcd.points) 45 | colors = np.array(pcd.colors) 46 | return coords, colors, pcd 47 | 48 | 49 | def batched_coordinates(coords, dtype=torch.int32, device=None): 50 | r"""Create a `ME.SparseTensor` coordinates from a sequence of coordinates 51 | 52 | Given a list of either numpy or pytorch tensor coordinates, return the 53 | batched coordinates suitable for `ME.SparseTensor`. 54 | 55 | Args: 56 | :attr:`coords` (a sequence of `torch.Tensor` or `numpy.ndarray`): a 57 | list of coordinates. 58 | 59 | :attr:`dtype`: torch data type of the return tensor. torch.int32 by default. 60 | 61 | Returns: 62 | :attr:`batched_coordindates` (`torch.Tensor`): a batched coordinates. 63 | 64 | .. warning:: 65 | 66 | From v0.4, the batch index will be prepended before all coordinates. 67 | 68 | """ 69 | assert isinstance( 70 | coords, collections.abc.Sequence 71 | ), "The coordinates must be a sequence." 72 | assert np.array( 73 | [cs.ndim == 2 for cs in coords] 74 | ).all(), "All coordinates must be in a 2D array." 75 | D = np.unique(np.array([cs.shape[1] for cs in coords])) 76 | assert len(D) == 1, f"Dimension of the array mismatch. All dimensions: {D}" 77 | D = D[0] 78 | if device is None: 79 | if isinstance(coords, torch.Tensor): 80 | device = coords[0].device 81 | else: 82 | device = "cpu" 83 | assert dtype in [ 84 | torch.int32, 85 | torch.float32, 86 | ], "Only torch.int32, torch.float32 supported for coordinates." 87 | 88 | # Create a batched coordinates 89 | N = np.array([len(cs) for cs in coords]).sum() 90 | bcoords = torch.zeros((N, D + 1), dtype=dtype, device=device) # uninitialized 91 | 92 | s = 0 93 | for b, cs in enumerate(coords): 94 | if dtype == torch.int32: 95 | if isinstance(cs, np.ndarray): 96 | cs = torch.from_numpy(np.floor(cs)) 97 | elif not ( 98 | isinstance(cs, torch.IntTensor) or isinstance(cs, torch.LongTensor) 99 | ): 100 | cs = cs.floor() 101 | 102 | cs = cs.int() 103 | else: 104 | if isinstance(cs, np.ndarray): 105 | cs = torch.from_numpy(cs) 106 | 107 | cn = len(cs) 108 | # BATCH_FIRST: 109 | bcoords[s : s + cn, 1:] = cs 110 | bcoords[s : s + cn, 0] = b 111 | s += cn 112 | return bcoords -------------------------------------------------------------------------------- /tests/python/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Chris Choy (chrischoy@ai.stanford.edu). 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | # this software and associated documentation files (the "Software"), to deal in 5 | # the Software without restriction, including without limitation the rights to 6 | # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | # of the Software, and to permit persons to whom the Software is furnished to do 8 | # so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in all 11 | # copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | # 21 | # Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural 22 | # Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part 23 | # of the code. 24 | -------------------------------------------------------------------------------- /tests/python/chwise_conv.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Chris Choy (chrischoy@ai.stanford.edu). 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | # this software and associated documentation files (the "Software"), to deal in 5 | # the Software without restriction, including without limitation the rights to 6 | # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | # of the Software, and to permit persons to whom the Software is furnished to do 8 | # so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in all 11 | # copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | # 21 | # Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural 22 | # Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part 23 | # of the code. 24 | import torch 25 | import unittest 26 | 27 | from MinkowskiEngine import SparseTensor, MinkowskiChannelwiseConvolution 28 | import MinkowskiEngine as ME 29 | 30 | 31 | from tests.common import data_loader 32 | 33 | 34 | def get_random_coords(dimension=2, tensor_stride=2): 35 | torch.manual_seed(0) 36 | # Create random coordinates with tensor stride == 2 37 | coords = torch.rand(10, dimension + 1) 38 | coords[:, :dimension] *= 5 # random coords 39 | coords[:, -1] *= 2 # random batch index 40 | coords = coords.floor().int() 41 | coords = ME.utils.sparse_quantize(coords) 42 | coords[:, :dimension] *= tensor_stride # make the tensor stride 2 43 | return coords, tensor_stride 44 | 45 | 46 | class TestConvolution(unittest.TestCase): 47 | 48 | def test(self): 49 | print(f"{self.__class__.__name__}: test") 50 | in_channels, D = 3, 2 51 | coords, feats, labels = data_loader(in_channels, batch_size=2) 52 | 53 | # Create random coordinates with tensor stride == 2 54 | out_coords, tensor_stride = get_random_coords() 55 | 56 | feats = feats.double() 57 | feats.requires_grad_() 58 | input = SparseTensor(feats, coords=coords) 59 | 60 | conv = MinkowskiChannelwiseConvolution( 61 | in_channels, 62 | kernel_size=3, 63 | stride=1, 64 | bias=False, 65 | dimension=D).double() 66 | 67 | print('Initial input: ', input) 68 | output = conv(input) 69 | print('Conv output: ', output) 70 | 71 | output.F.sum().backward() 72 | print(input.F.grad) 73 | 74 | def test_gpu(self): 75 | print(f"{self.__class__.__name__}: test_gpu") 76 | if not torch.cuda.is_available(): 77 | return 78 | 79 | device = torch.device('cuda') 80 | in_channels, D = 3, 2 81 | coords, feats, labels = data_loader(in_channels, batch_size=2) 82 | 83 | # Create random coordinates with tensor stride == 2 84 | out_coords, tensor_stride = get_random_coords() 85 | 86 | feats = feats.double() 87 | feats.requires_grad_() 88 | input = SparseTensor(feats, coords=coords).to(device) 89 | conv = MinkowskiChannelwiseConvolution( 90 | in_channels, 91 | kernel_size=3, 92 | stride=1, 93 | bias=False, 94 | dimension=D).double().to(device) 95 | 96 | print('Initial input: ', input) 97 | output = conv(input) 98 | print('Conv output: ', output) 99 | 100 | 101 | if __name__ == '__main__': 102 | unittest.main() 103 | -------------------------------------------------------------------------------- /tests/python/common.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Chris Choy (chrischoy@ai.stanford.edu). 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | # this software and associated documentation files (the "Software"), to deal in 5 | # the Software without restriction, including without limitation the rights to 6 | # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | # of the Software, and to permit persons to whom the Software is furnished to do 8 | # so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in all 11 | # copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | # 21 | # Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural 22 | # Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part 23 | # of the code. 24 | import os 25 | import numpy as np 26 | 27 | import torch 28 | import MinkowskiEngine as ME 29 | 30 | from urllib.request import urlretrieve 31 | 32 | if not os.path.isfile("1.ply"): 33 | urlretrieve("http://cvgl.stanford.edu/data2/minkowskiengine/1.ply", "1.ply") 34 | 35 | 36 | def load_file(file_name): 37 | try: 38 | import open3d as o3d 39 | except ImportError: 40 | raise ImportError("Please install open3d with `pip install open3d`.") 41 | 42 | pcd = o3d.io.read_point_cloud(file_name) 43 | coords = np.array(pcd.points) 44 | colors = np.array(pcd.colors) 45 | return coords, colors, pcd 46 | 47 | 48 | def get_coords(data): 49 | coords = [] 50 | for i, row in enumerate(data): 51 | for j, col in enumerate(row): 52 | if col != " ": 53 | coords.append([i, j]) 54 | return np.array(coords) 55 | 56 | 57 | def data_loader( 58 | nchannel=3, 59 | max_label=5, 60 | is_classification=True, 61 | seed=-1, 62 | batch_size=2, 63 | dtype=torch.float32, 64 | ): 65 | if seed >= 0: 66 | torch.manual_seed(seed) 67 | 68 | data = [" X ", " X X ", " XXXXX "] 69 | 70 | # Generate coordinates 71 | coords = [get_coords(data) for i in range(batch_size)] 72 | coords = ME.utils.batched_coordinates(coords) 73 | 74 | # features and labels 75 | N = len(coords) 76 | feats = torch.arange(N * nchannel).view(N, nchannel).to(dtype) 77 | label = (torch.rand(batch_size if is_classification else N) * max_label).long() 78 | return coords, feats, label 79 | -------------------------------------------------------------------------------- /tests/python/conv_on_coords.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Chris Choy (chrischoy@ai.stanford.edu). 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | # this software and associated documentation files (the "Software"), to deal in 5 | # the Software without restriction, including without limitation the rights to 6 | # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | # of the Software, and to permit persons to whom the Software is furnished to do 8 | # so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in all 11 | # copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | # 21 | # Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural 22 | # Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part 23 | # of the code. 24 | import torch 25 | import unittest 26 | 27 | from MinkowskiEngine import SparseTensor, MinkowskiConvolution, \ 28 | MinkowskiConvolutionTranspose 29 | import MinkowskiEngine as ME 30 | 31 | 32 | from tests.common import data_loader 33 | 34 | 35 | def get_random_coords(dimension=2, tensor_stride=2): 36 | torch.manual_seed(0) 37 | # Create random coordinates with tensor stride == 2 38 | coords = torch.rand(10, dimension + 1) 39 | coords[:, :dimension] *= 5 # random coords 40 | coords[:, -1] *= 2 # random batch index 41 | coords = coords.floor().int() 42 | coords = ME.utils.sparse_quantize(coords) 43 | coords[:, :dimension] *= tensor_stride # make the tensor stride 2 44 | return coords, tensor_stride 45 | 46 | 47 | class TestConvolution(unittest.TestCase): 48 | 49 | def test(self): 50 | print(f"{self.__class__.__name__}: test") 51 | in_channels, out_channels, D = 2, 3, 2 52 | coords, feats, labels = data_loader(in_channels, batch_size=2) 53 | 54 | # Create random coordinates with tensor stride == 2 55 | out_coords, tensor_stride = get_random_coords() 56 | 57 | feats = feats.double() 58 | feats.requires_grad_() 59 | input = SparseTensor(feats, coords=coords) 60 | cm = input.coords_man 61 | print(cm._get_coords_key(1)) 62 | 63 | conv = MinkowskiConvolution( 64 | in_channels, 65 | out_channels, 66 | kernel_size=3, 67 | stride=1, 68 | bias=False, 69 | dimension=D).double() 70 | 71 | print('Initial input: ', input) 72 | print('Specified output coords: ', out_coords) 73 | output = conv(input, out_coords) 74 | 75 | # To specify the tensor stride 76 | out_coords_key = cm.create_coords_key(out_coords, tensor_stride=2) 77 | output = conv(input, out_coords_key) 78 | print('Conv output: ', output) 79 | 80 | output.F.sum().backward() 81 | print(input.F.grad) 82 | 83 | def test_tr(self): 84 | print(f"{self.__class__.__name__}: test_tr") 85 | in_channels, out_channels, D = 2, 3, 2 86 | coords, feats, labels = data_loader(in_channels, batch_size=2) 87 | # tensor stride must be at least 2 for convolution transpose with stride 2 88 | coords[:, :2] *= 2 89 | out_coords = torch.rand(10, 3) 90 | out_coords[:, :2] *= 10 # random coords 91 | out_coords[:, 2] *= 2 # random batch index 92 | out_coords = out_coords.floor().int() 93 | 94 | feats = feats.double() 95 | feats.requires_grad_() 96 | 97 | input = SparseTensor(feats, coords=coords, tensor_stride=2) 98 | cm = input.coords_man 99 | print(cm._get_coords_key(2)) 100 | 101 | conv_tr = MinkowskiConvolutionTranspose( 102 | in_channels, 103 | out_channels, 104 | kernel_size=3, 105 | stride=2, 106 | bias=False, 107 | dimension=D).double() 108 | print('Initial input: ', input) 109 | print('Specified output coords: ', out_coords) 110 | output = conv_tr(input, out_coords) 111 | print('Conv output: ', output) 112 | 113 | output.F.sum().backward() 114 | print(input.F.grad) 115 | 116 | 117 | if __name__ == '__main__': 118 | unittest.main() 119 | -------------------------------------------------------------------------------- /tests/python/direct_pool.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021 NVIDIA CORPORATION. 2 | # Copyright (c) 2018-2020 Chris Choy (chrischoy@ai.stanford.edu). 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | # this software and associated documentation files (the "Software"), to deal in 6 | # the Software without restriction, including without limitation the rights to 7 | # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 8 | # of the Software, and to permit persons to whom the Software is furnished to do 9 | # so, subject to the following conditions: 10 | # 11 | # The above copyright notice and this permission notice shall be included in all 12 | # copies or substantial portions of the Software. 13 | # 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | # SOFTWARE. 21 | # 22 | # Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural 23 | # Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part 24 | # of the code. 25 | import torch 26 | import unittest 27 | 28 | from MinkowskiEngine import MinkowskiDirectMaxPoolingFunction 29 | 30 | from utils.gradcheck import gradcheck 31 | 32 | 33 | class TestCase(unittest.TestCase): 34 | def test(self): 35 | if not torch.cuda.is_available(): 36 | return 37 | pool = MinkowskiDirectMaxPoolingFunction() 38 | in_map = torch.randint(0, 5, (10,)).int() 39 | out_map = torch.randint(0, 3, (10,)).int() 40 | in_feat = torch.rand(5, 16).double() 41 | in_feat.requires_grad_() 42 | out_nrows = 3 43 | out_feat = pool.apply(in_map, out_map, in_feat, out_nrows) 44 | print(out_feat) 45 | out_feat.sum().backward() 46 | 47 | self.assertTrue( 48 | gradcheck( 49 | pool, 50 | (in_map, out_map, in_feat, out_nrows), 51 | ) 52 | ) 53 | 54 | if not torch.cuda.is_available(): 55 | return 56 | 57 | in_map = in_map.cuda() 58 | out_map = out_map.cuda() 59 | in_feat = in_feat.cuda() 60 | 61 | out_feat = pool.apply(in_map, out_map, in_feat, out_nrows) 62 | print(out_feat) 63 | 64 | self.assertTrue( 65 | gradcheck( 66 | pool, 67 | (in_map, out_map, in_feat, out_nrows), 68 | ) 69 | ) 70 | 71 | def test_long(self): 72 | if not torch.cuda.is_available(): 73 | return 74 | pool = MinkowskiDirectMaxPoolingFunction() 75 | in_map = torch.randint(0, 5, (10,)) 76 | out_map = torch.randint(0, 3, (10,)) 77 | in_feat = torch.rand(5, 16).double() 78 | in_feat.requires_grad_() 79 | out_nrows = 3 80 | out_feat = pool.apply(in_map, out_map, in_feat, out_nrows) 81 | print(out_feat) 82 | out_feat.sum().backward() 83 | 84 | self.assertTrue( 85 | gradcheck( 86 | pool, 87 | (in_map, out_map, in_feat, out_nrows), 88 | ) 89 | ) 90 | 91 | if not torch.cuda.is_available(): 92 | return 93 | 94 | in_map = in_map.cuda() 95 | out_map = out_map.cuda() 96 | in_feat = in_feat.cuda() 97 | 98 | out_feat = pool.apply(in_map, out_map, in_feat, out_nrows) 99 | print(out_feat) 100 | 101 | self.assertTrue( 102 | gradcheck( 103 | pool, 104 | (in_map, out_map, in_feat, out_nrows), 105 | ) 106 | ) 107 | -------------------------------------------------------------------------------- /tests/python/global.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Chris Choy (chrischoy@ai.stanford.edu). 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | # this software and associated documentation files (the "Software"), to deal in 5 | # the Software without restriction, including without limitation the rights to 6 | # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | # of the Software, and to permit persons to whom the Software is furnished to do 8 | # so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in all 11 | # copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | # 21 | # Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural 22 | # Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part 23 | # of the code. 24 | import os 25 | import argparse 26 | import numpy as np 27 | from urllib.request import urlretrieve 28 | try: 29 | import open3d as o3d 30 | except ImportError: 31 | raise ImportError('Please install open3d with `pip install open3d`.') 32 | 33 | import torch 34 | import MinkowskiEngine as ME 35 | from examples.common import Timer 36 | 37 | # Check if the weights and file exist and download 38 | if not os.path.isfile('1.ply'): 39 | print('Downloading a room ply file...') 40 | urlretrieve("http://cvgl.stanford.edu/data2/minkowskiengine/1.ply", '1.ply') 41 | 42 | parser = argparse.ArgumentParser() 43 | parser.add_argument('--file_name', type=str, default='1.ply') 44 | parser.add_argument('--voxel_size', type=float, default=0.02) 45 | parser.add_argument('--batch_size', type=int, default=2) 46 | parser.add_argument('--max_kernel_size', type=int, default=7) 47 | 48 | 49 | def load_file(file_name, voxel_size): 50 | pcd = o3d.io.read_point_cloud(file_name) 51 | coords = np.array(pcd.points) 52 | feats = np.array(pcd.colors) 53 | 54 | quantized_coords = np.floor(coords / voxel_size) 55 | unique_coords, unique_feats = ME.utils.sparse_quantize(quantized_coords, feats) 56 | return unique_coords, unique_feats, pcd 57 | 58 | 59 | def generate_input_sparse_tensor(file_name, voxel_size=0.05, batch_size=1): 60 | # Create a batch, this process is done in a data loader during training in parallel. 61 | batch = [ 62 | load_file(file_name, voxel_size), 63 | ] * batch_size 64 | coordinates_, featrues_, pcds = list(zip(*batch)) 65 | coordinates, features = ME.utils.sparse_collate(coordinates_, featrues_) 66 | 67 | # Normalize features and create a sparse tensor 68 | return features, coordinates 69 | 70 | 71 | if __name__ == '__main__': 72 | config = parser.parse_args() 73 | device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') 74 | 75 | # Define a model and load the weights 76 | feats = [3, 8, 16, 32, 64, 128] 77 | features, coordinates = generate_input_sparse_tensor( 78 | config.file_name, 79 | voxel_size=config.voxel_size, 80 | batch_size=config.batch_size) 81 | pool = ME.MinkowskiGlobalAvgPooling() 82 | 83 | # Measure time 84 | print('Forward') 85 | for feat in feats: 86 | timer = Timer() 87 | features = torch.rand(len(coordinates), feat).to(device) 88 | 89 | # Feed-forward pass and get the prediction 90 | for i in range(20): 91 | sinput = ME.SparseTensor(features, coordinates=coordinates, device=device) 92 | 93 | timer.tic() 94 | soutput = pool(sinput) 95 | timer.toc() 96 | print( 97 | f'{timer.min_time:.12f} for feature size: {feat} with {len(sinput)} voxel' 98 | ) 99 | 100 | print('Backward') 101 | for feat in feats: 102 | timer = Timer() 103 | sinput._F = torch.rand(len(sinput), feat).to(device).requires_grad_() 104 | soutput = pool(sinput) 105 | loss = soutput.F.sum() 106 | # Feed-forward pass and get the prediction 107 | for i in range(20): 108 | timer.tic() 109 | loss.backward() 110 | timer.toc() 111 | print( 112 | f'{timer.min_time:.12f} for feature size {feat} with {len(sinput)} voxel' 113 | ) 114 | -------------------------------------------------------------------------------- /tests/python/kernel_map.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Chris Choy (chrischoy@ai.stanford.edu). 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | # this software and associated documentation files (the "Software"), to deal in 5 | # the Software without restriction, including without limitation the rights to 6 | # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | # of the Software, and to permit persons to whom the Software is furnished to do 8 | # so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in all 11 | # copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | # 21 | # Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural 22 | # Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part 23 | # of the code. 24 | import unittest 25 | 26 | import torch 27 | 28 | from MinkowskiEngine import SparseTensor, MinkowskiConvolution, MinkowskiAlgorithm 29 | 30 | from tests.python.common import data_loader 31 | 32 | 33 | class TestKernelMap(unittest.TestCase): 34 | def test_kernelmap_gpu(self): 35 | print(f"{self.__class__.__name__}: test_kernelmap_gpu") 36 | if not torch.cuda.is_available(): 37 | return 38 | 39 | in_channels, out_channels, D = 2, 3, 2 40 | coords, feats, labels = data_loader(in_channels) 41 | feats = feats.double() 42 | feats.requires_grad_() 43 | input = SparseTensor( 44 | feats, 45 | coordinates=coords, 46 | minkowski_algorithm=MinkowskiAlgorithm.SPEED_OPTIMIZED, 47 | device="cuda", 48 | ) 49 | 50 | # Initialize context 51 | conv = ( 52 | MinkowskiConvolution( 53 | in_channels, 54 | out_channels, 55 | kernel_size=3, 56 | stride=2, 57 | bias=True, 58 | dimension=D, 59 | ) 60 | .double() 61 | .cuda() 62 | ) 63 | output = conv(input) 64 | 65 | iC = input.C.cpu().numpy() 66 | oC = output.C.cpu().numpy() 67 | print(iC) 68 | print(oC) 69 | kernel_maps = output.coordinate_manager.kernel_map( 70 | 1, 71 | 2, 72 | stride=2, 73 | kernel_size=3, 74 | ) 75 | for kernel_index, in_out_map in kernel_maps.items(): 76 | for i, o in zip(in_out_map[0], in_out_map[1]): 77 | print(kernel_index, iC[i], "->", oC[o]) 78 | self.assertTrue(sum(len(in_map[0]) for k, in_map in kernel_maps.items()) == 16) 79 | 80 | def test_kernelmap(self): 81 | print(f"{self.__class__.__name__}: test_kernelmap") 82 | in_channels, out_channels, D = 2, 3, 2 83 | coords, feats, labels = data_loader(in_channels) 84 | feats = feats.double() 85 | feats.requires_grad_() 86 | input = SparseTensor(feats, coordinates=coords) 87 | 88 | # Initialize context 89 | conv = MinkowskiConvolution( 90 | in_channels, 91 | out_channels, 92 | kernel_size=3, 93 | stride=2, 94 | bias=True, 95 | dimension=D, 96 | ).double() 97 | output = conv(input) 98 | 99 | iC = input.C.numpy() 100 | oC = output.C.numpy() 101 | print(iC) 102 | print(oC) 103 | kernel_maps = output.coordinate_manager.kernel_map( 104 | 1, 2, stride=2, kernel_size=3 105 | ) 106 | for kernel_index, in_out_map in kernel_maps.items(): 107 | for i, o in zip(in_out_map[0], in_out_map[1]): 108 | print(kernel_index, iC[i], "->", oC[o]) 109 | self.assertTrue(sum(len(in_map[0]) for k, in_map in kernel_maps.items()) == 16) 110 | -------------------------------------------------------------------------------- /tests/python/norm.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020 NVIDIA CORPORATION. 2 | # Copyright (c) 2018-2020 Chris Choy (chrischoy@ai.stanford.edu). 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | # this software and associated documentation files (the "Software"), to deal in 6 | # the Software without restriction, including without limitation the rights to 7 | # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 8 | # of the Software, and to permit persons to whom the Software is furnished to do 9 | # so, subject to the following conditions: 10 | # 11 | # The above copyright notice and this permission notice shall be included in all 12 | # copies or substantial portions of the Software. 13 | # 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | # SOFTWARE. 21 | # 22 | # Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural 23 | # Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part 24 | # of the code. 25 | import torch 26 | import unittest 27 | 28 | from MinkowskiEngine import ( 29 | SparseTensor, 30 | MinkowskiInstanceNorm, 31 | MinkowskiInstanceNormFunction, 32 | ) 33 | from utils.gradcheck import gradcheck 34 | 35 | from tests.python.common import data_loader 36 | 37 | 38 | class TestNormalization(unittest.TestCase): 39 | def test_inst_norm(self): 40 | in_channels = 2 41 | coords, feats, labels = data_loader(in_channels) 42 | feats = feats.double() 43 | input = SparseTensor(feats, coords) 44 | input.F.requires_grad_() 45 | norm = MinkowskiInstanceNorm(num_features=in_channels).double() 46 | 47 | out = norm(input) 48 | print(out) 49 | 50 | fn = MinkowskiInstanceNormFunction() 51 | self.assertTrue( 52 | gradcheck( 53 | fn, (input.F, input.coordinate_map_key, None, input.coordinate_manager) 54 | ) 55 | ) 56 | 57 | def test_inst_norm_gpu(self): 58 | in_channels = 2 59 | coords, feats, labels = data_loader(in_channels) 60 | feats = feats.double() 61 | 62 | device = torch.device("cuda") 63 | input = SparseTensor(feats, coords, device=device) 64 | input.F.requires_grad_() 65 | norm = MinkowskiInstanceNorm(num_features=in_channels).to(device).double() 66 | 67 | out = norm(input) 68 | print(out) 69 | 70 | fn = MinkowskiInstanceNormFunction() 71 | self.assertTrue( 72 | gradcheck( 73 | fn, (input.F, input.coordinate_map_key, None, input.coordinate_manager) 74 | ) 75 | ) 76 | 77 | 78 | if __name__ == "__main__": 79 | unittest.main() 80 | -------------------------------------------------------------------------------- /tests/python/union.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020 NVIDIA CORPORATION. 2 | # Copyright (c) Chris Choy (chrischoy@ai.stanford.edu). 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | # this software and associated documentation files (the "Software"), to deal in 6 | # the Software without restriction, including without limitation the rights to 7 | # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 8 | # of the Software, and to permit persons to whom the Software is furnished to do 9 | # so, subject to the following conditions: 10 | # 11 | # The above copyright notice and this permission notice shall be included in all 12 | # copies or substantial portions of the Software. 13 | # 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | # SOFTWARE. 21 | # 22 | # Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural 23 | # Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part 24 | # of the code. 25 | import torch 26 | import unittest 27 | 28 | import MinkowskiEngine as ME 29 | from MinkowskiEngine import SparseTensor, MinkowskiUnion 30 | 31 | 32 | class TestUnion(unittest.TestCase): 33 | def test_union(self): 34 | coords1 = torch.IntTensor([[0, 0], [0, 1]]) 35 | coords2 = torch.IntTensor([[0, 1], [1, 1]]) 36 | feats1 = torch.DoubleTensor([[1], [2]]) 37 | feats2 = torch.DoubleTensor([[3], [4]]) 38 | union = MinkowskiUnion() 39 | 40 | input1 = SparseTensor( 41 | coordinates=ME.utils.batched_coordinates([coords1]), features=feats1 42 | ) 43 | 44 | input2 = SparseTensor( 45 | coordinates=ME.utils.batched_coordinates([coords2]), 46 | features=feats2, 47 | coordinate_manager=input1.coordinate_manager, # Must use same coords manager 48 | ) 49 | 50 | input1.requires_grad_() 51 | input2.requires_grad_() 52 | output = union(input1, input2) 53 | print(output) 54 | 55 | self.assertTrue(len(output) == 3) 56 | self.assertTrue(5 in output.F) 57 | output.F.sum().backward() 58 | 59 | # Grad of sum feature is 1. 60 | self.assertTrue(torch.prod(input1.F.grad) == 1) 61 | self.assertTrue(torch.prod(input2.F.grad) == 1) 62 | 63 | def test_union_gpu(self): 64 | device = torch.device("cuda") 65 | 66 | coords1 = torch.IntTensor([[0, 0], [0, 1]]) 67 | coords2 = torch.IntTensor([[0, 1], [1, 1]]) 68 | feats1 = torch.DoubleTensor([[1], [2]]) 69 | feats2 = torch.DoubleTensor([[3], [4]]) 70 | union = MinkowskiUnion() 71 | 72 | input1 = SparseTensor(feats1, coords1, device=device, requires_grad=True) 73 | input2 = SparseTensor( 74 | feats2, 75 | coords2, 76 | device=device, 77 | coordinate_manager=input1.coordinate_manager, 78 | requires_grad=True, 79 | ) 80 | output_gpu = union(input1, input2) 81 | output_gpu.F.sum().backward() 82 | print(output_gpu) 83 | self.assertTrue(len(output_gpu) == 3) 84 | self.assertTrue(1 in output_gpu.F) 85 | self.assertTrue(5 in output_gpu.F) 86 | self.assertTrue(4 in output_gpu.F) 87 | 88 | 89 | if __name__ == "__main__": 90 | unittest.main() 91 | -------------------------------------------------------------------------------- /tests/python/utility_functions.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020 NVIDIA CORPORATION. 2 | # Copyright (c) 2018-2020 Chris Choy (chrischoy@ai.stanford.edu). 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | # this software and associated documentation files (the "Software"), to deal in 6 | # the Software without restriction, including without limitation the rights to 7 | # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 8 | # of the Software, and to permit persons to whom the Software is furnished to do 9 | # so, subject to the following conditions: 10 | # 11 | # The above copyright notice and this permission notice shall be included in all 12 | # copies or substantial portions of the Software. 13 | # 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | # SOFTWARE. 21 | # 22 | # Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural 23 | # Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part 24 | # of the code. 25 | import torch 26 | import unittest 27 | 28 | import MinkowskiEngine as ME 29 | 30 | 31 | class TestUtility(unittest.TestCase): 32 | def test(self): 33 | self.assertTrue(ME.is_cuda_available() == torch.cuda.is_available()) 34 | if ME.is_cuda_available(): 35 | print(ME.cuda_version()) 36 | print(ME.get_gpu_memory_info()) 37 | -------------------------------------------------------------------------------- /tests/run_test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | 4 | if __name__ == '__main__': 5 | unittest.main() 6 | --------------------------------------------------------------------------------