英特尔®数据分析加速库(英特尔® DAAL)是一种高性能库,它提供了丰富的算法集,从面向数据集的最基本的描述统计,到更高级的数据挖掘和机器学习算法。它可以帮助开发人员轻松地开发高度优化的大数据算法。该加速库支持众多常见的数据平台,例如 Hadoop*、Spark*, R和 Matlab*。
Matlab* 是一种多模式数值计算和交互式软件,广泛用于解决各种设计和科学问题。
本文旨在为 Matlab* 和英特尔 DAAL 开发人员展示如何使用来自 Matlab* 的英特尔 DAAL。
前提条件:
在您的系统上安装英特尔® DAAL;
安装 C++ 编译器,例如 Microsoft Visual Studio* 2015 (MSVS 2015);
在系统上安装 Matlab*;
注意:本文使用 MATLAB R2015b 和面向 Windows 的英特尔 DAAL 2017 进行测试
原则:通过 MexFunction 链接 Matlab 和英特尔 DAAL 函数
Matlab 提供了一些机制,支持开发人员连接用其它语言编写的程序,例如 C++、Fortran 等。与 C++ 语言的基本连接是通过一个被称为“mexFunction”的 C++ 函数实现的,该函数由Matlab MEX 库提供。.通过在 *.c 或 *.cppBy 文件中创建“mexFunction”,能够在 Matlab* 平台中编译和调用函数,就像在函数中构建那样。*.c 文件被称为 MEX 文件,函数名称为 Mex 文件名。英特尔 DAAL 具有 C++、Java 和 Python 接口。我们将使用这种机制从 Matlab* 调用英特尔 DAAL C++ 函数。
第一部分:C++ 端
cpp 文件可使用 C++ 编辑器编写,例如 MSVS2015;像记事本这样的任意 C 语言编辑器,或者 Matlab* IDE 中
第一步:在 cpp 中编写基本的 mexFunction
创建“mexFunction”
#include "mex.h" void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]){...;}
在这里,mxArray *prhs[] 能够接受来自 Matlab 工作区的输入。
mxArray *plhs[] 能够将函数计算结果传至 Matlab 工作区。
在函数中,我们可以添加英特尔 DAAL 算法,例如获得数据集的绝对值。
/* retrieve the input data from data source */ DataSource<xxx> dataSource(...); dataSource.loadDataBlock(); /* Create an algorithm */ abs::Batch<float> algorithm; /* Set an input object for the algorithm */ algorithm.input.set(abs::data, dataSource.getNumericTable()); /* Compute Abs function */ algorithm.compute(); /* Print the results of the algorithm */ services::SharedPtr<abs::Result> res = algorithm.getResult();
请在英特尔 DAAL 开发人员指南中查看完整的c++ 示例。
下面是 C 语言中 mexFunction 的基本结构。
第二步:输入并转换矩阵(可选)
正如上面的定义所示,函数 mexFunction 能够简化 MEX 文件与 Matlab 工作区之间的数据传输(通过 mxArray)。在有些情况下,可以直接读取外部输入数据源,并传输至函数中的英特尔 DAAL 算法。但有时候,用户希望将 Matlab 矩阵传输至英特尔 DAAL 函数。这时我们可以考虑转换 mxArray 和 C 中普通阵列之间的矩阵。
函数mxGetpr()能够读取 Matlab* 输入的矩阵。但是这会出现严重的问题,mxGetpr()的矩阵按照以列为主的顺序存储,而 C 阵列默认情况下使用以行为主的顺序。例如在 mexFunction 函数中,prhs[] 指输入矩阵结构 mxArray,输入矩阵按照以列为主的顺序存储,即:通用矩阵
1 2 3
4 5 6
7 8 9
作为 [1 4 7 2 5 8 3 6 9] 存储在 prhs[] 中
但是,C 语言中的默认读取顺序是以行为主,也就是说,将阵列转换为矩阵时,
[1 4 7 2 5 8 3 6 9](尺寸为 3*3)将被读取为:
1 4 7
2 5 8
3 6 9
因此,您需要考虑转置 Matlab* 中的输入矩阵数据,或者在 *.cpp 文件中的 mexFunction 中进行转换,或者通过其他读取方式来支持英特尔 DAAL 算法。
Matlab 中的一段代码示例如下所示:
input1=input1'; [output1,...]=yourfunctionname(input1,...) output1=output1';
*请记住,每次输入一个新的矩阵时,必须对其进行转换。(mexArray 到 C 阵列)
*如果输入矩阵还需要在 Matlab* 中处理,则必须转换为以列为主的顺序。(C 阵列到 mexArray)
*请记住,每次输出一个矩阵时,必须对其进行转换。(C 阵列到 mexArray)
第三步:定义英特尔® DAAL 函数输入和输出
在英特尔® DAAL 计算中,要求 NumericTable 类作为算法输入。因此,在设置算法输入之前,输入矩阵应转换为 NumericTable,以便被英特尔® DAAL 算法识别。
下面显示了从 inputMatrix(第二步处理的 C++ 矩阵)到 inputData(DAAL 的 NumericTable)的转换:
SharedPtr<NumericTable>inputData = SharedPtr<NumericTable>(new Matrix<double>(number_of_colome, number_of_row, inputMatrixPtr))
以下是针对 Abs 算法设置输入的代码示例。inputMatrix 来自 Matlab 工作区。
#include "daal.h" #include "mex.h" #include "matrix.h" using namespace std; using namespace daal; using namespace daal::services; using namespace daal::data_management; using namespace daal::algorithms; using namespace daal::algorithms::math; #define inputA prhs[0] #define outputA plhs[0] void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { /*Input Arguments Check if needed*/ if (!mxIsDouble(inputA) || mxIsComplex(inputA)) { mexErrMsgIdAndTxt("Sample:prhs", "Input matrix must be double");} */ /*Defination*/ mwSize nrow, ncol; double *pxtrain; double *poutA; /*Define the Size and Pointer of Input Matrix*/ nrow = mxGetM(inputA); ncol = mxGetN(inputA); pxtrain = mxGetPr(inputA); /*Convert MexArray to C Array (Matlab to C++) if needed*/ //matrix_cr_conv(pxtrain, ncol, nrow); /*Create an Intel DAAL NumericTable*/ SharedPtr<NumericTable>inputdataA = SharedPtr<NumericTable>(new Matrix<double>(ncol, nrow, pxtrain)); /* Create an algorithm */ abs::Batch<double> abs; /* Set an input object for the algorithm */ abs.input.set(abs::data, inputdataA); /* Compute Abs function */ abs.compute(); /*Define Output Pointer*/ SharedPtr<Matrix<double>>result = staticPointerCast<Matrix<double>, NumericTable>(abs.getResult()->get(abs::value)); /*Create Output Matlab Matrix*/ outputA = mxCreateDoubleMatrix(nrow,ncol, mxREAL); /*Define Output Pointer*/ poutA = mxGetPr(outputA); int i; for (i = 0; i < nrow*ncol; i++) { poutA[i] = (*result)[0][i]; } /*Convert C Array to MexArray (C++ to Matlab)* if needed/ //matrix_cr_conv(poutA, nrow, ncol); }
如欲了解关于英特尔® DAAL 编程的更多信息,请参考 daal_ur_guides 和示例:
https://software.intel.com/zh-cn/daal-programming-guide
要获得并输出结果,首先必须从算法(请参考指南)获得结果,然后创建输出矩阵,最后定义算法结果的输出指示器。
此外,不要忘了上文提及的转置输出矩阵。
关于调试
如果要在 C++ 编译器 IDE 中调试 *.cpp 文件,不仅需要设置英特尔® DAAL 环境参数,还需要设置 Matlab* 环境参数。
包括路径:%MATLAB ROOT%\extern\include;
库路径:
%MATLAB ROOT%\lib\win64;%MATLAB ROOT%\extern\lib\win64\microsoft;
路径:%MATLAB ROOT%\bin\win64;
和 libmx.lib; libmex.lib; libmat.lib;
应添加至额外的依赖性(配置属性>>Linker>>输入>> 额外属性)
第二部分:Matlab* 端
创建 *.cpp 文件后,便可通过 Matlab 平台来构建和调用函数。
第一步:在 Matlab 中设置用于英特尔®DAAL 的环境*
设置该环境最简单的方法是通过英特尔 Parallel Studio 编译器命令提示符启动 Matlab*:
- 从“开始所有”应用打开命令提示符,英特尔 Parallel Studio XE 201X;英特尔编译器 xx 命令提示符;英特尔 64 Visual Studio 201X 环境或 IA-32 Visual Studio 201X 环境)。
- C:\Program Files (x86)\IntelSWTools>>"%MATLAB ROOT%\bin\matlab.exe"
然后在 Matlab 命令窗口中,getenv() 函数和 setenv() 函数可用于向 Matlab* 的新环境添加包括和库路径。
(或者,如果打开编译器命令提示符时发生编译器或链接错误,您可以手动的方式在 Matlab* 命令窗口中检查和设置环境,如下所示)
英特尔 DAAL 安装在默认路径 (C:\Program Files (x86)\IntelSWTools\)。
要添加至 'include'列表:
C:\Program Files (x86)\IntelSWTools\compilers_and_libraries_xxxx.x.xxx\windows\compiler\include;
C:\Program Files (x86)\IntelSWTools\compilers_and_libraries_xxxx.x.xxx\windows\compiler\include\intel64;
C:\Program Files (x86)\IntelSWTools\compilers_and_libraries_xxxx.x.xxx\windows\daal\include;
要添加至 'lib'列表:
C:\Program Files (x86)\IntelSWTools\compilers_and_libraries_xxxx.x.xxx\windows\compiler\lib;
C:\Program Files (x86)\IntelSWTools\compilers_and_libraries_xxxx.x.xxx\windows\compiler\lib\intel64;
C:\Program Files (x86)\IntelSWTools\compilers_and_libraries_xxxx.x.xxx\windows\compiler\lib\intel64_win;
C:\Program Files (x86)\IntelSWTools\compilers_and_libraries_xxxx.x.xxx\windows\daal\lib\intel64_win;
下面是一个向 'INCLUDE'列表添加路径的示例
>>setenv('INCLUDE',[getenv('INCLUDE') ';C:\Program Files (x86)\IntelSWTools\compilers_and_libraries_xxxx.x.xxx\windows\daal\include']);
setenv('LIBPATH',[getenv('LIBPATH') ';C:\Program Files (x86)\IntelSWTools\compilers_and_libraries_xxx\windows\lib\intel64'])
然后,在 Matlab* 命令行设置编译器,使用
>>mex -setup
识别 C/C++ 语言编译,例如 Microsoft Visual Studio*。
第二步:通过 cpp 文件创建 mexfile
首先,将当前的文件夹分配 (cd) 至 cpp 文件的位置,然后使用下面的命令,以静态的方式将 mexfile 链接至英特尔® DAAL 库。
>>C:\Users\xxx\Desktop\Matlab\daal_abs_sample
>>mex -v -largeArrayDims yourfunctionname.cpp daal_core.lib daal_thread.lib
如果您希望在 Matlab* 中使用静态库,则可以使用 daal_core.lib(这将增加 mexfile 的体积);
如果您不需要多线程计算,则可以使用 daal_sequential.lib。
如果 getenv('PATH') 列表中没有路径,则可能不包含路径。
成功构建 mexfile 时,屏幕上将会显示:MEX completed successfully and one yourfunctionname.mexw64 file was produced。
第三步:将 mexfunction 作为 matlab build-in 函数运行
现在,您可以充分利用 "yourfunctionname"函数(名称必须与 cpp 文件的名称相同),可以在 mexfile 所处的路径中调用该函数。
[output1, output2...]=yourfunctionname (input1, input2, input3...);
下面是通过 m_daal_abs.cpp 调用‘m_daal_abs’函数的示例。
附加文件:daal_abs_sample.rar
如欲了解关于 mex 和 mexFunction 的更多信息,请访问:
http://www.mathworks.com/help/matlab/ref/mex.html
http://www.mathworks.com/help/matlab/apiref/mexfunction.html
如欲了解关于英特尔 DAAL 开发人员指南的更多信息,请访问:
https://software.intel.com/zh-cn/daal-programming-guide