猫になりたい

コンサルのデータ分析屋、計量経済とか機械学習をやっています。pyてょnは3.7を使ってマスコレルウィンストングリーン。

Python: Intel MKL版numpyをanaconda有償化の影響を回避しながら手軽にインストールする

(以下の情報はすべて記事執筆時(2021/04)のものです)

この記事ではanaconda有償化の影響を回避しながら高速化されたIntel MKL版のnumpyを簡単にインストールする方法を解説します。

2020/04にanacondaが大規模商用利用ではanacondaとdefaultsチャンネルの使用を有償化したことは有名かと思います。 これにより仕事でIntel MKL版numpyを手軽にインストール出来なくなりそうだったので、利用規約に抵触しない形で簡単にIntel MKL版numpyをインストールする方法を調べ、まとめました。 scipy、scikit-learnの高速化版も見つけた方法でインストールが可能です。
尚、各位このブログを鵜呑みにするのではなく利用規約(Terms of Service)を各自で確認する様にして下さい。

TL;DR

anacondaの利用規約

anacondaの利用規約は「大規模な商用利用」を禁止

2020/04にanacondaの利用規約が改定され、「大規模な商用利用」ではanacondaの無償版を利用できなくなりました。 尚、ここでいう「大規模な商用利用」は利用規約の原文を読むと「規模が200人以上の営利団体による利用」と解釈できます。*1 *2

minicondaとdefaults以外のチャンネルの組み合わせは無償利用可能

しかしこの規約はanacondaとそれに類するもの一切合切の利用を禁止するものではありません。 anacondaのCEO曰く、

  • minicondaとconda-forgeチャンネルの組み合わせは無償で利用できる*3

ですし、conda-forgeのブログには、

  • この利用規約の変更はdefaultsチャンネルとrepo.anaconda.comでホストされているその他のソフトウェアにのみ適用される*4

との記載があります。

つまりminiconda + defaults以外のチャンネルの組み合わせでは引き続き無償でanaconda相当の環境が使用できるわけです。

しかしconda-forge経由で入るnumpyはIntel MKL版ではない

ここまでだけ読むとじゃあminiconda + defaults以外のチャンネルを使えば何も問題ないじゃないかと思うかもしれません。 しかしanaconda(のdefaultsチャンネル経由)でインストールされたnumpyはIntel MKLを利用しているため、conda-forge(pip)で入れられるOpenBLASを使用したnumpyよりも早いということが知られています。*5*6 しかしconda-forgeでインストールできるnumpyはOpenBLAS版であるため、単純にminiconda環境に乗り換えただけでは今までより計算速度が遅くなってしまいます。

もちろん一から自分でビルドすれば有償化の影響を回避しつつIntel MKL版numpyをインストールできるのでしょうがそれは流石に面倒です。そこでIntel MKL版numpyを簡単にインストールする方法について調べてみました。

Intelチャンネル版numpy

intel公式がIntel MKL版を用意してくれている

調べた結果、Intelが公式にIntel MKL版numpyをintelチャンネルで以下に公開していることがわかりました。

anaconda.org

intelチャンネルからnumpyをインストールする方法

以下にintelチャンネルからnumpyをインストールする方法を記載します。
尚、yamlの方ではchannelnodefaultsを設定してdefaultsチャンネルを利用しない(利用規約への抵触を避ける)様にしていますが、 minicondaも初期設定ではdefaultsチャンネルを使うようになっていますので、うっかりdefaultsチャンネルからパッケージをインストールしてしまわないように

  1. conda config --remove channels defaultsでdefaultsチャンネルを取り除き、
  2. conda config --add channels conda-forgeでconda-forgeチャンネルを初期値に設定しておく

と良いでしょう。

CLIからインストールする場合

conda install -c intel numpy

yamlで仮想環境を作る場合

name: intel_numpy
channels:
  - intel
  - nodefaults # defaultsチャンネルを使わないように設定
dependencies:
  - python=3.7 # Intelが配布しているnumpyは3.7までしか対応していない
  - intel::numpy

intelチャンネル版とdefaultsチャンネル版numpyの速度比較

ではdefaultsチャンネルとintelチャンネルのnumpyの違いは何なのでしょうか? どちらもIntel MKLを採用していると思われますが(明確な記載は発見できず)、Intel版は公式で配布されているだけあってさらなるチューニングがされている可能性も考えられます。 そこでintel、defaults、conda-forgeの3種のチャンネルからインストールしたnumpyの実行速度を比較してみることにしました。

実験はGCP上でIntel(R) Xeon(R) CPU @ 2.20GHzを使って行いました。
実行速度の比較にはIntel公式が使用していたコードを改変した以下のものを使用しました。

import numpy as np
import time

np.random.seed(8492)

N = 6000
M = 10000

k_list = [64, 80, 96, 104, 112, 120, 128, 144, 160, 176, 192, 200, 208, 224, 240, 256, 384]

def get_gflops(M, N, K):
    return M*N*(2.0*K-1.0) / 1000**3

np.show_config()

for K in k_list:
    a = np.array(np.random.random((M, N)), dtype=np.double, order='C', copy=False)
    b = np.array(np.random.random((N, K)), dtype=np.double, order='C', copy=False)
    A = np.matrix(a, dtype=np.double, copy=False)
    B = np.matrix(b, dtype=np.double, copy=False)

    C = A*B

    start = time.time()

    C = A*B
    C = A*B
    C = A*B
    C = A*B
    C = A*B

    end = time.time()

    tm = (end-start) / 5.0
    # 行列のKの大きさ、計算時間、GFLOPS
    print ('{0:4}, {1:9.7}, {2:9.7}'.format(K, tm, get_gflops(M, N, K) / tm))

結果は以下のグラフの通りです。

f:id:shikiponn:20210411200519p:plain
インストール元のチャンネル別numpy(1.19.2)の実行速度比較

グラフを見るとIntel版の方が気持ちdefaults版より実行時間が短いように見えます。 この程度の差であればあまり気にしなくても良さそうですが、環境によってはdefaultsチャンネル版とOpenBLAS版で倍の性能差が出るとのことなので、Intelチャンネル版とdefaultsチャンネル版でももっと差がつく場合があるそうです。 なのでカリカリにチューニングする必要がある場合は積極的にIntelチャンネル版のnumpyを積極的に試して良いかもしれません。
逆に個人の趣味開発などでは利用規約が問題になることも無いでしょうし、わざわざintelチャンネル版を使わずずとも今まで通りdefaultsチャンネル版を使用すれば良さそうです。

scipy、scikit-learnも intelチャンネルに用意されている

ここまではnumpyだけの話をしてきましたが先程記載したIntelチャンネルを見ると判るように、他にも様々なパッケージがIntelチャンネルには用意されています。 中にはscipy、scikit-learnもあり、numpyと同様に通常のものより高速な動作が期待できます(実際にどれだけ早いのかは未確認ですが高速であることは間違いないようです)。*7 尚、scikit-learnの高速版を使用するにはdaal4pyもインストールしてpathを適切に設定する必要があることに注意して下さい(インストール時のlogを参照のこと)。

intelpython3メタパッケージを利用すれば複数パッケージをまとめてインストール可能

上記Intelチャンネル内の各種パッケージをまとめてインストールするためにintelpython3_coreintelpython3_fullの2つのメタパッケージが用意されています。 これを利用して

conda install -c intel intelpython3_core

等とすることでIntelチャンネルのパッケージをまとめてインストールすることができます。
intelpython3_coreintelpython3_fullの違いはパッケージの数だけ(勿論fullの方が多い)と思われます。
full版を入れるとなんとxgboostも一緒に入ります。

実際にIntelチャンネルを利用して環境を使用する際は、個別にnumpyなどを入れるのではなくintelpython3_coreを使用するのが効率的でしょう。

intelチャンネル版パッケージの問題点・不明点

自分の調査した限りここで紹介したIntel版のnumpy等の各種パッケージには以下の問題点・不明点があります

問題点:Windowsではpandasインポート時にエラーが出る

windowsでintelチャンネルのnumpyを入れた環境を作り、その後のその環境内でpandasをimportすると「numpyが正常にビルドされていない」というエラーが出てimportに失敗する現象を確認しています。

問題点:使えるPythonのバージョンが低い

記事執筆時点でのpythonの最新版は3.9ですが、Intelチャンネルの各種パッケージをインストールできる最大のバージョンは3.7です。

不明点:numpy以外のパッケージが通常版と比べてどれだけ早いか不明

これは私が実験していないだけなのですが、Intelチャンネル版のscipyとscikit-learnがどれだけpipやconda-forgeのものより早いかは不明です。

まとめ

以上ここまでanaconda有償化の影響を回避ししつつ、Intel MKL版のnumpyやその他の高速化されているであろうパッケージをインストールする方法についてまとめました。
使えるpythonのバージョンには制限があるものの、defaultチャンネル版よりも若干高速なnumpyとその他インテルが最適化してくれたであろうパッケージが使えるIntelチャンネルは良い代替案になりそうです。
最後に今回の調査内容を踏まえたおすすめの環境構築用のyamlを記して終わりにしたいと思います。

おすすめの環境構築用yamlファイル

name: intel-all
channels:
  - intel  # 優先的にintelチャンネルを利用するようにする
  - conda-forge  # intelチャンネルにないパッケージはconda-forgeから入れる
  - nodefaults # defaultチャンネルを除外する
dependencies:
  - python=3.7 # Intelが配布しているpkgは3.7までしか対応していない
  - intel::intelpython3_core  # Intel® Distribution for Pythonを可能な限り使う

参考文献