MLlib 线性代数加速指南
简介
本指南提供必要信息,以启用 Spark MLlib 的线性代数加速处理。
Spark MLlib 将 Vector(向量)和 Matrix(矩阵)定义为机器学习算法的基本数据类型。在此基础上,BLAS 和 LAPACK 操作由 dev.ludovic.netlib 实现和支持(算法也可能调用 Breeze)。dev.ludovic.netlib
可以使用优化的原生线性代数库(下文称作“原生库”或“BLAS 库”)来实现更快的数值处理。Intel MKL 和 OpenBLAS 是两种流行的库。
官方发布的 Spark 二进制文件不包含这些原生库。
以下部分将描述如何安装原生库、正确配置它们,以及如何将 dev.ludovic.netlib
指向这些原生库。
安装原生线性代数库
Intel MKL 和 OpenBLAS 是两种流行的原生线性代数库。您可以根据您的偏好选择其中之一。我们提供了如下基本说明。
Intel MKL
- 下载并安装 Intel MKL。应在集群的所有节点上完成安装。我们假设安装位置是 $MKLROOT(例如 /opt/intel/mkl)。
- 在系统库搜索路径中创建指向
libmkl_rt.so
的具有特定名称的软链接。例如,确保/usr/local/lib
位于系统库搜索路径中,并运行以下命令$ ln -sf $MKLROOT/lib/intel64/libmkl_rt.so /usr/local/lib/libblas.so.3 $ ln -sf $MKLROOT/lib/intel64/libmkl_rt.so /usr/local/lib/liblapack.so.3
OpenBLAS
安装应在集群的所有节点上完成。大多数发行版都提供通用版本的 OpenBLAS。您可以使用发行版包管理器(如 apt
或 yum
)来安装它。
对于 Debian / Ubuntu
sudo apt-get install libopenblas-base
sudo update-alternatives --config libblas.so.3
对于 CentOS / RHEL
sudo yum install openblas
检查 MLlib 是否已启用原生库
要验证原生库是否已正确加载,请启动 spark-shell
并运行以下代码
scala> import dev.ludovic.netlib.blas.NativeBLAS
scala> NativeBLAS.getInstance()
如果它们正确加载,则会打印 dev.ludovic.netlib.blas.NativeBLAS = dev.ludovic.netlib.blas.JNIBLAS@...
。否则,会打印警告信息
WARN InstanceBuilder: Failed to load implementation from:dev.ludovic.netlib.blas.JNIBLAS
...
java.lang.RuntimeException: Unable to load native implementation
at dev.ludovic.netlib.blas.InstanceBuilder.nativeBlas(InstanceBuilder.java:59)
at dev.ludovic.netlib.blas.NativeBLAS.getInstance(NativeBLAS.java:31)
...
您还可以将 dev.ludovic.netlib
指向特定的库名称和路径。例如,对于 Intel MKL,可以使用 -Ddev.ludovic.netlib.blas.nativeLib=libmkl_rt.so
或 -Ddev.ludovic.netlib.blas.nativeLibPath=$MKLROOT/lib/intel64/libmkl_rt.so
。对于 LAPACK 和 ARPACK,您有类似的参数:-Ddev.ludovic.netlib.lapack.nativeLib=...
、-Ddev.ludovic.netlib.lapack.nativeLibPath=...
、-Ddev.ludovic.netlib.arpack.nativeLib=...
和 -Ddev.ludovic.netlib.arpack.nativeLibPath=...
。
如果系统未正确配置原生库,将使用 Java 实现(javaBLAS)作为备用选项。
Spark 配置
Intel MKL 或 OpenBLAS 中多线程的默认行为可能与 Spark 的执行模型不兼容,无法达到最优效果 1。
因此,将这些原生库配置为对操作使用单线程实际上可能会提高性能(参见 SPARK-21305)。通常,将其与 spark.task.cpus
的数量匹配是最佳的,spark.task.cpus
默认值为 1
,并且通常保持为 1
。
您可以使用 config/spark-env.sh
中的选项来设置 Intel MKL 或 OpenBLAS 的线程数
- 对于 Intel MKL
MKL_NUM_THREADS=1
- 对于 OpenBLAS
OPENBLAS_NUM_THREADS=1
-
请参考以下资源以了解如何配置这些 BLAS 实现的线程数:Intel MKL 或 Intel oneMKL 和 OpenBLAS。 ↩