Python y Cuda

Python + CUDA = PyCUDA
Clase 15, 01/06/2015
http://fisica.cab.cnea.gov.ar/gpgpu/index.php/en/icnpg/clases
cp -a /share/apps/codigos/alumnos_icnpg2015/pycuda .
http://bit.ly/1PZTg1B
¿ Qué es Python?
●
Lenguaje multipropósito (Web, GUI, Scripting, cintífico).
●
Orientado a Objetos.
●
Interpretado.
●
Producido para tener alta legibilidad y alta productividad.
Características:
●
Todo en python es un objeto (de verdad, TODO).
●
Shell interactiva.
●
Multiplataforma.
●
Varias implementaciones: CPython, Jython, PyPy.
●
Incluye baterías.
Algunos usuarios:
Herramientas:
●
Python tiene una de las comunidades de desarrolladores más grandes. Hay herramientas
para casi todo.
●
Desarrollo web: Django.
●
Bibliotecas gráficas: wxPython, PyQt, PyOpenGL.
●
Bases de datos: PyMySQL, pyodbc, ect.
●
Cálculo científico: scipy, numpy, matplotlib, scikts.
●
Cálculo paralelo: PyOpenCL, PyCUDA, scikts.cuda.
Interpretado vs. compilado
Flujo de creación de un programa en C/Fortran:
Edición
Compilación
Linkedición
Ejecución
Interpretado vs. compilado
Flujo de creación de un programa en Python:
Edición
Ejecución
Sintaxis
●
Podemos trabajar en consola (en linux ya está instalado, simplemente escribir
python) o bien en un script:
>>> print “Hola inmundo!”
●
No hay que usar llaves, ni “;”. Los bloques se definen por indentación:
a=3
b = "hola manola"
if a == 3 and "manola" in b:
# esto es un comentario
print b
c = a*5
else:
b = "hola manola"
c = a/3.0
# esto ya esta afuera del if/else
d = "hola manola"
Tipos de datos
# strings
name = "Nicolas"
# multi-line string
bio = '''Mi nombre es Nicolás
naci en Rafaela, Santa Fe'''
# another multi-line string
quote = """Sombondrolo la cantarpio
aea - N.R."""
#listas
lista1 = []
lista2 = [1,2,3,4,5,6,7,8,9,10]
lista3 = ["hola","manola","pepe"]
lista4 = [1, "hola", lista1, lista3]
#enteros
year = 2015
year = int("2015")
# floats
pi = 3.14159265
pi = float("3.14159265")
# diccionarios
person = {}
person['nicolas'] = 'Ingeniero'
person.update({'favoritos':['Cortazar', 'Pink Floyd', 'Dolina'],
'genero':'male',})
person[55] = 'numero'
# Null
data = None
#tuplas (datos inmutables)
a = (123,"hola")
a[0] = "chau" ----> Error!
#booleanos
Ej: tipos.py
this_is_true = True
this_is_also_true = bool("any object")
this_is_false = False or 0 or "" or [] or {} or None
Algo de magia - Strings
animales = "liebre " + "perro "
animales +="gato "
#animales = "liebre perro gato"
animales = ", ".join(["liebre","perro", "gato"])
# animales = liebre, perro, gato
fecha = "%d de %s, %d" % (1, 'Junio', 2015)
# 1 de Junio, 2015
fecha = "%(nombre)s %(apellido)s" %{'nombre':'Nicolas', 'apellido':'Chiaraviglio'}
# Nicolas Chiaraviglio
print 2 * "hola "
# hola hola
Algo de magia - Iteradores
for x in range(0,10):
print x
#0123456789
frutas = ['manzana', 'banana', 'pera', 'frutilla', 'vino tinto']
for fr in fruta:
print fr
# manzana banana pera frutilla vino tinto
num = [1,2,3,4,5]
for i,fr in zip(num,frutas):
print i, fr
# 1 manzana 2 banana 3 pera 4 frutilla 5 vino tinto
for i,fr in enumerate(frutas):
print i, fr
# 0 manzana 1 banana 2 pera 3 frutilla 4 vino tinto
Algo de magia - Listas
from random import randint
a = [randint(0,121) for i in range(0,1000)]
b = [i for i in a if not i%2]
b = [k**2 - j for j,k in enumerate(a) if not k%2 and j%2]
Ej: iteradoresListas.py
También: funciones, generadores, clases
def fibonacci(n = 3):
resultado =[]
a,b = 0,1
for i in range(0,n):
resultado.append(a)
a,b = b, a + b
return resultado
print fibonacci(10)
# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
print fibonacci()
# [0, 1, 1]
Ej: funcGeneradores.py
def fibonacci(n):
a,b = 0,1
while True:
yield a
a,b = b, a + b
generador = fibonacci()
for i in range(0,10):
print generador.next()
# 0, 1, 1, 2, 3, 5, 8, 13, 21, 34
Numpy - Python para cálculo numérico
●
Soporte de operaciones que actúan sobre arrays N-dimensionales (eficiencia).
●
Herramientas para integración con C/C++ y Fortran.
●
Funciones de álgebra lineal: Transformadas, integrales, números aleatorios.
●
También incluye baterías
A los bifes:
●
Definiciones: Vectores, Matrices, Tipos
●
Operaciones entre vectores/matrices
●
Sistemas de ecuaciones
●
Reshape
●
Broadcast
Demo: demoNumpy.py
Entonces... PyCUDA?
●
PyCuda permite acceder al API de Cuda desde Python.
Pero... y la performance?
Python
Cuda
Manipulación de datos
Flujo general del programa
Cálculo
I/O
“Scripting for the brain, GPUs for inner loop”Klöckner
Flujo de trabajo de PyCUDA
Edición
Cache?
no
Ejecución
nvcc
Source Module (“...”)
Envío a GPU
Ejecución en GPU
.cubin
Algunos ejemplos
import pycuda.driver as cuda
import pycuda.autoinit, pycuda.compiler
import numpy as np
a = np.random.randn(4,4).astype(np.float32)
a_gpu = cuda.mem_alloc(a.nbytes)
cuda.memcpy_htod(a_gpu,a)
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
__global__ void twice (float *a)
{
int tid = threadIdx.x + threadIdx.y * 4;
a[tid] *= 2;
}
int main( int argc, const char** argv ) {
int N = 4;
float *a, gpu_a*, *a_doubled;
mod = pycuda.compiler.SourceModule("""
__global__ void twice (float *a)
{
int tid = threadIdx.x + threadIdx.y * 4;
a[tid] *= 2;
}
""")
func = mod.get_function("twice")
func(a_gpu, block=(4,4,1))
a_doubled = np.empty_like(a)
cuda.memcpy_dtoh(a_doubled,a_gpu)
print a_doubled
print a
a = (float *)malloc(sizeof(float) * N);
a_doubled = (float *)malloc(sizeof(float) * N);
cudaMalloc((void**)&gpu_a, sizeof(float) * N);
srand(time(NULL));
for (int i = 0; i < N; i++)
a[i] = random()/RAND_MAX;
cudaMemcpy(gpu_a, a, sizeof(float) * N, cudaMemcpyHostToDevice);
dim3 blockDim(N,N,1);
dim3 gridDim(1,1,1);
twice<<<gridDim,blockDim>>>(a);
cudaMemcpy(a_doubled, gpu_a, sizeof(float) * N,
cudaMemcpyHostToDevice);
for (int i = 0; i < N; i++)
printf("%f\t",a_doubled[i]);
for (int i = 0; i < N; i++)
printf("%f\t",a[i]);
return 0;
Ejs: twice.cu - twice.py
}
Todavía escribimos mucho?- gpuarray
import numpy
import pycuda.autoinit
import pycuda.gpuarray as gpuarray
x = np.random.randn(4,4).astype(np.float32)
a_gpu = gpuarray.to_gpu(x)
a_doubled = (2*a_gpu).get()
print a_doubled
print a_gpu
Ej: twice2.py
Y algo más complicado?
from pycuda.curandom import rand as curand
a_gpu = curand((50,))
b_gpu = curand((50,))
from pycuda.elementwise import ElementwiseKernel
lin_comb = ElementwiseKernel(
" float a, float *x, float b, float *y, float *z",
" z[i] = a * x[i] + b * y[i]")
c_gpu = gpuarray.empty_like(a_gpu)
lin_comb(5, a_gpu, 6, b_gpu, c_gpu)
assert la.norm((c_gpu - (5 * a_gpu + 6 * b_gpu)).get()) < 1e-5
import numpy as np
import pycuda.autoinit
import pycuda.gpuarray as gpuarray
from pycuda.curandom import rand as curand
from pycuda.reduction import ReductionKernel
dot = ReductionKernel(dtype_out = np.float32, neutral ="0",
reduce_expr = "a+b", map_expr = "x[i] * y[i]",
arguments = "const float *x, const float *y")
x = curand((1000*1000), dtype = np.float32)
y = curand((1000*1000), dtype = np.float32)
x_dot_y = dot(x,y).get()
x_dor_y_cpu = np.dot(x.get(), y.get())
Ej: element.py
Ej: Reductions.py
Esta Charla
●
Empresas que usan Python - http://bit.ly/1AvYbR2
●
Introducción a Python - http://bit.ly/1AvYo6V
●
Estructuras de datos en Python - http://bit.ly/1jPmL3p
●
Guía de Numpy/Scipy - http://bit.ly/1GGwAO2
●
Documentación PyCUDA - http://bit.ly/1J8SLMZ
●
Charla de A. Klöckner
sobre PyCUDA/PyOpenCL - http://bit.ly/1J8SLMZ
●
Repositorio de PyCUDA - http://bit.ly/1LLArt1
●
Guía de instalación de PyCUDA - http://bit.ly/1dzM6jH