我有一个非常大的数据(不适合GPU内存),包含许多向量,其中每个向量是几MB。 我想使用多个GPU设备计算使用高斯内核的Gram矩阵。
换句话说,对于每对向量x,y,我需要计算x-y的范数。所以,如果我有N个向量,我有(N ^ 2 + N)/ 2个这样的对。我不关心利用对称性来节省空间或时间,它可以做到整个N ^ 2.
如何使用VexCL进行操作?我知道它是唯一支持多个GPU的库,而且我用普通的OpenCL做了很多工作,到目前为止还没有成功。
请注意,数据集甚至不适合机器的RAM,我正在从内存映射文件中读取向量块。
非常感谢!!
答案 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);
// ...
我希望这足以让你开始。