Skip to content

Instantly share code, notes, and snippets.

@cmaureir
Last active August 29, 2015 14:01
Show Gist options
  • Save cmaureir/889d7bc3a1b90fbe6869 to your computer and use it in GitHub Desktop.
Save cmaureir/889d7bc3a1b90fbe6869 to your computer and use it in GitHub Desktop.
Haralick on GPU

La GPU

Vamos a considerar las GPUs nuevas (Tesla K20m), por lo cual es bueno entender un par de detalles acerca del Hardware:

La RAM de la GPU (Memoria Global) es 4800 MB, a esta memoria acceden todas las hebras de las funciones que llamemos, pero el acceso es lento, pues es caro a nivel de hardware, por lo mismolas hebras tienen unas memorias chicas a las cuales pueden acceder más rápido, las cuales no están dentro de la memoria global; éstas son los Registros y la Memoria compartida.

Los Registros son la memoria que tiene cada hebra, y que ninguna otra hebra puede acceder, es decir es única por cada hebra.

La memoria compartida es una memoria que es como si fuera un registro pero compartido por todas las hebras de un bloque.

Cuando lanzamos una función en la GPU (Kernel) decimos, quiero lanzar X bloques de Y hebras, eso quiere decir que tendremos un total de Y*X hebras distintas corriendo en paralelo.

La memoria compartida POR BLOQUE es de 49152 bytes. Los máximos registros POR BLOQUE es de 65536 bytes.

Tanto los bloques como las hebras se pueden enviar en 3 dimensiones, pero no es mas que una multiplicación, por ejemplo, enviar (2,2,2) bloques y (3,3,3) hebras serían (2*2*2) * (3*3*3) = 216 hebras en total, la gracia es que podemos mandar muchos bloques y lo que hace la GPU es que si superan la memoria de la GPU ejecuta unos bloques primero y cuando se va desocupando la memoria va mandando los otros, los limites son: Máximo número de bloques: (2147483647, 65535, 65535) Máximo número de hebras: (1024, 1024, 64)

Y un par de datos adicionales, en 1 GPU tenemos 13 Multiprocesadores con 192 CUDA cores, es decir tenemos 2496 CUDA cores, la mayor cantidad de hebras que podemos tener por Multiprocesador es 2048, y el máximo de hebras por bloque son 1024.

Procesamiento de la Imagen

Entonces, para interactuar con la GPU debemos considerar, que vamos a enviar información, por lo general arreglos, los cuales quedan en la memoria global, y si queremos escribir ciertos resultados, debemos reservar espacio tambien, entonces:

Cada feature es un flotante, o sea 4 bytes, son 11 por cada pixel. La matriz de co_occ es de 256x256 y si la dejamos con unsigned int sería 1 byte x 256 x 256, entonces el total es de: 65536 bytes

Las submatrices que queremos enviar a la GPU son cuadradas y de tamaño (borde*2 + 1), consideremos borde=1, tendríamos submatrices de 3x3, tambien como unsigned int, entonces sería 9 bytes. lo cual tambien depende de la cantidad de pixeles que tenga la imagen, pues vamos a tener 1 sub-matrix por cada pixel, consideremos una imagen de 200x300 pixeles, tambien como unsigned int, o sea: 60000 bytes.

Resumiendo:

  • Arreglo con las sub-matrices: 6000 bytes (pixeles imagen) x 9 bytes (sub matrices) = 540000 bytes = 527.34375 Kbytes = 0.514 Mbytes
  • Matrices de co-ocurrencia: 65536 bytes (tamaño) x 60000 (cantidad de pixeles) = 3932160000 bytes = 3840000.0 Kbyes = 3750.0 Mbytes
  • Arreglo de salida con las features: 11x4 bytes (features float) x 60000 (cantidad de pixeles) = 2640000 bytes = 2578.125 Kbytes = 2.51 Mbytes
  • Total: 3753 Mbytes = 3.67 Gbytes

Si te das cuenta, no estamos usando toda la memoria de la GPU, pero estamos usando un ejemplo de juguete, una imagen de 200x300 y un borde igual a 1.

El Problema

Mi idea era la siguiente, cada hebra toma una sub-matriz y calcula la matriz de co-ocurrencia, luego escribe los resultados de los features a un arreglo de salida. ¿Por qué puede salir mal? yo quería generar la matriz de co-ocurrencia como registro de la hebra para que se accediera rápido, pero el máximo de registros por bloque de hebras es 65536 bytes, que es justo el tamaño de una matriz de co-ocurrencia.

Entonces, cual es el acercamiento que quiero probar, dejar TODO en memoria global y ver que tan lento es comparado a la versión Matlab® y C++, entonces despues podemos comenzar a hacer a mejorar la implementación cargando pedacitos de datos en la memoria compartida o registros.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment