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