PyOpenCL Kronecker产品内核

时间:2016-09-10 23:31:10

标签: python opencl gpgpu matrix-multiplication pyopencl

我有以下代码用于确认用于计算两个平方矩阵的kronecker乘积的手写方法。第一部分确实验证了我的重复和平铺ab的方法分别产生相同的输出。

import pyopencl as cl
import numpy
from time import time

N = 3
num_iter = 1

a = numpy.random.rand(N,N)
b = numpy.random.rand(N,N)
c = numpy.kron(a, b)

abig = numpy.repeat(numpy.repeat(a,N,axis=1),N,axis=0)
bbig = numpy.tile(b,(N,N))
cbig = abig*bbig

print(numpy.allclose(c,cbig))

然后我尝试使用PyOpenCL将此乘法移植到GPU。我首先将bigabigb分别分配为d_ad_b在GPU内存上。我还在主机上将h_C分配为空数组,并在设备上将d_C分配为相同的大小。

context = cl.create_some_context()
queue = cl.CommandQueue(context)

h_C = numpy.empty(cbig.shape)

d_a = cl.Buffer(context, cl.mem_flags.READ_ONLY | cl.mem_flags.COPY_HOST_PTR, hostbuf=abig)
d_b = cl.Buffer(context, cl.mem_flags.READ_ONLY | cl.mem_flags.COPY_HOST_PTR, hostbuf=bbig)
d_c = cl.Buffer(context, cl.mem_flags.WRITE_ONLY, h_C.nbytes)

kernelsource = open("../GPUTest.cl").read()
program = cl.Program(context, kernelsource).build()
kronecker = program.kronecker
kronecker.set_scalar_arg_dtypes([numpy.int32, None, None, None])

for i in range(num_iter):
    kronecker(queue, (N**2, N**2), None, N**2, d_a, d_b, d_c)
    queue.finish()

cl.enqueue_copy(queue, h_C, d_c)

print(h_C)

以下是GPUTest.cl的内容:

__kernel void kronecker(const int N,__global float* A,__global float*B,__global float* C)
{
    int i = get_global_id(0);
    int j = get_global_id(1);

    C[i,j] = A[i,j]*B[i,j];
}

但是,我的输出结果并非如此。我相信我的错误在于我如何处理线程ID。从阅读矩阵点产品的另一个例子来看,我的印象是ids本质上是块内元素的位置,因为这是元素,我只需要从同一位置拉出元素A和B将它们相乘。这些id是否需要组合成一个索引才能更好地解决内存实际分配的方式?

只是略有关联,但有没有办法利用平铺或内存共享方法?这只是对最简单的计算方法的一次尝试,我希望得到一种不需要ab的重复/平铺版本的算法。采用a的单个元素,将b的整数乘以它,然后将结果存储在c的图块中。

2 个答案:

答案 0 :(得分:0)

问题是内核没有为输入和输出内存地址取索引。参数应该是C[i+j*N],以便适当地在整个内存块中移动。

答案 1 :(得分:0)

我也为kronecker产品开发了一个内核。我会把它放在这里作为参考。对于

A#B = C,

其中#是the kronecker product,A是mxn矩阵,B是pxq矩阵,C是xxy矩阵,x = m p,y = n q,以下内核将计算C:

__kernel void kroneckerProdFast(__global float* res,
                                __global float* a,
                                __global float* b,
                                int p,
                                int q){
    int xi = get_global_id(0);
    int x = get_global_size(0); 
    int yi = get_global_id(1);
    int y = get_global_size(1); 

    int n = y / q;
    int mi = xi / p;
    int ni = yi / q;
    int pi = xi % p;
    int qi = yi % q;

    res[xi * y + yi] = a[mi * n + ni] * b[pi * q + qi];
} 

来自PyOpenCL的调用将是:

program.kroneckerProdFast(queue,res.shape, None, resf_buf, a_buf, b_buf,np.int32(b.shape[0]),np.int32(b.shape[1]))