Skip to content

Commit

Permalink
Merge pull request #564 from mrava87/patch-cusignal
Browse files Browse the repository at this point in the history
feature: remove cusignal dependency
  • Loading branch information
mrava87 authored Jan 10, 2024
2 parents 54bef33 + 05df62b commit a6d09c1
Show file tree
Hide file tree
Showing 6 changed files with 24 additions and 86 deletions.
4 changes: 2 additions & 2 deletions docs/source/faq.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ working with linear operators is indeed that you don't really need to access the
of an operator.


**2. Can I have an older version of** ``cupy`` **or** ``cusignal`` **installed in my system (** ``cupy-cudaXX<8.1.0`` **or** ``cusignal>=0.16.0`` **)?**
**2. Can I have an older version of** ``cupy`` **installed in my system (** ``cupy-cudaXX<10.6.0``)?**

Yes. Nevertheless you need to tell PyLops that you don't want to use its ``cupy``
backend by setting the environment variable ``CUPY_PYLOPS=0`` or ``CUPY_SIGNAL=0``.
backend by setting the environment variable ``CUPY_PYLOPS=0``.
Failing to do so will lead to an error when you import ``pylops`` because some of the ``cupyx``
routines that we use are not available in earlier version of ``cupy``.
11 changes: 5 additions & 6 deletions docs/source/gpu.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@ GPU Support

Overview
--------
From ``v1.12.0``, PyLops supports computations on GPUs powered by
`CuPy <https://cupy.dev/>`_ (``cupy-cudaXX>=8.1.0``) and `cuSignal <https://docs.rapids.ai/api/cusignal/stable/>`_ (``cusignal>=0.16.0``).
They must be installed *before* PyLops is installed.
PyLops supports computations on GPUs powered by `CuPy <https://cupy.dev/>`_ (``cupy-cudaXX>=10.6.0``).
This library must be installed *before* PyLops is installed.

.. note::

Set environment variables ``CUPY_PYLOPS=0`` and/or ``CUSIGNAL_PYLOPS=0`` to force PyLops to ignore
``cupy`` and ``cusignal`` backends.
This can be also used if a previous version of ``cupy`` or ``cusignal`` is installed in your system, otherwise you will get an error when importing PyLops.
Set environment variable ``CUPY_PYLOPS=0`` to force PyLops to ignore the ``cupy`` backend.
This can be also used if a previous (or faulty) version of ``cupy`` is installed in your system,
otherwise you will get an error when importing PyLops.



Expand Down
14 changes: 3 additions & 11 deletions docs/source/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -514,16 +514,8 @@ disable this option. For more details of GPU-accelerated PyLops read :ref:`gpu`.

CuPy
----
`CuPy <https://cupy.dev/>`_ is a library used as a drop-in replacement to NumPy
for GPU-accelerated
computations. Since many different versions of CuPy exist (based on the
`CuPy <https://cupy.dev/>`_ is a library used as a drop-in replacement to NumPy and some parts of SciPy
for GPU-accelerated computations. Since many different versions of CuPy exist (based on the
CUDA drivers of the GPU), users must install CuPy prior to installing
PyLops. To do so, follow their
`installation instructions <https://docs.cupy.dev/en/stable/install.html>`__.

cuSignal
--------
`cuSignal <https://docs.rapids.ai/api/cusignal/stable/>`_ is a library is used as a drop-in replacement to `SciPy Signal <https://docs.scipy.org/doc/scipy/reference/signal.html>`_ for
GPU-accelerated computations. Similar to CuPy, users must install
cuSignal prior to installing PyLops. To do so, follow their
`installation instructions <https://github.com/rapidsai/cusignal#installation>`__.
`installation instructions <https://docs.cupy.dev/en/stable/install.html>`__.
8 changes: 4 additions & 4 deletions pylops/signalprocessing/convolve1d.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ def _matvec(self, x: NDArray) -> NDArray:
if type(self.h) is not type(x):
self.h = to_cupy_conditional(x, self.h)
self.convfunc, self.method = _choose_convfunc(
self.h, self.method, self.dims
self.h, self.method, self.dims, self.axis
)
return self.convfunc(x, self.h, mode="same")

Expand All @@ -109,7 +109,7 @@ def _rmatvec(self, x: NDArray) -> NDArray:
if type(self.hstar) is not type(x):
self.hstar = to_cupy_conditional(x, self.hstar)
self.convfunc, self.method = _choose_convfunc(
self.hstar, self.method, self.dims
self.hstar, self.method, self.dims, self.axis
)
return self.convfunc(x, self.hstar, mode="same")

Expand Down Expand Up @@ -165,7 +165,7 @@ def _matvec(self, x: NDArray) -> NDArray:
if type(self.h) is not type(x):
self.h = to_cupy_conditional(x, self.h)
self.convfunc, self.method = _choose_convfunc(
self.h, self.method, self.dims
self.h, self.method, self.dims, self.axis
)
x = np.pad(x, self.pad)
y = self.convfunc(self.h, x, mode="same")
Expand All @@ -177,7 +177,7 @@ def _rmatvec(self, x: NDArray) -> NDArray:
if type(self.h) is not type(x):
self.hstar = to_cupy_conditional(x, self.hstar)
self.convfunc, self.method = _choose_convfunc(
self.hstar, self.method, self.dims
self.hstar, self.method, self.dims, self.axis
)
x = np.pad(x, self.padd)
y = self.convfunc(self.hstar, x)
Expand Down
34 changes: 8 additions & 26 deletions pylops/utils/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,13 @@
import cupyx.scipy.fft as cp_fft
from cupyx.scipy.linalg import block_diag as cp_block_diag
from cupyx.scipy.linalg import toeplitz as cp_toeplitz
from cupyx.scipy.signal import convolve as cp_convolve
from cupyx.scipy.signal import correlate as cp_correlate
from cupyx.scipy.signal import fftconvolve as cp_fftconvolve
from cupyx.scipy.signal import oaconvolve as cp_oaconvolve
from cupyx.scipy.sparse import csc_matrix as cp_csc_matrix
from cupyx.scipy.sparse import eye as cp_eye

if deps.cusignal_enabled:
import cusignal

cu_message = "cupy package not installed. Use numpy arrays of " "install cupy."

cusignal_message = (
"cusignal package not installed. Use numpy arrays of" "install cusignal."
)


def get_module(backend: str = "numpy") -> ModuleType:
"""Returns correct numerical module based on backend string
Expand Down Expand Up @@ -138,10 +133,7 @@ def get_convolve(x: npt.ArrayLike) -> Callable:
if cp.get_array_module(x) == np:
return convolve
else:
if deps.cusignal_enabled:
return cusignal.convolution.convolve
else:
raise ModuleNotFoundError(cusignal_message)
return cp_convolve


def get_fftconvolve(x: npt.ArrayLike) -> Callable:
Expand All @@ -164,10 +156,7 @@ def get_fftconvolve(x: npt.ArrayLike) -> Callable:
if cp.get_array_module(x) == np:
return fftconvolve
else:
if deps.cusignal_enabled:
return cusignal.convolution.fftconvolve
else:
raise ModuleNotFoundError(cusignal_message)
return cp_fftconvolve


def get_oaconvolve(x: npt.ArrayLike) -> Callable:
Expand All @@ -190,11 +179,7 @@ def get_oaconvolve(x: npt.ArrayLike) -> Callable:
if cp.get_array_module(x) == np:
return oaconvolve
else:
raise NotImplementedError(
"oaconvolve not implemented in "
"cupy/cusignal. Consider using a different"
"option..."
)
return cp_oaconvolve


def get_correlate(x: npt.ArrayLike) -> Callable:
Expand All @@ -217,10 +202,7 @@ def get_correlate(x: npt.ArrayLike) -> Callable:
if cp.get_array_module(x) == np:
return correlate
else:
if deps.cusignal_enabled:
return cusignal.convolution.correlate
else:
raise ModuleNotFoundError(cusignal_message)
return cp_correlate


def get_add_at(x: npt.ArrayLike) -> Callable:
Expand Down
39 changes: 2 additions & 37 deletions pylops/utils/deps.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
__all__ = [
"cupy_enabled",
"cusignal_enabled",
"devito_enabled",
"numba_enabled",
"pyfftw_enabled",
Expand Down Expand Up @@ -51,35 +50,6 @@ def cupy_import(message: Optional[str] = None) -> str:
return cupy_message


def cusignal_import(message: Optional[str] = None) -> str:
cusignal_test = (
util.find_spec("cusignal") is not None
and int(os.getenv("CUSIGNAL_PYLOPS", 1)) == 1
)
if cusignal_test:
try:
import_module("cusignal") # noqa: F401

cusignal_message = None
except (ImportError, ModuleNotFoundError) as e:
cusignal_message = (
f"Failed to import cusignal. Falling back to CPU (error: {e}) . "
"Please ensure your CUDA environment is set up correctly; "
"for more details visit 'https://github.com/rapidsai/cusignal#installation'"
)
print(UserWarning(cusignal_message))
else:
cusignal_message = (
"Cusignal not installed or os.getenv('CUSIGNAL_PYLOPS') == 0. "
f"In order to be able to use {message} "
"ensure 'os.getenv('CUSIGNAL_PYLOPS') == 1' and run "
"'conda install cusignal'; "
"for more details visit ''https://github.com/rapidsai/cusignal#installation''"
)

return cusignal_message


def devito_import(message: Optional[str] = None) -> str:
if devito_enabled:
try:
Expand Down Expand Up @@ -207,20 +177,15 @@ def sympy_import(message: Optional[str] = None) -> str:


# Set package availability booleans
# cupy and cusignal: the package is imported to check everything is working correctly,
# if not the package is disabled. We do this here as both libraries are used as drop-in
# cupy: the package is imported to check everything is working correctly,
# if not the package is disabled. We do this here as this library is used as drop-in
# replacement for many numpy and scipy routines when cupy arrays are provided.
# all other libraries: we simply check if the package is available and postpone its import
# to check everything is working correctly when a user tries to create an operator that requires
# such a package
cupy_enabled: bool = (
True if (cupy_import() is None and int(os.getenv("CUPY_PYLOPS", 1)) == 1) else False
)
cusignal_enabled: bool = (
True
if (cusignal_import() is None and int(os.getenv("CUSIGNAL_PYLOPS", 1)) == 1)
else False
)
devito_enabled = util.find_spec("devito") is not None
numba_enabled = util.find_spec("numba") is not None
pyfftw_enabled = util.find_spec("pyfftw") is not None
Expand Down

0 comments on commit a6d09c1

Please sign in to comment.