我是使用RViennaCL
套餐的新手,试图进行GPU
矩阵乘法。
尝试一个简单的案例我在我创建的包(cpp
)中的src
文件夹中创建了一个gpuUtils
文件,其代码如下:
#include "viennacl/ocl/backend.hpp"
#include "viennacl/linalg/prod.hpp"
#include "viennacl/tools/random.hpp"
#include "viennacl/matrix.hpp"
//' PU matrix multiplication
//'
//' @export
// [[Rcpp::export]]
SEXP matMult(){
viennacl::tools::uniform_random_numbers<float> randomNumber;
viennacl::matrix<float> vcl_A(400, 400);
viennacl::matrix<float> vcl_B(400, 400);
for (unsigned int i = 0; i < vcl_A.size1(); ++i)
for (unsigned int j = 0; j < vcl_A.size2(); ++j)
vcl_A(i,j) = randomNumber();
for (unsigned int i = 0; i < vcl_B.size1(); ++i)
for (unsigned int j = 0; j < vcl_B.size2(); ++j)
vcl_B(i,j) = randomNumber();
viennacl::matrix<float> vcl_C = viennacl::linalg::prod(vcl_A, vcl_B);
return Rcpp::wrap(vcl_C);
}
然后我build
包裹:
$ R CMD build gpuUtils
* checking for file ‘gpuUtils/DESCRIPTION’ ... OK
* preparing ‘gpuUtils’:
* checking DESCRIPTION meta-information ... OK
* cleaning src
* checking for LF line-endings in source and make files and shell scripts
* checking for empty or unneeded directories
* building ‘gpuUtils_0.0.0.9000.tar.gz’
但是当我尝试安装它时,我得到了:
$ R CMD INSTALL gpuUtils_0.0.0.9000.tar.gz
* installing to library ‘/home/usr/R’
* installing *source* package ‘gpuUtils’ ...
** libs
g++ -I/opt/ohpc/pub/libs/gnu7/R/3.4.2/lib64/R/include -DNDEBUG -I/usr/local/cuda-9.0/include/ -I"/home/usr/R/Rcpp/include" -I"/home/usr/R/RViennaCL/include" -I/usr/local/include -fpic -g -O2 -c gpuUtils.cpp -o gpuUtils.o
In file included from /home/usr/R/Rcpp/include/RcppCommon.h:195:0,
from /home/usr/R/Rcpp/include/Rcpp.h:27,
from /home/usr/R/RViennaCL/include/viennacl/ocl/forwards.h:29,
from /home/usr/R/RViennaCL/include/viennacl/ocl/context.hpp:36,
from /home/usr/R/RViennaCL/include/viennacl/ocl/backend.hpp:26,
from gpuUtils.cpp:1:
/home/usr/R/Rcpp/include/Rcpp/internal/wrap.h: In instantiation of ‘SEXPREC* Rcpp::internal::wrap_dispatch_unknown_iterable(const T&, Rcpp::traits::false_type) [with T = viennacl::matrix<float, viennacl::row_major>; SEXP = SEXPREC*; Rcpp::traits::false_type = Rcpp::traits::integral_constant<bool, false>]’:
/home/usr/R/Rcpp/include/Rcpp/internal/wrap.h:732:43: required from ‘SEXPREC* Rcpp::internal::wrap_dispatch_unknown(const T&, Rcpp::traits::false_type) [with T = viennacl::matrix<float, viennacl::row_major>; SEXP = SEXPREC*; Rcpp::traits::false_type = Rcpp::traits::integral_constant<bool, false>]’
/home/usr/R/Rcpp/include/Rcpp/internal/wrap.h:770:41: required from ‘SEXPREC* Rcpp::internal::wrap_dispatch_eigen(const T&, Rcpp::traits::false_type) [with T = viennacl::matrix<float, viennacl::row_major>; SEXP = SEXPREC*; Rcpp::traits::false_type = Rcpp::traits::integral_constant<bool, false>]’
/home/usr/R/Rcpp/include/Rcpp/internal/wrap.h:787:39: required from ‘SEXPREC* Rcpp::internal::wrap_dispatch_unknown_importable(const T&, Rcpp::traits::false_type) [with T = viennacl::matrix<float, viennacl::row_major>; SEXP = SEXPREC*; Rcpp::traits::false_type = Rcpp::traits::integral_constant<bool, false>]’
/home/usr/R/Rcpp/include/Rcpp/internal/wrap.h:807:52: required from ‘SEXPREC* Rcpp::internal::wrap_dispatch(const T&, Rcpp::traits::wrap_type_unknown_tag) [with T = viennacl::matrix<float, viennacl::row_major>; SEXP = SEXPREC*]’
/home/usr/R/Rcpp/include/Rcpp/internal/wrap_end.h:30:38: required from ‘SEXPREC* Rcpp::wrap(const T&) [with T = viennacl::matrix<float, viennacl::row_major>; SEXP = SEXPREC*]’
gpuUtils.cpp:25:26: required from here
/home/usr/R/Rcpp/include/Rcpp/internal/wrap.h:523:17: error: static assertion failed: cannot convert type to SEXP
static_assert(!sizeof(T), "cannot convert type to SEXP");
^~~~~~~~~~~~~
make: *** [gpuUtils.o] Error 1
ERROR: compilation failed for package ‘gpuUtils’
* removing ‘/home/usr/R/gpuUtils’
* restoring previous ‘/home/usr/R/gpuUtils’
这表明viennacl::matrix
需要编写自己的wrap
函数。
因此,我尝试在as
内针对自定义模板wrap
和Rcpp
函数执行非常好的vignette,使其适应viennacl::matrix
情况。< / p>
这是我的cpp
代码:
#include <RcppCommon.h>
#include "viennacl/ocl/backend.hpp"
#include "viennacl/matrix.hpp"
// [[Rcpp::plugins("cpp11")]]
// Provide Forward Declarations
namespace Rcpp {
namespace traits{
// Setup non-intrusive extension via template specialization for
// 'viennacl' class
// Support for wrap
template <typename T> SEXP wrap(const viennacl::matrix<T> & obj);
// Support for as<T>
template <typename T> class Exporter< viennacl::matrix<T> >;
}
}
#include <Rcpp.h>
// Define template specializations for as<> and wrap
namespace Rcpp {
namespace traits{
// Defined wrap case
template <typename T> SEXP wrap(const viennacl::matrix<T> & obj){
const int RTYPE = Rcpp::traits::r_sexptype_traits<T>::rtype ;
return Rcpp::Matrix< RTYPE >(obj.begin(), obj.end());
};
// Defined as< > case
template<typename T> class Exporter< viennacl::matrix<T> > {
typedef typename viennacl::matrix<T> OUT ;
// Convert the type to a valid rtype.
const static int RTYPE = Rcpp::traits::r_sexptype_traits< T >::rtype ;
Rcpp::Matrix<RTYPE> mat;
public:
Exporter(SEXP x) : mat(x) {
if (TYPEOF(x) != RTYPE)
throw std::invalid_argument("Wrong R type for mapped 2D array");
}
OUT get() {
// Need to figure out a way to perhaps do a pointer pass?
OUT x(mat.size());
std::copy(mat.begin(), mat.end(), mat.begin());
return x;
}
};
}
}
//' viennacl matrix templating
//'
//' @export
// [[Rcpp::export]]
void matTemplate(Rcpp::NumericMatrix in_mat){
viennacl::matrix<double> viennacl_mat = Rcpp::as< viennacl::matrix<double> >(in_mat);
Rcpp::NumericMatrix out_mat = Rcpp::wrap(viennacl_mat);
}
构建良好:
$ R CMD build gpuUtils
* checking for file ‘gpuUtils/DESCRIPTION’ ... OK
* preparing ‘gpuUtils’:
* checking DESCRIPTION meta-information ... OK
* cleaning src
* checking for LF line-endings in source and make files and shell scripts
* checking for empty or unneeded directories
* building ‘gpuUtils_0.0.0.9000.tar.gz’
但仍然得到同样的错误:
$ R CMD INSTALL gpuUtils_0.0.0.9000.tar.gz
* installing to library ‘/home/usr/R’
* installing *source* package ‘gpuUtils’ ...
** libs
g++ -I/opt/ohpc/pub/libs/gnu7/R/3.4.2/lib64/R/include -DNDEBUG -I/usr/local/cuda-9.0/include/ -I"/home/usr/R/Rcpp/include" -I"/home/usr/R/RViennaCL/include" -I/usr/local/include -fpic -g -O2 -c gpuUtils.cpp -o gpuUtils.o
In file included from /home/usr/R/Rcpp/include/RcppCommon.h:195:0,
from gpuUtils.cpp:1:
/home/usr/R/Rcpp/include/Rcpp/internal/wrap.h: In instantiation of ‘SEXPREC* Rcpp::internal::wrap_dispatch_unknown_iterable(const T&, Rcpp::traits::false_type) [with T = viennacl::matrix<double, viennacl::row_major>; SEXP = SEXPREC*; Rcpp::traits::false_type = Rcpp::traits::integral_constant<bool, false>]’:
/home/usr/R/Rcpp/include/Rcpp/internal/wrap.h:732:43: required from ‘SEXPREC* Rcpp::internal::wrap_dispatch_unknown(const T&, Rcpp::traits::false_type) [with T = viennacl::matrix<double, viennacl::row_major>; SEXP = SEXPREC*; Rcpp::traits::false_type = Rcpp::traits::integral_constant<bool, false>]’
/home/usr/R/Rcpp/include/Rcpp/internal/wrap.h:770:41: required from ‘SEXPREC* Rcpp::internal::wrap_dispatch_eigen(const T&, Rcpp::traits::false_type) [with T = viennacl::matrix<double, viennacl::row_major>; SEXP = SEXPREC*; Rcpp::traits::false_type = Rcpp::traits::integral_constant<bool, false>]’
/home/usr/R/Rcpp/include/Rcpp/internal/wrap.h:787:39: required from ‘SEXPREC* Rcpp::internal::wrap_dispatch_unknown_importable(const T&, Rcpp::traits::false_type) [with T = viennacl::matrix<double, viennacl::row_major>; SEXP = SEXPREC*; Rcpp::traits::false_type = Rcpp::traits::integral_constant<bool, false>]’
/home/usr/R/Rcpp/include/Rcpp/internal/wrap.h:807:52: required from ‘SEXPREC* Rcpp::internal::wrap_dispatch(const T&, Rcpp::traits::wrap_type_unknown_tag) [with T = viennacl::matrix<double, viennacl::row_major>; SEXP = SEXPREC*]’
/home/usr/R/Rcpp/include/Rcpp/internal/wrap_end.h:30:38: required from ‘SEXPREC* Rcpp::wrap(const T&) [with T = viennacl::matrix<double, viennacl::row_major>; SEXP = SEXPREC*]’
gpuUtils.cpp:68:56: required from here
/home/usr/R/Rcpp/include/Rcpp/internal/wrap.h:523:17: error: static assertion failed: cannot convert type to SEXP
static_assert(!sizeof(T), "cannot convert type to SEXP");
^~~~~~~~~~~~~
make: *** [gpuUtils.o] Error 1
ERROR: compilation failed for package ‘gpuUtils’
* removing ‘/home/usr/R/gpuUtils’
* restoring previous ‘/home/usr/R/gpuUtils’
答案 0 :(得分:2)
简短回答:是的。 RViennaCl仅提供ViennaCl标头,但没有as()
和wrap()
函数用于R和C ++数据结构之间的通信。使用RViennaCl的gpuR
包使用不同的方法,通过将适当的对象暴露给R,并使用适当的函数作用于这些对象。当然,您可以使用这些对象在GPU上进行矩阵乘法。
因此,如果您对R和ViennaCl数据结构之间的通信感兴趣,则必须自己编写这些函数。但是,这不是一项简单的任务,因为RViennaCL会修补ViennaCL标头以包含Rcpp.h
(例如https://github.com/cdeterman/RViennaCL/blob/master/inst/include/viennacl/ocl/backend.hpp#L29)。这使得无法像上面尝试那样使用通常的扩展机制。我认为RViennaCL包含RcppCommon.h
就足够了,这样可以扩展。但我没有尝试过。我已经为此提交了https://github.com/cdeterman/RViennaCL/issues/4。
您可以将available converters与转换为R数据结构和从R数据结构转换的包合并,而不是为ViennaCL编写as()
和wrap()
。所以在使用LinkingTo: Rcpp, RViennaCL, RcppEigen
的包中,这个功能对我有用:
#define VIENNACL_HAVE_EIGEN
#include <RcppEigen.h>
#include <viennacl/ocl/backend.hpp>
#include <viennacl/matrix.hpp>
//' viennacl matrix crossprod
//'
//' @export
// [[Rcpp::export]]
Eigen::MatrixXd vclCrossprod(const Eigen::MatrixXd &in_densematrix){
int rows = in_densematrix.rows();
int cols = in_densematrix.cols();
viennacl::matrix<double> viennacl_densematrix(rows, cols);
viennacl::copy(in_densematrix, viennacl_densematrix);
viennacl::matrix<double> viennacl_result = viennacl::linalg::prod(
viennacl::trans(viennacl_densematrix),
viennacl_densematrix);
Eigen::MatrixXd eigen_result(cols, cols);
viennacl::copy(viennacl_result, eigen_result);
return eigen_result;
}
然而,对于我尝试过的例子,这种方法效率不高。如果您正在做一些比矩阵乘法更复杂的事情,这可能会改变。
或者你可以试试我正在研究的RcppArrayFire,如果你主要对GPGPU感兴趣,特别是对ViennaCl不感兴趣。