1

pycudaおよびpyfftパッケージを使用して、マルチ CPU およびシングル GPU計算用に次のパターンを Python で実装しようとしています。

GPU (NVIDIA CUDA を使用) を使用して FFT を実行できるように、複数のプロセス(たとえば、multiprocessing.Pool() で起動)が必要です。

ただし、次の問題があります。

あまりにも多くのプロセスを実行したり、プロセスごとにあまりにも多くの FFT を実行したりすると、スクリプト全体が停止せずに保留されたままになります(また、予定されているすべての FFT を計算することもありません)。さらなる調査から、これは GPU のメモリ制限(現在、NVIDIA GeForce GT 750M で 2048MB) が原因であると思われます。マルチプロセッシング プールが制御を取り戻すことができないようです。これを回避する方法はありますか?

各プロセスは 2048 MB 未満しか必要としないため、各プロセスが GPU の使用を予約できるキューのようなものが必要です。プロセスがコンテキストを解放すると、キュー内の次のプロセスがそれを使用し始めます。これは実行可能ですか?

あるいは、特定の時間に 1 つのプロセスだけが GPU を使用するように強制することはできますか?
これらのソリューションを個別に試しましたが、機能しません (または、正しく実装していない可能性があります)。

  1. proc_stream.synchronize() でストリームを同期する
  2. pycuda.tools.clear_context_caches() を使用して、コンテキスト キャッシュをクリアします。
  3. cuda.compute_mode = cuda.compute_mode.EXCLUSIVE で計算モードを変更します

注:解決策 2. はいくらかのメモリを解放するように見えますが、計算が遅くなり、問題は解決しません。たとえば、計算する fft の数を増やすと、スクリプトは同じ動作を示します。

ここにコード。簡単なタスクから始めると、ここでは各プロセスが 1 つの FFT を計算します (次に、execute() でバッチ オプションを使用して、さらに FFT を連続して実行できます)。

import multiprocessing
import pycuda.driver as cuda
import pycuda.gpuarray as gpuarray
from pycuda.tools import make_default_context
from pyfft.cuda import Plan

def main():
    # generates simple matrix, (e.g. image with a signal at the center)
    size = 4096
    center = size/2
    in_matrix = np.zeros((size, size), dtype='complex64')
    in_matrix[center:center+2, center:center+2] = 10.

    pool_size = 4  # integer up to multiprocessing.cpu_count()
    pool = multiprocessing.Pool(processes=pool_size)
    func = FuncWrapper(in_matrix, size)
    nffts = 16  # total number of ffts to be computed
    par = np.arange(nffts)

    results = pool.map(func, par)
    pool.close()
    pool.join()

    print results

そしてここに関数ラッパーがあります:

class FuncWrapper(object):
    def __init__(self, matrix, size):
        self.in_matrix = matrix
        self.size = size
        print("Func initialized with matrix size=%i" % size)

    def __call__(self, par):
        proc_id = multiprocessing.current_process().name

        # take control over the GPU
        cuda.init()
        context = make_default_context()
        device = context.get_device()
        proc_stream = cuda.Stream()

        # move data to GPU
        # multiplication self.in_matrix*par is just to have each process computing
        # different matrices
        in_map_gpu = gpuarray.to_gpu(self.in_matrix*par)

        # create Plan, execute FFT and get back the result from GPU
        plan = Plan((self.size, self.size), dtype=np.complex64,
                    fast_math=False, normalize=False, wait_for_finish=True,
                    stream=proc_stream)
        plan.execute(in_map_gpu, wait_for_finish=True)
        result = in_map_gpu.get()

        # free memory on GPU
        del in_map_gpu

        mem = np.array(cuda.mem_get_info())/1.e6
        print("%s free=%f\ttot=%f" % (proc_id, mem[0], mem[1]))

        # release context
        context.pop()

        return par

ここで、nffts=16 および pool_size=4 で、スクリプトは正しく終了し、次の出力が得られます。

Func initialized with matrix size=4096
PoolWorker-1 free=1481.019392   tot=2147.024896
PoolWorker-2 free=1331.011584   tot=2147.024896
PoolWorker-3 free=1181.003776   tot=2147.024896
PoolWorker-4 free=1030.631424   tot=2147.024896
PoolWorker-1 free=881.074176    tot=2147.024896
PoolWorker-2 free=731.746304    tot=2147.024896
PoolWorker-3 free=582.418432    tot=2147.024896
PoolWorker-4 free=433.090560    tot=2147.024896
PoolWorker-1 free=582.754304    tot=2147.024896
PoolWorker-2 free=718.946304    tot=2147.024896
PoolWorker-3 free=881.254400    tot=2147.024896
PoolWorker-4 free=1030.684672   tot=2147.024896
PoolWorker-1 free=868.028416    tot=2147.024896
PoolWorker-2 free=731.713536    tot=2147.024896
PoolWorker-3 free=582.402048    tot=2147.024896
PoolWorker-4 free=433.090560    tot=2147.024896
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]

ただし、nffts=18 および pool_size=4 の場合、スクリプトは終了せず、次の出力が表示され、最後の行でスタックしたままになります。

Func initialized with matrix size=4096
PoolWorker-1 free=1416.392704   tot=2147.024896
PoolWorker-2 free=982.544384    tot=2147.024896
PoolWorker-1 free=1101.037568   tot=2147.024896
PoolWorker-2 free=682.991616    tot=2147.024896
PoolWorker-3 free=815.747072    tot=2147.024896
PoolWorker-4 free=396.918784    tot=2147.024896
PoolWorker-3 free=503.046144    tot=2147.024896
PoolWorker-4 free=397.144064    tot=2147.024896
PoolWorker-1 free=531.361792    tot=2147.024896
PoolWorker-1 free=397.246464    tot=2147.024896
PoolWorker-2 free=518.610944    tot=2147.024896
PoolWorker-2 free=397.021184    tot=2147.024896
PoolWorker-3 free=517.193728    tot=2147.024896
PoolWorker-4 free=397.021184    tot=2147.024896
PoolWorker-3 free=504.336384    tot=2147.024896
PoolWorker-4 free=149.123072    tot=2147.024896
PoolWorker-1 free=283.340800    tot=2147.024896

助けてくれて本当にありがとうございます!

4

0 に答える 0