Repository navigation
CUDA: Add support for passing tuples to kernels via vectorize #6563
Copy link
Copy link
Closed
Labels
CUDACUDA related issue/PRCUDA related issue/PRfeature_requestgood second issueA good issue for second time contributorsA good issue for second time contributors
Milestone
Description
Feature request
numba version used: 0.53.0.dev0+357.g4d3d2673c.dirty
I would like to pass tuples to CUDA kernels by using vectorize similar to #6343. Here is the code and subsequent error
from numba import cuda, vectorize
import numpy as np
import pkg_resources
# working based on https://github.com/numba/numba/pull/6343
print('numba version used: ' + str(pkg_resources.get_distribution("numba").version))
@cuda.jit
def f(r, x):
r[0] = x[0][0]
r[1] = x[1]
r[2] = x[2][0]
z = np.ones(1, dtype=np.int64)
x = (1 * z, 10, (4, 3))
r = np.zeros(len(x), dtype=np.int64)
# Use the syntax: kernel_function[blockspergrid, threadsperblock](arg0, arg1, ..., argn)
f[1, 1](r, x)
print(r)
def f2(r2, x2):
out = 0
# if the next two lines are commented out, the error is TypeError: argument #2 has invalid type of <class 'tuple'>
for i in range(len(x2)):
out += x2[i]
return out
z2 = np.arange(1024, dtype=np.int64)
list_tuple = []
for n in range(1024):
list_tuple.append((n, n+1, n+2))
x2 = (1 * z2, list_tuple)
r2 = np.zeros((len(z2),len(x2)), dtype=np.int64)
v_cuda = vectorize(['int64(int64, int64)'], target = 'cuda')(f2)
out = v_cuda(r2, x2)Error is
File "D:\Documents\Cristi\Tools\Python\GitHub\numba\6343.py", line 39, in <module>
v_cuda = vectorize(['int64(int64, int64)'],)(f2)
File "D:\Kit\PortableApps\Miniconda_numba_dev\lib\site-packages\numba\np\ufunc\decorators.py", line 120, in wrap
vec.add(sig)
File "D:\Kit\PortableApps\Miniconda_numba_dev\lib\site-packages\numba\np\ufunc\deviceufunc.py", line 399, in add
corefn, return_type = self._compile_core(devfnsig)
File "D:\Kit\PortableApps\Miniconda_numba_dev\lib\site-packages\numba\cuda\vectorizers.py", line 15, in _compile_core
cudevfn = cuda.jit(sig, device=True, inline=True)(self.pyfunc)
File "D:\Kit\PortableApps\Miniconda_numba_dev\lib\site-packages\numba\cuda\decorators.py", line 134, in device_jit
debug=debug)
File "D:\Kit\PortableApps\Miniconda_numba_dev\lib\site-packages\numba\cuda\compiler.py", line 294, in compile_device
return DeviceFunction(pyfunc, return_type, args, inline=True, debug=False)
File "D:\Kit\PortableApps\Miniconda_numba_dev\lib\site-packages\numba\cuda\compiler.py", line 325, in __init__
debug=self.debug, inline=self.inline)
File "D:\Kit\PortableApps\Miniconda_numba_dev\lib\site-packages\numba\core\compiler_lock.py", line 32, in _acquire_compile_lock
return func(*args, **kwargs)
File "D:\Kit\PortableApps\Miniconda_numba_dev\lib\site-packages\numba\cuda\compiler.py", line 48, in compile_cuda
locals={})
File "D:\Kit\PortableApps\Miniconda_numba_dev\lib\site-packages\numba\core\compiler.py", line 603, in compile_extra
return pipeline.compile_extra(func)
File "D:\Kit\PortableApps\Miniconda_numba_dev\lib\site-packages\numba\core\compiler.py", line 353, in compile_extra
return self._compile_bytecode()
File "D:\Kit\PortableApps\Miniconda_numba_dev\lib\site-packages\numba\core\compiler.py", line 415, in _compile_bytecode
return self._compile_core()
File "D:\Kit\PortableApps\Miniconda_numba_dev\lib\site-packages\numba\core\compiler.py", line 395, in _compile_core
raise e
File "D:\Kit\PortableApps\Miniconda_numba_dev\lib\site-packages\numba\core\compiler.py", line 386, in _compile_core
pm.run(self.state)
File "D:\Kit\PortableApps\Miniconda_numba_dev\lib\site-packages\numba\core\compiler_machinery.py", line 339, in run
raise patched_exception
File "D:\Kit\PortableApps\Miniconda_numba_dev\lib\site-packages\numba\core\compiler_machinery.py", line 330, in run
self._runPass(idx, pass_inst, state)
File "D:\Kit\PortableApps\Miniconda_numba_dev\lib\site-packages\numba\core\compiler_lock.py", line 32, in _acquire_compile_lock
return func(*args, **kwargs)
File "D:\Kit\PortableApps\Miniconda_numba_dev\lib\site-packages\numba\core\compiler_machinery.py", line 289, in _runPass
mutated |= check(pss.run_pass, internal_state)
File "D:\Kit\PortableApps\Miniconda_numba_dev\lib\site-packages\numba\core\compiler_machinery.py", line 262, in check
mangled = func(compiler_state)
File "D:\Kit\PortableApps\Miniconda_numba_dev\lib\site-packages\numba\core\typed_passes.py", line 100, in run_pass
raise_errors=self._raise_errors)
File "D:\Kit\PortableApps\Miniconda_numba_dev\lib\site-packages\numba\core\typed_passes.py", line 72, in type_inference_stage
infer.propagate(raise_errors=raise_errors)
File "D:\Kit\PortableApps\Miniconda_numba_dev\lib\site-packages\numba\core\typeinfer.py", line 1071, in propagate
raise errors[0]
TypingError: No implementation of function Function(<built-in function len>) found for signature:
len(int64)
There are 16 candidate implementations:
- Of which 16 did not match due to:
Overload of function 'len': File: <numerous>: Line N/A.
With argument(s): '(int64)':
No match.
During: resolving callee type: Function(<built-in function len>)
During: typing of call at D:\Documents\Cristi\Tools\Python\GitHub\numba\6343.py (28)
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
CUDACUDA related issue/PRCUDA related issue/PRfeature_requestgood second issueA good issue for second time contributorsA good issue for second time contributors
Activity
stuartarchibald commentedon Dec 11, 2020
Thanks for the request. Just to check, you'd like to be able to pass a
tupleas an argument to a@vectorizefunction, ideally targetting theCUDAbackend?cristipurdel commentedon Dec 11, 2020
Yes, exactly.
My understanding, based at least for my needs, is that the degree of difficulty to add new features is ranked something like:
vectorize(cuda)
guvectorize(cuda)
njit(cuda)
vectorize(parallel)
guvectorize(parallel)
vectorize(cpu)
guvectorize(cpu)
Most features are added at the "bottom" (since it is easier to do small steps improvements) and then make way to introduce them for the ones on the "top".
For using some easier stuff, I found @vectorize cuda, is really powerful, but if I want to run some more complex stuff, I really hate to fall back to guvectorize(cpu) or use other modules e.g. numpy.
The reason I request the above, was that I was hoping it could trickle up the difficulty ranking.
Maybe it would also be helpful to make in the docs, a simplified euler diagram of which features do not work with each "decorator". So that in the future, it will be a unified decorator (hopefully vectorize) ... to rule them all :)
stuartarchibald commentedon Dec 14, 2020
I'm not really sure what this means. The difficulty in adding new features is not hugely connected to the decorators involved, it's often more about how well a feature maps to a given target and what the constraints are in the implementation, e.g.
@vectorizehas to produce a valid NumPy ufunc.You may wish to look at CuPy, which provides a NumPy interface for CUDA GPUs and can share "arrays" with Numba via https://numba.readthedocs.io/en/stable/cuda/cuda_array_interface.html
These decorators do different things to provide flexibility of expression for users. For each hardware target,
@vectorizeexists to permit writingufuncs,@guvectorizeexists to permit writing generalised ufuncs and@jitexists to provide a more general compilation mechanism.[-]CUDA: Add support for passing tuples to kernels via vectorize, extend functionality of #6343[/-][+]CUDA: Add support for passing tuples to kernels via vectorize[/+]cristipurdel commentedon Dec 14, 2020
From what I have experienced, vectorize has teh least amount of features.
I could use CuPy or tensorflow, but I can not use the numba's vectorize implementation.
stuartarchibald commentedon Dec 14, 2020
@vectorizeis implementing this specification: https://numpy.org/doc/stable/reference/ufuncs.html out of interest, what specific features are you looking for from that specification?cristipurdel commentedon Dec 15, 2020
Support for passing tuples, and later on lists, dictionaries, on the cuda target
Also matmul and minverse (currently not available in numpy), would be welcomed also
stuartarchibald commentedon Dec 15, 2020
I think some of this is outside of the specification but agree that accepting more array-like types could be useful.
gmarkall commentedon Jan 29, 2021
It seems that regular NumPy ufuncs accept tuples:
So I think this is a reasonable feature request for the CUDA target.
gmarkall commentedon Jan 29, 2021
A starter patch:
which enables the following to work:
but causes one test fail:
gmarkall commentedon Jan 29, 2021
I've added this to the 0.54 milestone, to remind me to take a look at a proper implementation ahead of 0.54.
ashutoshvarma commentedon Feb 5, 2021
While looking into starter patch by @gmarkall
The
test_auto_transferis failing due the following change :-Without it all tests pass without problem
Since
arywould always be eithernp.ndarrayorDeviceNDArraytype, keepingary.dtypeshould be fine? (correct me if I missed something )Ideally, the above change should not break anything, but for some reason, if
aryis of DeviceNDArray type thennp.asarray(ary).dtypegives the wrong dtype.For DeviceNDArray ary,
np.asarray(ary)will always be afloat64ndarray irrespective of original dtypeAfter digging more, looks like problem might be in
DeviceNDArray.__array__()methodnumba/numba/cuda/cudadrv/devicearray.py
Lines 482 to 486 in 00ad127
In above, passing even
None(dtype) to__array__of ndarray will return new array with default dtype (float64)ndarray.__array__docs - https://numpy.org/doc/stable/reference/generated/numpy.ndarray.__array__.htmlChanging
__array__(dtype)to either__array__(self.dtype)or__array__()should fix this.gmarkall commentedon Feb 8, 2021
My local testing indicates that PR #6698 fixes the issue that comes up when running tests with the starter patch. Many thanks for tracing through this and finding fix, @ashutoshvarma!
I'd have to go back and check, but I think that
aryended up being a tuple if the user passes a tuple to the ufunc, as in #6563 (comment) (if that's not the case, then somehow I found that we'd get something that didn't have adtypepopping up here, but don't recall how it occurred).CUDA: Support passing tuples to ufuncs
gmarkall commentedon Mar 31, 2021
Now that #6698 is in (the fix for #6697) this can be fixed - #6878 contains the fix.
cristipurdel commentedon May 14, 2021
Mayne I am missing something, but my desired initial output is not working
Please reopen the issue
gmarkall commentedon May 14, 2021
I have a couple of queries about your initial example:
makes the argument
x2off2anint, butf2tries to take its length:Secondly,
x2is a tuple of an array and a list of tuples:Is the example as you intended? If so, can you explain a bit more about why either of the above should work? (perhaps I'm missing something?)
cristipurdel commentedon May 15, 2021
For the first part:
I was trying to do a loop over the input data with vectorize, since I found guvectorize too slow, but it should be fix now in #6889.
If it is not possible at the moment to do operations with a for loop using vectorize, the incident can remain closed.
For the second part:
I was trying to use smth like an 2D array equivalent to pass to vectorize, in order to use the for loop, since again, I found guvectorize too slow.
gmarkall commentedon May 17, 2021
There's no change in performance with #6889 - it only tells the user if they're using
guvectorizein an inefficient way. Once it's merged, you might find that yourguvectorizecase produces a warning - if so,guvectorizemay not be appropriate for the use case, or the way in which the problem is mapped to aguvectorizefunction may need to be changed.You can use for loops in
@vectorizefunctions - the issue in the above code is that it treats a scalar as if it is something that has length. If you replacelen(x2)with something else (e.g. an integer), then this would remove that problem.The problem here is the list - you can't pass a list to a vectorized function, only tuples and arrays.
For further discussion related to the above code, it would be good to create a thread on the Numba Discourse forums: https://numba.discourse.group