我正在尝试使用pyopenCL计算python中网络摄像头流的平均值。作为测试,我试图计算多个帧上的代表矩阵的平均值,如下所示:
import pyopencl as cl
import numpy as np
import time
import os
os.environ['PYOPENCL_CTX']='0'
ctx = cl.create_some_context()
queue = cl.CommandQueue(ctx)
length = 480
width = 320
nFrames = 60
matrix = np.zeros(shape=(length,width,nFrames)).astype(np.float32)
for i in range(nFrames):
matrix[:,:,i] = float(i)
matrix_GPU = np.zeros(shape=(length,width)).astype(np.float32)
matrix_CPU = np.zeros_like(matrix_GPU)
final_matrix = np.zeros_like(matrix2t)
matrix_GPU_vector = np.reshape(matrix_GPU,matrix_GPU.size)
mf = cl.mem_flags
dest_buf = cl.Buffer(ctx, mf.WRITE_ONLY, matrix_GPU.nbytes)
prg = cl.Program(ctx, """
__kernel void summatrices(const unsigned int size,
__global float * a,
__global float * b,
__global float * sum)
{
int i = get_global_id(0);
sum[i] = a[i] + b[i];
}
""").build()
t0 = time.time()
for i in range(nFrames):
matrix_GPU = matrix[:,:,i].astype(np.float32)
matrix_GPU_vector = np.reshape(matrix_GPU,matrix_GPU.size)
a_buf = cl.Buffer(ctx, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf=matrix_GPU_vector)
b_buf = cl.Buffer(ctx, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf=final_matrix)
prg.summatrices(queue, matrix_GPU_vector.shape, None,np.int32(len(matrix_GPU_vector)), a_buf, b_buf, dest_buf)
temp_matrix = np.empty_like(matrix_GPU_vector)
cl.enqueue_copy(queue, temp_matrix , dest_buf)
final_matrix = temp_matrix
final_matrix = final_matrix/nFrames
final_matrix = np.reshape(final_matrix,(length,width))
delta_t = time.time() - t0
print 'OpenCL GPU Multiplication: ' + str(delta_t)
matrix_CPU = np.sum(matrix[:,:,:], axis=2)/nFrames
delta_t = time.time() - (t0 + delta_t)
print 'OpenCL CPU Multiplication: ' + str(delta_t)
#print matrix
#print final_matrix
#print matrix_CPU
eq = (final_matrix==matrix_CPU).all()
print eq
然而,似乎我的代码在我的GPU上比在我的CPU上慢了30倍。这很可能是由于我使用for-loop和我缺乏工作组分配。
是否可以剥离python for-loop并正确分配我的工作组?
答案 0 :(得分:0)
既然你说它是一个测试,我想在一天结束时你想要做的计算比一些添加更多。以下是您可以尝试增强代码的两件事:
cl.enqueue_write_buffer()
函数或cl.enqueue_copy()
。似乎第一个函数现在已弃用并由第二个函数替换。所以它应该像cl.enqueue_copy(queue, a_buf, matrix_GPU_vector)
matrix_GPU
它已经在内存中正确对齐了。 顺便说一句,如果您进行测试以模拟从网络摄像头接收流的应用,那么您不应该使用RGB矩阵吗?我的意思是你可以接收24位RGB图像,可以用int8更好地模拟,没有?
答案 1 :(得分:0)
既然你说你以后会做更高级的事情:
我会在非阻塞模式下工作并创建4个缓冲区,a1 / a2,b1 / b2(在开始时只创建一次)。 还有2个队列,一个用于I / O,一个用于内核。 然后每个奇数帧使用I / O_queue将数据复制到a1和b1,并使用kernel_queue运行内核。每个偶数帧使用a2 / b2:
IO->a1-| a2-| a1-|
IO->b1-| b2-| b1-|
KER-> ke-| ke-| ke-|
IO-> re re re
您应该使用事件a来检查在复制数据之前是否未启动内核(使用buffer.enqueue_copy()的返回值)。或者内核2仅在内核1等之后运行......
由于OpenCL允许添加一批操作,您可以在for循环中添加所有内容,然后只等到最后一个内核完成。
这很棘手,但如果您遵循该系统,它将为您提供最大可能的速度。