1

我正在尝试使用 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 循环和我缺乏工作组分配。

是否可以去掉 python for-loop 并正确分配我的工作组?

4

2 回答 2

0

既然你说这是一个测试,我想在一天结束时你想做的计算比一些添加的要多得多。您可以尝试以下两件事来增强您的代码:

  1. 不要每次都创建a_buf 和b_buf。创建缓冲区的成本很高。在循环之外创建它们,然后在循环中使用cl.enqueue_write_buffer()函数或 cl.enqueue_copy(). 似乎第一个功能现在已弃用并被第二个功能取代。所以它应该是这样的cl.enqueue_copy(queue, a_buf, matrix_GPU_vector)
  2. 我想它不会花费太多,但不要重塑matrix_GPU它已经在内存中正确对齐的矩阵。

顺便说一句,如果您进行测试以模拟从网络摄像头接收流的应用程序,您不应该使用 RGB 矩阵吗?我的意思是你可以接收到 24 位 RGB 图像,用 int8 可以更好地模拟,不是吗?

于 2013-07-19T10:04:57.150 回答
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 循环中添加所有内容,然后等到最后一个内核完成。

这很棘手,但如果您遵循该系统,它将为您提供最大可能的速度。

于 2013-07-19T13:26:20.553 回答