使用numba.cuda在GPU上运行Sympy lambdify函数

使用numba.cuda在GPU上运行Sympy lambdify函数,cuda,sympy,numba,Cuda,Sympy,Numba,我正在尝试使用numba.cuda在GPU上运行任意sympy lambdify函数。到目前为止,由于numba.jit允许函数返回值,但numba.cuda.jit不允许函数返回值(numba.cuda.jit内核无法返回值),我在每一步都遇到了错误。这可能是因为我对numba的工作原理有一个根本性的误解,但文档中的示例有点稀少,我尝试对每个给定的示例进行变异,以尝试做我不想做的事情 我尝试过的例子: 非CUDA jit功能(有效) 相同代码的CUDA jit示例 import sympy f

我正在尝试使用numba.cuda在GPU上运行任意sympy lambdify函数。到目前为止,由于numba.jit允许函数返回值,但numba.cuda.jit不允许函数返回值(numba.cuda.jit内核无法返回值),我在每一步都遇到了错误。这可能是因为我对numba的工作原理有一个根本性的误解,但文档中的示例有点稀少,我尝试对每个给定的示例进行变异,以尝试做我不想做的事情

我尝试过的例子:

非CUDA jit功能(有效)

相同代码的CUDA jit示例

import sympy
from sympy.abc import y
from numba import cuda

f = sympy.lambdify(y, sympy.sin(y), 'math')
g = cuda.jit(f)
g(1) #error
返回以下内容:

TypingError: Failed in nopython mode pipeline (step: nopython frontend)
No conversion from float64 to none for '$8return_value.3', defined at None
File "<lambdifygenerated-5>", line 2:
def _lambdifygenerated(y):
    return (sin(y))
    ^

During: typing of assignment at <lambdifygenerated-5> (2)

File "<lambdifygenerated-5>", line 2:
def _lambdifygenerated(y):
    return (sin(y))
返回值为:

26.9 ms ± 15.7 ms per loop (mean ± std. dev. of 7 runs, 5 loops each)
958 ms ± 16.3 ms per loop (mean ± std. dev. of 7 runs, 5 loops each)
[ 0.          0.84147098  0.90929743 ... -0.87103474 -0.05727351
  0.80914472]
我正在尝试使用numba.cuda在GPU上运行任意sympy lambdify函数


在目前的开发状态下,这在Numba中是不受支持的,也无法实现。Numba仅支持GPU上的Python语言功能框架,如果无法将函数直接降低到支持的
math
函数,则GPU上不支持外部函数。

Symphy库在Numba cuda jit内核中不受支持。你需要坚持下去,谢谢你的回复。看来我需要从另一个方向来明确地将Symphy表达式转换为那些受支持的python特性……我能提出的最明显的建议是将您的
f
函数实现为一个函数。不过,我承认这和lambda有很大的区别。谢谢你的帮助!虽然我认为我以前尝试过,但实际上我最近刚刚取得了一些小的成功,首先将f转换为numba.jit函数,然后在cuda内核中调用它。不确定这是否是一种正确的方法,但与CPU版本的代码相比,它确实显示了一些相当显著的加速。如果这不是我最终需要的Symphy函数的范围,我肯定会深入研究那些cuda设备函数。再次感谢!打印
f.\uuuuu文档\uuuuu
以查看
lamdify
生成的代码。到目前为止,我只看了
numpy
产品
lambdify
基本上根据目标语言进行词汇替换。因此
synpy.sin
被更改为
math.sin
np.sin
。我不认为
numba
可以在该函数内部“编译”它。
import sympy
import numpy
from sympy.abc import y
from numba import cuda

f = sympy.lambdify(y, sympy.sin(y), 'math')

@cuda.jit
def increment_by_one(an_array):
    # Thread id in a 1D block
    tx = cuda.threadIdx.x
    # Block id in a 1D grid
    ty = cuda.blockIdx.x
    # Block width, i.e. number of threads per block
    bw = cuda.blockDim.x
    # Compute flattened index inside the array
    pos = tx + ty * bw
    if pos < an_array.size:  # Check array boundaries
        an_array[pos] += 1
        
array = numpy.arange(3.)
print(array) #returns [0. 1. 2.]
blockspergrid = 2
threadsperblock = 32
increment_by_one[blockspergrid, threadsperblock](array)
print(array) #returns [1. 2. 3.]
import sympy
import numpy
from sympy.abc import y
from numba import cuda

f = sympy.lambdify(y, sympy.sin(y), 'math')

@cuda.jit
def cuda_f(an_array):
    # Thread id in a 1D block
    tx = cuda.threadIdx.x
    # Block id in a 1D grid
    ty = cuda.blockIdx.x
    # Block width, i.e. number of threads per block
    bw = cuda.blockDim.x
    # Compute flattened index inside the array
    pos = tx + ty * bw
    if pos < an_array.size:  # Check array boundaries
        an_array[pos] = f(an_array[pos])
        
array = numpy.arange(3.)
print(array) #returns [0. 1. 2.]
cuda_f(array)
blockspergrid = 2
threadsperblock = 32
cuda_f[blockspergrid, threadsperblock](array) #error
print(array)
TypingError: Failed in nopython mode pipeline (step: nopython frontend)
Untyped global name 'f': cannot determine Numba type of <class 'function'>

File "<ipython-input-7-9ef7fd8543d7>", line 19:
def cuda_f(an_array):
    <source elided>
    if pos < an_array.size:  # Check array boundaries
        an_array[pos] += f(an_array[pos])
        ^
import sympy
import numpy
from sympy.abc import y
from numba import cuda
import numba

f = sympy.lambdify(y, sympy.sin(y), 'math')
g = numba.jit(f)

@cuda.jit
def sympy_kernel(x, out):
    startx = cuda.grid(1)    
    stridex = cuda.gridsize(1) 

    for i in range(startx, x.shape[0], stridex):
        out[i] = g(x[i])

@numba.jit
def sympy_cpu(x, out):
    for i in range(len(out)):
        out[i] = g(x[i])
        
        
array = numpy.arange(100000000.)
array_device = cuda.to_device(array)
out = numpy.arange(100000000.)
out_device = cuda.to_device(out)
blockspergrid = 64
threadsperblock = 64
%timeit -n5 sympy_kernel[blockspergrid, threadsperblock](array_device, out_device); cuda.synchronize()
%timeit -n5 sympy_cpu(array, out)
out_host = out_device.copy_to_host()
print(out_host)
26.9 ms ± 15.7 ms per loop (mean ± std. dev. of 7 runs, 5 loops each)
958 ms ± 16.3 ms per loop (mean ± std. dev. of 7 runs, 5 loops each)
[ 0.          0.84147098  0.90929743 ... -0.87103474 -0.05727351
  0.80914472]