Умножение матриц в SYCL с использованием 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 (...)
, но ни один из них, похоже, не помогает отладить мой конкретный случай. Может быть, потому что это не для новичков.
Из того, что я понял до сих пор,
a_host.data()
показывает тип возврата
std::vector<double>
(не должно быть
std::vector< std::vector<double> >
?).
Я пробовал использовать
std::array
со статически известными размерами, и это работает.
Как я могу сделать это с помощью 2D
std::vector
?
Любая помощь будет оценена.
2 ответа
2D
std::vector<std::vector<T>>
не имеет элементов, хранящихся в памяти непрерывно.
Лучшим способом было бы объявить
std::vector<T>
с размерами M*N, то есть линейными массивами, и работать с ними как с смежными блоками.
Поскольку вектор назначения
C
, должен быть 2D, создайте ядро, которое индексирует как строки, так и столбцы. SYCL
index
фактически заполняется линейно доступными блоками памяти.
Вот что я сделал, чтобы он работал, используя
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 на стероидах:-)).