KirIn 落書き帳

素人がプログラミング, FPGA, LSIをお勉強しているメモ書きです。間違いがあればご指導していただけたら幸いです。

pythonでGPGPUやってみる

pythonでPyOpenclでGPGPUをやってみたいと思います。

f:id:KirIn:20140915232439j:plain

PyOpenclpythonOpenCLを操作できるライブラリです。 OpenCLとはヘテロジニアス環境のためのフレームワークです。

今回は行列積をCPU(numpy.dot)とGPUでの演算時間を比較してみます。 今回はメモリ転送などの時間は考慮せずに単純に演算時間のみで比較したいと思ってます。

PC CPU Memory
macbook air 2012 Intel core i5 4 GB
# -*- coding: utf-8 -*-
 
import numpy
from numpy import linalg
import time
import pyopencl
from pyopencl import mem_flags

# size = 1024
for size in range(100,2000, 300):
    print "matrix : ", size, " x ", size
    a = numpy.random.randint(0, 256, (size,size)).astype(numpy.int32)
    b = numpy.random.randint(0, 256, (size,size)).astype(numpy.int32)
    dest = numpy.empty_like(a)
 
    start = time.time()
    dest1 = numpy.dot(a, b)
    end = time.time()
    print "compute with CPU (numpy) : ", end - start  , " sec"
 
    dest1 = numpy.empty_like(a)
 
    context = pyopencl.create_some_context(interactive=False)
    queue = pyopencl.CommandQueue(context)
    a_buf = pyopencl.Buffer(context, mem_flags.READ_ONLY | mem_flags.COPY_HOST_PTR, hostbuf=a)
    b_buf = pyopencl.Buffer(context, mem_flags.READ_ONLY | mem_flags.COPY_HOST_PTR, hostbuf=b)
    dest_buf = pyopencl.Buffer(context, mem_flags.WRITE_ONLY, dest1.nbytes)
 
    program = pyopencl.Program(context, '''
    __kernel void matrix_mul(
        __global const int* a,
        __global const int* b,
        __global int* dest,
        const int n
    )
    {
        const int i = get_global_id(0);
        const int j = get_global_id(1);
        const int dest_index = j * n + i;
 
        dest[dest_index] = 0;
        for(int k = 0; k < n; k++){
            dest[dest_index] += a[j * n + k] * b[k * n + i];
        }
    }
    ''').build()
 
    n = numpy.int32(size) # カーネル関数にスカラー値を渡すにはnumpyの型を使う
    start = time.time()
    e = program.matrix_mul(queue, a.shape, None, a_buf, b_buf, dest_buf, n)
    e.wait()
    stop = time.time()
 
    pyopencl.enqueue_copy(queue, dest1, dest_buf)
    print "compute with GPGPU : ", stop - start, " sec"

実装結果

行列積 CPU(numpy) GPU
100 x 100 0.000992059707642 0.000531911849976
400 x 400 0.0700681209564 0.0166277885437
700 x 700 0.587120056152 0.298397064209
1000 x 1000 8.99130797386 1.30098700523
1300 x 1300 21.1716349125 2.89547991753
1600 x 1600 40.0069048405 5.48878097534
1900 x 1900 64.19876194 9.76343679428

やはりGPUは早いみたいです。 ただメモリ転送の部分がクリティカルパスになるというお話を聞いたので今後実験してみたいと思います。