In [ ]:
#Código extraído de: https://documen.tician.de/pycuda/tutorial.html
#4o ejemplo: https://documen.tician.de/pycuda/array.html#pycuda.gpuarray.GPUArray

GPUArray

La clase GPUArray asocia un array de numpy con un array en el device, maneja transferencias entre el host y el device y expresa las operaciones de array's en la GPU con sintaxis de array's de numpy. (Ver: numpy.ndarray)

El módulo pycuda.autoinit realiza lo necesario para preparar a CUDA para lanzamiento de kernels a la GPU. Lo necesario se refiere a: initialization, context creation, and cleanup. Esto puede realizarse de forma manual si se desea en lugar de utilizar pycuda.autoinit. (Ver: Notas del curso MNO para revisar qué es un kernel.)

Realizamos transferencias de numpy arrays alojados en el host (CPU) hacia el device (GPU) y deben utilizarse tipos de dato de numpy. Algo tan sencillo como:

value = 256

va = numpy.int32(value)

debe usarse. Para esto existen diferentes métodos en PyCUDA proveídos por el módulo de pycuda.driver (por ejemplo mem_alloc, memcpy_htod, memcpy_dth) y la clase GPUArray.


In [1]:
import pycuda.gpuarray as gpuarray
import pycuda.autoinit

import numpy as np

In [2]:
np.random.seed(0)

In [3]:
a = np.random.randn(4,4)

In [4]:
a.dtype


Out[4]:
dtype('float64')

In [5]:
print(a)


[[ 1.76405235  0.40015721  0.97873798  2.2408932 ]
 [ 1.86755799 -0.97727788  0.95008842 -0.15135721]
 [-0.10321885  0.4105985   0.14404357  1.45427351]
 [ 0.76103773  0.12167502  0.44386323  0.33367433]]

In [6]:
a.nbytes


Out[6]:
128

Se utiliza el método to_gpu() para instanciar la clase GPUArray y regresa una copia exacta (data_type, shape) del numpy.ndarray a y el método get() para almacenar la instancia de la clase GPUArray en un numpy.ndarray. Ver diferencia entre get() y memcpy_dtoh()


In [7]:
a_gpu = gpuarray.to_gpu(a)
a_doubled = (2*a_gpu).get()

In [8]:
a_gpu.dtype


Out[8]:
dtype('float64')

In [9]:
print(a_gpu)


[[ 1.76405235  0.40015721  0.97873798  2.2408932 ]
 [ 1.86755799 -0.97727788  0.95008842 -0.15135721]
 [-0.10321885  0.4105985   0.14404357  1.45427351]
 [ 0.76103773  0.12167502  0.44386323  0.33367433]]

In [10]:
a_doubled.dtype


Out[10]:
dtype('float64')

In [11]:
print(a_doubled)


[[ 3.52810469  0.80031442  1.95747597  4.4817864 ]
 [ 3.73511598 -1.95455576  1.90017684 -0.30271442]
 [-0.2064377   0.821197    0.28808714  2.90854701]
 [ 1.52207545  0.24335003  0.88772647  0.66734865]]

Es posible utilizar element wise functions en las instancias de la clase GPUArray disponibles en el módulo pycuda.math para las funciones contenidas en math


In [12]:
from pycuda.cumath import floor as cufloor
from pycuda.cumath import exp as cuexp

In [13]:
cufloor(2*a_gpu)


Out[13]:
array([[ 3.,  0.,  1.,  4.],
       [ 3., -2.,  1., -1.],
       [-1.,  0.,  0.,  2.],
       [ 1.,  0.,  0.,  0.]])

In [14]:
cuexp(a_gpu)


Out[14]:
array([[5.83603919, 1.49205924, 2.66109578, 9.40172515],
       [6.47247125, 0.37633413, 2.58593829, 0.85954061],
       [0.90192956, 1.50771989, 1.15493443, 4.28137195],
       [2.14049632, 1.12938701, 1.55871729, 1.3960884 ]])

In [15]:
np.floor(2*a)


Out[15]:
array([[ 3.,  0.,  1.,  4.],
       [ 3., -2.,  1., -1.],
       [-1.,  0.,  0.,  2.],
       [ 1.,  0.,  0.,  0.]])

In [16]:
np.exp(a)


Out[16]:
array([[5.83603919, 1.49205924, 2.66109578, 9.40172515],
       [6.47247125, 0.37633413, 2.58593829, 0.85954061],
       [0.90192956, 1.50771989, 1.15493443, 4.28137195],
       [2.14049632, 1.12938701, 1.55871729, 1.3960884 ]])

In [ ]: