ArrayクラスはPyOpenCLが独自に(つまりOpenCL規格とは独立して)定義する配列データのコンテナです。
クラスのコンストラクタは以下のように宣言されています。
class pyopencl.array.Array( cq, #(1) shape, #(2) dtype, #(3) order='C', allocator=None, data=None, offset=0, strides=None, events=None)
Arrayクラスの属性はnumpyから派生したものか、OpenCLのバックグラウンドオブジェクトとの連携に使うものに分けられます。
OpenCL関連で最重要な属性はdataです。data属性はOpenCL Bufferに変換したオブジェクトを戻すことににって、OpenCL規格に基づいたPyOpenCLランタイムライブラリとの連携が可能となります。
numpy系統の属性は以下のものがあります。
getはデバイスが管理するメモリ空間からホストメモリにnumpy.ndarrayとしてコピーします。
get(queue=None, ary=None, async=False)
引数は空でも構いません。
setはArrayクラス内に配列を設定します。
set(ary, queue=None, async=False)
実行するとnumpy.ndarryオブジェクトの中身をデバイスメモリに移動します。
以下は実装例とその出力です。
CLSetArrayTest.py.
import numpy as np import pyopencl as cl import pyopencl.array as clarr import os os.environ['PYOPENCL_COMPILER_OUTPUT'] = '1' platforms = cl.get_platforms() ctx = cl.Context([platforms[0].get_devices(cl.device_type.GPU)[0]]) queue = cl.CommandQueue(ctx) a = np.arange(5).astype(np.uint32) a_mem = clarr.Array(queue, (5,), dtype=np.uint32) a_mem.set(a) print(a_mem.get())
出力.
/Library/Frameworks/Python.framework/Versions/3.5/bin/python3.5 /Users/komatsu/PycharmProjects/MyPythonProject/CLSetArrayTest.py [0 1 2 3 4]
Arrayクラスはnumpy配列と同じように部分配列にアクセスすることができます。
以下は実装例とその出力です。
CLArraySubSeqTest.py.
import numpy as np import pyopencl as cl import pyopencl.array as clarr import warnings import os os.environ['PYOPENCL_COMPILER_OUTPUT'] = '1' a = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]).astype(np.float32) b = np.array([10, 20, 30, 40, 50, 60, 70, 80, 90, 100]).astype(np.float32) platforms = cl.get_platforms() ctx = cl.Context([platforms[0].get_devices(cl.device_type.GPU)[0]]) queue = cl.CommandQueue(ctx) a_mem = clarr.to_device(queue, a) print(a_mem[4:9].get())
出力.
/Library/Frameworks/Python.framework/Versions/3.5/bin/python3.5 /Users/komatsu/PycharmProjects/MyPythonProject/CLArraySubSeqTest.py [ 5. 6. 7. 8. 9.]
viewは配列をそのままのデータで戻します。ただしdtypeに異なる型を指定した場合に、各要素のバイトから配列を再構成します。
view(dtype=None)
引数はデータの再解釈をするdtypeを指定します。
以下は実装例とその出力です。
import numpy as np import pyopencl as cl import pyopencl.array as clarr import pyopencl.tools as cltool import warnings import os os.environ['PYOPENCL_COMPILER_OUTPUT'] = '1' a = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]).astype(np.uint32) platforms = cl.get_platforms() ctx = cl.Context([platforms[0].get_devices(cl.device_type.GPU)[0]]) queue = cl.CommandQueue(ctx) a = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]).astype(np.uint32) a_mem = clarr.to_device(queue, a) a_view = a_mem.view() print(a_view) a.resize((5, 2)) new_mem = clarr.to_device(queue, a) print(new_mem) new_view_16 = new_mem.view(np.uint8) print(new_view_16)
出力.
[ 1 2 3 4 5 6 7 8 9 10] [[ 1 2] [ 3 4] [ 5 6] [ 7 8] [ 9 10]] [[ 1 0 0 0 2 0 0 0] [ 3 0 0 0 4 0 0 0] [ 5 0 0 0 6 0 0 0] [ 7 0 0 0 8 0 0 0] [ 9 0 0 0 10 0 0 0]]
新たなshapeを持った配列を戻します。
reshape(*shape, **kwargs)
基本的な動作はnumpyと同様と考えて支障ないかと思います。
以下は実装例とその出力です。
CLReshapeTest.py.
import numpy as np import pyopencl as cl import pyopencl.array as clarr import os os.environ['PYOPENCL_COMPILER_OUTPUT'] = '1' a = np.arange(10).reshape(5, 2).astype(np.uint32) print(a) platforms = cl.get_platforms() ctx = cl.Context([platforms[0].get_devices(cl.device_type.GPU)[0]]) queue = cl.CommandQueue(ctx) a_mem = clarr.to_device(queue, a) new_mem = a_mem.reshape(1, 10) a_mem.finish() print(new_mem.get())
出力.
/Library/Frameworks/Python.framework/Versions/3.5/bin/python3.5 /Users/komatsu/PycharmProjects/MyPythonProject/CLReshapeTest.py [[0 1] [2 3] [4 5] [6 7] [8 9]] [[0 1 2 3 4 5 6 7 8 9]]
transposeは配列の転置ツールです。
transpose(axes=None)
配列を転置し、転置した配列を戻します。axesは整数型のリストで指定すると、これを元に転置をします。オプションですので指定する必要はありません。
以下は実装例とその出力です。
CLTransposeTest.py.
import numpy as np import pyopencl as cl import pyopencl.array as clarr from pyopencl.clrandom import rand as clrnd import warnings import os os.environ['PYOPENCL_COMPILER_OUTPUT'] = '1' platforms = cl.get_platforms() ctx = cl.Context([platforms[0].get_devices(cl.device_type.GPU)[0]]) queue = cl.CommandQueue(ctx) a = np.arange(8).astype(np.uint32).reshape((4, 2)) print(a) a_gpu = clarr.to_device(queue, a) print(a_gpu.transpose().get())
出力.
/Library/Frameworks/Python.framework/Versions/3.5/bin/python3.5 /Users/komatsu/PycharmProjects/MyPythonProject/CLTransposeTest.py [[0 1] [2 3] [4 5] [6 7]] [[0 2 4 6] [1 3 5 7]]
配列をスカラー型の要素で埋めます。
fill(value, queue=None, wait_for=None)
valueにはスカラー型の値を指定します。値は元データと同じdtypeであるものとします。
以下が実装例と出力となります。
CLFillTest.py.
import numpy as np import pyopencl as cl import pyopencl.array as clarr import warnings import os os.environ['PYOPENCL_COMPILER_OUTPUT'] = '1' platforms = cl.get_platforms() ctx = cl.Context([platforms[0].get_devices(cl.device_type.GPU)[0]]) queue = cl.CommandQueue(ctx) a_gpu = clarr.Array(queue, (10,), dtype=np.float32) a_gpu.fill(1.0) a = a_gpu.get() print(a)
出力.
/Library/Frameworks/Python.framework/Versions/3.5/bin/python3.5 /Users/komatsu/PycharmProjects/MyPythonProject/CLFillTest.py [ 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]
ravelは多次元配列のレベルを削減する場合に使います。
ravel()
配列を平らにしたデータを戻します。
実装例は以下のようになります。
CLRavelTest.py.
import numpy as np import pyopencl as cl import pyopencl.array as clarr from pyopencl.clrandom import rand as clrnd import warnings import os os.environ['PYOPENCL_COMPILER_OUTPUT'] = '1' platforms = cl.get_platforms() ctx = cl.Context([platforms[0].get_devices(cl.device_type.GPU)[0]]) queue = cl.CommandQueue(ctx) a = np.arange(8).astype(np.uint32).reshape(4, 2) print(a) a_mem = clarr.to_device(queue, a) print(a_mem.ravel().get())
出力.
/Library/Frameworks/Python.framework/Versions/3.5/bin/python3.5 /Users/komatsu/PycharmProjects/MyPythonProject/CLRavelTest.py [[0 1] [2 3] [4 5] [6 7]] [0 1 2 3 4 5 6 7]
デバイスメモリ内の各要素にデータを指定するメソッドです。
setitem(subscript, value, queue=None, wait_for=None)
subscriptは配列の添字、valueは値を指定します。
CLSetItemTest.py.
import numpy as np import pyopencl as cl import pyopencl.array as clarr import os os.environ['PYOPENCL_COMPILER_OUTPUT'] = '1' platforms = cl.get_platforms() ctx = cl.Context([platforms[0].get_devices(cl.device_type.GPU)[0]]) queue = cl.CommandQueue(ctx) a = np.arange(5).astype(np.uint32) a_mem = clarr.Array(queue, (5,), dtype=np.uint32) a_mem.setitem(4, 15) print(a_mem.get())
出力.
/Library/Frameworks/Python.framework/Versions/3.5/bin/python3.5 /Users/komatsu/PycharmProjects/MyPythonProject/CLSetItemTest.py [ 0 0 0 0 15]
Arrayは最大値と最小値関数を持ちます。
subsetが付く関数は、添字を格納した配列で指定した範囲での最小・最大値を取得します。
実装例は以下のようになります。
CLMinMaxTest.py.
import numpy as np import pyopencl as cl import pyopencl.array as clarr import warnings import os os.environ['PYOPENCL_COMPILER_OUTPUT'] = '1' a = np.arange(33, 99, 3).astype(np.float32) b = np.array([10, 9, 8, 7, 6, 5, 4, 3, 2, 1]).astype(np.uint32) platforms = cl.get_platforms() ctx = cl.Context([platforms[0].get_devices(cl.device_type.GPU)[0]]) queue = cl.CommandQueue(ctx) with warnings.catch_warnings(): warnings.simplefilter("ignore") a_mem = clarr.to_device(queue, a) b_mem = clarr.to_device(queue, b) with warnings.catch_warnings(): warnings.simplefilter("ignore") a_mem = clarr.to_device(queue, a) overall_max_a = clarr.max(a_mem) print(overall_max_a.get()) with warnings.catch_warnings(): warnings.simplefilter("ignore") max_a = clarr.subset_max(b_mem, a_mem) print(max_a.get()) c = np.array([5, 10, 15]).astype(np.uint32) c_mem = clarr.to_device(queue, c) with warnings.catch_warnings(): warnings.simplefilter("ignore") min_a = clarr.subset_min(c_mem, a_mem) print(min_a.get())
出力.
/Library/Frameworks/Python.framework/Versions/3.5/bin/python3.5 /Users/komatsu/PycharmProjects/MyPythonProject/CLMinMaxTest.py 96.0 63.0 48.0
numpy.isnanはArrayに対して適用可能です。
以下が実装例となります。
import numpy as np import pyopencl as cl import pyopencl.array as clarr import os os.environ['PYOPENCL_COMPILER_OUTPUT'] = '1' a = np.array([1, float('nan'), float('nan'), 4, 5, 6, 7, 8, 9, 10]).astype(np.float32) b = np.array([10, 9, 8, 7, 6, 5, 4, 3, 2, 1]).astype(np.float32) platforms = cl.get_platforms() ctx = cl.Context([platforms[0].get_devices(cl.device_type.GPU)[0]]) queue = cl.CommandQueue(ctx) a_mem = clarr.to_device(queue, a) b_mem = clarr.to_device(queue, b) print((np.isnan(a_mem.get())).any()) print((np.isnan(b_mem.get())).any())
PythonのoperatorモジュールをArrayに対して適用することができます。
以下が実装例となります。
CLOperatorTest.py.
import numpy as np import pyopencl as cl import pyopencl.array as clarr import operator as op import os os.environ['PYOPENCL_COMPILER_OUTPUT'] = '1' a = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]).astype(np.float32) b = np.arange(10).astype(np.float32) platforms = cl.get_platforms() ctx = cl.Context([platforms[0].get_devices(cl.device_type.GPU)[0]]) queue = cl.CommandQueue(ctx) a_mem = clarr.to_device(queue, a) b_mem = clarr.to_device(queue, b) eqtest = op.eq(a_mem, b_mem) print(eqtest) getest = op.ge(a_mem, b_mem) print(getest) gttest = op.gt(a_mem, b_mem) print(gttest) letest = op.le(a_mem, b_mem) print(letest)
出力.
/Library/Frameworks/Python.framework/Versions/3.5/bin/python3.5 /Users/komatsu/PycharmProjects/MyPythonProject/CLOperatorTest.py [0 0 0 0 0 0 0 0 0 0] [1 1 1 1 1 1 1 1 1 1] [1 1 1 1 1 1 1 1 1 1] [0 0 0 0 0 0 0 0 0 0]
reverse関数は配列の順序を逆転させます。操作としては、Arrayのインスタンスからreverseと呼び出すだけです。
a_mem = a_mem.reverse()
以下が実装例となります。
CLReverseTest.py.
import numpy as np import pyopencl as cl import pyopencl.array as clarr import os os.environ['PYOPENCL_COMPILER_OUTPUT'] = '1' a = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]).astype(np.float32) b = np.arange(10).astype(np.float32) platforms = cl.get_platforms() ctx = cl.Context([platforms[0].get_devices(cl.device_type.GPU)[0]]) queue = cl.CommandQueue(ctx) a_mem = clarr.to_device(queue, b) a_mem = a_mem.reverse() print(a_mem.get())
出力.
/Library/Frameworks/Python.framework/Versions/3.5/bin/python3.5 /Users/komatsu/PycharmProjects/MyPythonProject/CLReverseTest.py [ 9. 8. 7. 6. 5. 4. 3. 2. 1. 0.]
[a[indices[0]], …, a[indices[n]]]という形態を持つArrayを戻します。
pyopencl.array.take(a, indices, out=None, queue=None, wait_for=None)
indices自体がaの添字として機能します。
実装例は以下のようになります。
CLTakeTest.py.
import numpy as np import pyopencl as cl import pyopencl.array as clarr import os os.environ['PYOPENCL_COMPILER_OUTPUT'] = '1' a = np.arange(100).astype(np.float32) b = np.arange(0, 36, 2).astype(np.int32) platforms = cl.get_platforms() ctx = cl.Context([platforms[0].get_devices(cl.device_type.GPU)[0]]) queue = cl.CommandQueue(ctx) a_mem = clarr.to_device(queue, a) b_mem = clarr.to_device(queue, b) result = clarr.take(a_mem, b_mem) print(result.get())
出力.
/Library/Frameworks/Python.framework/Versions/3.5/bin/python3.5 /Users/komatsu/PycharmProjects/MyPythonProject/CLTakeTest.py [ 0. 2. 4. 6. 8. 10. 12. 14. 16. 18. 20. 22. 24. 26. 28. 30. 32. 34.]
if_positiveはpyopencl.arrayの関数で、配列aの添字iの値が正の場合は配列bの添字iの値、負の場合は配列cの添字iの値を戻すような操作を行えます。
実装例は以下のようになります。
CLIfPositiveTest.py.
import pyopencl.array as clarr import pyopencl as cl import numpy as np ctx = cl.Context(cl.get_platforms()[0].get_devices(cl.device_type.GPU)) queue = cl.CommandQueue(ctx) a = np.array((1, 5, 3, -2, 2, 2, -3, 2, -8, 9)).astype(np.int32) b = np.arange(10).astype(np.int32) c = np.arange(10,20).astype(np.int32) print(a) a_mem = clarr.to_device(queue, a) b_mem = clarr.to_device(queue, b) c_mem = clarr.to_device(queue, c) d = clarr.if_positive(a_mem, then_=b_mem, else_=c_mem) print(b_mem.get()) print(c_mem.get()) print(d)
出力.
/Library/Frameworks/Python.framework/Versions/3.5/bin/python3.5 /Users/komatsu/PycharmProjects/MyPythonProject/CLIfPositiveTest.py [ 1 5 3 -2 2 2 -3 2 -8 9] [0 1 2 3 4 5 6 7 8 9] [10 11 12 13 14 15 16 17 18 19] [ 0 1 2 13 4 5 16 7 18 9]
numpy.concatenate関数に対応するのが、pyopencl.array.concatenateです。
pyopencl.array.concatenate( arrays, axis=0, queue=None, allocator=None)
arrays引数で指定した配列を結合します。
以下が実装例となります。
CLConcatenateTest.py.
import numpy as np import pyopencl as cl import pyopencl.array as clarr import warnings import os os.environ['PYOPENCL_COMPILER_OUTPUT'] = '1' a = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]).astype(np.float32) b = np.array([10, 9, 8, 7, 6, 5, 4, 3, 2, 1]).astype(np.float32) platforms = cl.get_platforms() ctx = cl.Context([platforms[0].get_devices(cl.device_type.GPU)[0]]) queue = cl.CommandQueue(ctx) a_mem = clarr.to_device(queue, a) b_mem = clarr.to_device(queue, b) result_mem = clarr.concatenate((a_mem, b_mem)) print(result_mem.get())
出力.
/Library/Frameworks/Python.framework/Versions/3.5/bin/python3.5 /Users/komatsu/PycharmProjects/MyPythonProject/CLConcatenateTest.py [ 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 10. 9. 8. 7. 6. 5. 4. 3. 2. 1.]
差分計算関数もnumpyと同様にpyopencl.arrayは提供しています。
以下が実装例となります。
CLDiffTest.py.
import numpy as np import pyopencl as cl import pyopencl.array as clarr import warnings import os os.environ['PYOPENCL_COMPILER_OUTPUT'] = '1' a = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]).astype(np.float32) b = np.array([10, 8, 12, 15, 16, 15, 1, 2, 2, 1]).astype(np.float32) platforms = cl.get_platforms() ctx = cl.Context([platforms[0].get_devices(cl.device_type.GPU)[0]]) queue = cl.CommandQueue(ctx) a_mem = clarr.to_device(queue, a) b_mem = clarr.to_device(queue, b) diff_a_mem = clarr.diff(a_mem) diff_b_mem = clarr.diff(b_mem) print(diff_a_mem.get()) print(diff_b_mem.get())
出力.
/Library/Frameworks/Python.framework/Versions/3.5/bin/python3.5 /Users/komatsu/PycharmProjects/MyPythonProject/CLDiffTest.py [ 1. 1. 1. 1. 1. 1. 1. 1. 1.] [ -2. 4. 3. 1. -1. -14. 1. 0. -1.]
pyopencl.arrayライブラリはドット積関数についても提供しています。
以下が実装例となります。
CLDotTest.py.
import numpy as np import pyopencl as cl import pyopencl.array as clarr import pyopencl.tools as cltool import warnings import os os.environ['PYOPENCL_COMPILER_OUTPUT'] = '1' a = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]).astype(np.float32) b = np.array([10, 9, 8, 7, 6, 5, 4, 3, 2, 1]).astype(np.float32) platforms = cl.get_platforms() ctx = cl.Context([platforms[0].get_devices(cl.device_type.GPU)[0]]) queue = cl.CommandQueue(ctx) a_mem = clarr.to_device(queue, a) b_mem = clarr.to_device(queue, b) with warnings.catch_warnings(): warnings.simplefilter("ignore") result = clarr.dot(a_mem, b_mem) print(result.get())
出力.
/Library/Frameworks/Python.framework/Versions/3.5/bin/python3.5 /Users/komatsu/PycharmProjects/MyPythonProject/CLDotTest.py 220.0
Copyright 2018-2019, by Masaki Komatsu