1. ホーム
  2. java

[解決済み] Nvidia GPU (CUDA)でJavaを使用する

2022-04-26 21:03:07

質問

Javaで行うビジネスプロジェクトに取り組んでいるのですが、ビジネスマーケットを計算するために膨大な計算能力が必要です。単純な計算ですが、膨大な量のデータが必要です。

CUDA GPUをいくつか注文して試しているのですが、JavaはCUDAでサポートされていないので、何から手をつければいいのか悩んでいます。JNIインターフェイスを構築すべきでしょうか?JCUDAを使うべきでしょうか、それとも他の方法があるでしょうか?

私はこの分野の経験がないので、誰かが私を誘導し、私が研究と学習を始めることができるようにしたいと思います。

どのように解決するのですか?

まず最初に、CUDAを使えば自動的に計算が速くなるわけではない、という事実を知っておく必要があります。一方では、GPUプログラミングは芸術であり、それを手に入れるのはとてもとても難しいことだからです。 正しい . 一方、GPUが特定の用途にしか向いていないため 種類 の計算を行うことができます。

これは混乱するように聞こえるかもしれませんが、基本的に計算することができますので 何でも をGPU上で動作させることができます。もちろん、重要なのは、それなりのスピードアップが図れるかどうかです。ここで最も重要な分類は、ある問題が タスク並列 または データパラレル . 前者は,大雑把に言うと,複数のスレッドが多かれ少なかれ独立してそれぞれのタスクに取り組んでいる問題を指します.もうひとつは、以下のような問題です。 多数 スレッドが すべて同じ - が、データの異なる部分に対してです。

後者は、GPUが得意とする問題です。GPUには たくさん コアがあり、すべてのコアが同じ処理を行いますが、入力データの異なる部分に対して処理を行います。

単純な計算で膨大なデータを扱うとのことですが、どのように処理するのですか?これは完全にデータ並列な問題で、GPUに適しているように聞こえるかもしれませんが、もう1つ考慮すべき点があります。GPUは理論演算能力(FLOPS: Floating Point Operations Per Second)が非常に高いのです。GPUは理論上の計算能力(FLOPS:Floating Point Operations Per Second)は非常に速いのですが、メモリ帯域幅によって減速されることがよくあるのです。

ここで、もうひとつの問題の分類が生まれます。つまり、問題が メモリバウンド または <強い コンピュートバインド .

1つ目は、各データ要素に対して行われる命令数が少ない問題を指します。例えば、並列ベクトル加算を考えてみましょう。このとき必要なのは 読む 2つのデータ要素に1回の加算を行い、その後 書く を結果ベクトルに格納します。GPUでこれを実行しても、高速化は見込めません。なぜなら、1回の加算では、メモリの読み書きにかかる労力を補うことができないからです。

2つ目の用語、quot;comput bound"は、メモリの読み書きの回数に比べ、命令数が多い問題のことを指します。例えば、行列の乗算を考えてみましょう。行列の大きさをnとすると、命令数はO(n^3)となります。この場合、ある行列のサイズではGPUがCPUを上回ることが予想されます。他の例としては、多くの複雑な三角関数計算(サイン/コサインなど)をquot;few"データ要素で実行する場合があります。

目安としては、GPUのメインメモリから1つのデータ要素を読み書きするのに500命令程度のレイテンシがかかると考えればよいでしょう......。

したがって、GPUの性能を左右するもうひとつのポイントは データローカリティ : データの読み書きが必要な場合(ほとんどの場合、必要です ;-))、そのデータを GPU コアのできるだけ近くに保つようにする必要があります。このため、GPUには特定のメモリ領域(ローカルメモリまたは共有メモリと呼ばれる)があり、通常は数KBのサイズですが、計算に関与しようとするデータに対して特に効率的です。

そこで、もう一度強調しておきます。GPUプログラミングは芸術であり、CPUの並列プログラミングとはかけ離れたものなのです。JavaにおけるThreadsのような、並行処理のためのインフラはすべて ThreadPoolExecutors , ForkJoinPools などは、仕事をどうにかして分割して、複数のプロセッサに振り分ければいいという印象を与えるかもしれません。GPUでは、もっと低いレベルの問題に遭遇することがあります。占有率、レジスタの圧力、共有メモリの圧力、メモリの合体......いくつか例を挙げればきりがありません。

しかし、データ並列で演算に縛られるような問題を解く場合は、GPUに軍配が上がります。


一般論として。CUDAについて具体的な質問がありました。しかし、私は、OpenCLもご覧になることを強くお勧めします。OpenCLにはいくつかの利点があります。まず、ベンダーに依存しないオープンな業界標準であり、AMD、Apple、Intel、NVIDIAがOpenCLを実装しています。さらに、Javaの世界では、OpenCLのサポートがより広範に行われています。むしろCUDAに落ち着くのは、FFTのCUFFTやBLAS(行列/ベクトル演算)のCUBLASなど、CUDAのランタイムライブラリを使いたい場合だけです。OpenCLでも同様のライブラリを提供するアプローチはありますが、これらのライブラリに対するJNIバインディングを自作しない限り、Java側から直接利用することはできません。


また、2012年10月にOpenJDK HotSpotグループがプロジェクト「"Sumatra"」を開始したことも、興味深い話だと思います。 http://openjdk.java.net/projects/sumatra/ . このプロジェクトの目標は、GPUサポートを提供することです。 直接 をJVMで実行し、JITでサポートします。現在の状況と最初の成果は、以下のメーリングリストで見ることができます。 http://mail.openjdk.java.net/mailman/listinfo/sumatra-dev


しかし、少し前に、GPU上でのJavaに関連するリソースを集めました。ここでもう一度、順不同でまとめておきます。

( 免責事項 : の作者です。 http://jcuda.org/ http://jocl.org/ )

(Byte)コード変換とOpenCLコード生成。

https://github.com/aparapi/aparapi : AMDによって作成され、活発にメンテナンスされているオープンソースのライブラリです。特別なクラスである "Kernel" において、並列に実行されるべき特定のメソッドをオーバーライドすることができます。このメソッドのバイトコードは、独自のバイトコードリーダーを使用して実行時にロードされます。このコードはOpenCLコードに変換され、OpenCLコンパイラでコンパイルされます。その結果は、OpenCL デバイス(GPU または CPU)で実行することができます。OpenCLにコンパイルできない(あるいはOpenCLが利用できない)場合でも、コードはスレッドプールを使って並列に実行されます。

https://github.com/pcpratts/rootbeer1 : Java の一部を CUDA プログラムに変換するためのオープンソースライブラリです。あるクラスがGPU上で実行されるべきことを示すために実装することができる専用のインタフェースを提供する。Aparapiとは対照的に、関連するデータ(つまり、オブジェクトグラフの完全な関連部分!)を、GPUに適した表現に自動的にシリアライズしようとします。

https://code.google.com/archive/p/java-gpu/ : 注釈付きJavaコード(一部制限あり)をCUDAコードに変換し、コンパイルしてGPU上で実行するライブラリです。このライブラリは、博士論文の文脈で開発され、翻訳プロセスに関する深い背景情報を含んでいます。

https://github.com/ochafik/ScalaCL : OpenCLのためのScalaバインディング。特別なScalaコレクションをOpenCLで並列処理できるようにします。コレクションの要素に対して呼び出される関数は、通常のScala関数(いくつかの制限付き)であり、その後OpenCLカーネルに変換されます。

言語拡張

http://www.ateji.com/px/index.html : OpenCLを使用してGPU上で実行される並列コンストラクト(例:OpenMPスタイルの並列forループ)を可能にするJava用言語拡張です。残念ながら、この非常に有望なプロジェクトは、もはやメンテナンスされていません。

http://www.habanero.rice.edu/Publications.html (JCUDA) : 特殊なJavaコード(JCUDAコードと呼ばれる)をJava-CやCUDA-Cコードに変換し、GPU上でコンパイル・実行できるようにするためのライブラリ。ただし、このライブラリは一般には公開されていないようです。

https://www2.informatik.uni-erlangen.de/EN/research/JavaOpenMP/index.html : CUDAバックエンドによるOpenMPコンストラクトのためのJava言語拡張。

Java OpenCL/CUDAバインディングライブラリ

https://github.com/ochafik/JavaCL : Java bindings for OpenCL : 自動生成された低レベルバインディングに基づく、オブジェクト指向の OpenCL ライブラリ

http://jogamp.org/jocl/www/ : Java bindings for OpenCL : 自動生成された低レベルバインディングに基づく、オブジェクト指向の OpenCL ライブラリ

http://www.lwjgl.org/ OpenCL 用 Java バインディング: 自動生成される低レベルバインディングとオブジェクト指向の便利なクラス

http://jocl.org/ OpenCL用Javaバインディング: オリジナルのOpenCL APIを1:1にマッピングした低レベルのバインディングです。

http://jcuda.org/ CUDA用Javaバインディング:オリジナルのCUDA APIを1:1にマッピングした低レベルのバインディングです。

その他

http://sourceforge.net/projects/jopencl/ OpenCLのJavaバインディング。 2010年以降、メンテナンスが行われていないようです。

http://www.hoopoe-cloud.com/ CUDAのJavaバインディング。 メンテナンスは終了しているようです。