pyCuda,发送多个单变量参数的问题

Posted

技术标签:

【中文标题】pyCuda,发送多个单变量参数的问题【英文标题】:pyCuda, issues sending multiple single variable arguments 【发布时间】:2021-01-24 05:38:03 【问题描述】:

我在这里有一个 pycuda 程序,它从命令行读取图像并将颜色反转的版本保存回来:

import pycuda.autoinit
import pycuda.driver as device
from pycuda.compiler import SourceModule as cpp

import numpy as np
import sys
import cv2

modify_image = cpp("""
__global__ void modify_image(int pixelcount, unsigned char* inputimage, unsigned char* outputimage)

  int id = threadIdx.x + blockIdx.x * blockDim.x;
  if (id >= pixelcount)
    return;

  outputimage[id] = 255 - inputimage[id];

""").get_function("modify_image")

print("Loading image")

image = cv2.imread(sys.argv[1], cv2.IMREAD_UNCHANGED).astype(np.uint8)

print("Processing image")

pixels = image.shape[0] * image.shape[1]
newchannels = []
for channel in cv2.split(image):
  output = np.zeros_like(channel)
  modify_image(
    device.In(np.int32(pixels)),
    device.In(channel),
    device.Out(output),
    block=(1024,1,1), grid=(pixels // 1024 + 1, 1))
  newchannels.append(output)
finalimage = cv2.merge(newchannels)

print("Saving image")

cv2.imwrite("processed.png", finalimage)

print("Done")

即使在较大的图像上,它也能正常工作。然而,在尝试扩展程序的功能时,我遇到了一个非常奇怪的问题,在内核中添加第二个变量参数会导致程序完全失败,只是保存了一个完全黑色的图像。以下代码不起作用;

import pycuda.autoinit
import pycuda.driver as device
from pycuda.compiler import SourceModule as cpp

import numpy as np
import sys
import cv2

modify_image = cpp("""
__global__ void modify_image(int pixelcount, int width, unsigned char* inputimage, unsigned char* outputimage)

  int id = threadIdx.x + blockIdx.x * blockDim.x;
  if (id >= pixelcount)
    return;

  outputimage[id] = 255 - inputimage[id];

""").get_function("modify_image")

print("Loading image")

image = cv2.imread(sys.argv[1], cv2.IMREAD_UNCHANGED).astype(np.uint8)

print("Processing image")

pixels = image.shape[0] * image.shape[1]
newchannels = []
for channel in cv2.split(image):
  output = np.zeros_like(channel)
  modify_image(
    device.In(np.int32(pixels)),
    device.In(np.int32(image.shape[0])),
    device.In(channel),
    device.Out(output),
    block=(1024,1,1), grid=(pixels // 1024 + 1, 1))
  newchannels.append(output)
finalimage = cv2.merge(newchannels)

print("Saving image")

cv2.imwrite("processed.png", finalimage)

print("Done")

唯一的区别在于两行,内核头和它的调用。内核本身的实际代码没有改变,但是这个小添加完全破坏了程序。编译器和解释器都不会抛出任何错误。我不知道如何开始调试它,并且非常困惑。

【问题讨论】:

【参考方案1】:

好的,所以通过将变量参数更改为内核中的指针,它修复了代码,我不确定如何或为什么。这是内核的修改版本;

__global__ void modify_image(int* pixelcount, int* width, unsigned char* inputimage, unsigned char* outputimage)

  int id = threadIdx.x + blockIdx.x * blockDim.x;
  if (id >= *pixelcount)
    return;

  outputimage[id] = 255 - inputimage[id];

代码的其余部分保持不变。如果有人想解释为什么这是一个成功的修复,我将不胜感激。

【讨论】:

【参考方案2】:

device.In 及其亲属被设计用于支持 Python 缓冲区协议的对象(如 numpy 数组)。您的问题的根源是使用它们来传输非缓冲对象。

只需将具有正确 numpy dtype 的标量直接传递给内核调用。不要使用device.In。这在原始案例中起作用的事实完全是一个意外

【讨论】:

啊,好的,谢谢。这很有意义。我认为 In 和 Out 调用在所有情况下都是必要的,但我想不是

以上是关于pyCuda,发送多个单变量参数的问题的主要内容,如果未能解决你的问题,请参考以下文章

Pycuda 在函数参数中按值声明数组时返回错误

奇偶排序:在 CUDA 中使用多个块时结果不正确

PyCUDA 和 NumbaPro CUDA Python 有啥区别?

PyCuda - 使用 *.cubin - 未找到命名符号

关于 pycuda._driver.LogicError: cuMemcpyDtoH failed: invalid argument 的问题

如何在 pyCUDA 内核中生成随机数?