在 Matlab* 上使用英特尔® 数据分析加速库

英特尔® 数据分析加速库(英特尔® 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

有关编译器优化的更完整信息,请参阅优化通知
附件大小
Package icon daal_abs_sample.zip2.83 KB