Python でGPGPUプログラミングを開始したいと考えています。pyopencl または clyther から始めるべきですか? 違いは何ですか?
4 に答える
OpenCL は 2 つの部分で構成されています。通常は C で記述されたホスト側と、OpenCL で定義された C の派生物で記述されたデバイス側があります。このコードは、実行時にデバイス (通常は GPU) にコンパイルされます。
Clyther はすべてを抽象化しようとします。ホスト側のコードは Python で記述します。デバイス側のコードは Python のサブセットで記述します (Cython と同様の方法で)。これは非常にレベルが高く、使いやすいです。
PyOpenCL は、Python から OpenCL API への比較的低レベルのバインディングです。デバイス側のコードは、C99 の OpenCL のサブセットで記述されています。これにより、OpenCL への完全なアクセスと完全な制御が可能になります。抽象化されているものはほとんどありません。
両方の経験は限られていますが、両方が成熟したら、ほとんどのプロジェクトで Clyther を使用することを好むというのが私の印象です。より使いやすく、つまり、使用する可能性が高く、さらに使用する可能性が高くなります。また、PyOpenCL と Python よりも Clyther と Python の間でコードをやり取りする方が簡単であるため、コードのメンテナンスとリファクタリングが容易になるはずです。パフォーマンスが非常に重要なプロジェクトの場合は、PyOpenCL をお勧めします。これにより、低レベルの制御が向上し、ユーザーとハードウェア間のレイヤーが少なくなります。最終的に考えられるパフォーマンスは、Clyther よりも PyOpenCL の方が優れているはずです。
これが永遠に続くかどうかはわかりません。最終的に PyOpenCL が高レベルの構造を追加し、最終的に Clyther が低レベルの制御を追加する可能性があります。理想的な世界では、Clyther の開発者は PyOpenCL の上に構築されるようにコアを移動するので、選択する必要がなく、作業の重複を避けることができます。しかし、それが起こることはないと思います。
現在、PyOpenCL は Clyther よりも成熟しているように見えます。これは最初に開始されたものであり、その範囲はそれほど野心的ではありません。Clyther よりも優れたドキュメントがあり、より大きなユーザー コミュニティがあるようです。どちらもコード サイズはかなり似ています。Clyther は Python で約 4KLOC、C で 4KLOC です。PyOpenCL は Python コードで約 7KLOC、C++ コードで 9KLOC です。これはおおよそのもの (ビルド システム、例などを含む) であるため、おおよその同等性を超えたものを意味するものとして扱われるべきではありません。
PyOpenCLはCLytherよりもOpenCLのCバインディングに近いように思えます。
これは、OpenCLをすでに知っている場合、または他の言語からPythonに実装を移植することを計画している場合は、PyOpenCLが適している可能性があることを意味します。一方、CLytherはPyOpenCLよりも「Pythonic」のように見えるため、Pythonに精通している場合は、使用されているイディオムの方が理解しやすいかもしれません。
どちらもベータ版であるため、どちらにも必要な機能がすべて揃っていない可能性があり、どちらかにバグがある可能性があります。
幸運を!
PyOpenCl は、GPGPU プログラミングの楽しい部分であるカーネル側で多数の最適化を実行できるという点で PyCuda に似ていると思います。
これは C のカーネルですが、ホスト コードは pythonic です。
mod = SourceModule("""
__global__ void multiply_them(float *dest, float *a, float *b)
{
const int i = threadIdx.x;
dest[i] = a[i] * b[i];
}
""")
Clyther には、OpenCL や PyOpenCL と同様の C レベルのバインディングが含まれています。
clyther は、python 関数を openCL デバイス/カーネル関数として渡したり使用したりできるという点で「pythonic」です。
Pythonコードにインラインで記述できます
@kernel
@bind('global_work_size' ,'a.size')
@bind('local_work_size' , 1)
def sum(a,b,ret):
i = clrt.get_global_id(0)
ret[i] = a[i] + b[i]
sum(clarray1,clarray2,clarray3)