AMD製CPUのRyzenでNumpyが遅い問題を解決する方法


最近はAMD製のCPUであるRyzenを搭載したパソコンが増えてきました。性能が高いにもかかわらず価格が安いこともあり、とても魅力的です。

今回、実際にPythonのライブラリであるNumpyを使って行列の計算を行ってみたのですが、Intel製のCPUほどのパフォーマンスが出ないことが続いたので、どうやれば高速化できるのかを探ってみました。実際に、Numpyでの計算が速くなったので、その方法をご紹介したいと思います。




RyzenでNumpyを実行するととても遅い


AMD社のRyzenは最近ではとても性能が上がっていて、Intel製のCPUよりも高性能だと感じる場面が増えています。

実際、Ryzen 3 4300UやRyzen 7 4700Uを搭載したノートパソコンを使用する機会があったのですが、CINEBENCH R15というソフトを使ってベンチマークをとってみると下の図のようになりました。赤で示したものがRyzen、青で示したものがIntel Core iシリーズのCPUになります。





スコアが大きいほど性能が高くなります。処理速度が速いといってもいいでしょう。

これを見てわかる通り、ベンチマーク的にはRyzen 7 4700UはIntel製のCore i7-9750Hと同等、またRyzen 3 4300UはCore i5-1035G1やCore i5-8265Uと同程度といえます。

このため、プログラムで計算を実行すると、Ryzen 7 4700UとCore i7-9750Hは同じくらいの実行時間になると予想していました。


しかし、PythonのライブラリであるNumpyを使って簡単な行列積を計算してみると、これがとても遅いのです。実際、どれくらい計算に時間がかかるかを示すと以下のようになります。

実行時間が短いほど、計算が早く完了したことを意味します。




Numpyの実行条件は以下のようになります。すべてWindows PCで10,000×10,000の行列の行列積の計算を実行しました。

実行条件

Windows 10
Python 3.8.3-embeddedable
Numpy 1.19.1 (pipでインストールしたもの)

10,000×10,000の行列の行列積を計算


これを見るとわかるように、ベンチマーク的にはRyzen 3 4300UはCore i7-7500Uよりも1.7倍程度高速なのにも関わらず、10,000×10,000の行列積をNumpyで計算するとCore i7-7500Uよりも1.7倍も時間がかかっていました。


また、Ryzen 7 4700UとCore i7-9750Hはベンチマークを見る限り同等の性能を発揮するはずですが、Numpyで行列の計算をさせるとCore i5-1035G1よりも遅くなってしまいました。


「これでは科学的な計算に使えないのでは?」、「プログラミング用途にRyzen搭載のCPUは適していないのかな?」と悲しい気持ちになっていたのですが、偶然にもうまく高速化する方法が見つかりました。





MKLに対応したNumpyを使う


いろいろ調べてみたところ、NumpyにはopenBLASにリンクされたNumpyと、MKLにリンクされたNumpyの2種類があるようです。

pipで普通にインストールすると、openBLASにリンクされたNumpyがインストールされます。おそらく、筆者を含め、多くの方はこちらのNumpyを使っていらっしゃるのではないかと思います。


一方で、MKLというのはIntelが出しているMath Kernel Libraryという高速な数値計算ライブラリのことです。こちらを使うと、より高速な演算が可能になります。

MKLにリンクされたNumpyを使うためには、以下のように3つの方法があります。

(1)anacondaを使う
(2)MKLをインストールし、numpyを手動でコンパイルする
(3)MKLにリンク済みのnumpyをダウンロードしてインストールする


(1)のanacondaを使っている場合には、すでにMKLが入っているので特に何もする必要はありません。


(2)については、MKLを実際にダウンロードしてPCにインストールし、numpyを手動でコンパイルするというものです。

以下のページに方法が記載されていますので、この方法を採用したいという方はご確認ください。

pip で MKL にリンクされた numpy, scipy が自動的にインストールされるようにする (Qiita)



今回、実際に試したのが(3)の「MKLにリンク済みのnumpyをダウンロードしてインストールする」という方法です。MKLにリンク済みのnumpyというものが、以下のサイトからダウンロードできます。

Unofficial Windows Binaries for Python Extension Packages (カリフォルニア大学)

これをダウンロードして、インストールするとMKLに対応したNumpyを使うことができます。


インストールの方法は簡単で、上記サイトからnumpyをダウンロードし、ローカルのPCで以下のコマンドを実行するだけです。

実行例

pip install numpy-1.19.1+mkl-cp38-cp38-win_amd64.whl


今回はpython 3.8を利用したので、numpy-1.19.1+mkl-cp38-cp38-win_amd64.whlというものをダウンロードしました。使用するPythonのバージョンにあわせて、適宜ダウンロードしてください。


すでにNumpyがインストールされている場合はアンインストールするか、もしくは別の仮想環境を作ってそちらにインストールするかしてください。


基本的にはIntel製のCPUに対応したライブラリなので、AMD製のCPUであるRyzenではうまくいかないのではないかと思ったのですが、実際は下図のように高速化されました。





MKLにリンクされていないNumpyを使うと40秒近くかかっていたのが、MKLにリンクされたNumpyを使うことによって14秒程度にまで高速化されました。ベンチマークと照らし合わせても妥当な結果です。


今回はRyzen 7 4700Uは手元にPCがなかったので試すことができず、Ryzen 3 4300Uで実行しています。Ryzen 7 4700Uでも実行すれば、Core i7-9750Hと同等程度に速くなるのではないかと推測しています。


これまで筆者は、Intel CPU、AMD CPU関わらず、いつもpipでNumpyをインストールしていたので、openBLASにリンクされたものを使っていたことになります。

それが、MKLにリンク済みのnumpyを使用することで、この図のように約2.85倍高速化することができました。

一応、今回うまくいった条件を記載しておくと、以下のようになります。

実行条件

OS: Windows 10 Home
CPU: Ryzen 3 4300U
Python 3.8.3-embeddable
Numpy 1.19.1+MKL
  


Anacondaは使っていません。

Python 3.8.3-embeddableと書いているのは、超軽量で配布用のPythonになります。もちろん、普通にインストールするタイプのPythonでも問題なく動くとは思うのですが、今回は試すことができていません。

embeddable Pythonの使い方やライブラリ(パッケージ)の導入方法については、こちらの記事で解説していますのでご参照ください。

関連記事:Python Embeddableの使い方


また、次で解説しているように、今回の高速化では、MKL_DEBUG_CPU_TYPE = 5という環境変数は設定していません。





Ryzen搭載PCでAnacondaを使っている場合は環境変数をセットすると良いかも


今回MKLにリンクされたNumpyを使うことで高速化することができたのですが、いろいろ調べていた中で気がついたことをご紹介したいと思います。


前述したように、Anacondaを使うと、もともとMKLが入っているので特に何もする必要はないということでした。とすると、Ryzen搭載のPCでAnacondaのNumpyを使って計算をすれば高速になるのではないのかと思うのですが、実際のところは速度が遅いという報告がありました。

関連ページ:Setting up Anaconda for AMD Ryzen without MKL


このページの回答によると、以下のような環境変数を設定してあげることで、高速化できたということでした。


MKL_DEBUG_CPU_TYPE=5
  


Windowsで行うのであれば、システム環境変数に設定してあげるか、バッチファイル(.batファイル)内で環境変数を設定してあげて、pythonスクリプトを呼び出すなどすればよいのではないかと思います。


他には、Anacondaのnumpyやscipy,scikit-learnなど、MKLを使うライブラリに対する修正をしたライブラリがgithubで公開されています。AMD製のCPUを搭載したWindows PCでこれらのライブラリを使う場合に、高速化されるようです。

関連ページ:Anaconda-Windows-AMD (GitHub)


使用しているPythonのバージョンに合わせて、whlファイルをダウンロードしてインストールしてあげれば動くのではないかと思います。




まとめ


今回は、Ryzen搭載のPCでNumpyを高速化することができたのですが、最終的な原因というものは正直よくわかりませんでした。

いずれにしても、ここで紹介した方法のどれかを使うことで処理速度が向上し、少しでもお役に立てればうれしく思います。



このエントリーをはてなブックマークに追加



関連記事 

1.Python Embeddableの使い方
2.Pythonが使えるレンタルサーバー バージョンと速度の比較からおすすめを紹介


▲ このページの上部へ戻る