Commit 72d154f4 authored by 牛辰龙's avatar 牛辰龙

init

parents
Pipeline #93 failed with stages
# Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to make participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies within all project spaces, and it also applies when
an individual is representing the project or its community in public spaces.
Examples of representing a project or community include using an official
project e-mail address, posting via an official social media account, or acting
as an appointed representative at an online or offline event. Representation of
a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at <opensource-conduct@fb.com>. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq
# Contributing to PointContrast
We want to make contributing to this project as easy and transparent as
possible.
## Pull Requests
We actively welcome your pull requests.
1. Fork the repo and create your branch from `master`.
2. If you've added code that should be tested, add tests.
3. If you've changed APIs, update the documentation.
4. Ensure the test suite passes.
5. Make sure your code lints.
6. If you haven't already, complete the Contributor License Agreement ("CLA").
## Contributor License Agreement ("CLA")
In order to accept your pull request, we need you to submit a CLA. You only need
to do this once to work on any of Facebook's open source projects.
Complete your CLA here: <https://code.facebook.com/cla>
## Issues
We use GitHub issues to track public bugs. Please ensure your description is
clear and has sufficient instructions to be able to reproduce the issue.
Facebook has a [bounty program](https://www.facebook.com/whitehat/) for the safe
disclosure of security bugs. In those cases, please go through the process
outlined on that page and do not file a public issue.
## License
By contributing to PointContrast, you agree that your contributions will be licensed
under the LICENSE file in the root directory of this source tree.
\ No newline at end of file
MIT License
Copyright (c) Facebook, Inc. and its affiliates.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
\ No newline at end of file
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
- Please complete all sections of this template if applicable. For installation, you must report the environment. Otherwise, your issue will be closed automatically.
************************************************************************************
**To Reproduce**
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.
- a minimally reproducible code.
************************************************************************************
**Expected behavior**
A clear and concise description of what you expected to happen.
************************************************************************************
**Desktop (please complete the following information):**
- OS: [e.g. Ubuntu 18.04]
- Python version: [e.g. 3.8.5]
- Pytorch version: [e.g. 1.7.1]
- CUDA version: [e.g. 11.1]
- NVIDIA Driver version: [e.g. 450.11]
- Minkowski Engine version [e.g. 0.5.0]
- 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.)
```
wget -q https://raw.githubusercontent.com/NVIDIA/MinkowskiEngine/master/MinkowskiEngine/diagnostics.py ; python diagnostics.py
```
************************************************************************************
**Additional context**
Add any other context about the problem here.
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
*.so
*.[o,d,a]
*.swo
*.swp
*.swn
*.pyc
build/
objs/
dist/
MinkowskiEngine.egg-info/
This diff is collapsed.
MIT License
Copyright (c) 2020 NVIDIA CORPORATION.
Copyright (c) 2018-2020 Chris Choy (chrischoy@ai.stanford.edu)
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural
Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part
of the code.
include Makefile
recursive-include src *.hpp *.cpp *.cu *.cuh *.h
recursive-include pybind *.hpp *.cpp
###############################################################################
# Uncomment for debugging
# DEBUG := 1
# Pretty build
Q ?= @
# Uncomment for CPU only build. From the command line, `python setup.py install --cpu_only`
# CPU_ONLY := 1
CXX ?= g++
PYTHON ?= python
EXTENSION_NAME := minkowski
# BLAS choice:
# atlas for ATLAS
# blas for default blas
# mkl for MKL. For conda, conda install -c intel mkl mkl-include
# openblas for OpenBlas (default)
BLAS ?= openblas
CUDA_HOME ?= $(shell $(PYTHON) -c 'from torch.utils.cpp_extension import _find_cuda_home; print(_find_cuda_home())')
# Custom (MKL/ATLAS/OpenBLAS) include and lib directories.
# Leave commented to accept the defaults for your choice of BLAS
# (which should work)!
# BLAS_INCLUDE_DIRS ?=
# BLAS_LIBRARY_DIRS ?=
###############################################################################
# PYTHON Header path
PYTHON_HEADER_DIR := $(shell $(PYTHON) -c 'from distutils.sysconfig import get_python_inc; print(get_python_inc())')
PYTORCH_INCLUDES := $(shell $(PYTHON) -c 'from torch.utils.cpp_extension import include_paths; [print(p) for p in include_paths()]')
PYTORCH_LIBRARIES := $(shell $(PYTHON) -c 'from torch.utils.cpp_extension import library_paths; [print(p) for p in library_paths()]')
# HEADER DIR is in pythonX.Xm folder
INCLUDE_DIRS := $(PYTHON_HEADER_DIR)
INCLUDE_DIRS += $(PYTHON_HEADER_DIR)/..
INCLUDE_DIRS += $(PYTORCH_INCLUDES)
LIBRARY_DIRS := $(PYTORCH_LIBRARIES)
# Determine ABI support
WITH_ABI := $(shell $(PYTHON) -c 'import torch; print(int(torch._C._GLIBCXX_USE_CXX11_ABI))')
# Determine platform
UNAME := $(shell uname -s)
ifeq ($(UNAME), Linux)
LINUX := 1
else ifeq ($(UNAME), Darwin)
OSX := 1
OSX_MAJOR_VERSION := $(shell sw_vers -productVersion | cut -f 1 -d .)
OSX_MINOR_VERSION := $(shell sw_vers -productVersion | cut -f 2 -d .)
CXX := /usr/local/opt/llvm/bin/clang
# brew install llvm libomp
INCLUDE_DIRS += /usr/local/opt/llvm/include
LIBRARY_DIRS += /usr/local/opt/llvm/lib
endif
ifneq ($(CPU_ONLY), 1)
# CUDA ROOT DIR that contains bin/ lib64/ and include/
# CUDA_HOME := /usr/local/cuda
NVCC ?= $(CUDA_HOME)/bin/nvcc
INCLUDE_DIRS += ./ $(CUDA_HOME)/include
LIBRARY_DIRS += $(CUDA_HOME)/lib64
endif
SRC_DIR := ./src
OBJ_DIR := ./objs
CPP_SRCS := $(wildcard $(SRC_DIR)/*.cpp)
CU_SRCS := $(wildcard $(SRC_DIR)/*.cu)
OBJS := $(patsubst $(SRC_DIR)/%.cpp,$(OBJ_DIR)/%.o,$(CPP_SRCS))
CU_OBJS := $(patsubst $(SRC_DIR)/%.cu,$(OBJ_DIR)/cuda/%.o,$(CU_SRCS))
STATIC_LIB := $(OBJ_DIR)/lib$(EXTENSION_NAME).a
# We will also explicitly add stdc++ to the link target.
LIBRARIES := stdc++ c10 caffe2 torch torch_python _C
ifneq ($(CPU_ONLY), 1)
LIBRARIES += cudart cublas cusparse caffe2_gpu c10_cuda
CUDA_ARCH := -gencode arch=compute_30,code=sm_30 \
-gencode arch=compute_35,code=sm_35 \
-gencode=arch=compute_50,code=sm_50 \
-gencode=arch=compute_52,code=sm_52 \
-gencode=arch=compute_60,code=sm_60 \
-gencode=arch=compute_61,code=sm_61 \
-gencode=arch=compute_70,code=sm_70 \
-gencode=arch=compute_75,code=sm_75 \
-gencode=arch=compute_75,code=compute_75
endif
# BLAS configuration: mkl, atlas, open, blas
BLAS ?= openblas
ifeq ($(BLAS), mkl)
# MKL
LIBRARIES += mkl_rt
COMMON_FLAGS += -DUSE_MKL
MKLROOT ?= /opt/intel/mkl
BLAS_INCLUDE_DIRS ?= $(MKLROOT)/include
BLAS_LIBRARY_DIRS ?= $(MKLROOT)/lib $(MKLROOT)/lib/intel64
else ifeq ($(BLAS), openblas)
# OpenBLAS
LIBRARIES += openblas
else ifeq ($(BLAS), blas)
# OpenBLAS
LIBRARIES += blas
else
# ATLAS
LIBRARIES += atlas
ATLAS_PATH := $(shell $(PYTHON) -c "import numpy.distutils.system_info as si; ai = si.atlas_info(); [print(p) for p in ai.get_lib_dirs()]")
BLAS_LIBRARY_DIRS += $(ATLAS_PATH)
endif
INCLUDE_DIRS += ./src/3rdparty
INCLUDE_DIRS += $(BLAS_INCLUDE_DIRS)
LIBRARY_DIRS += $(BLAS_LIBRARY_DIRS)
# Debugging
ifeq ($(DEBUG), 1)
COMMON_FLAGS += -DDEBUG -g -O0
# https://gcoe-dresden.de/reaching-the-shore-with-a-fog-warning-my-eurohack-day-4-morning-session/
NVCCFLAGS := -g -G # -rdc true
else
COMMON_FLAGS += -DNDEBUG -O3
endif
WARNINGS := -Wall -Wcomment -Wno-sign-compare -Wno-deprecated-declarations
# Automatic dependency generation (nvcc is handled separately)
CXXFLAGS += -MMD -MP
# Fast math
CXXFLAGS += -ffast-math -funsafe-math-optimizations -fno-math-errno
# BATCH FIRST
CXXFLAGS += -DBATCH_FIRST=1
# Complete build flags.
COMMON_FLAGS += $(foreach includedir,$(INCLUDE_DIRS),-I$(includedir)) \
-DTORCH_API_INCLUDE_EXTENSION_H -DTORCH_EXTENSION_NAME=$(EXTENSION_NAME) \
-D_GLIBCXX_USE_CXX11_ABI=$(WITH_ABI)
CXXFLAGS += -fopenmp -fPIC -fwrapv -std=c++14 $(COMMON_FLAGS) $(WARNINGS)
NVCCFLAGS += -std=c++14 -ccbin=$(CXX) -Xcompiler -fPIC $(COMMON_FLAGS)
LINKFLAGS += -pthread -fPIC $(WARNINGS) -Wl,-rpath=$(PYTHON_LIB_DIR) -Wl,--no-as-needed -Wl,--sysroot=/
LDFLAGS += $(foreach librarydir,$(LIBRARY_DIRS),-L$(librarydir)) \
$(foreach library,$(LIBRARIES),-l$(library))
ifeq ($(CPU_ONLY), 1)
ALL_OBJS := $(OBJS)
CXXFLAGS += -DCPU_ONLY
else
ALL_OBJS := $(OBJS) $(CU_OBJS)
endif
all: $(STATIC_LIB)
$(RM) -rf build dist
$(OBJ_DIR):
@ mkdir -p $@
@ mkdir -p $@/cuda
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp | $(OBJ_DIR)
@ echo CXX $<
$(Q)$(CXX) $< $(CXXFLAGS) -c -o $@
$(OBJ_DIR)/cuda/%.o: $(SRC_DIR)/%.cu | $(OBJ_DIR)
@ echo NVCC $<
$(Q)$(NVCC) $(NVCCFLAGS) $(CUDA_ARCH) -M $< -o ${@:.o=.d} \
-odir $(@D)
$(Q)$(NVCC) $(NVCCFLAGS) $(CUDA_ARCH) -c $< -o $@
$(STATIC_LIB): $(ALL_OBJS) | $(OBJ_DIR)
$(RM) -f $(STATIC_LIB)
@ echo LD -o $@
ar rc $(STATIC_LIB) $(ALL_OBJS)
clean:
@- $(RM) -rf $(OBJ_DIR) build dist
# Copyright (c) 2020 NVIDIA CORPORATION.
# Copyright (c) 2018-2020 Chris Choy (chrischoy@ai.stanford.edu).
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
# of the Software, and to permit persons to whom the Software is furnished to do
# so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
# Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural
# Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part
# of the code.
from typing import Union
import torch
from torch.nn import Module
from torch.autograd import Function
from MinkowskiEngineBackend._C import CoordinateMapKey, RegionType, BroadcastMode
from MinkowskiSparseTensor import SparseTensor, _get_coordinate_map_key
from MinkowskiCoordinateManager import CoordinateManager
from MinkowskiCommon import (
MinkowskiModuleBase,
get_minkowski_function,
)
class MinkowskiBroadcastFunction(Function):
@staticmethod
def forward(
ctx,
input_features: torch.Tensor,
input_features_global: torch.Tensor,
operation_type: BroadcastMode,
in_coords_key: CoordinateMapKey,
glob_coords_key: CoordinateMapKey,
coords_manager: CoordinateManager,
):
assert isinstance(operation_type, BroadcastMode)
ctx.saved_vars = (
input_features,
input_features_global,
operation_type,
in_coords_key,
glob_coords_key,
coords_manager,
)
fw_fn = get_minkowski_function("BroadcastForward", input_features)
return fw_fn(
input_features,
input_features_global,
operation_type,
in_coords_key,
glob_coords_key,
coords_manager._manager,
)
@staticmethod
def backward(ctx, grad_out_feat):
if not grad_out_feat.is_contiguous():
grad_out_feat = grad_out_feat.contiguous()
(
input_features,
input_features_global,
operation_type,
in_coords_key,
glob_coords_key,
coords_manager,
) = ctx.saved_vars
bw_fn = get_minkowski_function("BroadcastBackward", grad_out_feat)
grad_in_feat, grad_in_feat_glob = bw_fn(
input_features,
input_features_global,
grad_out_feat,
operation_type,
in_coords_key,
glob_coords_key,
coords_manager._manager,
)
return grad_in_feat, grad_in_feat_glob, None, None, None, None
class MinkowskiBroadcastBase(MinkowskiModuleBase):
def __init__(self, operation_type):
MinkowskiModuleBase.__init__(self)
assert isinstance(operation_type, BroadcastMode)
self.operation_type = operation_type
self.broadcast = MinkowskiBroadcastFunction()
def forward(self, input: SparseTensor, input_glob: SparseTensor):
assert isinstance(input, SparseTensor)
output = self.broadcast.apply(
input.F,
input_glob.F,
self.operation_type,
input.coordinate_map_key,
input_glob.coordinate_map_key,
input.coordinate_manager,
)
return SparseTensor(
output,
coordinate_map_key=input.coordinate_map_key,
coordinate_manager=input.coordinate_manager,
)
def __repr__(self):
return self.__class__.__name__
class MinkowskiBroadcastAddition(MinkowskiBroadcastBase):
r"""Broadcast the reduced features to all input coordinates.
.. math::
\mathbf{y}_\mathbf{u} = \mathbf{x}_{1, \mathbf{u}} + \mathbf{x}_2
\; \text{for} \; \mathbf{u} \in \mathcal{C}^\text{in}
For all input :math:`\mathbf{x}_\mathbf{u}`, add :math:`\mathbf{x}_2`. The
output coordinates will be the same as the input coordinates
:math:`\mathcal{C}^\text{in} = \mathcal{C}^\text{out}`.
.. note::
The first argument takes a sparse tensor; the second argument takes
features that are reduced to the origin. This can be typically done with
the global reduction such as the :attr:`MinkowskiGlobalPooling`.
"""
def __init__(self):
MinkowskiBroadcastBase.__init__(self, BroadcastMode.ELEMENTWISE_ADDITON)
class MinkowskiBroadcastMultiplication(MinkowskiBroadcastBase):
r"""Broadcast reduced features to all input coordinates.
.. math::
\mathbf{y}_\mathbf{u} = \mathbf{x}_{1, \mathbf{u}} \times \mathbf{x}_2
\; \text{for} \; \mathbf{u} \in \mathcal{C}^\text{in}
For all input :math:`\mathbf{x}_\mathbf{u}`, multiply :math:`\mathbf{x}_2`
element-wise. The output coordinates will be the same as the input
coordinates :math:`\mathcal{C}^\text{in} = \mathcal{C}^\text{out}`.
.. note::
The first argument takes a sparse tensor; the second argument takes
features that are reduced to the origin. This can be typically done with
the global reduction such as the :attr:`MinkowskiGlobalPooling`.
"""
def __init__(self):
MinkowskiBroadcastBase.__init__(self, BroadcastMode.ELEMENTWISE_MULTIPLICATION)
class MinkowskiBroadcast(Module):
r"""Broadcast reduced features to all input coordinates.
.. math::
\mathbf{y}_\mathbf{u} = \mathbf{x}_2 \; \text{for} \; \mathbf{u} \in
\mathcal{C}^\text{in}
For all input :math:`\mathbf{x}_\mathbf{u}`, copy value :math:`\mathbf{x}_2`
element-wise. The output coordinates will be the same as the input
coordinates :math:`\mathcal{C}^\text{in} = \mathcal{C}^\text{out}`. The
first input :math:`\mathbf{x}_1` is only used for defining the output
coordinates.
.. note::
The first argument takes a sparse tensor; the second argument takes
features that are reduced to the origin. This can be typically done with
the global reduction such as the :attr:`MinkowskiGlobalPooling`.
"""
def __repr__(self):
return self.__class__.__name__
def forward(self, input: SparseTensor, input_glob: SparseTensor):
assert isinstance(input, SparseTensor)
assert isinstance(input_glob, SparseTensor)
broadcast_feat = input.F.new(len(input), input_glob.size()[1])
batch_indices, batch_rows = input.coordinate_manager.origin_map(input.coordinate_map_key)
for b, rows in zip(batch_indices, batch_rows):
broadcast_feat[rows] = input_glob.F[b]
return SparseTensor(
broadcast_feat,
coordinate_map_key=input.coordinate_map_key,
coordinate_manager=input.coordinate_manager,
)
class MinkowskiBroadcastConcatenation(MinkowskiBroadcast):
r"""Broadcast reduced features to all input coordinates and concatenate to the input.
.. math::
\mathbf{y}_\mathbf{u} = [\mathbf{x}_{1,\mathbf{u}}, \mathbf{x}_2] \;
\text{for} \; \mathbf{u} \in \mathcal{C}^\text{in}
For all input :math:`\mathbf{x}_\mathbf{u}`, concatenate vector
:math:`\mathbf{x}_2`. :math:`[\cdot, \cdot]` is a concatenation operator.
The output coordinates will be the same as the input coordinates
:math:`\mathcal{C}^\text{in} = \mathcal{C}^\text{out}`.
.. note::
The first argument takes a sparse tensor; the second argument takes
features that are reduced to the origin. This can be typically done with
the global reduction such as the :attr:`MinkowskiGlobalPooling`.
"""
def forward(self, input: SparseTensor, input_glob: SparseTensor):
assert isinstance(input, SparseTensor)
assert isinstance(input_glob, SparseTensor)
broadcast_feat = input.F.new(len(input), input_glob.size()[1])
batch_indices, batch_rows = input.coordinate_manager.origin_map(input.coordinate_map_key)
for b, row_ind in zip(batch_indices, batch_rows):
broadcast_feat[row_ind] = input_glob.F[b]
broadcast_cat = torch.cat((input.F, broadcast_feat), dim=1)
return SparseTensor(
broadcast_cat,
coordinate_map_key=input.coordinate_map_key,
coordinate_manager=input.coordinate_manager,
)
# Copyright (c) 2020 NVIDIA CORPORATION.
# Copyright (c) 2018-2020 Chris Choy (chrischoy@ai.stanford.edu).
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
# of the Software, and to permit persons to whom the Software is furnished to do
# so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
# Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural
# Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part
# of the code.
import math
from typing import Union
import torch
from torch.nn import Parameter
from MinkowskiSparseTensor import SparseTensor
from MinkowskiEngineBackend._C import CoordinateMapKey, RegionType
from MinkowskiCommon import MinkowskiModuleBase
from MinkowskiKernelGenerator import KernelGenerator
class MinkowskiChannelwiseConvolution(MinkowskiModuleBase):
__slots__ = (
"in_channels",
"out_channels",
"kernel_generator",
"dimension",
"kernel",
"bias",
"conv",
)
r"""Channelwise (Depthwise) Convolution layer for a sparse tensor.
.. math::
\mathbf{x}_\mathbf{u} = \sum_{\mathbf{i} \in \mathcal{N}^D(\mathbf{u}, K) \cap
\mathcal{C}^\text{in}} W_\mathbf{i} \odot \mathbf{x}_{\mathbf{i} +
\mathbf{u}} \;\text{for} \; \mathbf{u} \in \mathcal{C}^\text{out}
where :math:`K` is the kernel size and :math:`\mathcal{N}^D(\mathbf{u}, K)
\cap \mathcal{C}^\text{in}` is the set of offsets that are at most :math:`\left
\lceil{\frac{1}{2}(K - 1)} \right \rceil` away from :math:`\mathbf{u}`
defined in :math:`\mathcal{S}^\text{in}`. :math:`\odot` indicates the
elementwise product.
.. note::
For even :math:`K`, the kernel offset :math:`\mathcal{N}^D`
implementation is different from the above definition. The offsets
range from :math:`\mathbf{i} \in [0, K)^D, \; \mathbf{i} \in
\mathbb{Z}_+^D`.
"""
def __init__(
self,
in_channels,
kernel_size=-1,
stride=1,
dilation=1,
bias=False,
kernel_generator=None,
dimension=-1,
):
r"""convolution on a sparse tensor
Args:
:attr:`in_channels` (int): the number of input channels in the
input tensor.
:attr:`kernel_size` (int, optional): the size of the kernel in the
output tensor. If not provided, :attr:`region_offset` should be
:attr:`RegionType.CUSTOM` and :attr:`region_offset` should be a 2D
matrix with size :math:`N\times D` such that it lists all :math:`N`
offsets in D-dimension.
:attr:`stride` (int, or list, optional): stride size of the
convolution layer. If non-identity is used, the output coordinates
will be at least :attr:`stride` :math:`\times` :attr:`tensor_stride`
away. When a list is given, the length must be D; each element will
be used for stride size for the specific axis.
:attr:`dilation` (int, or list, optional): dilation size for the
convolution kernel. When a list is given, the length must be D and
each element is an axis specific dilation. All elements must be > 0.
:attr:`bias` (bool, optional): if True, the convolution layer
has a bias.
:attr:`kernel_generator` (:attr:`MinkowskiEngine.KernelGenerator`,
optional): defines the custom kernel shape.
:attr:`dimension` (int): the spatial dimension of the space where
all the inputs and the network are defined. For example, images are
in a 2D space, meshes and 3D shapes are in a 3D space.
"""
super(MinkowskiChannelwiseConvolution, self).__init__()
assert (
dimension > 0
), f"Invalid dimension. Please provide a valid dimension argument. dimension={dimension}"
if kernel_generator is None:
kernel_generator = KernelGenerator(
kernel_size=kernel_size,
stride=stride,
dilation=dilation,
dimension=dimension,
)
self.kernel_generator = kernel_generator
self.in_channels = in_channels
self.dimension = dimension
self.kernel_shape = (kernel_generator.kernel_volume, self.in_channels)
Tensor = torch.FloatTensor
self.kernel = Parameter(Tensor(*self.kernel_shape))
self.bias = Parameter(Tensor(1, in_channels)) if bias else None
self.reset_parameters()
def forward(
self,
input: SparseTensor,
coords: Union[torch.IntTensor, CoordinateMapKey, SparseTensor] = None,
):
r"""
:attr:`input` (`MinkowskiEngine.SparseTensor`): Input sparse tensor to apply a
convolution on.
:attr:`coords` ((`torch.IntTensor`, `MinkowskiEngine.CoordinateMapKey`,
`MinkowskiEngine.SparseTensor`), optional): If provided, generate
results on the provided coordinates. None by default.
"""
assert isinstance(input, SparseTensor)
assert input.D == self.dimension
assert (
self.in_channels == input.shape[1]
), f"Channel size mismatch {self.in_channels} != {input.shape[1]}"
# Create a region_offset
region_type_, region_offset_, _ = self.kernel_generator.get_kernel(
input.tensor_stride, False
)
cm = input.coordinate_manager
in_key = input.coordinate_map_key
out_key = cm.stride(in_key, self.kernel_generator.kernel_stride)
N_out = cm.size(out_key)
out_F = input._F.new(N_out, self.in_channels).zero_()
kernel_map = cm.kernel_map(
in_key,
out_key,
self.kernel_generator.kernel_stride,
self.kernel_generator.kernel_size,
self.kernel_generator.kernel_dilation,
region_type=region_type_,
region_offset=region_offset_,
)
for k, in_out in kernel_map.items():
in_out = in_out.long().to(input.device)
out_F[in_out[1]] += input.F[in_out[0]] * self.kernel[k]
if self.bias is not None:
out_F += self.bias
return SparseTensor(out_F, coordinate_map_key=out_key, coordinate_manager=cm)
def reset_parameters(self, is_transpose=False):
with torch.no_grad():
n = (
self.out_channels if is_transpose else self.in_channels
) * self.kernel_generator.kernel_volume
stdv = 1.0 / math.sqrt(n)
self.kernel.data.uniform_(-stdv, stdv)
if self.bias is not None:
self.bias.data.uniform_(-stdv, stdv)
def __repr__(self):
s = "(in={}, region_type={}, ".format(
self.in_channels, self.kernel_generator.region_type
)
if self.kernel_generator.region_type in [RegionType.CUSTOM]:
s += "kernel_volume={}, ".format(self.kernel_generator.kernel_volume)
else:
s += "kernel_size={}, ".format(self.kernel_generator.kernel_size)
s += "stride={}, dilation={})".format(
self.kernel_generator.kernel_stride,
self.kernel_generator.kernel_dilation,
)
return self.__class__.__name__ + s
# Copyright (c) 2020 NVIDIA CORPORATION.
# Copyright (c) 2018-2020 Chris Choy (chrischoy@ai.stanford.edu).
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
# of the Software, and to permit persons to whom the Software is furnished to do
# so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
# Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural
# Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part
# of the code.
from collections import Sequence
import numpy as np
from typing import Union
import torch
from torch.nn import Module
import MinkowskiEngineBackend._C as MEB
StrideType = Union[int, Sequence, np.ndarray, torch.IntTensor]
def convert_to_int_list(
arg: Union[int, Sequence, np.ndarray, torch.Tensor], dimension: int
):
if isinstance(arg, list):
assert len(arg) == dimension
return arg
if isinstance(arg, (Sequence, np.ndarray, torch.Tensor)):
tmp = [i for i in arg]
assert len(tmp) == dimension
elif np.isscalar(arg): # Assume that it is a scalar
tmp = [int(arg) for i in range(dimension)]
else:
raise ValueError("Input must be a scalar or a sequence")
return tmp
def convert_to_int_tensor(
arg: Union[int, Sequence, np.ndarray, torch.IntTensor], dimension: int
):
if isinstance(arg, torch.IntTensor):
assert arg.numel() == dimension
return arg
if isinstance(arg, (Sequence, np.ndarray)):
tmp = torch.IntTensor([i for i in arg])
assert tmp.numel() == dimension
elif np.isscalar(arg): # Assume that it is a scalar
tmp = torch.IntTensor([int(arg) for i in range(dimension)])
else:
raise ValueError("Input must be a scalar or a sequence")
return tmp
def prep_args(
tensor_stride: Union[int, Sequence, np.ndarray, torch.IntTensor],
stride: Union[int, Sequence, np.ndarray, torch.IntTensor],
kernel_size: Union[int, Sequence, np.ndarray, torch.IntTensor],
dilation: Union[int, Sequence, np.ndarray, torch.IntTensor],
region_type: Union[int, MEB.RegionType],
D=-1,
):
assert torch.prod(
kernel_size > 0
), f"kernel_size must be a positive integer, provided {kernel_size}"
assert D > 0, f"dimension must be a positive integer, {D}"
tensor_stride = convert_to_int_tensor(tensor_stride, D)
stride = convert_to_int_tensor(stride, D)
kernel_size = convert_to_int_tensor(kernel_size, D)
dilation = convert_to_int_tensor(dilation, D)
region_type = int(region_type)
return (
tensor_stride,
stride,
kernel_size,
dilation,
region_type,
)
def get_postfix(tensor: torch.Tensor):
postfix = "GPU" if tensor.is_cuda else "CPU"
return postfix
class MinkowskiModuleBase(Module):
pass
def get_minkowski_function(name, variable):
fn_name = name + get_postfix(variable)
if hasattr(MEB, fn_name):
return getattr(MEB, fn_name)
else:
if variable.is_cuda:
raise ValueError(
f"Function {fn_name} not available. Please compile MinkowskiEngine with `torch.cuda.is_available()` is `True`."
)
else:
raise ValueError(f"Function {fn_name} not available.")
This diff is collapsed.
# Copyright (c) Chris Choy (chrischoy@ai.stanford.edu).
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
# of the Software, and to permit persons to whom the Software is furnished to do
# so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
# Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural
# Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part
# of the code.
import torch.nn.functional as F
from MinkowskiSparseTensor import SparseTensor
from MinkowskiTensorField import TensorField
def _wrap_tensor(input, F):
if isinstance(input, TensorField):
return TensorField(
F,
coordinate_field_map_key=input.coordinate_field_map_key,
coordinate_manager=input.coordinate_manager,
quantization_mode=input.quantization_mode,
)
else:
return SparseTensor(
F,
coordinate_map_key=input.coordinate_map_key,
coordinate_manager=input.coordinate_manager,
)
# Activations
def threshold(input, *args, **kwargs):
return _wrap_tensor(input, F.threshold(input.F, *args, **kwargs))
def relu(input, *args, **kwargs):
return _wrap_tensor(input, F.relu(input.F, *args, **kwargs))
def hardtanh(input, *args, **kwargs):
return _wrap_tensor(input, F.hardtanh(input.F, *args, **kwargs))
def hardswish(input, *args, **kwargs):
return _wrap_tensor(input, F.hardswish(input.F, *args, **kwargs))
def relu6(input, *args, **kwargs):
return _wrap_tensor(input, F.relu6(input.F, *args, **kwargs))
def elu(input, *args, **kwargs):
return _wrap_tensor(input, F.elu(input.F, *args, **kwargs))
def selu(input, *args, **kwargs):
return _wrap_tensor(input, F.selu(input.F, *args, **kwargs))
def celu(input, *args, **kwargs):
return _wrap_tensor(input, F.celu(input.F, *args, **kwargs))
def leaky_relu(input, *args, **kwargs):
return _wrap_tensor(input, F.leaky_relu(input.F, *args, **kwargs))
def prelu(input, *args, **kwargs):
return _wrap_tensor(input, F.prelu(input.F, *args, **kwargs))
def rrelu(input, *args, **kwargs):
return _wrap_tensor(input, F.rrelu(input.F, *args, **kwargs))
def glu(input, *args, **kwargs):
return _wrap_tensor(input, F.glu(input.F, *args, **kwargs))
def gelu(input, *args, **kwargs):
return _wrap_tensor(input, F.gelu(input.F, *args, **kwargs))
def logsigmoid(input, *args, **kwargs):
return _wrap_tensor(input, F.logsigmoid(input.F, *args, **kwargs))
def hardshrink(input, *args, **kwargs):
return _wrap_tensor(input, F.hardshrink(input.F, *args, **kwargs))
def tanhshrink(input, *args, **kwargs):
return _wrap_tensor(input, F.tanhshrink(input.F, *args, **kwargs))
def softsign(input, *args, **kwargs):
return _wrap_tensor(input, F.softsign(input.F, *args, **kwargs))
def softplus(input, *args, **kwargs):
return _wrap_tensor(input, F.softplus(input.F, *args, **kwargs))
def softmin(input, *args, **kwargs):
return _wrap_tensor(input, F.softmin(input.F, *args, **kwargs))
def softmax(input, *args, **kwargs):
return _wrap_tensor(input, F.softmax(input.F, *args, **kwargs))
def softshrink(input, *args, **kwargs):
return _wrap_tensor(input, F.softshrink(input.F, *args, **kwargs))
def gumbel_softmax(input, *args, **kwargs):
return _wrap_tensor(input, F.gumbel_softmax(input.F, *args, **kwargs))
def log_softmax(input, *args, **kwargs):
return _wrap_tensor(input, F.log_softmax(input.F, *args, **kwargs))
def tanh(input, *args, **kwargs):
return _wrap_tensor(input, F.tanh(input.F, *args, **kwargs))
def sigmoid(input, *args, **kwargs):
return _wrap_tensor(input, F.sigmoid(input.F, *args, **kwargs))
def hardsigmoid(input, *args, **kwargs):
return _wrap_tensor(input, F.hardsigmoid(input.F, *args, **kwargs))
def silu(input, *args, **kwargs):
return _wrap_tensor(input, F.silu(input.F, *args, **kwargs))
# Normalization
def batch_norm(input, *args, **kwargs):
return _wrap_tensor(input, F.batch_norm(input.F, *args, **kwargs))
def normalize(input, *args, **kwargs):
return _wrap_tensor(input, F.normalize(input.F, *args, **kwargs))
# Linear
def linear(input, *args, **kwargs):
return _wrap_tensor(input, F.linear(input.F, *args, **kwargs))
# Dropouts
def dropout(input, *args, **kwargs):
return _wrap_tensor(input, F.dropout(input.F, *args, **kwargs))
def alpha_dropout(input, *args, **kwargs):
return _wrap_tensor(input, F.alpha_dropout(input.F, *args, **kwargs))
# Loss functions
def binary_cross_entropy(input, target, *args, **kwargs):
return F.binary_cross_entropy(input.F, target, *args, **kwargs)
def binary_cross_entropy_with_logits(input, target, *args, **kwargs):
return F.binary_cross_entropy_with_logits(input.F, target, *args, **kwargs)
def poisson_nll_loss(input, target, *args, **kwargs):
return F.poisson_nll_loss(input.F, target, *args, **kwargs)
def cross_entropy(input, target, *args, **kwargs):
return F.cross_entropy(input.F, target, *args, **kwargs)
def hinge_embedding_loss(input, target, *args, **kwargs):
return F.hinge_embedding_loss(input.F, target, *args, **kwargs)
def kl_div(input, target, *args, **kwargs):
return F.kl_div(input.F, target, *args, **kwargs)
def l1_loss(input, target, *args, **kwargs):
return F.l1_loss(input.F, target, *args, **kwargs)
def mse_loss(input, target, *args, **kwargs):
return F.mse_loss(input.F, target, *args, **kwargs)
def multilabel_margin_loss(input, target, *args, **kwargs):
return F.multilabel_margin_loss(input.F, target, *args, **kwargs)
def multilabel_soft_margin_loss(input, target, *args, **kwargs):
return F.multilabel_soft_margin_loss(input.F, target, *args, **kwargs)
def multi_margin_loss(input, target, *args, **kwargs):
return F.multi_margin_loss(input.F, target, *args, **kwargs)
def nll_loss(input, target, *args, **kwargs):
return F.nll_loss(input.F, target, *args, **kwargs)
def smooth_l1_loss(input, target, *args, **kwargs):
return F.smooth_l1_loss(input.F, target, *args, **kwargs)
def soft_margin_loss(input, target, *args, **kwargs):
return F.soft_margin_loss(input.F, target, *args, **kwargs)
# Copyright (c) 2020 NVIDIA CORPORATION.
# Copyright (c) 2018-2020 Chris Choy (chrischoy@ai.stanford.edu).
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
# of the Software, and to permit persons to whom the Software is furnished to do
# so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
# Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural
# Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part
# of the code.
from typing import Union
import torch
from torch.autograd import Function
from MinkowskiEngineBackend._C import CoordinateMapKey
from MinkowskiSparseTensor import SparseTensor
from MinkowskiCoordinateManager import CoordinateManager
from MinkowskiCommon import (
MinkowskiModuleBase,
get_minkowski_function,
)
class MinkowskiInterpolationFunction(Function):
@staticmethod
def forward(
ctx,
input_features: torch.Tensor,
tfield: torch.Tensor,
in_coordinate_map_key: CoordinateMapKey,
coordinate_manager: CoordinateManager = None,
):
input_features = input_features.contiguous()
# in_map, out_map, weights = coordinate_manager.interpolation_map_weight(
# in_coordinate_map_key, tfield)
fw_fn = get_minkowski_function("InterpolationForward", input_features)
out_feat, in_map, out_map, weights = fw_fn(
input_features,
tfield,
in_coordinate_map_key,
coordinate_manager._manager,
)
ctx.save_for_backward(in_map, out_map, weights)
ctx.inputs = (
in_coordinate_map_key,
coordinate_manager,
)
return out_feat, in_map, out_map, weights
@staticmethod
def backward(
ctx, grad_out_feat=None, grad_in_map=None, grad_out_map=None, grad_weights=None
):
grad_out_feat = grad_out_feat.contiguous()
bw_fn = get_minkowski_function("InterpolationBackward", grad_out_feat)
(
in_coordinate_map_key,
coordinate_manager,
) = ctx.inputs
in_map, out_map, weights = ctx.saved_tensors
grad_in_feat = bw_fn(
grad_out_feat,
in_map,
out_map,
weights,
in_coordinate_map_key,
coordinate_manager._manager,
)
return grad_in_feat, None, None, None
class MinkowskiInterpolation(MinkowskiModuleBase):
r"""Sample linearly interpolated features at the provided points."""
def __init__(self, return_kernel_map=False, return_weights=False):
r"""Sample linearly interpolated features at the specified coordinates.
Args:
:attr:`return_kernel_map` (bool): In addition to the sampled
features, the layer returns the kernel map as a pair of input row
indices and output row indices. False by default.
:attr:`return_weights` (bool): When True, return the linear
interpolation weights. False by default.
"""
MinkowskiModuleBase.__init__(self)
self.return_kernel_map = return_kernel_map
self.return_weights = return_weights
self.interp = MinkowskiInterpolationFunction()
def forward(
self,
input: SparseTensor,
tfield: torch.Tensor,
):
# Get a new coordinate map key or extract one from the coordinates
out_feat, in_map, out_map, weights = self.interp.apply(
input.F,
tfield,
input.coordinate_map_key,
input._manager,
)
return_args = [out_feat]
if self.return_kernel_map:
return_args.append((in_map, out_map))
if self.return_weights:
return_args.append(weights)
if len(return_args) > 1:
return tuple(return_args)
else:
return out_feat
def __repr__(self):
return self.__class__.__name__ + "()"
# Copyright (c) Chris Choy (chrischoy@ai.stanford.edu).
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
# of the Software, and to permit persons to whom the Software is furnished to do
# so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
# Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural
# Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part
# of the code.
from abc import ABC, abstractmethod
import torch.nn as nn
from MinkowskiSparseTensor import SparseTensor
class MinkowskiNetwork(nn.Module, ABC):
"""
MinkowskiNetwork: an abstract class for sparse convnets.
Note: All modules that use the same coordinates must use the same net_metadata
"""
def __init__(self, D):
super(MinkowskiNetwork, self).__init__()
self.D = D
@abstractmethod
def forward(self, x):
pass
def init(self, x):
"""
Initialize coordinates if it does not exist
"""
nrows = self.get_nrows(1)
if nrows < 0:
if isinstance(x, SparseTensor):
self.initialize_coords(x.coords_man)
else:
raise ValueError('Initialize input coordinates')
elif nrows != x.F.size(0):
raise ValueError('Input size does not match the coordinate size')
# Copyright (c) Chris Choy (chrischoy@ai.stanford.edu).
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
# of the Software, and to permit persons to whom the Software is furnished to do
# so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
# Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural
# Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part
# of the code.
from typing import Union
import torch
import torch.nn as nn
from MinkowskiCommon import MinkowskiModuleBase
from MinkowskiSparseTensor import SparseTensor
from MinkowskiTensorField import TensorField
class MinkowskiNonlinearityBase(MinkowskiModuleBase):
MODULE = None
def __init__(self, *args, **kwargs):
super(MinkowskiNonlinearityBase, self).__init__()
self.module = self.MODULE(*args, **kwargs)
def forward(self, input):
output = self.module(input.F)
if isinstance(input, TensorField):
return TensorField(
output,
coordinate_field_map_key=input.coordinate_field_map_key,
coordinate_manager=input.coordinate_manager,
quantization_mode=input.quantization_mode,
)
else:
return SparseTensor(
output,
coordinate_map_key=input.coordinate_map_key,
coordinate_manager=input.coordinate_manager,
)
def __repr__(self):
return self.__class__.__name__ + "()"
class MinkowskiELU(MinkowskiNonlinearityBase):
MODULE = torch.nn.ELU
class MinkowskiHardshrink(MinkowskiNonlinearityBase):
MODULE = torch.nn.Hardshrink
class MinkowskiHardsigmoid(MinkowskiNonlinearityBase):
MODULE = torch.nn.Hardsigmoid
class MinkowskiHardtanh(MinkowskiNonlinearityBase):
MODULE = torch.nn.Hardtanh
class MinkowskiHardswish(MinkowskiNonlinearityBase):
MODULE = torch.nn.Hardswish
class MinkowskiLeakyReLU(MinkowskiNonlinearityBase):
MODULE = torch.nn.LeakyReLU
class MinkowskiLogSigmoid(MinkowskiNonlinearityBase):
MODULE = torch.nn.LogSigmoid
class MinkowskiPReLU(MinkowskiNonlinearityBase):
MODULE = torch.nn.PReLU
class MinkowskiReLU(MinkowskiNonlinearityBase):
MODULE = torch.nn.ReLU
class MinkowskiReLU6(MinkowskiNonlinearityBase):
MODULE = torch.nn.ReLU6
class MinkowskiRReLU(MinkowskiNonlinearityBase):
MODULE = torch.nn.RReLU
class MinkowskiSELU(MinkowskiNonlinearityBase):
MODULE = torch.nn.SELU
class MinkowskiCELU(MinkowskiNonlinearityBase):
MODULE = torch.nn.CELU
class MinkowskiGELU(MinkowskiNonlinearityBase):
MODULE = torch.nn.GELU
class MinkowskiSigmoid(MinkowskiNonlinearityBase):
MODULE = torch.nn.Sigmoid
class MinkowskiSiLU(MinkowskiNonlinearityBase):
MODULE = torch.nn.SiLU
class MinkowskiSoftplus(MinkowskiNonlinearityBase):
MODULE = torch.nn.Softplus
class MinkowskiSoftshrink(MinkowskiNonlinearityBase):
MODULE = torch.nn.Softshrink
class MinkowskiSoftsign(MinkowskiNonlinearityBase):
MODULE = torch.nn.Softsign
class MinkowskiTanh(MinkowskiNonlinearityBase):
MODULE = torch.nn.Tanh
class MinkowskiTanhshrink(MinkowskiNonlinearityBase):
MODULE = torch.nn.Tanhshrink
class MinkowskiThreshold(MinkowskiNonlinearityBase):
MODULE = torch.nn.Threshold
# Non-linear Activations (other)
class MinkowskiSoftmin(MinkowskiNonlinearityBase):
MODULE = torch.nn.Softmin
class MinkowskiSoftmax(MinkowskiNonlinearityBase):
MODULE = torch.nn.Softmax
class MinkowskiLogSoftmax(MinkowskiNonlinearityBase):
MODULE = torch.nn.LogSoftmax
class MinkowskiAdaptiveLogSoftmaxWithLoss(MinkowskiNonlinearityBase):
MODULE = torch.nn.AdaptiveLogSoftmaxWithLoss
# Dropouts
class MinkowskiDropout(MinkowskiNonlinearityBase):
MODULE = torch.nn.Dropout
class MinkowskiAlphaDropout(MinkowskiNonlinearityBase):
MODULE = torch.nn.AlphaDropout
class MinkowskiSinusoidal(MinkowskiModuleBase):
def __init__(self, in_channel, out_channel):
MinkowskiModuleBase.__init__(self)
self.in_channel = in_channel
self.out_channel = out_channel
self.kernel = nn.Parameter(torch.rand(in_channel, out_channel))
self.bias = nn.Parameter(torch.rand(1, out_channel))
self.coef = nn.Parameter(torch.rand(1, out_channel))
def forward(self, input: Union[SparseTensor, TensorField]):
out_F = torch.sin(input.F.mm(self.kernel) + self.bias) * self.coef
if isinstance(input, TensorField):
return TensorField(
out_F,
coordinate_field_map_key=input.coordinate_field_map_key,
coordinate_manager=input.coordinate_manager,
quantization_mode=input.quantization_mode,
)
else:
return SparseTensor(
out_F,
coordinate_map_key=input.coordinate_map_key,
coordinate_manager=input.coordinate_manager,
)
This diff is collapsed.
This diff is collapsed.
# Copyright (c) 2020 NVIDIA CORPORATION.
# Copyright (c) 2018-2020 Chris Choy (chrischoy@ai.stanford.edu).
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
# of the Software, and to permit persons to whom the Software is furnished to do
# so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
# Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural
# Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part
# of the code.
import torch
from torch.nn import Module
from torch.autograd import Function
from MinkowskiEngineBackend._C import CoordinateMapKey
from MinkowskiSparseTensor import SparseTensor
from MinkowskiCommon import (
MinkowskiModuleBase,
get_minkowski_function,
)
from MinkowskiCoordinateManager import CoordinateManager
class MinkowskiPruningFunction(Function):
@staticmethod
def forward(
ctx,
in_feat: torch.Tensor,
mask: torch.Tensor,
in_coords_key: CoordinateMapKey,
out_coords_key: CoordinateMapKey = None,
coords_manager: CoordinateManager = None,
):
ctx.in_coords_key = in_coords_key
ctx.out_coords_key = out_coords_key
ctx.coords_manager = coords_manager
in_feat = in_feat.contiguous()
fw_fn = get_minkowski_function("PruningForward", in_feat)
return fw_fn(
in_feat,
mask,
ctx.in_coords_key,
ctx.out_coords_key,
ctx.coords_manager._manager,
)
@staticmethod
def backward(ctx, grad_out_feat: torch.Tensor):
grad_out_feat = grad_out_feat.contiguous()
bw_fn = get_minkowski_function("PruningBackward", grad_out_feat)
grad_in_feat = bw_fn(
grad_out_feat,
ctx.in_coords_key,
ctx.out_coords_key,
ctx.coords_manager._manager,
)
return grad_in_feat, None, None, None, None
class MinkowskiPruning(MinkowskiModuleBase):
r"""Remove specified coordinates from a :attr:`MinkowskiEngine.SparseTensor`.
"""
def __init__(self):
super(MinkowskiPruning, self).__init__()
self.pruning = MinkowskiPruningFunction()
def forward(self, input: SparseTensor, mask: torch.Tensor):
r"""
Args:
:attr:`input` (:attr:`MinkowskiEnigne.SparseTensor`): a sparse tensor
to remove coordinates from.
:attr:`mask` (:attr:`torch.BoolTensor`): mask vector that specifies
which one to keep. Coordinates with False will be removed.
Returns:
A :attr:`MinkowskiEngine.SparseTensor` with C = coordinates
corresponding to `mask == True` F = copy of the features from `mask ==
True`.
Example::
>>> # Define inputs
>>> input = SparseTensor(feats, coords=coords)
>>> # Any boolean tensor can be used as the filter
>>> mask = torch.rand(feats.size(0)) < 0.5
>>> pruning = MinkowskiPruning()
>>> output = pruning(input, mask)
"""
assert isinstance(input, SparseTensor)
out_coords_key = CoordinateMapKey(
input.coordinate_map_key.get_coordinate_size()
)
output = self.pruning.apply(
input.F, mask, input.coordinate_map_key, out_coords_key, input._manager
)
return SparseTensor(
output, coordinate_map_key=out_coords_key, coordinate_manager=input._manager
)
def __repr__(self):
return self.__class__.__name__ + "()"
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
# Copyright (c) Chris Choy (chrischoy@ai.stanford.edu).
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
# of the Software, and to permit persons to whom the Software is furnished to do
# so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
# Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural
# Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part
# of the code.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment