Я пытаюсь сделать простой матрично-векторный продукт с OpenCL, используя библиотеку ViennaCL.
Вот мой главный:
#include "viennacl/scalar.hpp"#include "viennacl/vector.hpp"#include "viennacl/matrix.hpp"#include "viennacl/linalg/prod.hpp"#include "viennacl/matrix_proxy.hpp"#include "viennacl/linalg/lu.hpp"
int main()
{
viennacl::ocl::set_context_device_type(0, viennacl::ocl::gpu_tag());
std::vector<viennacl::ocl::device> devices = viennacl::ocl::current_context().devices();
viennacl::ocl::current_context().switch_device(devices[0]);
int Nx=10;
int Ny=10;
//GPU vectors
viennacl::matrix<float> vcl_A(Nx,Ny);
viennacl::vector<float> vcl_b(Ny);
viennacl::vector<float> vcl_c(Nx);
//CPU vectors
std::vector<float> stl_A(Nx*Ny);
std::vector<float> stl_b(Ny);
std::vector<float> stl_c(Nx);//filling CPU vectors
for (unsigned int i = 0; i < Nx; ++i)
for (unsigned int j = 0; j < Ny; ++j)
stl_A[i*Ny + j] = (float) (rand()%100);
for (unsigned int i = 0; i < stl_b.size(); ++i)
stl_b[i] = (float) (rand()%100);//copying input data to GPU
viennacl::fast_copy(&(stl_A[0]),
&(stl_A[0]) + stl_A.size(),
vcl_A);
viennacl::fast_copy(stl_b, vcl_b);//launching product c = A*b
vcl_c = viennacl::linalg::prod(vcl_A, vcl_b);//copying output data back to CPU
viennacl::copy(vcl_c, stl_c);
viennacl::backend::finish();
}
После этого мой вектор stl_c правильно вычисляет свой первый коэффициент, но каждые 9 других коэффициентов 0
,
Когда я изменяю размеры на верхние значения, я получаю более одного правильного коэффициента в начале моего вектора, но я все равно получаю кучу нулей для всех остальных коэффициентов.
Я предполагаю, что некоторые из моих копий сделаны неправильно, но, возможно, моя операция prod вызывает (локальная / глобальная проблема, но я предполагаю, что ViennaCL позаботится обо всем этом)
Любая идея о том, что я делаю не так? Любая помощь или совет будут по достоинству оценены.
(Я использую код на VS 2012, мой графический процессор — NVIDIA Geforce GTX 670)
1. Проблема:
Документация для viennacl::matrix
на странице manual-types-matrix
состояния:
Внутренняя память буфера
matrix<>
по умолчанию дополняется нулями, так что внутренний размер матрицы кратен, например, сила двух. Когда используешьfast_copy()
на матрице дополняемые нули должны учитываться правильно. запросinternal_size1()
а такжеinternal_size2()
сделать это.
Это означает, что элементы viennacl::matrix
не смежны, в отличие от тех, кто в std::vector
вы используете для имитации матрицы. Поэтому эта строка не делает то, что вы ожидаете:
viennacl::fast_copy(&(stl_A[0]), &(stl_A[0]) + stl_A.size(), vcl_A);
2. Решение:
Итак, как правильно скопировать матрицу хоста в матрицу ViennaCL?
Возможность использования std::vector<std::vector<float>>
представлять матрицу хоста, а затем использовать viennacl::copy
вместо vienna::fast_copy
, и заполнение элементов будет заботиться о вас.
std::vector<std::vector<float>> stl_A(Ny);
for (unsigned int i = 0; i < Ny; ++i) {
stl_A[i].resize(Nx);
for (unsigned int j = 0; j < Nx; ++j)
stl_A[i][j] = (float)(rand() % 100);
}
viennacl::copy(stl_A, vcl_A);
Другая возможность, как предлагается в документации, состоит в том, чтобы соответствовать внутренней компоновке viennacl::matrix
в матрице вашего хоста, используя internal_size
вместо Nx
а также Ny
при расчете смещений элементов (но не повторяя их).
std::vector<float> stl_A(vcl_A.internal_size());
for (unsigned int i = 0; i < Ny; ++i)
for (unsigned int j = 0; j < Nx; ++j)
stl_A[i*vcl_A.internal_size2() + j] = (float)(rand() % 100);
viennacl::fast_copy(&(stl_A[0]), &(stl_A[0]) + stl_A.size(), vcl_A);
3. Примечание:
Оба приведенных выше примера кода предназначены для рядные основнымы матрицы. Для матриц основных столбцов поменяйте местами циклы и используйте internal_size1()
вместо.