summaryrefslogtreecommitdiff
path: root/src/silx/opencl/convolution.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/silx/opencl/convolution.py')
-rw-r--r--src/silx/opencl/convolution.py95
1 files changed, 49 insertions, 46 deletions
diff --git a/src/silx/opencl/convolution.py b/src/silx/opencl/convolution.py
index 481e8fb..99ecd02 100644
--- a/src/silx/opencl/convolution.py
+++ b/src/silx/opencl/convolution.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python
# /*##########################################################################
#
-# Copyright (c) 2019 European Synchrotron Radiation Facility
+# Copyright (c) 2019-2023 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -29,20 +29,30 @@ __license__ = "MIT"
__date__ = "01/08/2019"
import numpy as np
-from copy import copy # python2
from .common import pyopencl as cl
import pyopencl.array as parray
from .processing import OpenclProcessing, EventDescription
from .utils import ConvolutionInfos
+
class Convolution(OpenclProcessing):
"""
A class for performing convolution on CPU/GPU with OpenCL.
"""
- def __init__(self, shape, kernel, axes=None, mode=None, ctx=None,
- devicetype="all", platformid=None, deviceid=None,
- profile=False, extra_options=None):
+ def __init__(
+ self,
+ shape,
+ kernel,
+ axes=None,
+ mode=None,
+ ctx=None,
+ devicetype="all",
+ platformid=None,
+ deviceid=None,
+ profile=False,
+ extra_options=None,
+ ):
"""Constructor of OpenCL Convolution.
:param shape: shape of the array.
@@ -70,9 +80,14 @@ class Convolution(OpenclProcessing):
"allocate_tmp_array": True,
"dont_use_textures": False,
"""
- OpenclProcessing.__init__(self, ctx=ctx, devicetype=devicetype,
- platformid=platformid, deviceid=deviceid,
- profile=profile)
+ OpenclProcessing.__init__(
+ self,
+ ctx=ctx,
+ devicetype=devicetype,
+ platformid=platformid,
+ deviceid=deviceid,
+ profile=profile,
+ )
self._configure_extra_options(extra_options)
self._determine_use_case(shape, kernel, axes)
@@ -88,7 +103,7 @@ class Convolution(OpenclProcessing):
}
extra_opts = extra_options or {}
self.extra_options.update(extra_opts)
- self.use_textures = not(self.extra_options["dont_use_textures"])
+ self.use_textures = not (self.extra_options["dont_use_textures"])
self.use_textures &= self.check_textures_availability()
def _get_dimensions(self, shape, kernel):
@@ -133,8 +148,7 @@ class Convolution(OpenclProcessing):
if axes in convol_infos.allowed_axes[uc_name]:
self.use_case_name = uc_name
self.use_case_desc = uc_params["name"]
- #~ self.use_case_kernels = uc_params["kernels"].copy()
- self.use_case_kernels = copy(uc_params["kernels"]) # TODO use the above line once we get rid of python2
+ self.use_case_kernels = uc_params["kernels"].copy()
if self.use_case_name is None:
raise ValueError(
"Cannot find a use case for data ndim = %d, kernel ndim = %d and axes=%s"
@@ -143,8 +157,7 @@ class Convolution(OpenclProcessing):
# TODO implement this use case
if self.use_case_name == "batched_separable_2D_1D_3D":
raise NotImplementedError(
- "The use case %s is not implemented"
- % self.use_case_name
+ "The use case %s is not implemented" % self.use_case_name
)
#
self.axes = axes
@@ -168,7 +181,7 @@ class Convolution(OpenclProcessing):
"allocate_tmp_array": "data_tmp",
}
# Nonseparable transforms do not need tmp array
- if not(self.separable):
+ if not (self.separable):
self.extra_options["allocate_tmp_array"] = False
# Allocate arrays
for option_name, array_name in option_array_names.items():
@@ -182,7 +195,7 @@ class Convolution(OpenclProcessing):
if isinstance(self.kernel, np.ndarray):
self.d_kernel = parray.to_device(self.queue, self.kernel)
else:
- if not(isinstance(self.kernel, parray.Array)):
+ if not (isinstance(self.kernel, parray.Array)):
raise ValueError("kernel must be either numpy array or pyopencl array")
self.d_kernel = self.kernel
self._old_input_ref = None
@@ -207,7 +220,7 @@ class Convolution(OpenclProcessing):
% (self.mode, str(mp.keys()))
)
# TODO
- if not(self.use_textures) and self.mode.lower() == "constant":
+ if not (self.use_textures) and self.mode.lower() == "constant":
raise NotImplementedError(
"mode='constant' is not implemented without textures yet"
)
@@ -228,28 +241,30 @@ class Convolution(OpenclProcessing):
compile_options = [str("-DUSED_CONV_MODE=%d" % self._c_conv_mode)]
if self.use_textures:
kernel_files = ["convolution_textures.cl"]
- compile_options.extend([
- str("-DIMAGE_DIMS=%d" % self.data_ndim),
- str("-DFILTER_DIMS=%d" % self.kernel_ndim),
- ])
+ compile_options.extend(
+ [
+ str("-DIMAGE_DIMS=%d" % self.data_ndim),
+ str("-DFILTER_DIMS=%d" % self.kernel_ndim),
+ ]
+ )
d_kernel_ref = self.d_kernel_tex
else:
kernel_files = ["convolution.cl"]
d_kernel_ref = self.d_kernel.data
- self.compile_kernels(
- kernel_files=kernel_files,
- compile_options=compile_options
- )
+ self.compile_kernels(kernel_files=kernel_files, compile_options=compile_options)
self.ndrange = self.shape[::-1]
self.wg = None
kernel_args = [
self.queue,
- self.ndrange, self.wg,
+ self.ndrange,
+ self.wg,
None,
None,
d_kernel_ref,
np.int32(self.kernel.shape[0]),
- self.Nx, self.Ny, self.Nz
+ self.Nx,
+ self.Ny,
+ self.Nz,
]
if self.kernel_ndim == 2:
kernel_args.insert(6, np.int32(self.kernel.shape[1]))
@@ -263,10 +278,7 @@ class Convolution(OpenclProcessing):
if self.separable:
if self.data_tmp is not None:
self.swap_pattern = {
- 2: [
- ("data_in", "data_tmp"),
- ("data_tmp", "data_out")
- ],
+ 2: [("data_in", "data_tmp"), ("data_tmp", "data_out")],
3: [
("data_in", "data_out"),
("data_out", "data_tmp"),
@@ -322,14 +334,14 @@ class Convolution(OpenclProcessing):
else:
raise ValueError("Please provide either arr= or shape=")
if ndim < dim_min or ndim > dim_max:
- raise ValueError("%s dimensions should be between %d and %d"
- % (name, dim_min, dim_max)
+ raise ValueError(
+ "%s dimensions should be between %d and %d" % (name, dim_min, dim_max)
)
return ndim
def _check_array(self, arr):
# TODO allow cl.Buffer
- if not(isinstance(arr, parray.Array) or isinstance(arr, np.ndarray)):
+ if not (isinstance(arr, parray.Array) or isinstance(arr, np.ndarray)):
raise TypeError("Expected either pyopencl.array.Array or numpy.ndarray")
# TODO composition with ImageProcessing/cast
if arr.dtype != np.float32:
@@ -351,14 +363,12 @@ class Convolution(OpenclProcessing):
self.data_in = array
data_in_ref = self.data_in
if output is not None:
- if not(isinstance(output, np.ndarray)):
+ if not (isinstance(output, np.ndarray)):
self._old_output_ref = self.data_out
self.data_out = output
# Update OpenCL kernel arguments with new array references
self.kernel_args = self._configure_kernel_args(
- self.kernel_args,
- data_in_ref,
- self.data_out
+ self.kernel_args, data_in_ref, self.data_out
)
def _separable_convolution(self):
@@ -372,9 +382,7 @@ class Convolution(OpenclProcessing):
# Batched: one kernel call in total
opencl_kernel = self.kernels.get_kernel(self.use_case_kernels[axis])
opencl_kernel_args = self._configure_kernel_args(
- self.kernel_args,
- input_ref,
- output_ref
+ self.kernel_args, input_ref, output_ref
)
ev = opencl_kernel(*opencl_kernel_args)
if self.profile:
@@ -395,9 +403,7 @@ class Convolution(OpenclProcessing):
self.data_out = self._old_output_ref
self._old_output_ref = None
self.kernel_args = self._configure_kernel_args(
- self.kernel_args,
- self.data_in,
- self.data_out
+ self.kernel_args, self.data_in, self.data_out
)
def _get_output(self, output):
@@ -433,7 +439,4 @@ class Convolution(OpenclProcessing):
res = self._get_output(output)
return res
-
__call__ = convolve
-
-