使用VexCL的Gram矩阵

时间:2014-02-10 16:03:29

标签: c++ opencl

我有一个非常大的数据(不适合GPU内存),包含许多向量,其中每个向量是几MB。 我想使用多个GPU设备计算使用高斯内核的Gram矩阵。

换句话说,对于每对向量x,y,我需要计算x-y的范数。所以,如果我有N个向量,我有(N ^ 2 + N)/ 2个这样的对。我不关心利用对称性来节省空间或时间,它可以做到整个N ^ 2.

如何使用VexCL进行操作?我知道它是唯一支持多个GPU的库,而且我用普通的OpenCL做了很多工作,到目前为止还没有成功。

请注意,数据集甚至不适合机器的RAM,我正在从内存映射文件中读取向量块。

非常感谢!!

1 个答案:

答案 0 :(得分:1)

你显然需要将你的矢量分成几组,比如m,将这些组逐个加载(或者更确切地说,两个加载)到你的GPU上并进行计算。这是一个完整的程序,它为当前加载的两个块进行计算(据我所知):

#include <vexcl/vexcl.hpp>

int main() {
    const size_t n = 1024; // Each vector size.
    const size_t m = 4;    // Number of vectors in a chunk.

    vex::Context ctx( vex::Filter::Count(1) );

    // The input vectors...
    vex::vector<double> chunk1(ctx, m * n);
    vex::vector<double> chunk2(ctx, m * n);

    // ... with some data.
    chunk1 = vex::element_index();
    chunk2 = vex::element_index();

    vex::vector<double> gram(ctx, m * m); // The current chunk of Gram matrix to fill.

    /*
     * chunk1 and chunk2 both have dimensions [m][n].
     * We want to take each of chunk2 m rows, subtract those from each of
     * chunk1 rows, and reduce the result along the dimension n.
     *
     * In order to do this, we create two virtual 3D matrices (x and y below,
     * those are just expressions and are never instantiated) sized [m][m][n],
     * where
     *
     *     x[i][j][k] = chunk1[i][k] for each j, and
     *     y[i][j][k] = chunk2[j][k] for each i.
     *
     * Then what we need to compute is
     *
     *     gram[i][j] = sum_k( (x[i][j][k] - y[i][j][k])^2 );
     *
     * Here it goes:
     */
    using vex::extents;

    auto x = vex::reshape(chunk1, extents[m][m][n], extents[0][2]);
    auto y = vex::reshape(chunk2, extents[m][m][n], extents[1][2]);

    // The single OpenCL kernel is generated and launched here:
    gram = vex::reduce<vex::SUM>(
            extents[m][m][n],     // The dimensions of the expression to reduce.
            pow(x - y, 2.0),      // The expression to reduce.
            2                     // The dimension to reduce along.
            );

    // Copy the result to host, spread it across your complete gram matrix.
    // I am lazy though, so let's just dump it to std::cout:
    std::cout << gram << std::endl;
}

我建议您加载chunk1一次,然后按顺序加载所有chunk2变体并进行计算,然后加载下一个chunk1等等。请注意切片,重新整形和多维减少操作仅支持具有单个计算设备的上下文。那么剩下的就是如何在所有计算设备上传播计算。最简单的方法是创建单个VexCL上下文,它将获取所有可用的GPU,然后创建命令队列的向量:

vex::Context ctx( vex::Filter::Any );

std::vector<std::vector<vex::command_queue>> q;
for(size_t d = 0; d < ctx.size(); ++d)
    q.push_back({ctx.queue(d)});


//...

// In a std::thread perhaps:
chunk1(q[d], m * n);
chunk2(q[d], m * n);
// ...

我希望这足以让你开始。