From 453ef6baeb71bbac9c71f45fc84abac72a5dd273 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danie=CC=88l=20de=20Kok?= Date: Mon, 23 May 2022 12:15:13 +0200 Subject: [PATCH 1/4] Replace use of gpu_is_available with has_cupy_gpu This PR is in preparation of better non-CUDA device support. Once we support non-CUDA GPUs, there may be GPUs available that are not 'CuPy GPUs'. In all places where we use `gpu_is_available` we actually mean: is 'CuPy available with a CUDA GPU'? So, this PR replaces uses of `gpu_is_available` to `has_cupy_gpu`. This allows us to use `gpu_is_available` in the future to check if any GPU is available. In addition to that, some code had expressions like ``` has_cupy and gpu_is_available() ``` This PR simplify such conditions to `has_cupy_gpu`, since `has_cupy_gpu` implies that `has_cupy`. --- thinc/tests/backends/test_ops.py | 14 +++++--------- thinc/tests/layers/test_tensorflow_wrapper.py | 6 +++--- thinc/tests/model/test_model.py | 5 ++--- thinc/util.py | 8 ++++---- 4 files changed, 14 insertions(+), 19 deletions(-) diff --git a/thinc/tests/backends/test_ops.py b/thinc/tests/backends/test_ops.py index e095142b1..0d06d4833 100644 --- a/thinc/tests/backends/test_ops.py +++ b/thinc/tests/backends/test_ops.py @@ -8,8 +8,8 @@ from packaging.version import Version from thinc.api import NumpyOps, CupyOps, Ops, get_ops from thinc.api import get_current_ops, use_ops -from thinc.util import torch2xp, xp2torch, gpu_is_available -from thinc.compat import has_torch, torch_version +from thinc.util import torch2xp, xp2torch +from thinc.compat import has_cupy_gpu, has_torch, torch_version from thinc.api import fix_random_seed from thinc.api import LSTM from thinc.types import Floats2d @@ -26,7 +26,7 @@ BLIS_OPS = NumpyOps(use_blis=True) CPU_OPS = [NUMPY_OPS, VANILLA_OPS] XP_OPS = [NUMPY_OPS] -if CupyOps.xp is not None and gpu_is_available(): +if has_cupy_gpu: XP_OPS.append(CupyOps()) ALL_OPS = XP_OPS + [VANILLA_OPS] @@ -591,9 +591,7 @@ def test_backprop_seq2col_window_two(ops, dtype): ops.xp.testing.assert_allclose(seq, expected, atol=0.001, rtol=0.001) -@pytest.mark.skipif( - CupyOps.xp is None or not gpu_is_available(), reason="needs GPU/CuPy" -) +@pytest.mark.skipif(not has_cupy_gpu, reason="needs GPU/CuPy") @pytest.mark.parametrize("nW", [1, 2]) def test_large_seq2col_gpu_against_cpu(nW): cupy_ops = CupyOps() @@ -615,9 +613,7 @@ def test_large_seq2col_gpu_against_cpu(nW): assert_allclose(cols, cols_gpu.get()) -@pytest.mark.skipif( - CupyOps.xp is None or not gpu_is_available(), reason="needs GPU/CuPy" -) +@pytest.mark.skipif(not has_cupy_gpu, reason="needs GPU/CuPy") @pytest.mark.parametrize("nW", [1, 2]) def test_large_backprop_seq2col_gpu_against_cpu(nW): cupy_ops = CupyOps() diff --git a/thinc/tests/layers/test_tensorflow_wrapper.py b/thinc/tests/layers/test_tensorflow_wrapper.py index ff254ffc0..c1b85da3b 100644 --- a/thinc/tests/layers/test_tensorflow_wrapper.py +++ b/thinc/tests/layers/test_tensorflow_wrapper.py @@ -2,8 +2,8 @@ import pytest from thinc.api import Adam, ArgsKwargs, Linear, Model, TensorFlowWrapper from thinc.api import get_current_ops, keras_subclass, tensorflow2xp, xp2tensorflow -from thinc.util import gpu_is_available, to_categorical -from thinc.compat import has_tensorflow +from thinc.util import to_categorical +from thinc.compat import has_cupy_gpu, has_tensorflow from ..util import check_input_converters, make_tempdir @@ -359,7 +359,7 @@ def test_tensorflow_wrapper_to_cpu(tf_model): @pytest.mark.skipif(not has_tensorflow, reason="needs TensorFlow") -@pytest.mark.skipif(not gpu_is_available(), reason="needs GPU/cupy") +@pytest.mark.skipif(not has_cupy_gpu, reason="needs GPU/cupy") def test_tensorflow_wrapper_to_gpu(model, X): model.to_gpu(0) diff --git a/thinc/tests/model/test_model.py b/thinc/tests/model/test_model.py index 9ec71fc93..087e481c5 100644 --- a/thinc/tests/model/test_model.py +++ b/thinc/tests/model/test_model.py @@ -6,8 +6,7 @@ from thinc.api import Shim, Softmax, chain, change_attr_values from thinc.api import concatenate, set_dropout_rate from thinc.api import use_ops, with_debug, wrap_model_recursive -from thinc.util import gpu_is_available -from thinc.compat import has_cupy +from thinc.compat import has_cupy_gpu import numpy from ..util import make_tempdir @@ -410,7 +409,7 @@ def test_model_gpu(): import ml_datasets ops = "cpu" - if has_cupy and gpu_is_available(): + if has_cupy_gpu: ops = "cupy" with use_ops(ops): diff --git a/thinc/util.py b/thinc/util.py index 16f0f0196..726cd5f94 100644 --- a/thinc/util.py +++ b/thinc/util.py @@ -44,7 +44,7 @@ def fix_random_seed(seed: int = 0) -> None: # pragma: no cover numpy.random.seed(seed) if has_torch: torch.manual_seed(seed) - if has_cupy and gpu_is_available(): + if has_cupy_gpu: cupy.random.seed(seed) if has_torch and has_torch_gpu: torch.cuda.manual_seed_all(seed) @@ -125,7 +125,7 @@ def to_numpy(data): # pragma: no cover def set_active_gpu(gpu_id: int) -> "cupy.cuda.Device": # pragma: no cover """Set the current GPU device for cupy and torch (if available).""" - if not gpu_is_available(): + if not has_cupy_gpu: raise ValueError("No GPU devices detected") device = cupy.cuda.device.Device(gpu_id) @@ -153,7 +153,7 @@ def prefer_gpu(gpu_id: int = 0) -> bool: # pragma: no cover """Use GPU if it's available. Returns True if so, False otherwise.""" from .backends.cupy_ops import CupyOps - if not gpu_is_available(): + if not has_cupy_gpu: return False else: require_gpu(gpu_id=gpu_id) @@ -163,7 +163,7 @@ def prefer_gpu(gpu_id: int = 0) -> bool: # pragma: no cover def require_gpu(gpu_id: int = 0) -> bool: # pragma: no cover from .backends import set_current_ops, CupyOps - if not gpu_is_available(): + if not has_cupy_gpu: raise ValueError("No GPU devices detected") set_current_ops(CupyOps()) From 8ee11d9777ace600f09a85d8f57f4687713798dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danie=CC=88l=20de=20Kok?= Date: Mon, 23 May 2022 16:34:13 +0200 Subject: [PATCH 2/4] Remove unused import --- thinc/util.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/thinc/util.py b/thinc/util.py index 726cd5f94..878c856e0 100644 --- a/thinc/util.py +++ b/thinc/util.py @@ -151,8 +151,6 @@ def require_cpu() -> bool: # pragma: no cover def prefer_gpu(gpu_id: int = 0) -> bool: # pragma: no cover """Use GPU if it's available. Returns True if so, False otherwise.""" - from .backends.cupy_ops import CupyOps - if not has_cupy_gpu: return False else: From 1088099e904e1b43d913072c33e153ca75de38ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danie=CC=88l=20de=20Kok?= Date: Tue, 24 May 2022 08:44:13 +0200 Subject: [PATCH 3/4] Improve error message when no CUDA GPU is found --- thinc/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/thinc/util.py b/thinc/util.py index 878c856e0..dd5ae548b 100644 --- a/thinc/util.py +++ b/thinc/util.py @@ -126,7 +126,7 @@ def to_numpy(data): # pragma: no cover def set_active_gpu(gpu_id: int) -> "cupy.cuda.Device": # pragma: no cover """Set the current GPU device for cupy and torch (if available).""" if not has_cupy_gpu: - raise ValueError("No GPU devices detected") + raise ValueError("No CUDA GPU devices detected") device = cupy.cuda.device.Device(gpu_id) device.use() From 09dd1ac54cdcb0d95f403b86b4b9388eaab3450e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danie=CC=88l=20de=20Kok?= Date: Tue, 24 May 2022 09:23:20 +0200 Subject: [PATCH 4/4] Fix another error message when no CUDA GPU is found --- thinc/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/thinc/util.py b/thinc/util.py index dd5ae548b..cdfdf4c1e 100644 --- a/thinc/util.py +++ b/thinc/util.py @@ -162,7 +162,7 @@ def require_gpu(gpu_id: int = 0) -> bool: # pragma: no cover from .backends import set_current_ops, CupyOps if not has_cupy_gpu: - raise ValueError("No GPU devices detected") + raise ValueError("No CUDA GPU devices detected") set_current_ops(CupyOps()) set_active_gpu(gpu_id)