5. IMPLEMENTACIÓN DEL KNN EN CUDA
5.5. Utilización de bibliotecas y recursos de CUDA
En este apartado se valorará el uso de la distintas bibliotecas y funcionalidades que ofrece CUDA y se comprobará si su uso implica una optimización considerable en el código. En el apartado 4.4, se mencionaron algunas de las bibliotecas más utilizadas para CUDA y que podían ser de utilidad para el algoritmo de búsqueda de vecinos. Principalmente conviene estudiar aquellas bibliotecas que den apoyo a la parte más crítica del algoritmo y la que más tiempo consume, la etapa de búsqueda. Es necesario por tanto recurrir a las funciones realizadas por Nvidia o por la comunidad para optimizar tanto los cálculos de distancias como la ordenación de vecinos.
La primera opción que se va a valorar consiste en utilizar un algoritmo de ordenación de vecinos (sorting) a partir de una matriz que almacena las distancias de toda la ventana con el pixel principal. Este algoritmo utiliza las funciones de Cublas para la gestión de Matrices junto con una biblioteca desarrollada por un usuario de CUDA, Vincent García [29]. El algoritmo de ordenación utilizado consiste en el algoritmo Shellsort, el cuál organiza la secuencia de datos en un array bidimensional y ordena los datos en columnas [30]. En la página web del desarrollador [29] existe una versión del algoritmo libre y fácilmente editable para adaptar a las necesidades del uso que se vaya a dar.
IMPLEMENTACIÓN DEL KNN EN CUDA
83
Se utiliza por tanto el algoritmo en cuestión, pero adaptado a la función de filtrado para este proyecto. Ejecutando el programa se obtienen los resultados de la Tabla 4
Tabla 4: Comparativa entre KNN V3 y KNN V4 utilizando la biblioteca Cublas y el algoritmo Shellsort [29]
KNN V3 KNN V4
Tiempo de lectura PCA_out
(ms) 0.798 0.813
Tiempo de lectura SVM_probs
(ms) 2.876- 2.696 Tiempo de búsqueda de vecinos (ms) 3322.719 9174.88 Tiempo de escritura de vecinos(ms) 1278.462 1328.7868 Tiempo de filtrado (ms) --- 272.75
Tiempo de escritura KNN_out
(ms) 0.5448 0.566
Tiempo en completar el KNN
(ms) 4914.97 10855.043
A la vista de estos resultados podemos observar que este algoritmo no está nada optimizado en comparación con las versiones anteriores del algoritmo. El problema reside en que este algoritmo de búsqueda utiliza todas las distancias entre pixeles de la ventana en la que se realiza la búsqueda para funcionar. Esto se traduce en que cada hilo va a necesitar trabajar simultáneamente con un mínimo de 7 filas de datos, equivalente a más de 2000 registros por hilo, lo que ocasiona una considerable reducción de los hilos activos simultáneamente. En las versiones utilizadas anteriormente, los únicos registros necesarios para la ordenación de vecinos eran la cadena provisional de vecinos, por lo que resulta un aumento significante de registros. Esto además queda corroborado por el propio autor del código en su tesis [31], en la cual describe este algoritmo y lo prueba con distintas plataformas comparando los resultados de cada una. De este mismo documento [31], se ha extraído la tabla de tiempos, reflejada en la Tabla 5:
84
Tabla 5: Resultados obtenidos con el algoritmo de búsqueda de autor Vincent García [31]
En la Tabla 5 [31], se muestran los resultados obtenidos en función del tamaño de la matriz (representado en las columnas con una “n”) y el número de dimensiones utilizadas (representado en las filas de la tabla con una “d ”). Para nuestro estudio, la ventana de búsqueda tiene un valor entre 2400 y 4800 pixeles con 3 dimensiones de búsqueda. En la tabla se encuentran resultados para el mismo número de parámetros, pero con 8 dimensiones como mínimo, pero atendiendo a la evolución de los resultados en función del número de parámetros, se podría estimar un tiempo similar con 3 dimensiones, entre 0.02 y 0.04 segundos en ejecutar el kernel. Sin embargo, hay que tener en cuenta que, en este algoritmo, todos los hilos trabajan conjuntamente en la misma ventana de búsqueda, a diferencia de la implementación que se ha venido utilizado en este estudio, donde cada hilo trabaja con su ventana asignada. Esto implica que para esta nueva implementación se requiere ejecutar el kernel tantas veces como ventanas se utilizan en el algoritmo, es decir, una por cada fila de la imagen, lo cual justifica los resultados obtenidos. De esta manera se llega a la conclusión que para esta implementación del algoritmo no es posible utilizar este método de búsqueda debido a la gran cantidad de datos que hay que manejar.
Otra de las bibliotecas mencionadas en el apartado 4.4 que puede ser de utilidad para este algoritmo es la función de CUDA “fast math”. Como su propio nombre indica, realiza las operaciones matemáticas más rápido de lo habitual, a costa de sacrificar la precisión de estas [26]. Este algoritmo puede resultar útil debido al gran número de operaciones que se realizan durante la etapa de búsqueda. Sin embargo, se deberá poner especial interés en que los resultados obtenidos se encuentren dentro del margen de error aceptable. Para obtener el mínimo error posible se ha decidido utilizar estas funciones exclusivamente en la etapa de búsqueda, ya que es la etapa que más operaciones requiere. Además de esto, hay que tener en cuenta que estas operaciones de matemáticas rápidas están dedicadas
IMPLEMENTACIÓN DEL KNN EN CUDA
85
para elementos de punto flotante, y tendrá menos error cuanto menor sea el exponente del punto flotante. Por este motivo, no se van a utilizar con fast math el cálculo de las distancias de fila y distancias de columna, ya que aparte de ser variables de tipo entero, estas alcanzan valores más altos.
Se ha decidido no utilizar durante la etapa de filtrado porque un error en el cálculo en esa etapa es más significativo, puesto que puede suponer un cambio en la asignación de la clase. Por el contrario, un error en la etapa de búsqueda puede suponer un error en la de vecinos, que entre todos los vecinos puede no influir lo suficiente como para alterar la clasificación del pixel.
De esta manera, tomando el código utilizado para el apartado 5.4, el único cambio se realizará en la etapa de cálculo de la distancia euclídea, colocando algunas de las operaciones rápidas de fast math [32], quedando como muestra la Figura 67:
Figura 67: Etapa de búsqueda utilizando fast math
Una vez compilado los resultados obtenidos son los mostrados en la Figura 68:
Figura 68: Diagrama de tiempos para el KNN V4
Se puede ver en la Figura 68, como efectivamente los resultados utilizando las bibliotecas de CUDA de matemáticas rápidas superan en optimización a los obtenidos en la versión anterior. Igualmente, en esta versión es especialmente necesario valorar de una manera más detallada los resultados del fichero de vecinos. Comparamos el fichero de vecinos con
86
el que tenemos de la versión original y el resultado de coincidencia es del 60%. con lo cual no es para nada aceptable y queda descartada.
Según los resultados, llegamos a la conclusión de que para nuestro algoritmo no es favorable utilizar las herramientas de búsqueda que nos ofrece CUDA, debido principalmente a la enorme cantidad de datos que manejamos durante la ejecución.