为什么 M1 Max 上的 numpy 原生速度比旧的 Intel i5 慢很多?

gra*_*ump 18 python numpy anaconda tensorflow apple-m1

我刚刚买了带有 M1 Max 芯片的新 MacBook Pro,正在设置 Python。我已经尝试了几种组合设置来测试速度 - 现在我很困惑。首先把我的问题放在这里:

\n
    \n
  • 为什么在 M1 Max 上本地运行的 python 比在配备 Intel i5 的旧 MacBook Pro 2016 上慢得多(约 100%)?
  • \n
  • 在 M1 Max 上,为什么本机运行(通过 miniforge)和通过 Rosetta(通过 anaconda)运行之间没有显着的速度差异 - 后者应该慢约 20%?
  • \n
  • 在 M1 Max 和本机运行上,为什么 conda 安装的 Numpy 和 TensorFlow 安装的 Numpy 之间没有显着的速度差异 - 哪个应该更快?
  • \n
  • 在 M1 Max 上,为什么在 PyCharm IDE 中运行总是比从终端运行慢约 20%,而在我的旧 Intel Mac 上却不会发生这种情况。
  • \n
\n

支持我的问题的证据如下:

\n
\n

以下是我尝试过的设置:

\n

1.Python安装方式

\n
    \n
  • Miniforge-arm64,以便 python 在 M1 Max 芯片上原生运行。(从活动监视器检查,Kindpython 进程是Apple)。
  • \n
  • 蟒蛇。然后 python 通过 Rosseta 运行。(从活动监视器检查,Kindpython 进程是Intel)。
  • \n
\n

2.Numpy安装方式

\n
    \n
  • conda install numpy:来自原始 conda-forge 频道的 numpy,或预装了 anaconda。
  • \n
  • Apple-TensorFlow:用miniforge安装的python,我直接安装tensorflow,numpy也会安装。据说,这样安装的numpy是针对Apple M1进行优化的,速度会更快。这是安装命令:
  • \n
\n
conda install -c apple tensorflow-deps\npython -m pip install tensorflow-macos\npython -m pip install tensorflow-metal\n
Run Code Online (Sandbox Code Playgroud)\n

3. 运行自

\n\n
\n

这是测试代码:

\n
conda install -c apple tensorflow-deps\npython -m pip install tensorflow-macos\npython -m pip install tensorflow-metal\n
Run Code Online (Sandbox Code Playgroud)\n

结果如下:

\n
+-----------------------------------+-----------------------+--------------------+\n|   Python installed by (run on)\xe2\x86\x92   | Miniforge (native M1) | Anaconda (Rosseta) |\n+----------------------+------------+------------+----------+----------+---------+\n| Numpy installed by \xe2\x86\x93 | Run from \xe2\x86\x92 |  Terminal  |  PyCharm | Terminal | PyCharm |\n+----------------------+------------+------------+----------+----------+---------+\n|          Apple Tensorflow         |   4.19151  |  4.86248 |     /    |    /    |\n+-----------------------------------+------------+----------+----------+---------+\n|        conda install numpy        |   4.29386  |  4.98370 |  4.10029 | 4.99271 |\n+-----------------------------------+------------+----------+----------+---------+\n
Run Code Online (Sandbox Code Playgroud)\n

这是相当慢的。为了比较,

\n
    \n
  • 在我的带有 i5 芯片的旧 MacBook Pro 2016 上运行相同的代码 - 它的成本2.39917s
  • \n
  • 另一篇文章(但不是英文)报告使用 M1 芯片(不是 Pro 或 Max)运行,miniforge+conda_installed_numpy 是2.53214s,而 miniforge+apple_tensorflow_numpy 是1.00613s
  • \n
  • 你也可以自己尝试一下。
  • \n
\n

以下是 CPU 信息详细信息:

\n
    \n
  • 我的旧 i5:
  • \n
\n
$ sysctl -a | grep -e brand_string -e cpu.core_count\nmachdep.cpu.brand_string: Intel(R) Core(TM) i5-6360U CPU @ 2.00GHz\nmachdep.cpu.core_count: 2\n
Run Code Online (Sandbox Code Playgroud)\n
    \n
  • 我的新 M1 Max:
  • \n
\n
% sysctl -a | grep -e brand_string -e cpu.core_count\nmachdep.cpu.brand_string: Apple M1 Max\nmachdep.cpu.core_count: 10\n
Run Code Online (Sandbox Code Playgroud)\n
\n

我严格遵循教程中的说明 - 但为什么会发生所有这些?是因为我的安装缺陷,还是因为M1 Max芯片?由于我的工作严重依赖本地运行,因此本地速度对我来说非常重要。对可能的解决方案的任何建议或您自己设备上的任何数据点将不胜感激:)

\n

gra*_*ump 17

2022 年 3 月 28 日更新:请参阅下面 @AndrejHribernik 的评论。

\n
\n

如何在M1 Max上安装numpy,具有最高的加速性能(Apple的vecLib)?这是截至 2021 年 12 月 6 日的答案。

\n
\n

脚步

\n

一、安装miniforge

\n

这样你的Python就可以在arm64上本地运行,而不是通过Rosseta翻译。

\n
    \n
  1. 下载Miniforge3-MacOSX-arm64.sh,然后
  2. \n
  3. 运行脚本,然后打开另一个 shell
  4. \n
\n
$ bash Miniforge3-MacOSX-arm64.sh\n
Run Code Online (Sandbox Code Playgroud)\n
    \n
  1. 创建一个环境(这里我使用 name np_veclib
  2. \n
\n
$ conda create -n np_veclib python=3.9\n$ conda activate np_veclib\n
Run Code Online (Sandbox Code Playgroud)\n

二. 安装 Numpy,并将 BLAS 接口指定为 vecLib

\n
    \n
  1. 要编译numpy,首先需要cython安装pybind11
  2. \n
\n
$ conda install cython pybind11\n
Run Code Online (Sandbox Code Playgroud)\n
    \n
  1. 编译numpy(感谢@Marijn的回答) - 不要使用conda install
  2. \n
\n
$ pip install --no-binary :all: --no-use-pep517 numpy\n
Run Code Online (Sandbox Code Playgroud)\n
    \n
  1. 2. 的替代方案是从源代码构建
  2. \n
\n
$ git clone https://github.com/numpy/numpy\n$ cd numpy\n$ cp site.cfg.example site.cfg\n$ nano site.cfg\n
Run Code Online (Sandbox Code Playgroud)\n

编辑复制的site.cfg:添加以下行:

\n
[accelerate]\nlibraries = Accelerate, vecLib\n
Run Code Online (Sandbox Code Playgroud)\n

然后构建并安装:

\n
[accelerate]\nlibraries = Accelerate, vecLib\n
Run Code Online (Sandbox Code Playgroud)\n
    \n
  1. 在 2 或 3 之后,现在测试 numpy 是否正在使用 vecLib:
  2. \n
\n
$ NPY_LAPACK_ORDER=accelerate python setup.py build\n$ python setup.py install\n
Run Code Online (Sandbox Code Playgroud)\n

然后,/System/Library/Frameworks/vecLib.framework/Headers应该打印类似的信息。

\n

三.使用 conda 进一步安装其他软件包

\n

让 conda 识别 pip 安装的包

\n
conda config --set pip_interop_enabled true\n
Run Code Online (Sandbox Code Playgroud)\n

必须执行此操作,否则如果 例如conda install pandas,则将numpy出现在The following packages will be installed列表中并再次安装。但新装的是conda-forge渠道的,速度慢。

\n
\n

与其他安装的比较:

\n

1. 竞争对手:

\n

除了上面那个最优的,我还尝试了其他几种安装

\n
    \n
  • A。np_defaultconda create -n np_default python=3.9 numpy
  • \n
  • B np_openblasconda create -n np_openblas python=3.9 numpy blas=*=*openblas*
  • \n
  • C。np_netlibconda create -n np_netlib python=3.9 numpy blas=*=*netlib*
  • \n
\n

上述 ABC 选项是直接从 conda-forge 通道安装的。numpy.show_config()将显示相同的结果。要查看差异,请检查conda list- 例如,openblas软件包安装在 B 中。请注意,arm64 不支持mkl或。blis

\n
    \n
  • D np_openblas_source.:首先通过安装openblas brew install openblas。然后添加[openblas]路径/opt/homebrew/opt/openblassite.cfg从源构建 Numpy。
  • \n
  • M1i9\xe2\x80\x939880H在这篇文章中。
  • \n
  • 我的旧i5-6360U2 核 MacBook Pro 2016 13 英寸。
  • \n
\n

2. 基准:

\n

这里我使用两个基准:

\n
    \n
  1. mysvd.py:我的SVD分解
  2. \n
\n
>>> import numpy\n>>> numpy.show_config()\n
Run Code Online (Sandbox Code Playgroud)\n
    \n
  1. dario.py:上面帖子中Dario Rade\xc4\x8di\xc4\x87的基准测试脚本。
  2. \n
\n

3. 结果:

\n
+-------+-----------+------------+-------------+-----------+--------------------+----+----------+----------+\n|  sec  | np_veclib | np_default | np_openblas | np_netlib | np_openblas_source | M1 | i9\xe2\x80\x939880H | i5-6360U |\n+-------+-----------+------------+-------------+-----------+--------------------+----+----------+----------+\n| mysvd |  1.02300  |   4.29386  |   4.13854   |  4.75812  |      12.57879      |  / |     /    |  2.39917 |\n+-------+-----------+------------+-------------+-----------+--------------------+----+----------+----------+\n| dario |     21    |     41     |      39     |    323    |         40         | 33 |    23    |    78    |\n+-------+-----------+------------+-------------+-----------+--------------------+----+----------+----------+\n
Run Code Online (Sandbox Code Playgroud)\n

  • 首先感谢@graphitump 出色的指导和可重复的测试用例。想说加速 BLAS 现在可以用 conda 指定。无需手动编译。它仍然不是 M1 架构上的默认 BLAS,因此需要显式指定 `conda create -n np_accelerate python=3.9 numpy “blas=*=*accelerate*”` (8认同)

mer*_*erv 13

可能的原因:不同的 BLAS 库

由于基准测试正在运行线性代数例程,因此这里可能测试的是 BLAS 实现。osx-64平台的默认 Anaconda 发行版将附带 Intel 的 MKL 实现;当第一次提出这个问题时, osx -arm64平台只有通用的 Netlib BLAS 和 OpenBLAS 实现选项。

我得到以下基准测试结果(2023 年 5 月更新):

macOS 英特尔酷睿 i9 (x86_64)

BLAS 实施 平均时间
mkl 0.95932
blis 1.72059
openblas 2.17023
accelerate 2.56365
netlib 5.72782

macOS M1 4P/4E (arm64)

BLAS 实施 平均时间
accelerate(macOS 13.3) 0.98718
accelerate(macOS 13.2) 1.03141
netlib 4.36523
openblas 10.33956

所以,我怀疑旧的MBP安装了MKL,而OP中的M1系统安装了Netlib或OpenBLAS。Apple Silicon 用户应确定哪个库在其系统上运行速度最快。共识似乎是,对于 M1 和 M2 系统,Apple 的 Accelerate 库性能最高。

应该指出的是,Accelerate 实现在 macOS 13.3 中进行了显着更新,这似乎提供了轻微的性能提升(约 5%)。

因此,M1/M2 用户应考虑包括以下要求:

'blas=*=accelerate'
Run Code Online (Sandbox Code Playgroud)

创建 Conda 环境时。


指定 BLAS 实施

以下是我测试的具体不同环境:

'blas=*=accelerate'
Run Code Online (Sandbox Code Playgroud)

并运行基准测试脚本 ( so-np-bench.py)

## Note that `conda-forge` channel is prioritized on my system
## also, `mamba` is a faster version of `conda`

# MKL
mamba create -n np_mkl python=3.9 numpy 'blas=*=mkl'

# BLIS
mamba create -n np_blis python=3.9 numpy 'blas=*=blis'

# OpenBLAS
mamba create -n np_openblas python=3.9 numpy 'blas=*=openblas'

# Accelerate
mamba create -n np_accelerate python=3.9 numpy 'blas=*=accelerate'

# Netlib
mamba create -n np_netlib python=3.9 numpy 'blas=*=netlib'
Run Code Online (Sandbox Code Playgroud)

使用 Accelerate 时可能需要注意的事项

请注意,由于 Accelerate 中的 LAPACK 实现较旧,SciPy 和 Accelerate 之间存在不兼容性。不过,它已在 macOS 13.3 中更新,可能会解决此类问题。查看这个线程的详细信息。


仿真模式 (Rosetta)

有时,可能必须在仿真模式下创建一个环境,例如,需要一个尚未构建osx-arm64 的包。以下是在 M1 上使用强制osx-64进行的基准测试(截至 2023 年 7 月) :

macOS M1 4P/4E(带有 osx-64 子目录的arm64)

BLAS 实施 平均时间
accelerate 1.71188
blis 2.41957
netlib 3.92932
openblas 5.98487
mkl 不适用(无法模拟)

这些运行使用与上面的osx-64相同的创建命令,但使用CONDA_SUBDIR=osx-64.

重要提示:运行openblas使用所有核心,但没有明显的好处。所以我绝对建议现在避免这样做。使用 OpenMP 的方式可能存在一些错误?

要点:如果您使用的是 Apple Silicon 机器,'blas=*=accelerate'无论您是否在模拟,都请使用。然而,本机环境似乎是最快的选择。

  • @graphitump BLAS 库将全部显示为与 `numpy.show_config()` 相同,因为它们(`libblas`、`libcblas`、`liblapack` 等)具有相同的名称并具有相同的 API,但链接到不同的库(`openblas`、`mkl` 等)。您必须检查“conda list”包*builds*,其中包含“openblas”、“netlib”等字符串。 (2认同)

小智 8

借助Miniforge3-MacOSX-arm64conda install -c conda-forge numpy "libblas=*=*accelerate",它可以在我的 Macbook M1 Max 上完美运行。

  • M1 Max 带 libblas 加速:1.024
  • M1 Max 不带 libblas 加速:2.672