NumPyでのBLISサポートについて説明するための一般的なトラッカーの問題は次のとおりです。 これまで、名目上無関係な2つのスレッドでこれについていくつか議論してきました。
したがって、これはこのような将来の議論を統合するための新しい問題です:-)
強調すべきいくつかの現在未解決の問題:
CC: @tkelman @ matthew-brett @fgvanzee
BLISがsite.cfg
含まれているようです。
libFLAMEもサポートできますか?
https://www.cs.utexas.edu/%7Eflame/web/libFLAME.htmlの説明は修正が必要な場合があり
@rgommerslibflameは確かにnetlibLAPACK APIを提供し、libflameがネイティブに提供しないすべての実装を提供します。
FWIW、BLISは、この号が発行されて以来、大きな進歩を遂げました。 たとえば、BLISはランタイム構成を実装するようになり、その構成時構成はランタイムインフラストラクチャの観点から再実装されました。 BLISは、より包括的なテストスイートに加えて、統合されたBLASテストドライバーを提供するようになりました。 ライブラリの自己初期化も実施されており、モノリシックヘッダーの生成(500以上の開発ヘッダーの代わりに単一のblis.h)が行われているため、インストールされた製品の管理が容易になります。 また、静的および共有ライブラリビルドのより標準化されたライブラリ命名規則に従い、 soname
ます。 最後に、そのビルドシステムは、コンパイラとアセンブラの互換性をチェックするよりもはるかにスマートです。 そして、それは私が頭のてっぺんから考えることができるものです。
@fgvanzeeありがとう。 その場合、私は+1で、 numpy.distutils
サポートを追加します。
現時点では本当に時間が足りないので、少なくとも9月まではこれに取り組むことができません。 他の誰かがこれに取り組みたい場合、それは比較的簡単なはずです(gh-7294と同じ線に沿って)。 トラブルシューティング/レビューのお手伝いをさせていただきます。
それは大きな進歩のように聞こえます。 numpy / scipy(パフォーマンスと安定性の面で)に関してOpenBLASの実行可能な代替手段になることからどれくらい離れていると思いますか?
(Fortranの混乱のため、Windowsにはまだconda
scipy-openblasがないことに注意してください:https://github.com/conda-forge/scipy-feedstock/blob/master/recipe/ meta.yaml#L14)
MSVC ABI互換のBLASおよびLAPACKが必要な場合でも、簡単で完全にオープンソースのオプションはありません。 今日ではclang-clとflangが存在しますが、問題は以前のようなコンパイラの可用性ではなく、ビルドシステムの柔軟性と、ライブラリの作成者がこれまで評価またはサポートしたことのない組み合わせを使用しようとすることです。 参照https://github.com/flame/blis/issues/57#issuecomment-284614032
@rgommers BLISは現在、OpenBLASの非常に実行可能な代替手段だと思います。 AMDがACMLを放棄し、新しいオープンソースの数学ライブラリソリューションの基盤としてBLISを完全に採用したことは十分に実行可能です。 (私たちは企業スポンサーを持っており、過去何年にもわたって国立科学財団によって後援されてきました。)
パフォーマンスに関しては、正確な特性は、対象の操作、浮動小数点データ型、ハードウェア、および関心のある問題サイズの範囲によって異なります。ただし、一般的に言えば、BLISは通常OpenBLASを満たすかそれを上回ります。最小の問題サイズ(300程度未満)を除くすべてのレベル3のパフォーマンス。 また、OpenBLASよりも柔軟なレベル3並列化戦略を採用しています(モノリシックアセンブリカーネル設計のため)。
安定性に関しては、BLISはかなり安定していると思います。 私たちはバグレポートに非常に敏感に対応するよう努めており、過去5か月ほどのコミュニティからの関心の高まりのおかげで、多くの問題を特定して修正することができました(主にビルドシステム関連)。 これにより、エンドユーザーとパッケージマネージャーのユーザーエクスペリエンスがスムーズになりました。
また、BLISは(ゼロ日から)BLASのような機能のスーパーセットを提供し、BLAS互換性レイヤーとは別の2つの新しいAPIを介して提供していることに注意してください。
これは、BLASリンケージを必要とするソフトウェアをすでに持っているレガシーユーザーをサポートするだけでなく、カスタムの密な線形代数ソリューションをゼロから構築することに関心のあるユーザー、つまりBLASインターフェイスに特別な親和性を感じないユーザーに優れたツールボックスを提供します。
BLISは、既存のBLAS実装とBLAS API自体の両方のさまざまな欠点に対する不満から生まれ、2012年以来、私の愛情のこもった仕事です。どこにも行きませんし、良くなるだけです。 :)
ああ、@ tkelmanに感謝します。 Cygwin :( :(
Linux / macOSでBLISに対してコンパイルされたnumpyを使用している人々からいくつかの経験を聞くのは興味深いでしょう。
コンテキスト@fgvanzeeをありがとう。 libFLAMEサポートを追加して、SciPyベンチマークスイートを試してみるのは興味深いことです。
@rgommers Re:libflame:関心をお寄せいただきありがとうございます。 libflameがTLCを使用する可能性があることに注意してください。 BLISほど形は良くありません。 (私たちが望むようにそれをサポートする時間/リソースがありません、そして過去6年間の私たちの注意のほぼ100%はそれがOpenBLASの実行可能で競争力のある代替物になることができる場所にBLISをもたらすことに集中しましたet al。)
ある時点で、BLISが成熟し、研究手段が使い果たされたら、libflame / LAPACKレベルの機能(コレスキー、LU、QR分解など)に注意を向ける可能性があります。 これは、これらの実装をBLISに段階的に追加するという形をとるか、最終的にlibflameを置き換えるまったく新しいプロジェクトを伴う場合があります。 後者の場合、BLISの低レベルAPIを利用するように設計されるため、BLASを介して現在避けられない関数呼び出しとメモリコピーのオーバーヘッドを回避できます。 これは、調査を楽しみにしている多くのトピックの1つにすぎません。
マルチスレッドを使用せずにIntelSkylakeでNumPy1.15とBLIS0.3.2を使用して、この記事のベンチマークを実行
Dotted two 4096x4096 matrices in 4.29 s.
Dotted two vectors of length 524288 in 0.39 ms.
SVD of a 2048x1024 matrix in 13.60 s.
Cholesky decomposition of a 2048x2048 matrix in 2.21 s.
Eigendecomposition of a 2048x2048 matrix in 67.65 s.
Intel MKL 2018.3:
Dotted two 4096x4096 matrices in 2.09 s.
Dotted two vectors of length 524288 in 0.23 ms.
SVD of a 2048x1024 matrix in 1.11 s.
Cholesky decomposition of a 2048x2048 matrix in 0.19 s.
Eigendecomposition of a 2048x2048 matrix in 7.83 s.
4.29秒で2つの4096x4096行列を点線で示しました。
@homocomputeris申し訳ありませんが、2つの行列の演算を説明するために使用される「ドット」動詞を聞いたことがありません。 それは行列の乗算ですか?
@fgvanzee最近のBLISでのWindowsサポートの状況はどうなっていますか? 以前はほとんどサポートされていなかったWindowsでビルドするようにしたことを覚えています...
@fgvanzeeそしてそうです、 numpy.dot
はPythonでGEMMを呼び出す従来の方法です。 (奇妙な名前の並べ替えですが、これは、vector-vector、vector-matrix、matrix-matrixをすべて同じAPIで処理するためです。)
@njsmith 「ネイティブ」Windowsサポートのステータスはほとんど変更されていません。 残念ながら、そのようなサポートを実現するための専門知識と関心はまだ不足しています。 ただし、Windows 10がリリースされてから、「UbuntuforWindows」または何らかのbash互換性環境が利用できるようです。 これはおそらく、Windowsサポートを実現するためのはるかに有望な手段です。 (しかし、繰り返しになりますが、私たちのグループの誰もWindowsで開発したり、Windowsを使用したりしていないため、そのオプションについても検討していません。)
とりあえず最後の投稿です...
@homocomputerisは、このようなベンチマークの場合、OpenBLASなどのよく知られたライブラリも表示するのに役立ちます。そうしないと、ハードウェアの速度がわからないためです。
@fgvanzeeネイティブのストライドサポートと言えば、最近のストライドにはどのような制限がありますか? それらは整列されている必要がありますか、正、非負、データサイズの正確な倍数、...? (覚えているかもしれませんが、numpy配列では、バイト単位で測定される完全に任意のストライドが可能です。)
@fgvanzee "bash for Windows"は、Windows上でLinux VMを実行することと実質的に同等です。特に高速でシームレスなVMですが、ネイティブ環境ではありません。 つまり、良いニュースは、すでにWindowsのbashをサポートしているということです:-)が、悪いニュースは、ネイティブのWindowsサポートに代わるものではないということです。
@njsmith私の結果は、記事とほぼ同じです。
たとえば、最新のMKL:
Dotted two 4096x4096 matrices in 2.09 s.
Dotted two vectors of length 524288 in 0.23 ms.
SVD of a 2048x1024 matrix in 1.11 s.
Cholesky decomposition of a 2048x2048 matrix in 0.19 s.
Eigendecomposition of a 2048x2048 matrix in 7.83 s.
CPUが最適化してマルチスレッド化できるすべてのものを使用するためにBLISをコンパイルする方法がわからないことに注意してください。 MKLには、多かれ少なかれ箱から出してすぐに使えるものがあります。
@njsmithその更新をありがとう。 ネイティブOSのサポートに勝るものはないことに同意します。 また、 @ homocomputerisのタイミングを適切に解釈するには、他のライブラリでベンチマークを実行する必要があることにも同意します。
ネイティブのストライドサポートと言えば、最近のストライドにはどのような制限がありますか? それらは整列されている必要がありますか、正、非負、データサイズの正確な倍数、...? (覚えているかもしれませんが、numpy配列では、バイト単位で測定される完全に任意のストライドが可能です。)
@njsmith整列? いいえ、ポジティブですか? その制約を解除したと思いますが、十分にテストされていません。 データ型の正確な倍数? はい、それでも。
@devinamatthewsを議論に
@homocomputeris size
異なる値でベンチマークを再実行していただけませんか? 著者が使用した2の累乗の値(4096)は、BLISの特に悪いユースケースであり、とにかくほとんどのアプリケーションにとって特に現実的ではないのではないかと思います。 代わりに4000(または3000または2000)を試すことをお勧めします。
@homocomputerisそして、BLISの結果はシングルスレッドであり、MKLの結果はマルチスレッドであると言いましたか?
FWIW、私はしばらく前にWindowsでBLISを構築することを検討しました。 現時点での主な問題点はビルドシステムです。 mingwのmakeにclangを使用してMSVC互換のバイナリを生成させることができるかもしれません。 それに費やすことができた時間でそれを実行することは決してありませんでしたが、それは可能のようです。
実際のソースコード内では、状況はそれほど悪くはありません。 最近、アセンブリカーネルにマクロを使用するように移行したため、Windowsサポートに対するもう1つの障壁がなくなりました。 https://github.com/flame/blis/issues/220#issuecomment-397842370およびhttps://github.com/flame/blis/pull/224を参照して
@insertinterestingnamehereチャイムをしてくれてありがとう、イアン。 再マクロ化されたアセンブリカーネルは、MSVCに対応することに一歩近づいています。 ただし、ご指摘のとおり、私たちのビルドシステムはWindowsのサポートを念頭に置いて設計されたものではありません。 さらに、MSVCはC99をまだサポートしていますか? そうでなければ、それは別のハードルです。 (BLISにはC99が必要です。)
さて、私はBLISが他のものに匹敵することを示すためだけに上記の例を挙げました、それで私はより具体的なものを何も含めなかったのです。
しかし、あなたが尋ねるように:smiley:
Intel MKL 2018.3は2スレッド(つまり、私の物理CPUコア)に制限されています:
Dotted two 3851x3851 matrices in 1.62 s.
Dotted two vectors of length 492928 in 0.18 ms.
SVD of a 1925x962 matrix in 0.54 s.
Cholesky decomposition of a 1925x1925 matrix in 0.10 s.
Eigendecomposition of a 1925x1925 matrix in 4.38 s.
BLIS0.3.2でコンパイルCFLAGS+=" -fPIC" ./configure --enable-cblas --enable-threading=openmp --enable-shared x86_64
Dotted two 3851x3851 matrices in 3.82 s.
Dotted two vectors of length 492928 in 0.39 ms.
SVD of a 1925x962 matrix in 12.82 s.
Cholesky decomposition of a 1925x1925 matrix in 2.02 s.
Eigendecomposition of a 1925x1925 matrix in 67.80 s.
したがって、BLISは、少なくともUnix / POSIX /その他のシステムでは、NumPyによって確実にサポートされる必要があるようです。Windowsのユースケースは「機能する場合は触れないでください」と想像しています。
私が知らないのは、MKL / BLISとLAPACK / libFLAMEの間の接続だけです。 Intelは、LAPACK、FFTなど、BLAS以外にも多くのものが最適化されていると主張しています。
@fgvanzee 2の累乗がBLISに悪いのはなぜですか? 最速のFFTが必要な場合、コロケーション方式では非常に一般的です。
numpy et al。の場合、mingw / MSYS2で建物を管理するだけで十分です---これは現在Windowsのopenblasで行っていることです(これはそれ自体
@ fgvanzeeC99についての良い点。 WRT C99プリプロセッサは、驚くべきことに、MSVC2017プリプロセッサでさえ完全には追いついていない。 おそらく彼らは現在それを修正しています(https://docs.microsoft.com/en-us/cpp/visual-cpp-language-conformance#note_D)。
@ fgvanzee @ njsmith任意のバイトストライドをサポートするために必要なことは次のとおりです。
1)インターフェースを変更します。 私が思い浮かぶ最も便利なことは、オブジェクトインターフェイスにstride_units
フラグのようなものを追加することです。
2)バイトストライドのみを使用するようにすべての内部をリファクタリングします。 いずれにせよ、これは悪い考えではないかもしれません。
3)パッキングするときは、データ型のアラインメントを確認し、そうでない場合は、汎用パッキングカーネルを使用します。
a) memcpy
を使用するには、汎用パッキングカーネルも更新する必要があります。 リテラルサイズパラメータを使用するように調整できれば、ひどく吸うべきではありません。
4)Cが整列されていない場合は、 memcpy
を使用してCにアクセスする仮想マイクロカーネルも使用します。
これは、入力行列と出力行列専用です。 alpha
とbeta
が任意のポインタである可能性がある場合は、さらに問題があります。 x86では、アラインされていないデータを問題なく読み書きできますが、他のアーキテクチャ(特にARM)が問題になることに注意してください。 コンパイラーは、自動ベクトル化時に追加のアライメントの問題を引き起こす可能性もあり
@homocomputeris :
gemm
操作がCの倍精度の実際の6x8マイクロタイルを更新すると、それらの6行はすべてL1キャッシュに設定された同じ結合性にマップされ、必然的にこれらの一部は削除される前に削除されることを意味します再利用。 これらのいわゆるコンフリクトミスは、パフォーマンスが時折急上昇するときにパフォーマンスグラフに表示されます。 私の知る限り、このパフォーマンスの打撃を回避する簡単な方法はありません。 すでに行列AとBをパック/コピーしているので、それほど影響はありませんが、大規模なメモリコピーヒットを取得せずに、行列Cをより好ましい先行次元にパックすることはできません。 (治療法は病気よりも悪いでしょう。)今、MKLにはこれを軽減する方法があり、競合ミスの数を最小限に抑える別の形状のマイクロカーネルに切り替えることができます。 それとも、彼らはそうではないが、私はBLISはこれを緩和するために何かをしようとしないことを知っています。 うまくいけば、それはあなたの質問に答えます。@fgvanzeeが更新されました。 BLISを構成に入れていたのに、どういうわけかMKLでコンパイルしたのは残念です。
SVDとEVDはLAPACKに実装されていますか?
@homocomputerisはい、LAPACKはSVDとEVDを実装しています。 そして、MKLの実装は非常に高速であると期待しています。
ただし、EVDは少しあいまいです。一般化された固有値問題とエルミート(または対称)EVDがあります。 三重対角EVDもありますが、エルミートEVDを実装している人を除いて、通常、それに興味を持っている人はほとんどいません。
NumPyは2018年末にPython2.7および3.4のサポートを終了します。これにより、C99に準拠した最新のMSVCコンパイラを使用できるようになります。これが、公式の2.7サポートがなくなる前に移行する理由の1つです。 最近のMSVCコンパイラでのC99サポートの詳細については、 http://tinyurl.com/yazmczelを参照してください。 サポートは完全ではありませんが(誰かが完全ですか?)、十分かもしれません。 一部の(Intel)が数値サポートの改善を要求しているため、NumPy自体をC99に移行する予定です。
@charrisこの情報をありがとう、チャールズ。 実装するものなら何でも十分なのかもしれませんが、試してみるまではわかりません。
いずれにせよ、BLISは、広く採用されるようになるためにMKLを打ち負かす必要はありません。 その直接の競争相手はOpenBLASです。
BLISは、広く採用されるようになるためにMKLを打ち負かす必要はありません。 その直接の競争相手はOpenBLASです。
これ以上同意できませんでした。 MKLは独自のリーグに属しています。
@njsmithちょうど好奇心が強い:numpyコミュニティは、たとえば、混合精度や混合ドメインでgemm
を実行できる新しいAPI /機能にどの程度関心がありますか? つまり、各オペランドは異なるデータ型である可能性があり、計算はAとBの一方または両方とは(潜在的に)異なる精度で実行されますか?
@fgvanzee興味があります、はい、組み合わせの潜在的な数は途方に暮れていますが。 しかし、現時点では型変換を行っているため、時間がかかり、メモリを消費します。 また、整数型用にルーチンを最適化するというアイデアも試してみましたが、オーバーフローの影響を取り返しのつかないのはブール型だけかもしれません。
そして、常にfloat16があります。 MLの人々は、これらの機能にもっと興味があるかもしれません。 @GaelVaroquauxの考え?
@charrisはい、ケースの数はgemm
には128の型の組み合わせがあり、4つの従来の浮動小数点データ型を想定しています。その数は、転置/活用パラメーターおよび行列ストレージの可能性から組み合わせインフレーションを除外します(この場合、 55,296)。
パフォーマンスの低いリファレンス実装を介しても128のケースを完全に実装することは注目に値し、オーバーヘッドを最小限に抑えるパフォーマンスの高い方法で実装することは非常に特別です。 (そして、BLISのオブジェクトベースの基盤のおかげで、これを実装する場合、追加のオブジェクトコードに関してはほとんどコストがかかりません。)
これに興味がある場合は、今後数日/数週間で私たちのプロジェクトをご覧ください。 :)
BLISフォークは安全ですか?
いずれにせよ、BLISは、広く採用されるようになるためにMKLを打ち負かす必要はありません。 その直接の競争相手はOpenBLASです。
確かに。 正直なところ、NumPy + BLASを自分のシステムで動作させることはできませんでしたが、前に引用した記事から判断すると、パフォーマンスは非常に似ているようです。
おそらく、libFLAMEはNumPyにリンクされていれば、LAPACK操作を高速化できます。
もう1つの興味深い質問は、AMDのBLIS / libFLAMEフォークを最新のZenCPUでベンチプレスして、改善が見られるかどうかを確認することです。 問題のあるIntelプロセッサに照らして、さらに興味深いものになります。
LinuxとWindowsでは、現在numpyの公式ホイールにはOpenBLASのビルド済みコピーが含まれているため、これらのプラットフォームでは、コピーを取得する最も簡単な方法はpip install numpy
です。 (もちろん、これは完全に公平ではありません。たとえば、そのバージョンは、BLISをローカルでビルドするために使用されるコンパイラとは異なるコンパイラでビルドされているためですが、アイデアを得ることができます。)
BLISフォークは安全ですか?
@jakirkham私はこれについて@devinamatthewsに話し、彼は答えはイエスであることを考えているようです。 BLISは、OpenBLASのようにスレッドプールを維持するのではなく、オンデマンドでスレッドを生成します(たとえば、 gemm
が呼び出されたとき)。
しかし、私たちは興味があります:numpyはどのようなスレッドモデルを期待/優先/依存しますか? 多くの非常に小さな問題を連続して呼び出すユースケースでオーバーヘッドを削減するためにスレッドプールが必要ですか? (BLISのオンデマンドスレッドは、そのような使用法には適していません。)
編集:同様に、pthreadが必要ですか、それともOpenMPに対応していますか?
情報をありがとう。
それで、pthread、OpenMP、両方を使用していますか? FWIW GCCのOpenMPには既知の問題があり、AFAIKが未解決であること@ogrisel )。 Pythonのmultiprocessing
モジュールを介してフォークすることは、最も一般的な並列処理戦略の1つであり、フォークセーフな方法でスレッド(できれば上記の理由からpthread)を使用できることは、Pythonでは一般的に非常に重要です。 最近では、たとえばfork-execを使用する
確かに、Nathanielは私よりもこれについてもっとよく知っているでしょうが、私はすでにこのコメントを書き始めているので、IIUC NumPyは外部ライブラリ(BLASなど)を介する場合を除いてスレッド自体を使用しません。 NumPyはGILを十分な頻度でリリースしますが、Pythonでのスレッド化はある程度効果的です。 Joblib、Daskなどのようなものはこの戦略を利用します。
スレッドプールに関しては、先日、PythonでNumPy / SciPyを使用して一連のBLASルーチンを実行するパフォーマンスを最大化するためにML手法をプロファイリングしていたので、これについて質問するのは興味深いことです。 OpenBLASと妥当な数のコアを使用すると、OpenBLASがスレッドプールを使用したという理由だけでPython(NumPyとSciPyを含む)で明示的なスレッドが使用されていなくても、このルーチンはルーチンの長さでコアを飽和させることができますルーチン。 そうです、スレッドプールは非常に価値があります。
別の点で、BLISは動的アーキテクチャ検出を処理しますか? これは、一度構築してさまざまな異なるシステムにデプロイできるアーティファクトを構築するために非常に重要です。
@jakirkhamコメントありがとうございます。 スレッドプールがない場合に観察されるコストは、渡す行列オペランドのサイズと、実行している操作によって異なると思います。 gemm
がターゲットとする典型的な操作だと思いますが(間違っている場合は修正してください)、どの問題サイズが典型的だと思いますか? A、B、Cが40x40の行列乗算を繰り返し実行した場合、BLISの作成/結合モデルのコストが明らかになると思いますが、400x400以上の場合はそれほど高くない可能性があります。 (TBH、そもそも40x40の問題を並列化することで大幅な高速化を期待するべきではありません。)
別の点で、BLISは動的アーキテクチャ検出を処理しますか? これは、一度構築してさまざまな異なるシステムにデプロイできるアーティファクトを構築するために非常に重要です。
はい。 この機能は、少し前の2017年後半に実装されました。BLISは、いわゆる「構成ファミリ」をターゲットにできるようになりました。使用する特定のサブ構成は、実行時にヒューリスティック( cpuid
介して選択されます。 intel64
、 amd64
、 x86_64
です。
@fgvanzee私は実際、小さなマトリックスでのパフォーマンスをOpenBLASの弱点の1つだと考えているので、BLISが再び遅くなるかどうかは少し心配です...人々は間違いなくあらゆる種類の状況でnumpyを使用するので、私たちはライブラリを本当に大切にしています。特定のケースに合わせて調整する必要なしに「ただ機能する」。 (これは、ベンチマークを実行するアルゴリズムの作成者と、専門のシステム管理者と1週間のスーパーコンピュータージョブを実行する専門家の2つの最も重要なケースである、古典的な密線形代数の設定とは少し異なると思います。)たとえば、人々はしばしばnumpyを使用します。 3x3マトリックス。
場合によっては、これを適切に処理することは、問題が小さすぎることに気づき、スレッドを完全にスキップすることの問題かもしれません。 3x3 gemmの場合、最適なことはおそらく可能な限り愚かであることです。
ただし、この種の調整(またはスレッドプール対スレッドプールなしのこと)は、BLISが広く展開され始めた場合に、コミュニティが参加して実行するものになる可能性があります。
実際、それは私に思い出させます:彼はより高いレベルでスレッドを管理していたので、彼のライブラリでgemmシングルスレッドを呼び出したいと知っていた誰かと先週話していました、そして彼は標準のblasライブラリでそれをする唯一の方法であることに不満を持っていましたこれを制御するには、ランダムなライブラリ内から呼び出すのに非常に便利なグローバル設定を使用します。 BLISのネイティブAPIを使用すると、ユーザーは呼び出しごとにスレッド構成を制御できますか? IIRCには、BLAS互換性レイヤーの外側にグローバル構成がまったくないので、そうだと思いますか?
私は実際、小さなマトリックスでのパフォーマンスをOpenBLASの弱点の1つだと考えているので、BLISが再び遅くなるかどうかは少し心配です...人々は間違いなくあらゆる種類の状況でnumpyを使用するので、私たちは「特定のケースに合わせて調整する必要はありません。
「正しく機能する」ことを望んでいることは理解していますが、現実的で正直になりたいと思っています。 3x3の問題があり、パフォーマンスが非常に重要である場合は、BLISを使用するべきではありません。 BLISが3x3のナイーブトリプルループよりも10倍遅く実行されると言っているのではなく、BLISの実装が得意とする問題のサイズではないというだけです。
小さな問題でOpenBLASに少し不満があると聞いて驚いています。 あなたの基準点は何ですか? 大きな問題よりもパフォーマンスが低いだけですか? 小さな問題で可能な限り最高のパフォーマンスを達成するには、大きな問題とは異なる戦略が必要です。そのため、ほとんどのプロジェクトはどちらか一方を対象とし、対象外のケースを最適に処理しません。
場合によっては、これを適切に処理することは、問題が小さすぎることに気づき、スレッドを完全にスキップすることの問題かもしれません。 3x3 gemmの場合、最適なことはおそらく可能な限り愚かであることです。
カットオフが理想的であることに同意します。 ただし、そのカットオフをどこに配置するかを決定することは簡単ではなく、アーキテクチャによって(およびレベル3の操作全体で)最も確実に異なります。 したがって、それは非常に可能ですが、まだ実装されていません(またはよく考えられていません)。
ただし、この種の調整(またはスレッドプール対スレッドプールなしのこと)は、BLISが広く展開され始めた場合に、コミュニティが参加して実行するものになる可能性があります。
はい。
実際、それは私に思い出させます:彼はより高いレベルでスレッドを管理していたので、彼のライブラリでgemmシングルスレッドを呼び出したいと知っていた誰かと先週話していました、そして彼は標準のblasライブラリでそれをする唯一の方法であることに不満を持っていましたこれを制御するには、ランダムなライブラリ内から呼び出すのに非常に便利なグローバル設定を使用します。
マルチスレッドアプリケーションからのシーケンシャルgemm
は、私たちが考えるのが好きなユースケースの1つです。 (リマインダー:シーケンシャルgemm
が彼の唯一のユースケースである場合、マルチスレッドを無効にしてBLISを構成するだけです。ただし、一度ビルドして後でスレッドを決定したいとします。)
BLISのネイティブAPIを使用すると、ユーザーは呼び出しごとにスレッド構成を制御できますか? IIRCには、BLAS互換性レイヤーの外側にグローバル構成がまったくないので、そうだと思いますか?
マルチスレッドを有効にしてBLISを構成した場合でも、並列処理はデフォルトで無効(1スレッド)になっています。 それが彼が問題を解決するための2番目の方法です。
しかし、彼が実行時に並列処理の程度を変更したいとします。 BLISの並列処理は、実行時に設定できます。 ただし、BLISがsetenv()
およびgetenv()
介して環境変数を内部的に設定および読み取る必要があります。 (詳細については、マルチスレッドwikiを参照してください。)したがって、それがあなたの友人にとって大きな問題であるかどうかはわかりません。 よりプログラム的な方法でスレッドを指定できる(環境変数を含まない)APIを実装したいのですが、まだ十分ではありません。 ほとんどの場合、それはインターフェースに関するものです。 インフラストラクチャはすべて整っています。 問題の一部は、並列化するときに1つの数値を指定するように私たち全員が何年にもわたって訓練されてきたことです(たとえば、 OMP_NUM_THREADS
など)。これは、BLISが好む情報を大幅に単純化しすぎています。 gemm
アルゴリズムには5つのループがあり、そのうち4つは並列化できます(将来的には5つ)。 1つの数値から推測できますが、ハードウェアトポロジに依存するため、通常は理想的ではありません。 これが、この面での進歩を妨げているものの一部です。
@devinamatthews同じ静脈に沿ってTBLISを追加するチャンスはありますか?
3x3の問題があり、パフォーマンスが非常に重要である場合は、BLISを使用するべきではありません。 BLISが3x3のナイーブトリプルループよりも10倍遅く実行されると言っているのではなく、BLISの実装が得意とする問題のサイズではないというだけです。
私は3x3の問題に対して最適なパフォーマンスを得ることにそれほど心配していません(それを得ることができれば明らかにそれは素晴らしいことですが!)。 しかし、極端な例を挙げると、numpyが基になる線形代数ライブラリとしてBLISを使用してコンパイルされ、一部のユーザーがnumpyを使用してコードにa @ b
を書き込んだ場合、実行速度が10倍遅くならないことを願っています。素朴な実装よりも。 ユーザーが3x3行列をマルチプルする前にnumpyを再構築することを期待することは、質問するには多すぎます:-)。 特に、ある場所で3x3行列を乗算する同じプログラムが、別の場所で1000x1000行列も乗算する可能性があるためです。
注意:シーケンシャルgemmが彼の唯一のユースケースである場合、マルチスレッドを無効にしてBLISを構成するだけです。 しかし、彼が一度ビルドして、後でスレッド化することを決定したいとします。
彼はPythonライブラリを出荷しています。 彼は、ユーザーが自分のライブラリを取得し、それを他のライブラリや独自のコードと組み合わせて、すべて同じプロセスで一緒に実行することを期待しています。 彼のライブラリはGEMMを使用しており、彼が制御していない、または知らない他のコードのいくつかもGEMMを使用したいと思うでしょう。 彼は、同じプロセスで発生する可能性のあるGEMMへの他の無関係な呼び出しに誤って影響を与えることなく、GEMMへの呼び出しのスレッドを制御できるようにしたいと考えています。 そして理想的には、GEMMのコピーを自分で出荷しなくてもこれを実行できるはずです。これは、適切に実行するのが非常に面倒であり、プログラムに大きなライブラリのコピーを2つ含める必要があるという概念的な不快感もあります。したがって、1つの整数変数number_of_threads
2つのコピーを取得できます。 それはもっと理にかなっていますか?
単純な実装よりも10倍遅く実行されないことを私は間違いなく望んでいます。
考えてみると、非常に小さい(3x3)問題の場合、ナイーブよりも数倍遅い場合でも驚くことはありませんが、クロスオーバーポイントは低く、おそらく16x16程度です。 そして、これはバンドエイドをかけるのが簡単な問題です。 (レベル3のすべての操作で実行したいと思います。)
彼はPythonライブラリを出荷しています。 彼は、ユーザーが自分のライブラリを取得し、それを他のライブラリや独自のコードと組み合わせて、すべて同じプロセスで一緒に実行することを期待しています。 彼のライブラリはGEMMを使用しており、彼が制御していない、または知らない他のコードのいくつかもGEMMを使用したいと思うでしょう。 彼は、同じプロセスで発生する可能性のあるGEMMへの他の無関係な呼び出しに誤って影響を与えることなく、GEMMへの呼び出しのスレッドを制御できるようにしたいと考えています。 そして理想的には、GEMMのコピーを自分で出荷しなくてもこれを実行できるはずです。これは、適切に実行するのが非常に面倒であり、プログラムに大きなライブラリのコピーを2つ含める必要があるという概念的な不快感もあります。したがって、1つの整数変数number_of_threadsの2つのコピーを取得できます。 それはもっと理にかなっていますか?
はい、それは役に立ちました-詳細に感謝します。 彼は私たちのまだ存在しないスレッドAPIの完璧な候補になるようです。 (個人的には、環境変数の慣習は境界性の狂気であり、何度も協力者に私の気持ちを表明していると思います。とはいえ、HPCユーザー/ベンチマークの広い範囲にとって
これは間違いなく私たちのレーダーにあることを彼に伝えていただけませんか? ロバートとハドルします。 彼は、私の時間を後でではなく早く承認するのに十分な興味を持っているかもしれません。 (スレッドAPIはしばらくの間彼のウィッシュリストに載っています。)
@isurufお時間を
プルリクエストに関しては、コメント/リクエストがいくつかありますが(すべて非常にマイナーです)、プルリクエスト自体について会話を開始します。
PS: f2c
エラーを理解できてよかったです。 libf2cの十分な部分をBLASテストドライバーソース( libf2c.a
としてコンパイル)にインポートして、リンクするようにしましたが、ヘッダーファイルにいくつかのハッカーが必要でした。 (Fortranコードを維持するのは好きではありません-あなたが言うことができない場合に備えて、Fortranよりもf2cされたCを見たいと思います。)
Intel MKL 2018.3:
Dotted two 4096x4096 matrices in 2.09 s.
Dotted two vectors of length 524288 in 0.23 ms.
SVD of a 2048x1024 matrix in 1.11 s.
Cholesky decomposition of a 2048x2048 matrix in 0.19 s.
Eigendecomposition of a 2048x2048 matrix in 7.83 s.
上で使用したベンチマークに関する一言。 ロバートは、このベンチマーク(またはnumpy?)がコレスキー、EVD、およびSVDをどのように実装するかを知らない限り、これらの操作の結果はそれほど意味のあるものではないことを私に思い出させました。 たとえば、netlib LAPACKコードがコレスキー分解に使用されている場合、アルゴリズムのブロックサイズは間違っています(理想からはほど遠い)。 さらに、NumpyがMKLにリンクする方法によっては、MKLには高速のgemm
に加えてコレスキー分解が独自に実装されているため、状況がさらに歪む可能性があります。 MKL。
パフォーマンスの一般的な考え方を理解するためだけに使用している可能性があることは承知していますが、それで問題ありません。 非常に大まかな比較以外の目的でそれを使用することを許可しない詳細に隠れている悪魔がいる可能性があることを理解してください。
一般に、numpyは、LAPACKまたはLAPACKに似たライブラリが利用可能な場合と同様の操作を延期します。 MKLビルドは、IntelがMKL内に出荷するLAPACKの調整済みフォークをほぼ確実に使用しています。 BLISビルドは、おそらくリファレンスLAPACKなどを使用しています。
ある意味、これは公平です。高速SVDを実行するためにnumpy構成を選択しようとしている場合、MKLには調整済みバージョンがあり、BLISにはないことが関係します。 (OpenBLASはその中間にあると思います。ライブラリにLAPACKの修正バージョンが同梱されていますが、MKLのバージョンよりもリファレンス実装にはるかに近いです。)しかし、BLISとは何か、そしてその理由を理解しようとしているのであれば、確かにそうです。結果はそのように見えます。純粋なGEMMの効率だけでなく、SVDなどに含まれるものがはるかに多いことを覚えておくことが重要です。
ある意味で、これは公正です。
私は理解し、同意します。 以前に提案されたようなベンチマークを使用して単一のハードウェアの絶対パフォーマンスを測定する(つまり、実装がピークパフォーマンスと比較してどれだけ優れているかを判断する)人もいれば、実装を比較するためにそれを使用する人もいます。 コレスキーらについてのロバートのコメントだと思います。 後者よりも前者をターゲットにしています。
@njsmith @insertinterestingnamehere @rgommers @charris Isuruの迅速な作業のおかげで、彼のアパイヤーベースのWindowsサポートを洗練してBLISのmaster
ブランチにマージすることができました。 ご覧になり、これがnumpyに対するWindowsサポートの問題に対処するかどうかとその程度をお知らせください。
@fgvanzee PRにリンクできますか?
PRにリンクできますか?
確かに、ここにあります。
その初期ビルドセットアップは素晴らしいです! 少なくとも理論的には、WindowsでBLISを使用してnumpyを構築するのに十分なはずです。 dllの構築やMinGWのサポートなどは後で追加できます。
この場合に使用される依存関係について注意すべきことの1つは、pthreads-win32はLGPLです。 IDKは、もしあれば、それについて何をする必要がありますか。
ライセンスは難しい問題です。 法的な方針により、LGPLのような「コピーレフト」ライセンスの使用が困難である一方で、「パーミッシブ」ライセンスは問題ではない大企業をいくつか知っています。 LGPLコードをNumPy / SciPyコードベースまたはホイールに追加することは、正当かどうかにかかわらず、間違いなく懸念の原因になります。
ここではコードベースに追加していません。 LGPLコンポーネントをホイールで出荷することは問題ではありません。 現在、ランタイム例外のあるGPLであるgfortrandllを出荷しています。 gh-8689を参照
確かに。 その上、そのような企業もMKLを好むとしても、驚くことではありません。
おそらく、LGPLコンポーネントが静的にリンクされていないことを確認する必要があります。
@jakirkhamコメントありがとうございます。 スレッドプールがない場合に観察されるコストは、渡す行列オペランドのサイズと、実行している操作によって異なると思います。 gemmはターゲットとする典型的な操作だと思いますが(間違っている場合は修正してください)、どの問題サイズが典型的だと思いますか? A、B、Cが40x40の行列乗算を繰り返し実行した場合、BLISの作成/結合モデルのコストが明らかになると思いますが、400x400以上の場合はそれほど高くない可能性があります。 (TBH、そもそも40x40の問題を並列化することで大幅な高速化を期待するべきではありません。)
主にGEMMとSYRKが典型的です。 GEMVが登場することもありますが、可能であれば、それは大規模なGEMM操作に組み込まれることがよくあります。
少なくとも10 ^ 6要素のオーダーの1つの次元を持つことは私たちにとって珍しいことではありません。 もう1つは、10 ^ 3から10 ^ 6の範囲です。 したがって、それはかなり異なります。 これにスレッドプールを使用させるために必要なことはありますか、それとも自動的に行われますか? また、プロセスがフォークされた場合、スレッドプールはどのように動作しますか?
別の点で、BLISは動的アーキテクチャ検出を処理しますか? これは、一度構築してさまざまな異なるシステムにデプロイできるアーティファクトを構築するために非常に重要です。
はい。 この機能は、少し前の2017年後半に実装されました。BLISは、ヒューリスティック(cpuid命令など)を介して実行時に使用される特定のサブ構成を使用して、いわゆる「構成ファミリー」をターゲットにできるようになりました。 サポートされているファミリの例は、intel64、amd64、x86_64です。
これを少し前置きするために、BroadwellまでずっとNehalemを使用している古いコンピューターがあります。 たぶん、いくつかの新しいパーソナルマシンにはKabyLakeがあります。 したがって、サポートされていない組み込み関数を使用して古いマシンで実行している場合、クラッシュしないと同時に、提供されているアーキテクチャを最大限に活用できることが重要です。 Flameのサブ構成はこの範囲をサポートしていますか?異なるアーキテクチャーに適切なカーネルをディスパッチするための追加のコードが組み込まれていますか? これはどのくらいきめ細かくなりますか? これらのカーネルが存在することを確認するために、ビルド中に行う必要があることはありますか?
x86_64
構成を使用した@jakirkhamの構築により、次のことが可能になります。
これらのいくつかは、十分に新しいコンパイラやbinutilsバージョンを必要としますが、ビルドマシン上でのみ必要であることに注意してください。
AFAIK libflameには、どのアーキテクチャにも特化したカーネルはありません。これはすべてBLIS次第です。
@jakirkhamスレッドプールの実装を追加する必要があります。 今のところ、これは基本的なフォーク結合の実装であり、フォークセーフである必要があります。
AFAIK libflameには、どのアーキテクチャにも特化したカーネルはありません。これはすべてBLIS次第です。
これはほとんど正しいです。 libflameにはギブンス回転を適用するための組み込み関数(現在はSSEのみ)がいくつかありますが、これらのカーネルはlibflameに属しておらず、作成時にBLISが存在しなかったために存在するため、他に場所がありませんでした。それらを収容します。 最終的に、これらのカーネルは書き直され、更新され、BLISに再配置されます。
Flameのサブ構成はこの範囲をサポートしていますか?異なるアーキテクチャーに適切なカーネルをディスパッチするための追加のコードが組み込まれていますか? これはどのくらいきめ細かくなりますか? これらのカーネルが存在することを確認するために、ビルド中に行う必要があることはありますか?
@jakirkhamこの場合の「炎」とはどういう意味か
「Flame」を「BLIS」にテキストで置き換えると、答えは「はい、ほとんど」です。
それはどのくらいきめ細かくなりますか?
意味はわかりませんが、BLISでのカーネルサポートはOpenBLASほど広範囲ではありません。 たとえば、複雑なドメインtrsm
最適化しないことがよくあります。 カーネルは、いくつかの組み合わせで、サブ構成によって利用されます。 サブ構成はcpuid
介して選択されます。 サブ構成によって「登録」されたカーネルを正確に取得します。 ナットとボルトの詳細については、構成wikiを参照してください。
これらのカーネルが存在することを確認するために、ビルド中に行う必要があることはありますか?
ランタイムハードウェア検出が必要な場合は、特定のサブ構成(またはauto
を選択する)ではなく、構成時に構成ファミリー( intel64
、 x86_64
)をターゲットにします。特定のサブ構成)。 それでおしまい。
これにスレッドプールを使用させるために必要なことはありますか、それとも自動的に行われますか? また、プロセスがフォークされた場合、スレッドプールはどのように動作しますか?
このスレッドで前に述べたように、BLISはスレッドプールを使用しません。 そして、私はフォークの安全性についてDevinに任せます(そして彼はフォークは問題ないと考えているようです)。
参考までに、BLIS condaパッケージは、conda-forge上のlinux、osx、windowsで使用できます。 (現在、開発ブランチを構築しており、リリースを待っています)。 パッケージは、pthreadを有効にしてx86_64構成でビルドされました。
彼はPythonライブラリを出荷しています。 彼は、ユーザーが自分のライブラリを取得し、それを他のライブラリや独自のコードと組み合わせて、すべて同じプロセスで一緒に実行することを期待しています。 彼のライブラリはGEMMを使用しており、彼が制御していない、または知らない他のコードのいくつかもGEMMを使用したいと思うでしょう。 彼は、同じプロセスで発生する可能性のあるGEMMへの他の無関係な呼び出しに誤って影響を与えることなく、GEMMへの呼び出しのスレッドを制御できるようにしたいと考えています。
@njsmith私はロバートと話をしましたが、彼はこれに取り組む優先順位を上げても大丈夫です。 (また、簡単に調べてみると、2つ以上のアプリケーションスレッドが異なる程度の並列処理を使用しようとするといつでも現れる競合状態がBLISで見つかりました。その競合状態を修正すると、次のような人々のAPI関連のニーズに同時に対応できます。あなたの友達。)
@jakirkham Intelの連絡先の1つである@jeffhammondは、OpenMP実装が定期的にスレッドプールモデルを内部で採用していることを通知しています。 したがって、彼はBLIS内でスレッドプールを冗長に実装することを思いとどまらせています。
さて、あなたが示唆しているように、numpyがpthreadを必要とする/好む場合があります。その場合、fork / joinスタイルのpthreadAPIの下で発生する実際のfork / joinに戻る可能性があります。
それで、pthread、OpenMP、両方を使用していますか?
また、この質問に答えるのを忘れていることに気づきました。 BLISのマルチスレッド並列処理は構成可能です。pthreadまたはOpenMPを使用できます。 (ただし、ライブラリの初期化に使用されるpthread_once()
に依存しているため、これをBLISのpthreadへの無条件のランタイム依存性と混同しないでください。)
残念ながら、OpenMPの実装(GOMPなど)が一般的にフォークに対してより堅牢にならない限り、Pythonでは実際には安全なオプションではありません。 特に、NumPyほどスタックが低いものではありません。
残念ながら、OpenMPの実装(GOMPなど)が一般的にフォークに対してより堅牢にならない限り、Pythonでは実際には安全なオプションではありません。 特に、NumPyほどスタックが低いものではありません。
けっこうだ。 したがって、numpyはBLISを介したマルチスレッド化のために--enable-threading=pthreads
構成オプションに依存するようです。
pthreadsでコンパイルした場合、numpyを呼び出すPythonプロセス/スレッドプールでネストされた並列処理を行うときにオーバーサブスクリプションの問題を回避するためのプログラム制御を取得するためのパブリックAPIはありますか?
より具体的には、私が探しているパブリックシンボルの種類は次のとおりです。
https://github.com/tomMoral/loky/pull/135/files#diff -e49a2eb30dd7db1ee9023b8f7306b9deR111
MKLおよびOpenMPのhttps://github.com/IntelPython/smpで行われていることと同様です。
pthreadsでコンパイルした場合、numpyを呼び出すPythonプロセス/スレッドプールでネストされた並列処理を行うときにオーバーサブスクリプションの問題を回避するためのプログラム制御を取得するためのパブリックAPIはありますか?
@ogriselすばらしい質問です、オリヴィエ。 実行時にスレッドパラメータを設定する方法はありますが、現在はグローバルセマンティクスで行われています。 (呼び出しごとではなくグローバルでgemm
などに)フィードするため、これは最適で
私は現在、BLISのいわゆる「エキスパート」サブAPIの1つを使用して、追加のデータ構造をgemm
に渡すことができるようにする、基になるコードのマイナーな再設計に取り組んでいます。呼び出しごとに、並列化戦略を指定する呼び出し元。 前述のデータ構造により、ユーザーは単一のスレッド数を指定でき、BLISは自動的に最善を尽くして、行列乗算アルゴリズムの各ループの並列処理または並列処理のレベルを取得します(BLISが推奨するとおり)。
いずれにせよ、この新しいアプローチはあなたのニーズを満たすと思います。 私はすでに変更を途中で終えているので、新機能がgithubにプッシュされてからわずか1週間かそこらだと思います。 この計画があなたにとってうまくいくように聞こえるかどうか、および/またはこのトピックに関して他の懸念や要求があるかどうかを私に知らせてください。
PS:私はあなたが提供したlokyリンクを見ました。 これらのシンボルはすべて、スレッドのグローバル設定用に設定されています。 私が提案したソリューションは、グローバルに設定することを妨げるものではありませんが、それが唯一の選択肢ではないように設計されています。 したがって、最大8つのコア/スレッドを使用したい人は、アプリケーションに2つのスレッドを生成させ、それぞれが4方向の並列処理を取得するgemm
インスタンスを呼び出すことができます。 または、2つのアプリケーションスレッドが2方向の並列処理でgemm
を呼び出し、3番目のスレッドが4方向の並列処理を使用します。 (あなたはその考えを理解します。)
環境変数を介してフィードします。
どういう意味ですか? Pythonのctypesを使用して、特定のPythonプロセスで既に初期化された後、デフォルト/グローバルBLISスレッドプールのサイズを再構成することは可能ですか?
環境変数を介してフィードします。
どういう意味ですか?
@ogriselこれが意味するのは、OpenMPのomp_get_num_threads()
やomp_set_num_threads()
と同様に、スレッド数を設定または取得するための小さなAPIがBLISにあるということです。 ただし、これらのBLIS API関数は、 getenv()
およびsetenv()
への呼び出しとして実装されます。 これは、BLISの元のユースケースの1つが、シェルに1つ以上の環境変数( bash
)を設定してから、BLISにリンクされたアプリケーションを実行することであったという事実の歴史的な成果物にすぎません。その環境変数アプローチに基づいて単純に構築するのが便利だったとき。 これは、並列処理のスレッド数を指定するための最終的な完璧な方法になることを意図したものではありませんでした。
特定のPythonプロセスで既に初期化された後、Pythonのctypesを使用してBLISスレッドプールのサイズを再構成することは可能ですか?
BLISはスレッドプールを明示的に使用しません。 むしろ、pthreadを介して並列処理を抽出するためにcreate / joinモデルを使用します。 しかし、はい、BLISが初期化された後、アプリケーション(または呼び出しライブラリ)は、少なくとも原則として、関数呼び出しを介して実行時にスレッドの数を変更できます。 (ただし、これが実際に機能するかどうかはわかりません。Pythonが環境変数を設定/取得しようとするBLISをどのように処理するかわからないためです。)しかし、前述したように、いくつかの変更を完了すると、アプリケーション/ライブラリは、レベル3の操作が呼び出されたときに、呼び出しごとにカスタム並列化スキームを指定できます。 これは、最初に小さなstruct
データ型を初期化し、次にそのstruct
をBLIS APIの拡張された「エキスパート」バージョンにgemm
などで渡すことによって行われます。)これ環境変数を必要としない/望まない人にとっては、環境変数は不要になります。 うまくいけば、これはあなたの質問に答えます。
ご説明ありがとうございます。 呼び出しごとのエキスパートAPIは興味深いものですが、Pythonレベルの呼び出し元に公開するために特定のAPIを維持するためにnumpyが必要になります。 それが欲しいかどうかはわかりません。 グローバル(プロセスレベル)並列処理レベルの現在の値を変更する方法を持っているnumpyユーザーにとっては十分だと思います。 個人的には、env変数の現在の値を変更することで達成できるかどうかは、後続のBLAS-3呼び出しでこの変更が考慮されている限り問題ありません。
@charris float16は、個人的な経験はありませんが、少なくとも予測時には、一部の機械学習ワークロードにとって確かに興味深いかもしれません。
グローバル(プロセスレベル)並列処理レベルの現在の値を変更する方法を持っているnumpyユーザーにとっては十分だと思います。 個人的には、env変数の現在の値を変更することで達成できるかどうかは、後続のBLAS-3呼び出しでこの変更が考慮されている限り問題ありません。
知っておくと良い。 その場合、BLISはnumpyで使用する準備ができていることにはるかに近いです。 (最初にこれらの進行中の変更を行いたいと思います。これにより、以前は気づかなかった競合状態も修正されます。)
getenv
は超高速ではないため、呼び出しごとに再チェックされる環境変数に依存しない方がよいでしょう。後で削除するのが理にかなっているかもしれません。 (また、私は?それはでも、スレッドセーフであることが保証はないと思う)しかし、 bli_thread_set_num_threads
BLISは、呼び出し停止してもいるので、API呼び出しは問題ないはずですgetenv
API呼び出し、すべての時間を関係なく動作し続けるように調整できます。
長期的には、裸を超えたBLASAPIをnumpyで公開し始めるのは理にかなっていると思います。 そもそもBLISを魅力的なものにしていることの1つは、ストライドマトリックスを乗算する機能など、他のBLASライブラリにはない機能を提供することです。また、さまざまな方法でBLASAPIを拡張する作業が進行
numpyのAPIにライブラリ固有の詳細をハードコーディングしたくはありません(たとえば、 np.matmul
がBLISのJC、IC、JR、およびIRパラメーターに対応する引数を取り始めたくない)が、その機能を提供するバックエンドでのみ機能する一般的な「この呼び出しのスレッド数」引数を提供することは理にかなっているかもしれません。
私が言及していないことの1つは、インデックスの精度です。 ほとんどのシステム提供ライブラリは32ビット整数を使用しているようですが、これは最近の一部のアプリケーションの制限です。 ある時点で、すべてのインデックスが64ビットであるとよいでしょう。これには、おそらくライブラリを提供する必要があります。 インデックスサイズに関して現在何をしているのかわかりません。 @ matthew-brettまだ32ビット整数でコンパイルしていますか?
@charris BLISの整数サイズは、configure-timeで構成可能です:32ビットまたは64ビット。 さらに、内部整数サイズとは別に、BLASAPIで使用される整数サイズを構成できます。
実際、それは私に思い出させます:彼はより高いレベルでスレッドを管理していたので、彼のライブラリでgemmシングルスレッドを呼び出したいと知っていた誰かと先週話していました、そして彼は標準のblasライブラリでそれをする唯一の方法であることに不満を持っていましたこれを制御するには、ランダムなライブラリ内から呼び出すのに非常に便利なグローバル設定を使用します。
@njsmith前述の競合状態を修正し、スレッドセーフな呼び出しごとのマルチスレッドAPIも実装しました。 友達をfa08e5e (またはそのコミットの子孫)に向けてください。 マルチスレッドのドキュメントも更新され、基本的な例を示して、読者に選択肢を説明します。 コミットは今のところdev
ブランチにありますが、すぐにmaster
にマージする予定です。 (私はすでにほとんどのペースでコードを実行しています。)
編集:マイナーな修正コミットを反映するようにリンクが更新されました。
サポートされているタイプへの可能な追加として、 long double
どうですか? 一部のアーキテクチャは(まだソフトウェアで)四倍精度をサポートし始めており、ある時点で拡張精度がインテルの四倍精度に置き換えられることを期待しています。 これがすぐに差し迫っているとは思いませんが、ここ数年で物事はそのようになり始めていると思います。
@charris特に機械学習/ AIアプリケーションのため、 bfloat16
やfloat16
サポートを検討する初期段階にありますが、 double double
需要も認識しています。
@charris https://en.wikipedia.org/wiki/Long_doubleによると、 long double
はさまざまな意味を持ちます。
パフォーマンスの観点からは、SIMDバージョンがないため、float80(つまり、x87 long double)の利点は見られません。 BLISでdouble double
SIMDバージョンを書くことができれば、パフォーマンスは向上するはずです。
ソフトウェアでのfloat128の実装は、ハードウェアでのfloat64よりも少なくとも1桁遅くなります。 すべてのFPE処理をスキップし、SIMDに対応するfloat128の新しい実装を作成するのが賢明です。 libquadmathでの実装は正しいものの、BLISのような高性能のBLAS実装に注目する価値はありません。
うん、それは問題だ。 拡張精度は努力する価値がないと思います。四倍精度の必要性はむらがあり、ほとんどの場合、倍精度は適切ですが、必要な場合は必要です。 パフォーマンスについては心配していません。必要なのは速度ではなく精度です。 もちろん、ソフトウェア実装である四倍精度のロングダブルを備えたARM64にサポートを拡張しただけですが、ハードウェアはいつか続くと思います。何かをテストして準備ができていると便利かもしれません。
これが前進するのを見て興奮しています!
ちなみに、
私は約1年前に、PyPi用にBlisをパッケージ化し、Cythonバインディングを追加する作業を行いました: https :
Blisは、このようなC拡張機能としてパッケージ化するのが非常に簡単であることがわかりました。 私にとっての主な障害は、Windowsのサポートでした。 記憶から、それはC99の問題でした、しかし私は間違って覚えているかもしれません。
私が追加したCythonインターフェースは興味深いかもしれません。 特に、私はCythonの融合型を使用しているので、float型とdouble型の両方について、memory-viewまたはrawポインターのいずれかで呼び出すことができる単一のnogil
関数があります。 より多くのタイプにさらにブランチを追加することも問題ありません。 融合型は基本的にテンプレートです。オーバーヘッドをゼロにして、コンパイル時の条件付き実行を可能にします。
スタンドアロンのBlisパッケージを維持し、ホイールを構築し続け、Cythonの優れたインターフェイスを維持することなど、非常に喜ばしいことです。 その後、他のBLASライブラリがサポートするものに制限されることなく、BlisのAPIをさらに公開できます。
@honnibalこのスレッドでの応答が遅れてすみません、マシュー。
メッセージありがとうございます。 他の人がBLISに興奮するのを見るのはいつも幸せです。 もちろん、Pythonエコシステム(アプリケーション、ライブラリ、モジュールなど)にさらに統合することにした場合は、必要に応じていつでもアドバイスさせていただきます。
Windowsのサポートについては、 @ isurufが最近追加した
また、コールごとのスレッドの使用法について質問がある場合はお知らせください。 (このトピックをカバーするために、マルチスレッドのドキュメントを更新しました。)
非常に興味深い、@ fgvanzeeに感謝します。
私はEpycを調べなければなりませんでした-それはZen(おそらくある時点でZen +に更新されたのですか?)アーキテクチャに基づくブランド名のようです。 おそらくZenに名前を変更したほうがいいですか? 私たちのユーザーベースにとって、Ryzen / Threadripperはより興味深いブランドであり、Zenを認識しているかもしれませんが、おそらくEpycは認識していません。
EpycはAMDサーバーラインの名前です。 これは、過去のAMDOpteron製品の後継です。
残念ながら、コードはベクターISA(AVX2など)、CPUコアマイクロアーキテクチャ(Ice Lakeなど)、SOC /プラットフォーム統合(Intel Xeon Platinumプロセッサなど)に依存するため、BLISがアーキテクチャターゲットにラベルを付けるための独自の方法はありません。 )。 BLISは、場合によってはマイクロアーキテクチャのコード名を使用しますが(Dunningtonなど)、それがすべての人にとって良いわけではありません。
@fgvanzee GCC march / mtune / mcpu名に対応するエイリアスを追加することを検討してください...
@rgommers RyzenとEpycをカバーするBLIS内のサブ構成は、両方の製品をキャプチャするため、実際にはすでにzen
という名前が付けられています。
Ryzen / ThreadripperまたはEpycのどちらがより興味深いブランドであるか(numpyユーザーにとっても)については、次のように言います。1つのAMD Zenシステムしかベンチマークできなかった場合、それは最高級のEpycになります。理由は次のとおりです。(a) Ryzenと同様のマイクロアーキテクチャを使用しています。 (b)最大64個の物理コアが得られます(ボーナスとして、これらのコアはやや斬新なNUMAのような構成で配置されています)。 (c)BLISおよびその他の実装に最大のストレスをかけます。 そしてそれは基本的に私たちがここでしたことです。
ありがたいことに、1つのZenシステムしかベンチマークできないというルールはありません。 :)しかし、特にそもそもアクセスを取得することに関して、他のハードルがあります。 現在、Ryzen / Threadripperシステムにアクセスできません。 アクセスできるようになった場合は、実験を繰り返し、それに応じて結果を公開します。
ジェフは、私たちが直面している命名の落とし穴のいくつかを指摘しています。 一般に、サブ構成とカーネルセットにはマイクロアーキテクチャの観点から名前を付けますが、まだ微妙な違いがあります。 たとえば、Haswell、Broadwell、Skylake、Kaby Lake、CoffeeLakeでhaswell
サブ構成を使用します。 これは、それらがすべて基本的に同じベクトルISAを共有しているためです。これは、BLISカーネルコードが気にするほとんどすべてです。 しかし、それはほとんどユーザーが気にする必要のない実装の詳細です。 ./configure auto
を使用すると、 zen
やhaswell
などの名前が付けられているかどうかに関係なく、ほとんどの場合、システムに最適なサブ構成とカーネルセットが得られます。 今のところ、スレッドスキームを最適に選択する場合は、さらに実践的なアプローチをとる必要があります。そこで、Jeffが言及するSoC /プラットフォーム統合が登場します。
@jeffhammondご提案ありがとうございます。 私は過去にそれらのエイリアスを追加することを検討しました。 しかし、私はそれが価値があるとは確信していません。 それは構成レジストリにかなりの混乱を追加し、そもそもそれを見る人々はおそらくサブ構成とカーネルセットの命名スキームをすでに知っているので、特定のマイクロアーキテクチャの改訂がないことで混乱することはありませんそのファイル(またはconfig
ディレクトリ)内の名前。 さて、BLISが、たとえば./configure haswell
を介してサブ構成を手動で識別する必要がある場合、スケールは間違いなくあなたの提案に有利になると思います。 しかし、 ./configure auto
は非常にうまく機能しているので、現時点では必要はないと思います。 (必要に応じて、このトピックに関する問題を開いて、コミュニティメンバー間でより幅広い議論を開始できます。十分な需要がある場合は、いつでも考えを変えることができます。)
はい、命名は常に複雑です:) @ fgvanzeeと@jeffhammondの回答に感謝します
#13132と#13158は関連しています
議論は少し夢中になりました。 numpyでBLISを公式にサポートするために解決する必要がある残りの問題は何ですか?
素朴に、conda-forgeのBLISを使用してnumpyテストを実行しようとしました(https://github.com/numpy/numpy/issues/14180#issuecomment-525292558を参照)。Linuxでは、すべてのテストに合格しました(ただし、おそらく私は何かを逃した)。
また、同じ環境でtest scipy test suiteを実行しようとしましたが、誰かがコメントした場合に備えて、 scipy.linalg
(https://github.com/scipy/scipy/issues/10744を参照)に多数の失敗があります。それ。
conda-forgeのBLISは、 libflame
ではなくBLISをBLAS実装として使用するLAPACK実装としてReferenceLAPACK(netlib)を使用することに注意してください。
conda-forgeのBLISオプションについて、(OpenBLASオプションとは異なり)箱から出してシングルスレッドであるというのは正しいですか?
conda-forgeの議論をconda-forgeに移す方がおそらく良いでしょう🙂
最も参考になるコメント
MSVCABIをターゲットとするclang.exeを使用してWindowsでBLISを構築することは確かに可能です。 私は数時間を過ごしました、そしてここに変更があります。 必要な変更の数は、OpenBLASと比較して驚くほど少なかった。
ログはこちらです。 すべてのBLISおよびBLASテストに合格します。