使用 2D std::vector 在 SYCL 上进行矩阵乘法
Matrix Multiplication on SYCL using 2D std::vector
我是 SYCL 和 C++ 的新手。这是我使用 2D std::vector
.
进行简单矩阵乘法的内核
void MatrixMulParallel(queue& q,
const std::vector<std::vector<double>>& a_host,
const std::vector<std::vector<double>>& b_host,
std::vector<std::vector<double>>& c_gpu) {
/*
To Multiply: C[M][P] = A[M][N] * B[N][P]
*/
PROFILE_FUNCTION();
try {
size_t M = a_host.size();
size_t N = a_host[0].size();
size_t P = b_host[0].size();
// Create device buffers for A, B, C
buffer a(a_host.data(), range<2>{M, N});
buffer b(b_host.data(), range<2>{N, P});
buffer c(c_gpu.data(), range<2>{M, P});
PROFILE_SCOPE("Starting Multiply on GPU");
std::cout << "GPU::Multiplying A and B into C.\n";
auto e = q.submit([&](handler& h) {
auto A = a.get_access<access::mode::read>(h);
auto B = b.get_access<access::mode::read>(h);
auto C = c.get_access<access::mode::write>(h);
h.parallel_for(range<2>{M, P}, [=](id<2> index) {
// index[0] allows accessing ROW index, index[1] is column index
int row = index[0];
int col = index[1];
auto sum = 0.0;
for (int i = 0; i < N; i++)
sum += A[row][i] * B[i][col]; // Error #1
C[index] = sum; // Error #2
});
});
e.wait();
}
catch (sycl::exception const& e) {
std::cout << "An exception is caught while multiplying matrices.\n";
terminate();
}
}
我收到 两个 错误,提示如下:
- 错误 #1:
invalid operands to binary expression ('const std::vector<double, std::allocator<double>>' and 'const std::vector<double, std::allocator<double>>')
- 错误 #2:
no viable overloaded '='
我尝试查找与 invalid operands for binary expression (...)
类似的错误,但其中 none 似乎有助于调试我的具体案例。可能是因为这对初学者不友好。
据我目前的了解,a_host.data()
显示 return 类型 std::vector<double>
(不应该是 std::vector< std::vector<double> >
吗?)。
我已经尝试使用具有静态已知大小的 std::array
,并且有效。
如何使用 2D std::vector
制作此作品?
如有任何帮助,我们将不胜感激。
2D std::vector<std::vector<T>>
没有连续存储在内存中的元素。
更好的方法是声明 std::vector<T>
大小为 M*N,即线性数组,并将它们作为连续块进行操作。
由于目标向量 C
应该是二维的,因此创建一个在行和列中都建立索引的内核。 SYCL index
实际上填满了 linearly-accessible 个内存块。
这是我使用 std::vector
使它工作的方法:
template <typename T>
void MatrixMulParallelNaive(queue& q,
const std::vector<T>& a_host,
const std::vector<T>& b_host,
std::vector<T>& c_gpu) {
/*
To Multiply: C[M][P] = A[M][N] * B[N][P]
*/
PROFILE_FUNCTION();
try {
buffer<double, 1> a(a_host.data(), range<1>{a_host.size()}); // 1D
buffer<double, 1> b(b_host.data(), range<1>{b_host.size()}); // 1D
buffer<double, 2> c(c_gpu.data(), range<2>{M, P}); // Create 2D buffer
PROFILE_SCOPE("Starting Multiply on GPU");
std::cout << "GPU::Multiplying A and B into C.\n";
auto e = q.submit([&](handler& h) {
auto A = a.get_access<access::mode::read>(h);
auto B = b.get_access<access::mode::read>(h);
auto C = c.get_access<access::mode::write>(h);
h.parallel_for(range<2>{M, P}, [=](id<2> index) {
// Threading index that iterates over C.
int row = index[0];
int col = index[1];
auto sum = 0.0;
// Compute result of ONE element of C
for (int i = 0; i < N; i++)
sum += A[row * M + i] * B[i * N + col];
C[index] = sum;
});
});
e.wait();
}
catch (sycl::exception const& e) {
std::cout << "An exception is caught while multiplying matrices.\n";
terminate();
}
}
更一般地说,在进行 HPC 时避免使用非紧凑型数据结构。
它对内存层次结构不如连续数组元素友好,并且初始化复杂。使用类似于 md_span
和 md_array
的东西(基本上是类固醇上的 Fortran 数组 :-))。
我是 SYCL 和 C++ 的新手。这是我使用 2D std::vector
.
void MatrixMulParallel(queue& q,
const std::vector<std::vector<double>>& a_host,
const std::vector<std::vector<double>>& b_host,
std::vector<std::vector<double>>& c_gpu) {
/*
To Multiply: C[M][P] = A[M][N] * B[N][P]
*/
PROFILE_FUNCTION();
try {
size_t M = a_host.size();
size_t N = a_host[0].size();
size_t P = b_host[0].size();
// Create device buffers for A, B, C
buffer a(a_host.data(), range<2>{M, N});
buffer b(b_host.data(), range<2>{N, P});
buffer c(c_gpu.data(), range<2>{M, P});
PROFILE_SCOPE("Starting Multiply on GPU");
std::cout << "GPU::Multiplying A and B into C.\n";
auto e = q.submit([&](handler& h) {
auto A = a.get_access<access::mode::read>(h);
auto B = b.get_access<access::mode::read>(h);
auto C = c.get_access<access::mode::write>(h);
h.parallel_for(range<2>{M, P}, [=](id<2> index) {
// index[0] allows accessing ROW index, index[1] is column index
int row = index[0];
int col = index[1];
auto sum = 0.0;
for (int i = 0; i < N; i++)
sum += A[row][i] * B[i][col]; // Error #1
C[index] = sum; // Error #2
});
});
e.wait();
}
catch (sycl::exception const& e) {
std::cout << "An exception is caught while multiplying matrices.\n";
terminate();
}
}
我收到 两个 错误,提示如下:
- 错误 #1:
invalid operands to binary expression ('const std::vector<double, std::allocator<double>>' and 'const std::vector<double, std::allocator<double>>')
- 错误 #2:
no viable overloaded '='
我尝试查找与 invalid operands for binary expression (...)
类似的错误,但其中 none 似乎有助于调试我的具体案例。可能是因为这对初学者不友好。
据我目前的了解,a_host.data()
显示 return 类型 std::vector<double>
(不应该是 std::vector< std::vector<double> >
吗?)。
我已经尝试使用具有静态已知大小的 std::array
,并且有效。
如何使用 2D std::vector
制作此作品?
如有任何帮助,我们将不胜感激。
2D std::vector<std::vector<T>>
没有连续存储在内存中的元素。
更好的方法是声明 std::vector<T>
大小为 M*N,即线性数组,并将它们作为连续块进行操作。
由于目标向量 C
应该是二维的,因此创建一个在行和列中都建立索引的内核。 SYCL index
实际上填满了 linearly-accessible 个内存块。
这是我使用 std::vector
使它工作的方法:
template <typename T>
void MatrixMulParallelNaive(queue& q,
const std::vector<T>& a_host,
const std::vector<T>& b_host,
std::vector<T>& c_gpu) {
/*
To Multiply: C[M][P] = A[M][N] * B[N][P]
*/
PROFILE_FUNCTION();
try {
buffer<double, 1> a(a_host.data(), range<1>{a_host.size()}); // 1D
buffer<double, 1> b(b_host.data(), range<1>{b_host.size()}); // 1D
buffer<double, 2> c(c_gpu.data(), range<2>{M, P}); // Create 2D buffer
PROFILE_SCOPE("Starting Multiply on GPU");
std::cout << "GPU::Multiplying A and B into C.\n";
auto e = q.submit([&](handler& h) {
auto A = a.get_access<access::mode::read>(h);
auto B = b.get_access<access::mode::read>(h);
auto C = c.get_access<access::mode::write>(h);
h.parallel_for(range<2>{M, P}, [=](id<2> index) {
// Threading index that iterates over C.
int row = index[0];
int col = index[1];
auto sum = 0.0;
// Compute result of ONE element of C
for (int i = 0; i < N; i++)
sum += A[row * M + i] * B[i * N + col];
C[index] = sum;
});
});
e.wait();
}
catch (sycl::exception const& e) {
std::cout << "An exception is caught while multiplying matrices.\n";
terminate();
}
}
更一般地说,在进行 HPC 时避免使用非紧凑型数据结构。
它对内存层次结构不如连续数组元素友好,并且初始化复杂。使用类似于 md_span
和 md_array
的东西(基本上是类固醇上的 Fortran 数组 :-))。