diff --git a/.github/workflows/building-conda.yml b/.github/workflows/building-conda.yml index d01972b..49b5d16 100644 --- a/.github/workflows/building-conda.yml +++ b/.github/workflows/building-conda.yml @@ -13,27 +13,18 @@ jobs: # We have trouble building for Windows - drop for now. os: [ubuntu-18.04, macos-10.15] # windows-2019 python-version: ['3.7', '3.8', '3.9', '3.10'] - torch-version: [1.13.0] # [1.12.0, 1.13.0] - cuda-version: ['cpu', 'cu102', 'cu113', 'cu116', 'cu117'] + torch-version: [1.13.0, 2.0.0] + # We have trouble building for `cu116` due to PyTorch 1.13.0 bugs + cuda-version: ['cpu', 'cu117', 'cu118'] exclude: - - torch-version: 1.12.0 - cuda-version: 'cu117' - - torch-version: 1.13.0 - cuda-version: 'cu102' + - torch-version: 2.0.0 + python-version: '3.7' - torch-version: 1.13.0 - cuda-version: 'cu113' - - os: macos-10.15 - cuda-version: 'cu102' - - os: macos-10.15 - cuda-version: 'cu113' - - os: macos-10.15 - cuda-version: 'cu116' + cuda-version: 'cu118' - os: macos-10.15 cuda-version: 'cu117' - - os: windows-2019 - cuda-version: 'cu102' - - os: windows-2019 # Complains about CUDA mismatch. - python-version: '3.7' + - os: macos-10.15 + cuda-version: 'cu118' steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/building.yml b/.github/workflows/building.yml index 0e6f982..ae489f1 100644 --- a/.github/workflows/building.yml +++ b/.github/workflows/building.yml @@ -11,26 +11,24 @@ jobs: fail-fast: false matrix: os: [ubuntu-18.04, macos-10.15, windows-2019] - python-version: ['3.7', '3.8', '3.9', '3.10'] - torch-version: [1.12.0, 1.13.0] - cuda-version: ['cpu', 'cu102', 'cu113', 'cu116', 'cu117'] + python-version: ['3.7', '3.8', '3.9', '3.10', '3.11'] + torch-version: [1.13.0, 2.0.0] + cuda-version: ['cpu', 'cu116', 'cu117', 'cu118'] exclude: - - torch-version: 1.12.0 - cuda-version: 'cu117' - torch-version: 1.13.0 - cuda-version: 'cu102' + python-version: '3.11' + - torch-version: 2.0.0 + python-version: '3.7' - torch-version: 1.13.0 - cuda-version: 'cu113' - - os: macos-10.15 - cuda-version: 'cu102' - - os: macos-10.15 - cuda-version: 'cu113' + cuda-version: 'cu118' + - torch-version: 2.0.0 + cuda-version: 'cu116' - os: macos-10.15 cuda-version: 'cu116' - os: macos-10.15 cuda-version: 'cu117' - - os: windows-2019 - cuda-version: 'cu102' + - os: macos-10.15 + cuda-version: 'cu118' steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/cuda/cu118-Linux-env.sh b/.github/workflows/cuda/cu118-Linux-env.sh new file mode 100644 index 0000000..18d97b8 --- /dev/null +++ b/.github/workflows/cuda/cu118-Linux-env.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +CUDA_HOME=/usr/local/cuda-11.8 +LD_LIBRARY_PATH=${CUDA_HOME}/lib64:${LD_LIBRARY_PATH} +PATH=${CUDA_HOME}/bin:${PATH} + +export FORCE_CUDA=1 +export TORCH_CUDA_ARCH_LIST="3.5;5.0+PTX;6.0;7.0;7.5;8.0;8.6" diff --git a/.github/workflows/cuda/cu118-Linux.sh b/.github/workflows/cuda/cu118-Linux.sh new file mode 100755 index 0000000..000a3bd --- /dev/null +++ b/.github/workflows/cuda/cu118-Linux.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +OS=ubuntu1804 + +wget -nv https://developer.download.nvidia.com/compute/cuda/repos/${OS}/x86_64/cuda-${OS}.pin +sudo mv cuda-${OS}.pin /etc/apt/preferences.d/cuda-repository-pin-600 +wget -nv https://developer.download.nvidia.com/compute/cuda/11.8.0/local_installers/cuda-repo-${OS}-11-8-local_11.8.0-520.61.05-1_amd64.deb +sudo dpkg -i cuda-repo-${OS}-11-8-local_11.8.0-520.61.05-1_amd64.deb +sudo cp /var/cuda-repo-${OS}-11-8-local/cuda-*-keyring.gpg /usr/share/keyrings/ + +sudo apt-get -qq update +sudo apt install cuda-nvcc-11-8 cuda-libraries-dev-11-8 +sudo apt clean + +rm -f https://developer.download.nvidia.com/compute/cuda/11.8.0/local_installers/cuda-repo-${OS}-11-8-local_11.8.0-520.61.05-1_amd64.deb diff --git a/.github/workflows/cuda/cu118-Windows-env.sh b/.github/workflows/cuda/cu118-Windows-env.sh new file mode 100644 index 0000000..d0ff04b --- /dev/null +++ b/.github/workflows/cuda/cu118-Windows-env.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +CUDA_HOME=/c/Program\ Files/NVIDIA\ GPU\ Computing\ Toolkit/CUDA/v11.8 +PATH=${CUDA_HOME}/bin:$PATH +PATH=/c/Program\ Files\ \(x86\)/Microsoft\ Visual\ Studio/2017/BuildTools/MSBuild/15.0/Bin:$PATH + +export FORCE_CUDA=1 +export TORCH_CUDA_ARCH_LIST="6.0+PTX" diff --git a/.github/workflows/cuda/cu118-Windows.sh b/.github/workflows/cuda/cu118-Windows.sh new file mode 100755 index 0000000..b82a5a9 --- /dev/null +++ b/.github/workflows/cuda/cu118-Windows.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +# Install NVIDIA drivers, see: +# https://github.com/pytorch/vision/blob/master/packaging/windows/internal/cuda_install.bat#L99-L102 +curl -k -L "https://drive.google.com/u/0/uc?id=1injUyo3lnarMgWyRcXqKg4UGnN0ysmuq&export=download" --output "/tmp/gpu_driver_dlls.zip" +7z x "/tmp/gpu_driver_dlls.zip" -o"/c/Windows/System32" + +export CUDA_SHORT=11.8 +export CUDA_URL=https://developer.download.nvidia.com/compute/cuda/${CUDA_SHORT}.0/local_installers +export CUDA_FILE=cuda_${CUDA_SHORT}.0_522.06_windows.exe + +# Install CUDA: +curl -k -L "${CUDA_URL}/${CUDA_FILE}" --output "${CUDA_FILE}" +echo "" +echo "Installing from ${CUDA_FILE}..." +PowerShell -Command "Start-Process -FilePath \"${CUDA_FILE}\" -ArgumentList \"-s nvcc_${CUDA_SHORT} cuobjdump_${CUDA_SHORT} nvprune_${CUDA_SHORT} cupti_${CUDA_SHORT} cublas_dev_${CUDA_SHORT} cudart_${CUDA_SHORT} cufft_dev_${CUDA_SHORT} curand_dev_${CUDA_SHORT} cusolver_dev_${CUDA_SHORT} cusparse_dev_${CUDA_SHORT} thrust_${CUDA_SHORT} npp_dev_${CUDA_SHORT} nvrtc_dev_${CUDA_SHORT} nvml_dev_${CUDA_SHORT}\" -Wait -NoNewWindow" +echo "Done!" +rm -f "${CUDA_FILE}" diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index 0ff7a7a..78734f7 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -17,7 +17,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v2 with: - python-version: 3.9 + python-version: 3.8 - name: Install dependencies run: | @@ -26,30 +26,3 @@ jobs: - name: Run linting run: | flake8 . - - pyroma: - runs-on: ubuntu-latest - - strategy: - matrix: - torch-version: [1.13.0] - - steps: - - uses: actions/checkout@v2 - - - name: Set up Python - uses: actions/setup-python@v2 - with: - python-version: 3.9 - - - name: Install PyTorch ${{ matrix.torch-version }} - run: | - pip install torch==${{ matrix.torch-version }} --extra-index-url https://download.pytorch.org/whl/cpu - - - name: Install dependencies - run: | - pip install pyroma - - - name: Check package metadata - run: | - pyroma --min=10 . diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index a5dfdcf..6b177df 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -15,8 +15,8 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, windows-latest] - python-version: [3.7] - torch-version: [1.12.0, 1.13.0] + python-version: [3.8] + torch-version: [1.13.0, 2.0.0] steps: - uses: actions/checkout@v2 diff --git a/CMakeLists.txt b/CMakeLists.txt index e9f8c7f..e4f8385 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.0) project(torchcluster) set(CMAKE_CXX_STANDARD 14) -set(TORCHCLUSTER_VERSION 1.6.0) +set(TORCHCLUSTER_VERSION 1.6.1) option(WITH_CUDA "Enable CUDA support" OFF) option(WITH_PYTHON "Link to Python when building" ON) diff --git a/README.md b/README.md index 3951b26..61efba6 100644 --- a/README.md +++ b/README.md @@ -43,39 +43,39 @@ conda install pytorch-cluster -c pyg We alternatively provide pip wheels for all major OS/PyTorch/CUDA combinations, see [here](https://data.pyg.org/whl). -#### PyTorch 1.13 +#### PyTorch 2.0 -To install the binaries for PyTorch 1.13.0, simply run +To install the binaries for PyTorch 2.0.0, simply run ``` -pip install torch-spline-conv -f https://data.pyg.org/whl/torch-1.13.0+${CUDA}.html +pip install torch-spline-conv -f https://data.pyg.org/whl/torch-2.0.0+${CUDA}.html ``` -where `${CUDA}` should be replaced by either `cpu`, `cu116`, or `cu117` depending on your PyTorch installation. +where `${CUDA}` should be replaced by either `cpu`, `cu117`, or `cu118` depending on your PyTorch installation. -| | `cpu` | `cu116` | `cu117` | +| | `cpu` | `cu117` | `cu118` | |-------------|-------|---------|---------| | **Linux** | ✅ | ✅ | ✅ | | **Windows** | ✅ | ✅ | ✅ | | **macOS** | ✅ | | | -#### PyTorch 1.12 +#### PyTorch 1.13 -To install the binaries for PyTorch 1.12.0, simply run +To install the binaries for PyTorch 1.13.0, simply run ``` -pip install torch-spline-conv -f https://data.pyg.org/whl/torch-1.12.0+${CUDA}.html +pip install torch-spline-conv -f https://data.pyg.org/whl/torch-1.13.0+${CUDA}.html ``` -where `${CUDA}` should be replaced by either `cpu`, `cu102`, `cu113`, or `cu116` depending on your PyTorch installation. +where `${CUDA}` should be replaced by either `cpu`, `cu116`, or `cu117` depending on your PyTorch installation. -| | `cpu` | `cu102` | `cu113` | `cu116` | -|-------------|-------|---------|---------|---------| -| **Linux** | ✅ | ✅ | ✅ | ✅ | -| **Windows** | ✅ | | ✅ | ✅ | -| **macOS** | ✅ | | | | +| | `cpu` | `cu116` | `cu117` | +|-------------|-------|---------|---------| +| **Linux** | ✅ | ✅ | ✅ | +| **Windows** | ✅ | ✅ | ✅ | +| **macOS** | ✅ | | | -**Note:** Binaries of older versions are also provided for PyTorch 1.4.0, PyTorch 1.5.0, PyTorch 1.6.0, PyTorch 1.7.0/1.7.1, PyTorch 1.8.0/1.8.1, PyTorch 1.9.0, PyTorch 1.10.0/1.10.1/1.10.2 and PyTorch 1.11.0 (following the same procedure). +**Note:** Binaries of older versions are also provided for PyTorch 1.4.0, PyTorch 1.5.0, PyTorch 1.6.0, PyTorch 1.7.0/1.7.1, PyTorch 1.8.0/1.8.1, PyTorch 1.9.0, PyTorch 1.10.0/1.10.1/1.10.2, PyTorch 1.11.0 and PyTorch 1.12.0/1.12.1 (following the same procedure). For older versions, you need to explicitly specify the latest supported version number or install via `pip install --no-index` in order to prevent a manual installation from source. You can look up the latest supported version number [here](https://data.pyg.org/whl). diff --git a/conda/pytorch-cluster/README.md b/conda/pytorch-cluster/README.md index 6476246..6207e22 100644 --- a/conda/pytorch-cluster/README.md +++ b/conda/pytorch-cluster/README.md @@ -1,3 +1,3 @@ ``` -./build_conda.sh 3.9 1.13.0 cu116 # python, pytorch and cuda version +./build_conda.sh 3.9 2.0.0 cu117 # python, pytorch and cuda version ``` diff --git a/conda/pytorch-cluster/build_conda.sh b/conda/pytorch-cluster/build_conda.sh index 14355ea..21d94c2 100755 --- a/conda/pytorch-cluster/build_conda.sh +++ b/conda/pytorch-cluster/build_conda.sh @@ -10,6 +10,9 @@ if [ "${CUDA_VERSION}" = "cpu" ]; then export CONDA_CUDATOOLKIT_CONSTRAINT="cpuonly # [not osx]" else case $CUDA_VERSION in + cu118) + export CONDA_CUDATOOLKIT_CONSTRAINT="pytorch-cuda==11.8.*" + ;; cu117) export CONDA_CUDATOOLKIT_CONSTRAINT="pytorch-cuda==11.7.*" ;; diff --git a/conda/pytorch-cluster/meta.yaml b/conda/pytorch-cluster/meta.yaml index 1813327..897cb5c 100644 --- a/conda/pytorch-cluster/meta.yaml +++ b/conda/pytorch-cluster/meta.yaml @@ -1,6 +1,6 @@ package: name: pytorch-cluster - version: 1.6.0 + version: 1.6.1 source: path: ../.. diff --git a/setup.py b/setup.py index cdb38fe..0b8c798 100644 --- a/setup.py +++ b/setup.py @@ -11,7 +11,7 @@ from torch.utils.cpp_extension import (CUDA_HOME, BuildExtension, CppExtension, CUDAExtension) -__version__ = '1.6.0' +__version__ = '1.6.1' URL = 'https://github.com/rusty1s/pytorch_cluster' WITH_CUDA = False diff --git a/test/test_nearest.py b/test/test_nearest.py index e4d76f5..582818e 100644 --- a/test/test_nearest.py +++ b/test/test_nearest.py @@ -38,33 +38,27 @@ def test_nearest(dtype, device): batch_x = tensor([0, 0, 0, 0, 1, 1, 1, 1], torch.long, device) batch_y = tensor([0, 0, 0, 0], torch.long, device) with pytest.raises(ValueError): - out = nearest(x, y, batch_x, batch_y) + nearest(x, y, batch_x, batch_y) # Invalid input: instance 1 only in batch_x (implicitly as batch_y=None) with pytest.raises(ValueError): - out = nearest(x, y, batch_x, batch_y=None) - - # Valid input: instance 1 only in batch_y - batch_x = tensor([0, 0, 0, 0, 0, 0, 0, 0], torch.long, device) - batch_y = tensor([0, 0, 1, 1], torch.long, device) - out = nearest(x, y, batch_x, batch_y) - assert out.tolist() == [0, 0, 1, 1, 0, 0, 1, 1] + nearest(x, y, batch_x, batch_y=None) # Invalid input: instance 2 only in batch_x # (i.e.instance in the middle missing) batch_x = tensor([0, 0, 1, 1, 2, 2, 3, 3], torch.long, device) batch_y = tensor([0, 1, 3, 3], torch.long, device) with pytest.raises(ValueError): - out = nearest(x, y, batch_x, batch_y) + nearest(x, y, batch_x, batch_y) # Invalid input: batch_x unsorted batch_x = tensor([0, 0, 1, 0, 0, 0, 0], torch.long, device) batch_y = tensor([0, 0, 1, 1], torch.long, device) with pytest.raises(ValueError): - out = nearest(x, y, batch_x, batch_y) + nearest(x, y, batch_x, batch_y) # Invalid input: batch_y unsorted batch_x = tensor([0, 0, 0, 0, 1, 1, 1, 1], torch.long, device) batch_y = tensor([0, 0, 1, 0], torch.long, device) with pytest.raises(ValueError): - out = nearest(x, y, batch_x, batch_y) + nearest(x, y, batch_x, batch_y) diff --git a/torch_cluster/__init__.py b/torch_cluster/__init__.py index 22640c1..158f59b 100644 --- a/torch_cluster/__init__.py +++ b/torch_cluster/__init__.py @@ -3,7 +3,7 @@ import torch -__version__ = '1.6.0' +__version__ = '1.6.1' for library in [ '_version', '_grid', '_graclus', '_fps', '_rw', '_sampler', '_nearest', diff --git a/torch_cluster/nearest.py b/torch_cluster/nearest.py index d9131ce..1ba4db6 100644 --- a/torch_cluster/nearest.py +++ b/torch_cluster/nearest.py @@ -1,12 +1,15 @@ from typing import Optional -import torch import scipy.cluster +import torch -def nearest(x: torch.Tensor, y: torch.Tensor, - batch_x: Optional[torch.Tensor] = None, - batch_y: Optional[torch.Tensor] = None) -> torch.Tensor: +def nearest( + x: torch.Tensor, + y: torch.Tensor, + batch_x: Optional[torch.Tensor] = None, + batch_y: Optional[torch.Tensor] = None, +) -> torch.Tensor: r"""Clusters points in :obj:`x` together which are nearest to a given query point in :obj:`y`. @@ -43,9 +46,9 @@ def nearest(x: torch.Tensor, y: torch.Tensor, assert x.size(1) == y.size(1) if batch_x is not None and (batch_x[1:] - batch_x[:-1] < 0).any(): - raise ValueError("batch_x is not sorted") + raise ValueError("'batch_x' is not sorted") if batch_y is not None and (batch_y[1:] - batch_y[:-1] < 0).any(): - raise ValueError("batch_y is not sorted") + raise ValueError("'batch_y' is not sorted") if x.is_cuda: if batch_x is not None: @@ -72,30 +75,32 @@ def nearest(x: torch.Tensor, y: torch.Tensor, else: ptr_y = torch.tensor([0, y.size(0)], device=y.device) - # if an instance in batch_x is non-empty, it must be - # non-empty in batch_y as well - instance_nonempty_x = (ptr_x[:-1] != ptr_x[1:]) - instance_nonempty_y = (ptr_y[:len(ptr_x)-1] != ptr_y[1:len(ptr_x)]) - if (len(ptr_x) > len(ptr_y) or - (instance_nonempty_x & ~instance_nonempty_y).any()): - raise ValueError("Some batch index occurs in batch_x " - "that does not occur in batch_y") + # If an instance in `batch_x` is non-empty, it must be non-empty in + # `batch_y `as well: + nonempty_ptr_x = (ptr_x[1:] - ptr_x[:-1]) > 0 + nonempty_ptr_y = (ptr_y[1:] - ptr_y[:-1]) > 0 + if not torch.equal(nonempty_ptr_x, nonempty_ptr_y): + raise ValueError("Some batch indices occur in 'batch_x' " + "that do not occur in 'batch_y'") return torch.ops.torch_cluster.nearest(x, y, ptr_x, ptr_y) + else: - if (batch_x is None) != (batch_y is None): - raise ValueError("Either both or none of batch_x, batch_y " - "may be None") + + if batch_x is None and batch_y is not None: + batch_x = x.new_zeros(x.size(0), dtype=torch.long) + if batch_y is None and batch_x is not None: + batch_y = y.new_zeros(y.size(0), dtype=torch.long) # Translate and rescale x and y to [0, 1]. if batch_x is not None and batch_y is not None: - # if an instance in batch_x is non-empty, it must be - # non-empty in batch_y as well - if not torch.isin(torch.unique_consecutive(batch_x), - torch.unique_consecutive(batch_y), - assume_unique=True).all(): - raise ValueError("Some batch index occurs in batch_x " - "that does not occur in batch_y") + # If an instance in `batch_x` is non-empty, it must be non-empty in + # `batch_y `as well: + unique_batch_x = batch_x.unique_consecutive() + unique_batch_y = batch_y.unique_consecutive() + if not torch.equal(unique_batch_x, unique_batch_y): + raise ValueError("Some batch indices occur in 'batch_x' " + "that do not occur in 'batch_y'") assert x.dim() == 2 and batch_x.dim() == 1 assert y.dim() == 2 and batch_y.dim() == 1