Я пытаюсь сделать простой матрично-векторный продукт с 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, мой GPU - NVIDIA Geforce gtx 670)
1. Проблема:
Документация для viennacl::matrix
в 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()
.