UNIVERSIDAD DE EXTREMADURA Escuela Politécnica

Anuncio
UNIVERSIDAD DE EXTREMADURA
Escuela Politécnica
MÁSTER UNIVERSITARIO EN COMPUTACIÓN
GRID Y PARALELISMO
Trabajo Fin de Máster
Implementación paralela del algoritmo Pixel Purity
Index para clúster de GPUs
José Miguel Franco Valiente
Septiembre, 2012
.
.
.
UNIVERSIDAD DE EXTREMADURA
Escuela Politécnica
MÁSTER UNIVERSITARIO EN COMPUTACIÓN
GRID Y PARALELISMO
Trabajo Fin de Máster
Implementación paralela del algoritmo Pixel Purity
Index para clúster de GPUs
Autor:
Fdo:
Director:
Fdo:
José Miguel Franco Valiente
Antonio J. Plaza Miguel
Tribunal calificador
Presidente:
Fdo:
Secretario:
Fdo:
Vocal:
Fdo:
CALIFICACIÓN
FECHA
vi
Agradecimientos
Quiero manifestar mi agradecimiento a todas las personas que, directa o indirectamente han contribuido al resultado de este trabajo. En especial:
A Marı́a de los Ángeles, por su paciencia infinita, su gran ayuda y por sus ánimos recibidos
durante la realización de este trabajo.
A mi familia, por su apoyo incondicional y su confianza depositada en mi para poder llevar este
trabajo a buen puerto.
A Antonio Plaza y al grupo Hypercomp, por iniciarme en la lı́nea de investigación en el análisis
de datos hiperespectrales, por su buen trato recibido y su soporte y apoyo en las dudas que han
surgido durante la realización de este trabajo.
A CETA-CIEMAT, por permitirme el uso de sus recursos computacionales para la realización
de este trabajo y especialmente a su personal por dedicarme su tiempo para resolver mis dudas
y responder eficazmente a las incidencias detectadas.
vii
viii
Resumen
Desde hace unos años, el uso de las tarjetas gráficas (GPUs) para acelerar cálculos cientı́ficos se
ha hecho muy popular, debido principalmente a la relación precio - rendimiento que se puede alcanzar
con este tipo de dispositivos y al no necesitar éstos de grandes espacios ni instalaciones especiales
para poder trabajar con ellos. Además, este tipo de dispositivos está siendo integrados en los grandes computadores, aumentando de manera notable sus capacidades de cómputo y permitiendo que
arquitecturas hı́bridas de CPUs y GPUs aparezcan en los primeros puestos del ránking de supercomputadores Top500.
Además, la aparición de los proveedores de computación en la nube o Cloud Computing como
Amazon permite el acceso a cualquier usuario de a pie a recursos de computación de alto rendimiento,
pagando solamente por el uso que se le dé a dichos recursos. Ası́ pues, es posible configurar un clúster
de computadores con CPUs de alto rendimiento y tarjetas GPU integradas en cuestión de segundos
si se tiene un conocimiento básico de las APIs de los proveedores de cloud.
En concreto, en la lı́nea de investigación en el análisis de imágenes hiperespectrales para la observación remota de la Tierra, las GPUs están permitiendo disminuir el tiempo de procesamiento de este
tipo de imágenes, algo fundamental debido al campo de aplicación de esta disciplina que comprende
actividades como son la detección de incendios, detección de objetivos militares y el control de vertidos
en la atmósfera o en aguas entre otras.
Uno de los algoritmos más conocidos para la extracción de firmas espectrales puras o endmembers en imágenes multiespectrales o hiperespectrales es el algoritmo Pixel Purity Index o PPI. Este
algoritmo es de gran relevancia debido a que las imágenes hiperespectrales capturadas por los sensores actuales de observación remota de la Tierra almacenan en cada pı́xel de resolución espacial una
mezcla de sustancias puras. Esto quiere decir que un pı́xel representa una superficie, que suele ser
mı́nimo del orden del metro cuadrado, donde puede aparecer vegetación, agua, edificaciones, etcétera.
El algoritmo PPI se incluye en el paquete comercial ENVI, perteneciente a la compañı́a Exelis Visual
Information Solutions.
El núcleo de este trabajo reside en la implementación de una versión eficiente del algoritmo PPI
para clúster de computadores cuyos nodos de cálculo integran tarjetas GPU (o clúster de GPUs).
Para la implementación y ejecución de las pruebas se ha utilizado el clúster de GPUs de CETACIEMAT, localizado en Trujillo (Cáceres), que consta de 17 nodos de computación para el entorno
de Test equipados con GPUs C1060 (S1070) de Nvidia y 32 nodos de computación para el entorno de
Producción equipados con GPUs de la serie C2050 (S2050) y C2070 (S2070) de Nvidia.
La implementación desarrollada de PPI se basa en las implementaciones de este algoritmo desarrolladas previamente para clúster de computadores y para tarjetas GPU. Por este motivo, este trabajo
presenta un estudio comparativo de rendimiento entre las tres implementaciones paralelas comentadas.
Asimismo, se presenta un estudio de las diferentes implementaciones llevadas a cabo en el marco de
este trabajo con el fin de presentar la evolución del rendimiento desde la primera versión del algoritmo
hasta la última, la cual incluye varias optimizaciones (entre ellas el uso de varias GPUs).
Palabras clave Hiperespectral, Endmember, Pixel Purity Index, PPI, multiGPU, ENVI.
ix
x
Abstract
In recent years, the use of graphic cards (GPUs) to accelerate scientific calculations has become
very popular, mainly because of the price - performance ratio that can be achieved with these devices
and because neither large spaces nor special facilities are required to work with them. In addition,
these devices are being installed in supercomputers, resulting in a significant boost of their computing
capabilities and allowing hybrid architectures of CPUs and GPUs appear at the top of the ranking
Top500 of supercomputers.
Moreover, the emergence of providers of computing resources or Cloud Computing such as Amazon
allows any user to access to high performance computing resources, on a pay as you go service (paying
only for the use made). Furthermore, it is possible to configure and use a computer cluster with highperformance CPU nodes and integrated GPU cards just in few minutes if you have basic knowledge
of the APIs of cloud providers.
It is precisely in the research on the analysis of hyperspectral imagery for remote sensing of Earth
that GPUs are allowing to reduce the processing time of this kind of images, which is essential owing
to the scope of this field which includes actions such as fire detection, military target detection and
the control of waste in the atmosphere or water among others.
One of the best known algorithms for extracting pure spectral signatures or endmembers in multispectral or hyperspectral images is the algorithm Pixel Purity Index or PPI. This algorithm is highly
relevant because hyperspectral images captured by current sensors used in remote sensing store a
mixture of pure substances in each pixel of the spatial resolution. This means that a pixel represents
an area, usually of a size around a square metre, which may show vegetation, water, buildings and so
on. The PPI algorithm is included in the retail software package ENVI, nowadays belonging to the
company Exelis Visual Information Solutions.
The core of this work lies in the implementation of an efficient version of the PPI algorithm for a
computer cluster whose nodes have GPU cards (or GPU cluster). For its development and test the GPU
cluster of CETA-CIEMAT has been used, being its present location the town of Trujillo (Cáceres). The
afore mentioned infrastructure consists of 17 compute nodes for the Test environment equipped with
C1060 GPUs (S1070) from Nvidia and 32 compute nodes for the Production environment equipped
with C2050 series GPUs (S2050) and C2070 (S2070) also from Nvidia.
Our implementation of PPI is based on previously developed versions of this algorithm for computer
clusters and GPU cards. For this reason, a comparative study of performance of these three parallel
implementations is made and discussed. Moreover, in the present paper, the different versions of the
algorithm for a GPU cluster are compared to show how performance has evolved from the first to the
final version, the latter including several optimizations such as the use of multiple GPUs.
Keywords
Hyperspectral, Endmember, Pixel Purity Index, PPI, multiGPU, ENVI.
xi
xii
Índice general
1. Motivaciones y objetivos
1.1. Motivaciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.2. Objetivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.3. Organización del documento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1
1
2
2
2. Antecedentes
2.1. Análisis hiperespectral . . . . . . . . . . . . . .
2.1.1. Concepto de imagen hiperespectral . . .
2.1.2. Sensores hiperespectrales . . . . . . . .
2.2. Técnicas de análisis hiperespectral . . . . . . .
2.2.1. Pixel Purity Index (PPI) . . . . . . . .
2.2.2. Orthogonal Subspace Projection (OSP)
2.2.3. N-FINDR . . . . . . . . . . . . . . . . .
2.3. Necesidad de pararelismo . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
5
5
5
7
9
10
11
11
12
3. Arquitecturas paralelas consideradas
3.1. Procesamiento paralelo en clúster . . . . .
3.1.1. Message Passage Interface (MPI) .
3.2. Procesamiento paralelo en GPUs . . . . .
3.2.1. NvidiaTM CUDA . . . . . . . . . .
3.2.2. Escritura de programas en CUDA
3.3. El clúster de GPUs de CETA-CIEMAT .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
13
13
14
16
18
20
21
4. Método
4.1. Pixel Purity Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
27
27
5. Implementaciones paralelas
5.1. Implementación de PPI para un clúster de computadores . . . .
5.1.1. Estrategias de particionamiento de datos hiperespectrales
5.1.2. Detalle de la implementación . . . . . . . . . . . . . . . .
5.2. Implementación paralela de PPI para GPUs . . . . . . . . . . . .
5.3. Implementación paralela de PPI para un clúster de GPUs . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
31
31
31
33
35
37
6. Resultados experimentales
6.1. Descripción de las pruebas realizadas . . . . . . . . . . . .
6.1.1. Parámetros del algoritmo PPI . . . . . . . . . . . .
6.1.2. Entornos de pruebas . . . . . . . . . . . . . . . . .
6.2. Desarrollo de PPI para el clúster de GPUs . . . . . . . . .
6.2.1. Implementación sin optimizaciones . . . . . . . . .
6.2.2. Implementación Zero Copy . . . . . . . . . . . . .
6.2.3. Implementación con uso de memoria local . . . . .
6.2.4. Implementación con optimizaciones de compilación
6.2.5. Implementación basada en memoria compartida .
6.2.6. Implementación multiGPU . . . . . . . . . . . . .
6.3. Comparativa frente a otras implementaciones . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
39
39
39
43
43
43
50
53
58
61
66
70
.
.
.
.
.
.
7. Conclusiones y trabajo futuro
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
73
xiii
xiv
ÍNDICE GENERAL
Lista de tablas
2.1. Caracterı́sticas de algunos sensores hiperespectrales ya en funcionamiento o que estarán
disponibles a corto plazo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.1. Caracterı́sticas de la imagen hiperespectral AVIRIS, capturada en 1995 sobre la región
minera de Cuprite, En Nevada (Estados Unidos) . . . . . . . . . . . . . . . . . . . . .
6.2. Caracterı́sticas de la imagen hiperespectral AVIRIS, capturada en 2008 sobre la región
del lago St. Clair, en Michigan (Estados Unidos) . . . . . . . . . . . . . . . . . . . . .
6.3. Caracterı́sticas de la imagen hiperespectral AVIRIS, capturada en 2009 sobre el Parque
Nacional de Yellowstone, en Wyoming (Estados Unidos) . . . . . . . . . . . . . . . . .
6.4. Datos de ocupación de la GPU para la implementación MPI-CUDA sin optimizaciones
del algoritmo PPI para el entorno de Test del clúster de CETA-CIEMAT . . . . . . .
6.5. Datos de ocupación de la GPU para la implementación MPI-CUDA sin optimizaciones
del algoritmo PPI para el entorno de Producción del clúster de CETA-CIEMAT . . .
6.6. Resultados de ejecución (en sg.) de la implementación sin optimizaciones del algoritmo
PPI para clúster de GPUs (Imagen: Cuprite) . . . . . . . . . . . . . . . . . . . . . . .
6.7. Resultados de ejecución (en sg.) de la implementación sin optimizaciones del algoritmo
PPI para clúster de GPUs (Imagen: Lago St. Clair ) . . . . . . . . . . . . . . . . . . .
6.8. Resultados de ejecución (en sg.) de la implementación sin optimizaciones del algoritmo
PPI para clúster de GPUs (Imagen: Yellowstone) . . . . . . . . . . . . . . . . . . . . .
6.9. Datos de ocupación de la GPU para la implementación MPI-CUDA Zero Copy del
algoritmo PPI para el entorno de Producción del clúster de CETA-CIEMAT . . . . . .
6.10. Resultados de ejecución (en sg.) de la implementación Zero Copy del algoritmo PPI
para clúster de GPUs (Imagen: Cuprite) . . . . . . . . . . . . . . . . . . . . . . . . . .
6.11. Resultados de ejecución (en sg.) de la implementación Zero Copy del algoritmo PPI
para clúster de GPUs (Imagen: Lago St. Clair ) . . . . . . . . . . . . . . . . . . . . . .
6.12. Resultados de ejecución (en sg.) de la implementación Zero Copy del algoritmo PPI
para clúster de GPUs (Imagen: Yellowstone) . . . . . . . . . . . . . . . . . . . . . . .
6.13. Datos de ocupación de la GPU para la implementación MPI-CUDA local memory del
algoritmo PPI para el entorno de Producción del clúster de CETA-CIEMAT . . . . . .
6.14. Resultados de ejecución (en sg.) de la implementación local memory del algoritmo PPI
para clúster de GPUs (Imagen: Cuprite) . . . . . . . . . . . . . . . . . . . . . . . . . .
6.15. Resultados de ejecución (en sg.) de la implementación local memory del algoritmo PPI
para clúster de GPUs (Imagen: Lago St. Clair ) . . . . . . . . . . . . . . . . . . . . . .
6.16. Resultados de ejecución (en sg.) de la implementación local memory del algoritmo PPI
para clúster de GPUs (Imagen: Yellowstone) . . . . . . . . . . . . . . . . . . . . . . .
6.17. Datos de ocupación de la GPU para la implementación MPI-CUDA con optimizaciones
de compilación del algoritmo PPI para el entorno de Producción del clúster de CETACIEMAT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.18. Resultados de ejecución (en sg.) de la implementación con optimizaciones de compilación del algoritmo PPI para clúster de GPUs (Imagen: Cuprite) . . . . . . . . . . . . .
6.19. Resultados de ejecución (en sg.) de la implementación con optimizaciones de compilación del algoritmo PPI para clúster de GPUs (Imagen: Lago St. Clair ) . . . . . . . . .
6.20. Resultados de ejecución (en sg.) de la implementación con optimizaciones de compilación del algoritmo PPI para clúster de GPUs (Imagen: Yellowstone) . . . . . . . . . .
6.21. Datos de ocupación de la GPU para la implementación MPI-CUDA basada en memoria
compartida utilizados para el cálculo del tamaño del array a almacenar en dicho nivel
de la jerarquı́a de memoria . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
xv
9
40
40
41
44
45
47
48
49
51
51
52
53
54
55
56
57
58
59
60
60
62
xvi
LISTA DE TABLAS
6.22. Datos de ocupación de la GPU para la implementación MPI-CUDA basada en memoria
compartida del algoritmo PPI para el entorno de Producción del clúster de CETACIEMAT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.23. Resultados de ejecución (en sg.) de la implementación basada en memoria compartida
del algoritmo PPI para clúster de GPUs (Imagen: Cuprite) . . . . . . . . . . . . . . .
6.24. Resultados de ejecución (en sg.) de la implementación basada en memoria compartida
del algoritmo PPI para clúster de GPUs (Imagen: Lago St. Clair ) . . . . . . . . . . . .
6.25. Resultados de ejecución (en sg.) de la implementación basada en memoria compartida
del algoritmo PPI para clúster de GPUs (Imagen: Yellowstone) . . . . . . . . . . . . .
6.26. Datos de ocupación de la GPU para la implementación MPI-CUDA multiGPU del
algoritmo PPI para el entorno de Producción del clúster de CETA-CIEMAT . . . . . .
6.27. Resultados de ejecución (en sg.) de la implementación multiGPU del algoritmo PPI
para clúster de GPUs (Imagen: Cuprite) . . . . . . . . . . . . . . . . . . . . . . . . . .
6.28. Resultados de ejecución (en sg.) de la implementación multiGPU del algoritmo PPI
para clúster de GPUs (Imagen: Lago St. Clair ) . . . . . . . . . . . . . . . . . . . . . .
6.29. Resultados de ejecución (en sg.) de la implementación multiGPU del algoritmo PPI
para clúster de GPUs (Imagen: Yellowstone) . . . . . . . . . . . . . . . . . . . . . . .
6.30. Comparativa de resultados obtenidos para las versiones secuencial, clúster de computadores, GPUs y clúster de GPUs en el procesamiento de la imagen Cuprite . . . . . .
6.31. Comparativa de resultados obtenidos para las versiones secuencial, clúster de computadores, GPUs y clúster de GPUs en el procesamiento de la imagen Lago St. Clair . .
6.32. Comparativa de resultados obtenidos para las versiones secuencial, clúster de computadores, GPUs y clúster de GPUs en el procesamiento de la imagen Yellowstone . . .
62
63
64
65
66
68
69
69
70
71
71
Lista de figuras
2.1.
2.2.
2.3.
2.4.
Concepto de imagen hiperespectral . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Resultado de la toma de datos por parte de un sensor hiperespectral . . . . . . . . . .
Tipos de pı́xeles en imágenes hiperespectrales . . . . . . . . . . . . . . . . . . . . . . .
Relación señal-ruido (SNR) en los diferentes canales de AVIRIS a lo largo de los últimos
años (reproducido con permiso de Robert O. Green, investigador principal del proyecto
AVIRIS) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Representación de los modelos de mezcla en análisis hiperespectral: (a) Modelo de
mezcla lineal (b) Modelo de mezcla no lineal . . . . . . . . . . . . . . . . . . . . . . . .
Interpretación gráfica del modelo lineal de mezcla . . . . . . . . . . . . . . . . . . . . .
Representación gráfica del funcionamiento del algoritmo Orthogonal Subspace Projection (OSP) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Representación gráfica del funcionamiento del algoritmo N-FINDR . . . . . . . . . . .
11
12
3.1. Supercomputador Columbia, localizado en el Ames Research Center de NASA, California (Estados Unidos) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.2. Esquema hardware de una GPU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.3. Arquitectura GPU frente a CPU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.4. Operaciones en coma flotante CPU frente a GPU . . . . . . . . . . . . . . . . . . . . .
3.5. Ancho de banda de memoria en GB/s de CPU frente a GPU . . . . . . . . . . . . . .
3.6. Esquema del modelo de programación CUDA . . . . . . . . . . . . . . . . . . . . . . .
3.7. Esquema del modelo de memoria CUDA . . . . . . . . . . . . . . . . . . . . . . . . . .
3.8. Supercomputador Tianhe-1A . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.9. Clúster de GPUs MinoTauro del BSC . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.10. Arquitectura del entorno HPC de CETA-CIEMAT . . . . . . . . . . . . . . . . . . . .
3.11. Disposición de los elementos hardware del clúster Tesla de GPUs de CETA-CIEMAT .
3.12. Disposición de los elementos hardware del clúster Fermi de GPUs de CETA-CIEMAT
14
17
17
18
18
19
20
22
22
23
24
25
4.1. Selección de los pı́xeles extremos para un conjunto de skewers en el algoritmo PPI . .
28
5.1. Estrategias de particionamiento de imágenes hiperespectrales. (a) Particionamiento espectral. (b) Particionamiento espacial. (c) Particionamiento hı́brido. . . . . . . . . . .
5.2. Particionamiento de datos en el algoritmo PPI . . . . . . . . . . . . . . . . . . . . . .
32
35
2.5.
2.6.
2.7.
2.8.
6.1. Imagen real AVIRIS perteneciente a la región minera de Cuprite, en Nevada (Estados
Unidos) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.2. Imagen real AVIRIS perteneciente la región del lago St. Clair, en Michigan (Estados
Unidos) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.3. Imagen real AVIRIS perteneciente al Parque Nacional de Yellowstone, en Wyoming
(Estados Unidos) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.4. Resultados visuales obtenidos de la ejecución del algoritmo PPI para las versiones de
ENVI y clúster de GPUs sobre la imagen Cuprite . . . . . . . . . . . . . . . . . . . . .
6.5. Ejemplo de algunos de los minerales detectados en la imagen resultado de la ejecución
de PPI sobre la imagen Cuprite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.6. Firmas espectrales de los minerales detectados en la imagen resultado de la ejecución
de PPI para clúster de GPUs sobre la imagen Cuprite . . . . . . . . . . . . . . . . . .
6.7. Resultados visuales obtenidos de la ejecución del algoritmo PPI para las versiones de
ENVI y clúster de GPUs sobre la imagen Lago St. Clair . . . . . . . . . . . . . . . . .
xvii
5
6
7
8
9
10
40
41
42
45
46
46
47
xviii
LISTA DE FIGURAS
6.8. Gráficas de la implementación sin optimizaciones del algoritmo PPI para clúster de
GPUs (Imagen: Cuprite) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.9. Gráficas de la implementación sin optimizaciones del algoritmo PPI para clúster de
GPUs (Imagen: Lago St. Clair ) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.10. Gráficas de la implementación sin optimizaciones del algoritmo PPI para clúster de
GPUs (Imagen: Yellowstone) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.11. Gráficas de la implementación Zero Copy del algoritmo PPI para clúster de GPUs
(Imagen: Cuprite) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.12. Gráficas de la implementación Zero Copy del algoritmo PPI para clúster de GPUs
(Imagen: Lago St. Clair ) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.13. Gráficas de la implementación Zero Copy del algoritmo PPI para clúster de GPUs
(Imagen: Yellowstone) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.14. Gráficas de la implementación local memory del algoritmo PPI para clúster de GPUs
(Imagen: Cuprite) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.15. Gráficas de la implementación local memory del algoritmo PPI para clúster de GPUs
(Imagen: Lago St. Clair ) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.16. Gráficas de la implementación local memory del algoritmo PPI para clúster de GPUs
(Imagen: Yellowstone) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.17. Gráficas de la implementación con optimizaciones de compilación del algoritmo PPI
para clúster de GPUs (Imagen: Cuprite) . . . . . . . . . . . . . . . . . . . . . . . . . .
6.18. Gráficas de la implementación con optimizaciones de compilación del algoritmo PPI
para clúster de GPUs (Imagen: Lago St. Clair ) . . . . . . . . . . . . . . . . . . . . . .
6.19. Gráficas de la implementación con optimizaciones de compilación del algoritmo PPI
para clúster de GPUs (Imagen: Yellowstone) . . . . . . . . . . . . . . . . . . . . . . .
6.20. Gráficas de la implementación basada en memoria compartida del algoritmo PPI para
clúster de GPUs (Imagen: Cuprite) . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.21. Gráficas de la implementación basada en memoria compartida del algoritmo PPI para
clúster de GPUs (Imagen: Lago St. Clair ) . . . . . . . . . . . . . . . . . . . . . . . . .
6.22. Gráficas de la implementación basada en memoria compartida del algoritmo PPI para
clúster de GPUs (Imagen: Yellowstone) . . . . . . . . . . . . . . . . . . . . . . . . . .
6.23. Gráficas de la implementación multiGPU del algoritmo PPI para clúster de GPUs
(Imagen: Cuprite) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.24. Gráficas de la implementación multiGPU del algoritmo PPI para clúster de GPUs
(Imagen: Lago St. Clair ) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.25. Gráficas de la implementación multiGPU del algoritmo PPI para clúster de GPUs
(Imagen: Yellowstone) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
48
49
49
51
52
53
56
57
57
59
59
61
64
65
65
68
69
70
Capı́tulo 1
Motivaciones y objetivos
1.1.
Motivaciones
El presente trabajo se enmarca dentro de las lı́neas de investigación del grupo de Computación
Hiperespectral (HYPERCOMP ), perteneciente al Departamento de Tecnologı́a de Computadores y
Comunicaciones de la Universidad de Extremadura, y está dedicado a la implementación eficiente de un
algoritmo de procesamiento de imágenes hiperespectrales de la superficie terrestre para la extracción
de referencias espectrales puras o endmembers, haciendo uso de un clúster de computadores cuyos
nodos de cómputo están equipados con tarjetas GPU.
El algoritmo implementado es el llamado Pixel Purity Index o PPI. Las aplicaciones de este algoritmo son numerosas, entre ellas destacan aplicaciones militares (detección de targets u objetivos),
detección y monitorización de fuegos y agentes contaminantes en atmósfera y agua (agentes quı́micos
o vertidos), agricultura de precisión y detección de minerales, entre otras aplicaciones.
El algoritmo PPI es un algoritmo costoso computacionalmente hablando, debido a las iteraciones
que debe realizar sobre los pı́xeles de la imagen hiperespectral a procesar. Esta caracterı́stica provoca
que los resultados de su ejecución se demoren demasiado en el tiempo, algo inadmisible dada la
importancia de la respuesta temporal en las aplicaciones de dicho algoritmo. Además, la evolución de
los sensores hiperespectrales provoca que el tamaño de las imágenes capturadas sea cada vez mayor,
lo que también afecta al tiempo de ejecución del algoritmo. Este problema se puede generalizar a la
mayorı́a de los algoritmos de análisis de imágenes multiespectrales o hiperespectrales.
A dı́a de hoy, el problema de la mejora del rendimiento de los algoritmos de análisis hiperespectral
se ha abordado, según la literatura, optando por la paralelización de los algoritmos adaptada a diferentes infraestructuras de cómputo, como clústers de computadores, sistemas multiprocesador, tarjetas
gráficas programables de propósito general (GPUs) y sistemas reconfigurables. Todas las alternativas
presentan sus ventajas e inconvenientes, por lo que, de momento, no existe una solución que se adapte
mejor a todos los problemas.
La computación clúster presenta buenos resultados de rendimiento y se adapta adecuadamente
al problema, especialmente para el tratamiento de datos almacenados en un repositorio de datos en
tierra. El inconveniente reside en el procesamiento de datos en tiempo real, debido a que los datos
deben ser comprimidos y enviados desde el elemento de captura hasta la localización del clúster, lo
que penaliza la respuesta temporal. Además por razones más que evidentes, dado el elevado peso,
consumo energético y de espacio no es posible realizar una instalación de este tipo on-board.
Por otro lado, las implementaciones de los algoritmos de análisis hiperespectral orientadas a tarjetas
GPU están a niveles del estado del arte, debido a que son dispositivos de reciente aparición y a su
excelente relación precio - rendimiento. Trabajos recientemente publicados exponen rendimiento de
ejecución muy cercanos al tiempo real. Por contra, actualmente las tarjetas GPU tienen un alto coste
energético, por lo que de momento no son viables para su uso a bordo, pero dada su rápida evolución y
la inversión en eficiencia energética de los fabricantes, es cada dı́a más factible que lleguen a montarse
junto a los dispositivos de captura.
Por último, las sistemas reconfigurables son actualmente la implementación que menor coste
energético lleva asociado y el menor peso asociado, lo que las hacen recomendables para su instalación
a bordo. A dı́a de hoy, se han consiguido buenos resultados para algunos algoritmos de procesamiento
de imágenes hiperespectrales, pero tienen el inconveniente asociado de la limitación de recursos en
arquitecturas tolerantes a la radiación y al menor rendimiento de los algoritmos implementados frente
1
2
CAPÍTULO 1. MOTIVACIONES Y OBJETIVOS
a las soluciones anteriores.
Actualmente, el uso de tarjetas GPU aplicado a la computación cientı́fica es un hecho, debido a
su buen rendimiento, al bajo coste de adquisición y la aparición de entornos de programación que
facilitan la explotación de este tipo de recursos. Tanto es ası́ que los fabricantes están incluyendo este
tipo de dispositivos en sus infraestructuras de clúster de computación, consiguiendo sistemas muy
potentes que copan algunos de los puestos más altos del ranking de supercomputadores Top500.
Este hecho, unido al reciente auge de la computación en la nube, mediante la cual un cienfı́fico
o grupo de investigación puede tener acceso a recursos avanzados de supercomputación para su uso
puntual a un precio razonable, hacen necesario la evaluación de rendimiento de este tipo de infraestructuras para su aplicación al análisis de imagen hiperespectral.
Debido a esto, este trabajo tiene además como objetivo la elaboración de un estudio comparativo
de rendimiento de varias implementaciones paralelas del algoritmo PPI, en sus versiones para clúster
de computadores, GPU y clúster de GPUs. Esta última ha sido desarrollada especialmente para este
trabajo y está orientada a su explotación en el clúster de GPUs de Centro Extremeño de Tecnologı́as
Avanzadas (CETA), localizado en Trujillo (Cáceres). CETA es una subsede del Centro de Investigaciones Energéticas, Medioambientales y Tecnológicas (CIEMAT), un organismo público de investigación
perteneciente al Ministerio de Economı́a y Competitividad del Gobierno de España.
1.2.
Objetivos
Como se ha comentado en el apartado anterior este trabajo tiene como principal objetivo la implementación eficiente del algoritmo de análisis de imagen hiperespectral PPI orientado a una arquitectura
de clúster de computadores cuyos nodos de cálculo montan tarjetas GPUs. Para alcanzar este objetivo se presentan a continuación un conjunto de objetivos especı́ficos a llevar a cabo para completar el
objetivo final:
1. Realización de un estudio del algoritmo Pixel Purity Index en sus diferentes implementaciones,
para identificar sus posibilidades de implementación para un clúster de GPUs.
2. Estudio del lenguaje de programación CUDA, de la librerı́a MPI y de sus posibilidades de uso
conjunto para llevar a cabo la implementación del algoritmo.
3. Implementación del algoritmo PPI paralelo para su ejecución en el clúster de GPUs de CETACIEMAT y optimización del tiempo de ejecución.
4. Realización de un estudio comparativo de rendimiento de las implementaciones paralelas del
algoritmo PPI en sus versiones para clúster de computadores, GPUs y clúster de GPUs.
El siguiente apartado describe la organización de este documento para facilitar el seguimiento del
trabajo realizado para alcanzar estos ebjetivos.
1.3.
Organización del documento
El presente documento se organiza de la siguiente forma:
1. Motivaciones y objetivos El presente capı́tulo describe las motivaciones y objetivos del trabajo realizado. También se describe la organización general del documento.
2. Antecedentes En este capı́tulo se describen los conceptos fundamentales relacionados con el
análisis de imágenes hiperespectrales, desde el concepto de imagen hiperespectral hasta los conceptos básicos relativos a la extracción de firmas espectrales puras. Además, este capı́tulo introduce los antecedentes relacionados con la aplicación de técnicas de computación paralela a
problemas de análisis hiperespectral, describiendo la necesidad de pararalelismo y capacidad de
procesamiento en tiempo real para determinados contextos de aplicación.
3. Arquitecturas paralelas consideradas En este apartado se describen las caracterı́sticas de la
arquitectura paralela considerada, el clúster de GPUs de CETA-CIEMAT, haciendo un repaso
de los clúster de computadores y de las tarjetas gráficas programables (GPUs), que son la base
de esta solución hı́brida de cómputo, enumerando sus ventajas e incovenientes. Se presentan
también las herramientas de programación utilizadas para el desarrollo de la implementación
1.3. ORGANIZACIÓN DEL DOCUMENTO
3
de PPI para el clúster de GPUs: la librerı́a Message Passing Interface (MPI) y el entorno de
desarrollo para Nvidia CUDA.
4. Método En este capı́tulo se describe y muestra la utilidad del algoritmo PPI para el análisis
de imágenes hiperespectrales, ası́ como su funcionamiento y filosofı́a.
5. Implementaciones paralelas Es esta sección se presentan las implementaciones paralelas del
algoritmo PPI para clúster de computadores, tarjetas GPUs y clúster de GPUs (implementada
en el marco de este trabajo) utilizadas para la realización del estudio comparativo de rendimiento
que se describe en el capı́tulo posterior.
6. Resultados experimentales Este capı́tulo se divide en dos partes: la primera realiza un análisis comparativo de las diferentes evoluciones del algoritmo paralelo PPI para clúster de GPUs
implementadas durante el desarrollo de este trabajo, y la segunda compara los resultados obtenidos de la versión de mejor rendimiento en el clúster de GPUs con las versiones de PPI para
clúster de computadores y GPUs descritas en el capı́tulo anterior.
7. Conclusiones y trabajo futuro Este último capı́tulo está dedicado a la exposición de las
conclusiones obtenidas tras la realización de este trabajo y a la exposición de una propuesta de
trabajo futuro.
4
CAPÍTULO 1. MOTIVACIONES Y OBJETIVOS
Capı́tulo 2
Antecedentes
En este capı́tulo se describen los conceptos fundamentales relacionados con el análisis de imágenes
hiperespectrales. En primer lugar se describe el concepto de imagen hiperespectral, detallando sus
particularidades y caracterı́sticas. A continuación, se describen los sensores de adquisición de este
tipo de imágenes, destacando el sensor utilizado para capturar las imágenes incluidas en este trabajo.
Posteriormente, se da una visión general de las técnicas de extracción de firmas espectrales puras para
finalizar exponiendo la necesidad de aplicar técnicas de computación paralela al análisis hiperespectral.
2.1.
Análisis hiperespectral
En este apartado se definen algunos conceptos básicos asociados al análisis de imágenes hiperespectrales de la superficie terrestre. Primeramente, se define el concepto de imagen hiperespectral,
detallando particularidades y caracterı́sticas propias de este tipo de imágenes de alta dimensionalidad para pasar a continuación a la descripción de los sensores de adquisición de este tipo de datos,
haciendo hincapié en los utilizados en la captura de las imágenes usadas en este trabajo.
2.1.1.
Concepto de imagen hiperespectral
El análisis hiperespectral es una técnica avanzada de observación remota de la tierra caracterizada
por la disponibilidad de imágenes con gran resolución en el dominio espectral (cientos o miles de
bandas espectrales [14]). La evolución de las técnicas de análisis de datos hiperespectrales está marcada
principalmente por la evolución de los dispositivos de captura y la instrumentación avanzada para
la observación remota de la Tierra [38]. Los primeros sensores eran fundamentalmente de carácter
espacial. Poco después aparecieron instrumentos capaces de medir singularidades en el espectro de
la luz reflejada por los diferentes materiales presentes en el mundo real, utilizando varios canales
espectrales, provocando la necesidad del desarrollo de técnicas de análisis hiperespectral [19].
Figura 2.1: Concepto de imagen hiperespectral
Los sensores hiperespectrales actuales permiten la adquisición de imágenes digitales con un gran
número de canales espectrales muy cercanos entre sı́, obteniendo para cada porción de la escena o pı́xel
una firma espectral caracterı́stica para cada material [16]. Si se representa una imagen hiperespectral
de forma gráfica, se obtendrı́a un cubo cuyas dos primeras dimensiones, X e Y , corresponderı́an con
5
6
CAPÍTULO 2. ANTECEDENTES
las coordenadas espaciales de un pı́xel determinado en la imagen, y la dimensión Z representarı́a la
singularidad espectral de cada pı́xel según las diferentes longitudes de onda [9]. La figura 2.1 muestra
una representación gráfica del concepto de imagen hiperespectral.
Como se puede observar en la figura 2.1, las dimensiones espaciales de la imagen presentan los
conceptos de lı́nea y muestra, donde las lı́neas horizontales corresponderı́an a las lı́neas de la imagen
hiperespectral y las verticales a las muestras. Además, se presenta el concepto de banda o canal,
que representa la tercera dimensión de la imagen hiperespectral. Cada banda almacenará el valor
capturado para cada longitud de onda de trabajo del sensor hiperespectral. Por lo tanto, cada pı́xel
situado en la coordenada (x, y) es un vector de valores discretos, en el que cada elemento del vector
corresponde a una de las longitudes de onda empleadas en el proceso de adquisición de la imagen.
El resultado de la toma de datos sobre una determinada escena puede ser por lo tanto representado
en forma de cubo, con dos dimensiones para representar la ubicación espacial de un pı́xel y una tercera
que representa la singularidad espectral de cada pı́xel en diferentes longitudes de onda. Si denotamos
una imagen hiperespectral como un cubo de datos F , se puede representar un pı́xel del imagen de
coordenadas de resolución espacial (x, y) como F (x, y).
La figura 2.2 ilustra el proceso de captura de una imagen hiperespectral de forma simplificada,
tomando como dispositivo de ejemplo el sensor AVIRIS de NASA, que trabaja en un rango de logitudes
de onda entre 400 y 2.500 nm. Haciendo analogı́a con el procedimiento de toma de una foto con una
cámara digital convencional, los sensores hiperespectrales son capaces de hacer “fotos” mucho más
avanzadas, cuyos pı́xeles no solo almacenan los valores RGB, sino que además incluyen el resto de los
valores espectrales en los que también trabaja el sensor (224 en total en el caso de AVIRIS). Con estos
valores se obtiene una firma espectral caracterı́stica que será utilizada en el proceso de análisis de la
imagen [10].
Figura 2.2: Resultado de la toma de datos por parte de un sensor hiperespectral
Como consecuencia del proceso de captura de imágenes por los sensores hiperespectrales, hay que
destacar que en este tipo de imágenes es frecuente encontrar mezclas a nivel de subpı́xel. Este hecho
se debe principalmente a la insuficiente resolución espacial del sensor, normalmente del orden de
varios metros cuadrados por pı́xel, para separar materiales espectralmente puros. Este fénomeno no
es exclusivo de los sensores hiperespectrales, dado que ocurren de forma frencuente en la naturaleza
y a todas las escalas [38, 21, 23, 29]. Consecuentemente podemos clasificar los pı́xeles de una imagen
de forma general en dos grupos:
Pı́xeles puros: aquellos en los que solo aparece un tipo de material (por ejemplo agua).
Pı́xeles mezcla: aquellos en los que coexisten diferentes materiales a nivel de subpı́xel (por
ejemplo vegetación y suelo).
La mayor parte de los pı́xeles de una imagen hiperespectral son pı́xeles mezcla frente a los pı́xeles
puros, que pueden no existir en la propia imagen. La figura 2.3 muestra un ejemplo de adquisición de
pı́xeles puros (a nivel macroscópico, es decir, si el tamaño del pı́xel de la imagen no es lo suficientemente
grande para separar los diferentes materiales) y mezcla en imágenes hiperespectrales.
2.1. ANÁLISIS HIPERESPECTRAL
7
Figura 2.3: Tipos de pı́xeles en imágenes hiperespectrales
Otros factores que influyen en la obtención de pı́xeles mezcla son los efectos atmosféricos, los efectos
de dispersión múltiple debido a materiales que reflejan la luz de forma irregular (por ejemplo, algunos
tipos de vegetación o algunos minerales, entre otros), por lo que dicho fenómeno, y su caracterización,
es de gran interés en el desarrollo de técnicas de análisis de imágenes hiperespectrales.
Para finalizar, comentar que un pı́xel mezcla puede descomponerse en una colección de espectros de pı́xeles puros, denominados endmembers en la terminologı́a y en un conjunto de valores o
abundancias que indican la proporción o contribución individual de cada uno de los endmembers al
valor espectral del pı́xel mezcla. En los apartados siguientes se describen los modelos utilizados para
describir esta situación denominada modelo de mezcla. Además se describen los sensores espectrales,
haciendo hincapié en el sensor AVIRIS, utilizado para la adquisición de las imágenes consideradas en
este trabajo.
2.1.2.
Sensores hiperespectrales
Hoy en dı́a, existe un amplio abanico de sensores hiperespectrales para la observación remota de
la Tierra. Según [26], se puede definir un sensor hiperespectral como un dispositivo capaz de medir la
radiación reflejada en una gran cantidad de bandas muy estrechas. Este tipo de sensores son capaces
de distinguir materiales, sustancias y objetos que los sensores multiespectrales no son capaces de distinguir. Para cada pı́xel capturado se obtiene una firma espectral, que agrupa los valores de reflectancia
obtenidos para cada longitud de onda de trabajo del sensor, lo que permite una caracterización muy
precisa de la superficie terrestre [19, 20].
8
CAPÍTULO 2. ANTECEDENTES
Los sensores hiperespectrales pueden clasificarse según el modo en el que son transportados durante
el procedimiento de captura de datos [19, 20]. Actualmente, la mayor parte son aerotransportados,
como el Airborne Visible/Infrared Imaging Spectrometer (AVIRIS) de la NASA, utilizado para obtener
las imágenes que apoyan este trabajo. Un ejemplo de sensor de satélite es el Hyperion, también de
NASA y también son comunes los sensores de mano para muchos estudios de desarrollo y validación.
AVIRIS es un sensor hiperespectral aerotransportado, con capacidades analı́ticas en las zonas visible e infrarroja del espectro [16]. Comenzó a funcionar en 1987, siendo el primer sistema de adquisición
de imágenes capaz de obtener información en una gran cantidad de bandas espectrales estrechas y
contiguas. AVIRIS puede obtener información espectral de 224 canales espectrales, que abarcan un
rango de longitudes de onda entre 400 y 2.500 nanómetros, con un ancho entre bandas muy pequeño,
de aproximadamente 10 nanómetros.
En 1989, AVIRIS pasó a ser un instrumento aerotransportado con el que se han obtenido imágenes de Estados Unidos, Canadá y Europa. Hasta el dı́a de hoy, se han utilizado cuatro plataformas
diferentes en las campañas de toma de datos [15].
En cuanto a las caracterı́sticas propias del sensor hiperespectral de AVIRIS, se pueden destacar
las siguientes:
El sensor utiliza un explorador de barrido que permite obtener un total de 614 pı́xeles por cada
oscilación.
Posee un conjunto de espectrómetros que se pueden clasificar en dos grupos:
• Para la parte visible del espectro se utiliza el espectrómetro EFOS-A, que está compuesto
por un array de 32 detectores lineales.
• Para la cobertura del infrarrojo se utilizan los espectrómetros EFOS-B, EFOS-C y EFOS-D,
que están compuestos por arrays de 64 detectores lineales.
Dispone de un sistema de calibración a bordo, el cual hace uso de una lámpara halógena de cuarzo
que proporciona la radiación necesaria para comprobar el estado de los diferentes espectrómetros.
La señal medida por cada detector se amplifica y codifica utilizando 12 bits. Esta señal se
almacena en una memoria intermedia donde es sometida a una etapa de preprocesado, siendo
registrada a continuación en una cinta de alta densidad de 10,4 GB a una velocidad de 20,4
MB/s.
A lo largo de los años el sensor ha ido mejorando sus prestaciones en cuanto a la relación señalruido o signal to noise ratio (SNR). La figura 2.4 muestra una descripción de las prestaciones
del sensor en cuanto a la relación SNR (para cada una de sus 224 bandas) a lo largo de los años
en los que el sensor ha estado en funcionamiento [38].
Figura 2.4: Relación señal-ruido (SNR) en los diferentes canales de AVIRIS a lo largo de los últimos
años (reproducido con permiso de Robert O. Green, investigador principal del proyecto AVIRIS)
2.2. TÉCNICAS DE ANÁLISIS HIPERESPECTRAL
Paı́s
Resolución espacial
Resolución temporal
Rango espectral
Resolución espectral
Cobertura imágenes
Cobertura terrestre
Fecha lanzamiento
Tiempo de vida previsto
9
Hyperion1
EnMAP2
HyspIRI3
Estados Unidos
30 m
16 dı́as
400-2500 nm
10 nm
7,7 km
Parcial
2000
10 años
Alemania
30 m
4 dı́as
420-2450 nm
0,5-10 nm
30 km
Total
2012
6 años
Estados Unidos
60 m
18 dı́as
380-2500 nm
10 nm
120 km
Total
2018
6 años
Tabla 2.1: Caracterı́sticas de algunos sensores hiperespectrales ya en funcionamiento o que estarán
disponibles a corto plazo
A pesar de que AVIRIS puede considerarse como un sensor hiperespectral de referencia, existen
otros sensores hiperespectrales de gran relevancia para la comunidad cientı́fica. La tabla 2.1 presenta
algunas de las caracterı́sticas de otros sensores ya en funcionamiento o de puesta en funcionamiento
en breve.
2.2.
Técnicas de análisis hiperespectral
Como se comentaba en el apartado 2.1, la mayorı́a de las técnicas desarrolladas de análisis hiperespectral presuponen una mezcla a nivel de subpı́xel y se debe principalmente a la insuficiente
resolución espacial del sensor. Pero este fenómeno no es exclusivo del análisis hiperespectral, dado
que ocurre de forma natural en el mundo real, a todas las escalas, por lo que el diseño de técnicas
que sean capaces de modelarlo de forma adecuada resulta imprescindible. Dentro de las técnicas de
análisis hiperespectral podemos distinguir dos grupos, según el modelo de mezcla que suponen:
Modelo lineal: Asume que los elementos observados se relacionan de forma lineal durante el
proceso de observación (ver figura 2.5 (a)).
Modelo no lineal: Asume que los componentes se distribuyen de forma aleatoria, pudiendo
producirse incluso defectos de dispersión múltiple durante el proceso de observación (ver figura
2.5 (b)).
Figura 2.5: Representación de los modelos de mezcla en análisis hiperespectral: (a) Modelo de mezcla
lineal (b) Modelo de mezcla no lineal
En análisis hiperespectral, el modelo lineal de mezcla es el más utilizado, debido a su sencillez y
generalidad. Su objetivo es encontrar los vectores más extremos, conocidos como componentes espectralmente puros, pı́xeles puros o endmembers, y utilizarlos para “desmezclar” el resto de pı́xeles de la
imagen mediante algún modelo de mezcla (linear mixture model ). En este modelo, cada pı́xel puede
1 http://eo1.gsfc.nasa.gov
2 http://www.enmap.org
3 http://hyspiri.jpl.nasa.gov
10
CAPÍTULO 2. ANTECEDENTES
expresarse como una combinación de las firmas espectrales asociadas a los endmembers. Ası́ pues, es
crucial saber identificar los endmembers adecuadamente.
El modelo lineal de mezcla puede interpretarse de forma gráfica en un espacio bidimensional
utilizando un diagrama de dispersión entre dos bandas poco correlacionadas de la imagen, tal y como
se muestra en la figura 2.6). En ella puede apreciarse que todos los puntos de la imagen quedan
englobados dentro del triángulo formado por los tres puntos más extremos (elementos espectralmente
más puros). Los vectores asociados a estos puntos constituyen un nuevo sistema de coordenadas
con origen en el centroide de la nube de puntos, de forma que cualquier punto de la imagen puede
expresarse como combinación lineal de los puntos más extremos, siendo éstos seleccionados como
mejores candidatos a ser endmember [6].
Figura 2.6: Interpretación gráfica del modelo lineal de mezcla
Los algoritmos de extracción de firmas espectrales puras se pueden clasificar atendiendo a varios
criterios como el enfoque (estadı́sticos y geométricos) y la hipótesis de partida (presencia o ausencia de
endmembers), entre otros. Destacamos la clasificación según la información considerada, que agrupa
a los algoritmos de extracción de endmembers en dos grupos:
Algoritmos basados en la información espectral: Realizan la búsqueda de los pı́xeles más
puros considerando solo la información espectral.
Algoritmos basados en la información espectral y espacial: durante la búsqueda de los
endmembers combinan el uso de la información espacial y espectral (generalmente mediante
morfologı́a matemática o crecimiento de regiones).
El algoritmo paralelizado en el marco de este trabajo es el Pixel Purity Index o PPI. Este algoritmo se incluye dentro de los algoritmos basados en la información espectral. Otros algoritmos que
pertenecen a este grupo atendiendo a la misma clasificación son el Orthogonal Subspace Projection
(OSP) y el N-FINDR. Para conocer el funcionamiento de estos algoritmos se describen brevemente a
continuación.
2.2.1.
Pixel Purity Index (PPI)
El algoritmo Pixel Purity Index o PPI [7] fue desarrollado por Boardman, Kruse y Green en 1993 y
se basa en la generación repetitiva de vectores unitarios o skewers con orientación aleatoria en la nube
de puntos que forman la imagen hiperespectral. Cada punto de la imagen hiperespectral se proyecta
sobre cada skewer identificando los puntos extremos en la dirección definida por éste e incrementando
un contador asociado a estos puntos. Tras la ejecución de un número de iteraciones determinado se
obtiene una imagen de pureza formada por los valores de los contadores asociados a cada pı́xel de
resolución espacial de la imagen. El conjunto final de endmembers se extrae a través de un proceso
interactivo de análisis y visualización.
Este algoritmo ha sido objeto de paralelización en el marco de este trabajo y se definirá con más
detalle en el capı́tulo 4.
2.2. TÉCNICAS DE ANÁLISIS HIPERESPECTRAL
2.2.2.
11
Orthogonal Subspace Projection (OSP)
El algoritmo Orthogonal Subspace Projection o OSP fue desarrollado por Harsanyi y Chang en
1994 [17] para encontrar firmas espectrales utilizando el concepto de proyecciones ortogonales [34]. El
algoritmo hace uso del concepto de proyección ortogonal, que viene dado por la fórmula 2.1, donde U
es una matriz de firmas espectrales, UT es la traspuesta de dicha matriz e I es la matriz identidad.
PU⊥ = I − U (UT U )−1UT
(2.1)
El proceso efectuado por el algoritmo puede resumirse en los siguientes pasos:
1. Seleccionar el vector más brillante de la imagen como pı́xel inicial (primer endmember ).
2. Aplicar un operador de proyección ortogonal al resto de los pı́xeles de la imagen para identificar
aquel que sea más ortogonal con respecto al primer pı́xel seleccionado (segundo endmember ).
3. Aplicar de nuevo un operador de proyección ortogonal al resto de pı́xeles para identificar aquel
que sea más ortogonal a los dos endmembers seleccionados previamente.
4. Repetir el proceso hasta que seleccionemos el número de endmembers deseado.
Figura 2.7: Representación gráfica del funcionamiento del algoritmo Orthogonal Subspace Projection
(OSP)
2.2.3.
N-FINDR
El algoritmo N-FINDR fue desarrollado por Winter en 2003 y utiliza una técnica basada en
identificar los endmembers como los vértices del simplex de mayor volumen que puede formarse en
el conjunto de puntos. N-FINDR no trabaja con todo el cubo de datos sino con una simplificación
del mismo a tantas bandas como endmembers se deseen encontrar. Para este tipo de reducciones
se suele utilizar la técnica Principal Component Analysis o PCA [18] o Minimum Noise Fraction o
MNF [41]. El único parámetro que tiene este algoritmo es el número de endmembers a identificar. El
funcionamiento del algoritmo se describe en los siguientes pasos:
1. Aplicar una reducción dimensional empleando el algoritmo PCA, que ordena las bandas de la
imagen en términos de la varianza, o el MNF, que ordena las bandas de la imagen en términos
de el ratio señal/ruido.
2. Realizar una selección inicial de N endmembers de forma aleatoria.
3. Probar cada pı́xel de la imagen en la posición de cada posible endmember manteniendo aquellos
reemplazamientos que resulten en un incremento del volumen contenido en el hiperpolı́gono
formado por los endmembers.
4. Repetir el proceso hasta que no se produzcan reemplazamientos.
12
CAPÍTULO 2. ANTECEDENTES
Figura 2.8: Representación gráfica del funcionamiento del algoritmo N-FINDR
2.3.
Necesidad de pararelismo
El proceso de captura de datos por los sensores hiperespectrales de observación remota de la
Tierra produce enormes cantidades de datos de gran dimensionalidad que deben ser almacenados y
tratados de forma eficiente. Instituciones como NASA o la Agencia Espacial Europea (ESA) producen
del orden de Terabytes de datos hiperespectrales diariamente y la falta de infraestructuras dedicadas
al procesamiento de estos datos está dando lugar a que una parte significativa de los mismos acabe
siendo almacenada en una base de datos para su procesamiento en el futuro. Esto en ocasiones no
se materializa debido al alto coste computacional que supone el almacenamiento, procesamiento y
distribución de este tipo de imágenes de forma eficiente.
Los algoritmos de análisis hiperespectral anteriormente descritos se basan en operaciones matriciales muy costosas desde el punto de vista computacional [32]. Sin embargo, el carácter repetitivo de
estas operaciones las hace susceptibles a ser paralelizadas, con el fin de aumentar el rendimiento de
los algoritmos y disminuir el tiempo de generación del resultado, algo esencial teniendo en cuenta los
campos de aplicación del análisis hiperespectral como la detección de incendios, el control de vertidos
a la atmósfera y el agua y la detección de objetivos militares, entre otros.
Las técnicas de computación paralela han sido ampliamente aplicadas al procesamiento de imágenes de gran dimensionalidad, facilitando la obtención de tiempos muy reducidos y pudiendo utilizar
diferentes tipos de arquitecturas [33, 39, 27]. Acualmente, debido a la facilidad de acceso a arquitecturas paralelas de bajo coste, como GPUs, y a los servicios de computación de altas prestaciones
ofrecidos por los proveedores de Cloud Computing como Amazon, existe actualmente una comunidad de investigadores muy activa dedicada al desarrollo de algoritmos eficientes de procesamiento de
imágenes hiperespectrales.
Este trabajo tiene como principal objetivo la implementación de una versión del algoritmo PPI
para clúster de GPUs, una arquitectura paralela resultado de la incorporación de la tarjetas GPUs a
un clúster de computadores de memoria distribuida. El siguiente capı́tulo describe el uso de clúster
de computadores y de GPUs para el procesamiento de imágenes hiperespectrales y describe en detalle
la infraestructura utilizada para el desarrollo y la ejecución de las pruebas realizadas en el marco de
este trabajo: el clúster de GPUs de CETA-CIEMAT.
Capı́tulo 3
Arquitecturas paralelas
consideradas
En este apartado se describen las caracterı́sticas de la arquitectura paralela objetivo: el clúster
de GPUs de CETA-CIEMAT, haciendo un repaso de los clúster de computadores y de las tarjetas
gráficas programables (GPUs), que son la base de esta solución hı́brida de cómputo, enumerando sus
ventajas e incovenientes. Se presentan también las herramientas de programación utilizadas para el
desarrollo de la implementación de PPI para el clúster de GPUs: la librerı́a Message Passing Interface
(MPI) y el entorno de desarrollo para GPUs Compute Unified Device Architecture (CUDA) de Nvidia.
3.1.
Procesamiento paralelo en clúster
Hoy en dı́a todavı́a no se conoce el origen exacto del término computación clúster. Algunos estudios
atribuyen dicho origen a las investigaciones realizadas por Amdhal [5], quien acuñó las bases del
procesamiento paralelo con la denominada Ley de Amdhal, la cual permite determinar la mejora
máxima que puede alcanzar un sistema cuando sólo una parte del mismo se mejora. Esta ley permite
describir de forma matemática el factor de aceleración o speedup que se puede conseguir paralelizando
un bloque de código en una determinada arquitectura. La fórmula 3.1 define el cálculo del speedup
conseguido de una versión paralela de un cógido frente a su versión secuencial. T1 es el tiempo de
ejecución de código secuencial y TP el tiempo de la versión paralela.
S = T1 /TP
(3.1)
En la actualidad el término clúster de computadores o clúster se refiere habitualmente a una red
de computadores (interconectados entre sı́ mediante una red de comunicación) que trabajan de forma
conjunta como un único recurso computacional, abstrayendo al usuario de la infraestructura fı́sica
de interconexión y siendo a ojos de éste una sola máquina con una capacidad de cómputo mayor
a la habitual. Un ejemplo de clúster utilizado para el procesamiento de datos hiperespectrales es
el supercomputador Columbia, localizado en el centro Ames Research Center (ARC) de NASA, en
California (Estados Unidos). Consta de 10.240 procesadores y conexión de red de baja latencia de tipo
Infiniband. Otro ejemplo de clúster de computadores utilizado esporádicamente para el tratamiento de
datos hiperespectrales es el Mare Nostrum, localizado en el Barcelona Supercomputing Center (BSC)
en Barcelona (España). El Mare Nostrum también consta de 10.240 núcleos de computación y conexión
a red de baja latencia de tipo Myrinet (ver figura 3.1).
Los clúster de computación han supuesto desde su aparición una revolución en el cálculo cientı́fico,
principalmente por sus capacidades de procesamiento de grandes volúmenes de datos. Pueden estar
compuestos por máquinas con la misma configuración hardware y de sistema operativo (clúster homogéneo), de diferente configuración hardware y sistemas operativos similares (clúster semi-homogéneo)
o bien disponer de hardware de diferente rendimiento con distintos sistemas operativos (clúster heterogéneo).
A continuación se enumeran algunas de las caracterı́sticas genéricas ofrecidas por este tipo de
infraestructuras:
Alto rendimiento: Los clústers ofrecen un rendimiento superior, lo que los hace indicados
para la resolución de problemas de mayor tamaño. La capacidad de cálculo de un clúster es
13
14
CAPÍTULO 3. ARQUITECTURAS PARALELAS CONSIDERADAS
Figura 3.1: Supercomputador Columbia, localizado en el Ames Research Center de NASA, California
(Estados Unidos)
generalmente superior a la de un ordenador más caro que el conjunto de máquinas que componen el clúster [8]. Además, es relativamente sencillo incorporar nuevas máquinas a la red de
computadores para aumentar la capacidad de cómputo y realizarlo de manera transparente al
usuario.
Alta disponibilidad: En un clúster, el fallo de uno de los equipos conectados a la red no supone
la pérdida total del servicio. Al contar con múltiples nodos, en caso de error es relativamente fácil
extraer el nodo con problemas de la red y reemplazarlo por otro, sin que afecte al funcionamiento
del clúster.
Coste: Generalmente, un clúster se compone de múltiples máquinas de medio-bajo coste, fabricados a gran escala y que utilizan sistemas operativos estándar. En general, la construcción
de un clúster es sencilla y relativamente económica, especialmente en los clúster homogéneos.
En el caso de los clústers heterogéneos, es posible incluso implementar algoritmos capaces de
administrar la carga de cada nodo de acuerdo a las caracterı́sticas del mismo [30, 31]. Por otro
lado, los costes de mantenimiento de un clúster son altos, debido a la demanda energética de
los nodos de cálculo, del propio hardware de interconexión y de los sistemas de refrigeración
necesarios para su adecuado funcionamiento. Además, al estar basados en máquinas de bajo
coste, por lo general es necesario disponer de un gran espacio fı́sico para su instalación.
La popularidad de uso que alcanzaron los clústers provocó la necesidad de definir una serie de
librerı́as estándar que permitiesen a los usuarios y desarrolladores la utilización y control de este tipo
de sistemas de una manera más o menos intuitiva y estándar, que permitiesen la mayor abstracción
posible respecto al hardware de ejecución. Ejemplos de este tipo de librerı́as son Parallel Virtual
Machine (PVM) [40] y Message Passage Interface (MPI) [24]. Ésta última es la librerı́a utilizada
mayoritariamente por los clústers actuales, por lo que se describe brevemente a continuación.
3.1.1.
Message Passage Interface (MPI)
Según [3], MPI es un estándar que define la sintaxis y la semántica de las funciones contenidas en
una biblioteca de paso de mensajes diseñada para ser utilizada en programas que exploten la existencia
de múltiples procesadores. Actualmente es el estándar de comunicación entre los nodos que ejecutan
un determinado código en un sistema de memoria distribuida, como los clúster de computadores. MPI
no consiste en una implementación de una librerı́a, sino que se considera un protocolo de comunicación
entre máquinas. Debido a esto, existen multitud de implementaciones o “sabores” desarrollados en
diferentes lenguajes como C, C++, Fortran y ADA, entre otros. La principal ventaja de MPI sobre
otras bibliotecas de paso de mensajes es que se asegura la portabilidad de los programas que hacen uso
de la librerı́a, siempre que no se haga uso de funciones especı́ficas de una implementación. Además,
las implementaciones de MPI están optimizadas para una infraestructura hardware especı́fica (por
3.1. PROCESAMIENTO PARALELO EN CLÚSTER
15
ejemplo, una red de comunicaciones Infiniband), aumentando por consiguiente el rendimiento de las
operaciones de comunicación para dicha infraestructura.
Los mensajes en MPI están compuestos por el cuerpo, que contiene los datos que van a ser enviados,
y su envoltura, que contiene el emisor y el receptor del mensaje. El cuerpo de un mensaje MPI
está formado por tres partes:
Buffer: Dirección del área de memoria donde se encuentran los datos a enviar o donde se
almacenarán los datos recibidos.
Tipo de dato: Corresponde al tipo de los datos que se envı́a. En los casos simples es un tipo
primitivo, análogo a los tipos de cualquier lenguaje de programación como C. En los casos de
aplicaciones avanzadas, puede ser incluso una estructura formada por varios tipos de datos.
Contador: Es un número de secuencia, que junto con el tipo de datos, permite agrupar datos
de un mismo tipo en un solo mensaje. MPI estandariza los tipos de datos primitivos, evitando
que el desarrollador del código se preocupe por las diferencias que existan entre ellos cuando
interaccionan varias plataformas.
Los mensajes MPI contienen la fuente del mensaje, su destinatario, e información adicional que
se necesite para la transmisión y entrega del mensaje. Esta información consta de un identificador o
comunicador al que pertenecen los procesos fuente y destino y una etiqueta también llamada tag que
sirve para identificar el mensaje entre el conjunto de mensajes que pueda recibir el proceso.
El número de procesos requeridos para la ejecución del programa se asigna previamente, y no
se crean procesos adicionales mientras dure la ejecución del mismo. A cada proceso se le asigna un
identificador, accesible a través de la variable rank, en el rango {0 . . . P − 1} donde P es el número de
procesos. A través del uso de rank se puede determinar qué proceso ejecuta una determinada porción
de código. Esta variable contiene el identificador asignado a un proceso dentro del comunicador al
que pertenece. Por otro lado, el comunicador engloba la colección de procesos que pueden enviarse
mensajes entre sı́. Existe un comunicador básico llamado MPI COMM WORLD (nombre de la macro
en C) que agrupa todos los procesos activos durante la ejecución de una determinada aplicación.
Las funciones que define MPI se pueden clasificar en tres grupos diferenciados:
Funciones de inicialización, administración y finalización de las comunicaciones: Estas
funciones permiten la inicialización y finalización de la biblioteca de mensajes, la obtención del
número de procesos y el identificador del proceso (rank ) dentro del comunicador. Son cuatro
funciones que se utilizan en todo programa MPI, a saber:
• MPI Init: Inicializa la sesión MPI. Esta función debe utilizarse antes de cualquier otra
llamada a una función MPI.
• MPI Comm size: Obtiene el número total de procesos que pertenece a un comunicador.
• MPI Comm rank: Obtiene el identificador del proceso o rank dentro del comunicador al
que pertenece.
• MPI Finalize: Finaliza la sesión MPI. Esta función debe ser la última de la librerı́a
utilizada dentro de un programa MPI. Permite liberar la memoria utilizada por la librerı́a.
Funciones de transferencia de datos punto a punto
• MPI Send: Permite el envı́o de información desde un proceso a otro. Esta función es
bloqueante, es decir, que el proceso que realiza la llamada se bloquea hasta que la operación
de comunicación se complete. Este tipo de llamadas devuelve un código que indica el éxito
o el fracaso de la operación.
• MPI Recv: Permite la recepción de información desde otro proceso. Es una operación
bloqueante.
• MPI Isend: Versión de MPI Send no bloqueante. Las llamadas no bloqueantes deben
finalizar explı́citamente con llamadas como MPI Wait.
• MPI IRecv: Versión de MPI Recv no bloqueante.
• MPI Wait: Llamada bloqueante que finaliza cuando una operación de envı́o o recepción
se completa.
16
CAPÍTULO 3. ARQUITECTURAS PARALELAS CONSIDERADAS
• MPI Test: Permite comprobar si una operación de envı́o o recepción ha finalizado. Tras
comprobar el estado retorna.
Funciones de transferencia a varios procesos: Estas funciones son conocidas como operaciones colectivas o grupales, ya que están orientadas a un grupo de procesos. Este tipo de funciones
incluyen operaciones de difusión (broadcasting), reparto (scattering), recolección (gathering) y
reducción (reduction). Las funciones más populares de este grupo son las siguientes:
• MPI Barrier: Permite realizar una operación de sincronización de procesos. Esta sincronización no conlleva ningún intercambio de información y suele emplearse para dar por
finalizada una etapa del programa esperando a que todos los procesos finalicen sus tareas
antes de comenzar la siguiente.
• MPI Bcast: Permite a un proceso enviar una copia de sus datos al resto de procesos dentro del grupo definido por su comunicador. En el caso del comunicador global
(MPI COMM WORLD), se enviarı́a a todos los demás procesos.
• MPI Scatter: Es similar a la operación MPI Bcast, pero en este caso el dato a enviar se
reparte de forma equitativa entre el resto de procesos.
• MPI Gather: Es la operación contraria a MPI Scatter. Permite a un proceso realizar una
recolección de datos de un conjunto de procesos, agrupándolos en un área de memoria
común.
• MPI Reduce: Permite la recolección de datos de un conjunto de procesos, con la singularidad de que se realiza una combinación de éstos (por ejemplo, una suma o un promedio)
y se genere un resultado.
La especificación actual de MPI es la 2.2 y fue aprobada por el MPI Forum en Septiembre del
2009. Aunque es la última especificación, todas las funciones descritas en este apartado pertenecen a
la primera especificación, cuya última versión (1.3) fue aprobada en Julio de 2008. La segunda especificación consta mayoritariamente de funciones avanzadas de comunicación, por lo que actualmente
existe un gran grupo de usuarios que todavı́a utilizan la primera versión al cubrir ésta sus necesidades.
Como dato adicional, la tercera versión de la especificación está en proceso de borrador y se estima que
se aprobará en aproximadamente un año (2013). Esta nueva especificación incluirá, por ejemplo, las
versiones no bloqueantes de las operaciones colectivas. El MPI Forum ha publicado una web1 donde
se puede encontrar información del estado del borrador y de las discusiones sobre MPI 3.0.
Para finalizar, hay que comentar que la mayorı́a de las funciones descritas en este apartado se han
utilizado en las implementaciones del algoritmo PPI para clúster y clúster de GPUs implementadas
en el marco de este trabajo. Se describirá su uso en detalle en el capı́tulo 5.
3.2.
Procesamiento paralelo en GPUs
Una Unidad de Procesamiento Gráfico o GPU es un coprocesador diseñado inicialmente para
el procesamiento de gráficos principalmente cuya misión es liberar a la CPU en aplicaciones de uso
intensivo de gráficos como juegos y otras aplicaciones 3D interactivas. Recientemente, estos dispositivos
han dejado de ser considerados de uso exclusivo para procesamiento gráfico y están siendo utilizados
para computación de propósito general propiciado principalmente por la aparición de herramientas
y librerı́as que simplifican el desarrollo de programas que explotan las capacidades de cálculo de las
GPUs.
En la actualidad, existen dos fabricantes principales de tarjetas GPUs, a saber, Nvidia y AMD,
pero es el primero el que está liderando el mercado de las GPUs aplicadas a la computación de
altas prestaciones gracias al framework Compute Unified Device Architecture (CUDA), que facilita el
desarrollo de aplicaciones que explotan las capacidades de cómputo de sus productos. Por este motivo
cuando en este apartado se haga referencia a una GPU, se referirá a una GPU de Nvidia que soporte
CUDA.
Una GPU se compone de un conjunto de multiprocesadores que podrı́an clasificarse dentro de los
de tipo SIMD (Single Instruction Multiple Data) [12]. Cada uno de los multiprocesadores que compone
la GPU cuenta con los siguientes elementos de memoria (ver figura 3.2):
Un conjunto de registros por procesador.
1 http://meetings.mpi-forum.org/MPI
3.0 main page.php
3.2. PROCESAMIENTO PARALELO EN GPUS
17
Figura 3.2: Esquema hardware de una GPU
Una memoria compartida o caché paralela, que es compartida por todos los procesadores.
Una caché de constantes y otra de texturas, ambas de solo lectura.
La diferencia fundamental entre una GPU y una CPU radica en que la primera invierte más
transistores para el procesamiento de datos que para caché y control de flujo que la segunda, como
puede verse en la figura 3.3. Esto significa que una GPU está preparada especialmente para afrontar
problemas que pueden resolverse de forma paralela, y necesita muy poco control de flujo ya que estos
problemas se basan fundamentalmente en la ejecución de un mismo programa a cada elemento de
un conjunto de datos. Cabe destacar que a medida que van evolucionando GPUs y CPUs, tanto la
capacidad de procesamiento como el ancho de banda de las primeras crece de forma exponencial (ver
figuras 3.4 y 3.5).
Figura 3.3: Arquitectura GPU frente a CPU
Aun ası́, la comparación directa de rendimiento CPU y GPU no es del todo correcta dado que
las mediciones se basan en la ejecución de benchmarks de programas especı́ficos. Las GPUs, al ser
un hardware especializado, no implementan operaciones ni instrucciones de propósito general que
implementan las CPUs y no están destinadas a sustituir a éstas en ningún momento.
En el siguiente apartado se describen las caracterı́sticas fundamentales de Nvidia CUDA, utilizado
para todos los desarrollos para GPU que se han realizado en el marco de este trabajo.
18
CAPÍTULO 3. ARQUITECTURAS PARALELAS CONSIDERADAS
Figura 3.4: Operaciones en coma flotante CPU frente a GPU
Figura 3.5: Ancho de banda de memoria en GB/s de CPU frente a GPU
3.2.1.
NvidiaTM CUDA
CUDA son las siglas de Compute Unified Device Architecture y hace referencia tanto a un compilador como a un conjunto de herramientas de desarrollo creadas por Nvidia que permiten a los
programadores usar una variación del lenguaje de programación C para aprovechar la potencia de
computación masiva en paralelo de las GPUs de Nvidia para propósito general. CUDA presenta un
nuevo modelo de programación en paralelo que permite resolver problemas complejos de forma más
eficiente que si se tratase de una CPU.
Una de las singularidades es que utiliza un modelo de computación paralela donde cada uno de los
procesadores ejecuta un mismo bloque de código o kernel sobre diferentes datos en paralelo. CUDA
consigue el paralelismo a través de tres elementos estructurados y anidados: hilos, bloques y grids. Los
hilos se agrupan en bloques y los bloques en grids (ver figura 3.6). Un hilo o thread es la unidad más
básica e indivisible de paralelismo en CUDA. Estos elementos son utilizados para ejecutar bloques de
código organizados según el criterio del desarrollador, permitiendo elegir una configuración adecuada
para maximizar el rendimiento. La GPU permite definir un solo grid para cada ejecución de un kernel,
en el cual pueden definirse tantos bloques dentro del grid, e hilos dentro de cada bloque como se desee
(teniendo en cuenta las limitaciones de la versión de la arquitectura). El número de hilos de un bloque
será el mismo para la invocación de un kernel, pudiendo ser diferente para las siguientes invocaciones
que vayan a ser ejecutadas. La configuración de grids y bloques se puede definir utilizando varias
dimensiones, lo que permite afrontar problemas complejos de una manera más sencilla (por ejemplo,
el procesamiento de un cubo de datos hiperespectrales).
En cada multiprocesador de la GPU solamente puede ejecutarse un mismo bloque de código a la
vez, y mientras éste no termine no podrá ejecutarse otro. Por lo tanto, es muy importante controlar
qué hacen los hilos durante la ejecución y maximizar el número de hilos corriendo a la vez para
obtener el mayor rendimiento posible. La diferencia de estos hilos frente a los de la CPU es que
3.2. PROCESAMIENTO PARALELO EN GPUS
19
Figura 3.6: Esquema del modelo de programación CUDA
son extremadamente ligeros y operaciones como su creación y el cambio de contexto tienen un coste
insignificante. Las GPUs pueden manejar miles de hilos frente a los procesadores convencionales, que
solo pueden manejar unos pocos. Como cada hilo de un bloque ejecuta el mismo bloque de código,
el identificador de éstos puede ser utilizado para realizar parte del control de flujo y para calcular la
dirección de memoria de inicio de los datos a procesar. Éste es el motivo por el que CUDA facilita de
manera notable la realización de cálculos vectoriales y matriciales, muy utilizados en los algoritmos
de procesamiento de imágenes hiperespectrales.
Otra caracterı́stica de CUDA es que permite la compartición de datos entre los hilos de un mismo
bloque para evitar cálculos redundantes y compartir accesos a memoria con el fin de aumentar el
ancho de banda en dichos accesos. Estas caracterı́sticas vienen dadas principalmente por el modelo de
memoria.
El modelo de memoria de CUDA (ver figura 3.7) define una jerarquı́a de memoria para el acceso a
los datos. Siguiendo los elementos descritos en el modelo de programación, cada hilo posee su propia
memoria privada, de tiempo de acceso muy rápido. Por otro lado, cada bloque tiene acceso a su propia
memoria, que es compartida y está disponible para todos los hilos que componen el bloque. El tiempo
de vida de la memoria de hilo y de bloque es el mismo que la del elemento en sı́, es decir, cuando
el elemento termine su ejecución ésta dejará de estar disponible. En el nivel más alto de la jerarquı́a
se encuentra la memoria global, compartida entre todos lo hilos en ejecución en la GPU. Además,
existen dos tipos de memoria adicionales de solo lectura: la memoria de texturas y la memoria de
constantes. Estas dos memorias son globales a todos los hilos y están optimizadas para utilizarse con
tipos de datos especı́ficos. Estas tres memorias (global, constantes y texturas) tienen el mismo tiempo
de vida que la aplicación que las invoca, perdurando entre diferentes invocaciones de kernels dentro
de la misma ejecución de la aplicación.
Destacar que desde la aparición de la gama de GPUs Fermi, se proporciona un nuevo nivel de
memoria basado en cachés. Cada hilo, además de tener acceso a su memoria privada y a la memoria
compartida de bloque, tiene acceso a una caché de nivel 1 (L1) con velocidad de acceso similar a
la memoria compartida. De hecho, CUDA proporciona una función (cudaFuncSetCacheConfig) que
permite al desarrollador aumentar para cada kernel el tamaño de la memoria caché L1 en detrimento
del tamaño de la memoria compartida o viceversa. Por otro lado también se implementa un segundo
nivel de memoria caché (L2), de 768KB de tamaño para los chips de 512 cores, que cubre tanto la
memoria global de la GPU como la memoria del sistema. Una de las caracterı́sticas que presenta este
sistema de caché L2 que no está presente en las CPUs es la inclusión de un conjunto de instrucciones
de lectura-modificación-escritura de memoria que son atómicas y, por lo tanto, muy adecuadas para
20
CAPÍTULO 3. ARQUITECTURAS PARALELAS CONSIDERADAS
Figura 3.7: Esquema del modelo de memoria CUDA
gestionar el acceso a datos compartidos entre los diferentes bloques o incluso kernels. La finalidad
principal de las cachés L1 y L2 es ayudar a mejorar el rendimiento de los accesos aleatorios a memoria.
3.2.2.
Escritura de programas en CUDA
Una caracterı́stica importante del desarrollo de programas para GPUs es que tienen que desarrollarse en CUDA. Al ser una variación del lenguaje C no resulta especialmente complicado para un
desarrollador con experiencia en este lenguaje. El desarrollo de programas en CUDA se realiza principalmente utilizando un lenguaje de alto nivel como C o C++ (se pueden utilizar otros ya que existen
wrappers especı́ficos para otros lenguajes) e implementando las funciones que se deseen ejecutar en la
GPU utilizando las extensiones proporcionadas por CUDA. A continuación se describen los tipos de
datos y funciones, variables predefinidas y funciones más comúnmente utilizadas en el desarrollo de
estos programas.
Declaración de funciones:
•
device : Indica que una función será ejecutada por la GPU e invocada desde un kernel.
•
global : Indica que una función será ejecutada por la GPU y será llamada por el código
secuencial. Es el modificador utilizado en la declaración de un kernel.
•
host : Indica que una función será ejecutada por la CPU y será llamada por el código
secuencial. Es el modificador aplicado por omisión.
Declaración de variables:
•
device : La variable residirá en memoria global, siendo accesible por todos los threads
de cualquier grid durante el tiempo de vida de la aplicación.
•
constant : La variable residirá en memoria constante, siendo accesible por todos los
threads de cualquier grid durante el tiempo de vida de la aplicación. Es de solo lectura.
•
shared : La variable residirá en memoria compartida y será accesible por todos los hilos
de un bloque durante el tiempo de vida del mismo.
Variables predefinidas:
• dim3 gridDim: Dimensiones de un grid. Un grid puede tener 3 dimensiones como máximo
(x, y y z). En las GPUs actuales, el máximo valor para una dimensión es 65.535 por lo que
el número máximo de bloques en una grid será 65535 × 65535 × 65535.
• uint3 blockIdx: Índice de un bloque dentro de un grid. Almacena los valores para las 3
dimensiones en los atributos x, y y z.
3.3. EL CLÚSTER DE GPUS DE CETA-CIEMAT
21
• dim3 blockDim: Dimensiones de un bloque. Al igual que los grids, pueden tener hasta 3
dimensiones. Un bloque puede tener 1.024 hilos como máximo (x × y × z ≤ 1024, z ≤ 64).
• uint3 threadIdx: Índice de un hilo dentro de un bloque. Almacena los valores para las 3
dimensiones en los atributos x, y y z.
• int warpSize: Número de hilos en un warp. Un warp es un grupo de hilos paralelos que
controla un multiprocesador de una GPU. Un warp tiene 32 hilos.
Algunas funciones básicas:
• cudaMalloc: Reserva memoria en la GPU. Es similar a la función malloc de C para la
CPU.
• cudaFree: Libera la memoria de la GPU reservada para una dirección de memoria dada.
Es similar a la función free de C para la CPU. Si no se libera memoria entre ejecuciones
de kernels el espacio permanece ocupado.
• cudaMemcpy: Permite transferir memoria de manera bloqueante. Principalmente se utiliza
para transferencias de host a GPU y viceversa, aunque se puede utilizar de host a host
para, por ejemplo, copiar memoria a un área no paginable.
• cudaMemcpyAsync: Similar a la función cudaMemcpy pero no es bloqueante.
•
syncthreads: Sirve para establecer un punto de sincronización (barrera) entre los hilos
de un bloque.
La mayorı́a de estas funciones y variables se han utilizado en la implementación paralela del
algoritmo PPI para clúster de GPUs desarrollada bajo el marco de este trabajo. En el apartado
siguiente, se describe la infraestructura utilizada parar el desarrollo y la ejecución de las pruebas; el
clúster de GPUs de CETA-CIEMAT.
3.3.
El clúster de GPUs de CETA-CIEMAT
Tras la introducción realizada en los apartados anteriores a computación clúster y GPU, en este
apartado se describe una arquitectura de computación de reciente aparición que surge de la hibridación
de ambas soluciones de cómputo: el clúster de GPUs. Un clúster de GPUs es el resultado de equipar
cada nodo de cómputo de un clúster de computadores con una o varias GPU. Esta nueva arquitectura
pretende aprovechar las altas capacidades de cómputo de las tarjetas GPU para incrementar el rendimiento global de una infraestructura de tipo clúster. La incorporación de este tipo de dispositivos es
muy sencilla y puede realizarse sin que ello suponga una gran inversión económica, pudiendo incluso
ser incorporadas a una infraestructura clúster ya existente.
Tal es la potencia de cálculo alcanzada por este tipo de arquitectura de cómputo que ya copan algunas de las posiciones privilegiadas dentro del ránking de supercomputadores Top5002 . En el momento
de la escritura de esta memoria, el primer clúster de GPUs que podemos encontrar es el Tianhe-1A
(ver figura 3.8), en la posición 5, localizado en el National Supercomputing Center in Tianjin (China).
En el momento de su puesta en marcha (Octubre de 2010) llegó a alcanzar el número 1 del Top500.
Este supercomputador se compone de 14.336 nodos de CPU y 7.168 Nvidia Tesla M2050, llegando a
alcanzar los 2,507 Petaflops. En la actualidad, se utiliza para simulación aérea y extracción de petróleo
entre otros usos.
En lo que a España respecta, el clúster de GPUs más potente que existe a dı́a de hoy es MinoTauro
(ver figura 3.9), ubicado actualmente en el Centro Nacional de Análisis Genómico (CNAG) de Barcelona y perteneciente al Barcelona Supercomputing Center (BSC). Está formado por 128 CPUs de seis
núcleos y 64 tarjetas GPU Nvidia Tesla M2090. Actualmente es el supercomputador más eficiente de
Europa.
Otra instalación española a destacar es el clúster de GPUs del Centro Extremeño de Tecnologı́as
Avanzadas (CETA), ubicado en Trujillo (Cáceres). El CETA es una subsede del Centro de Investigaciones Energéticas, Medioambientales y Tecnológicas (CIEMAT) dedicado a la investigación, desarrollo y
servicio en tecnologı́as de la información y de las comunicaciones en beneficio de la ciencia, la industria
y la sociedad en general, en los ámbitos extremeño, español, europeo y latinoamericano. CIEMAT es
un Organismo Público de Investigación adscrito al Ministerio de Economı́a y Competitividad para la
2 http://www.top500.org/
3 Fuente:
http://goo.gl/M0fdo
22
CAPÍTULO 3. ARQUITECTURAS PARALELAS CONSIDERADAS
Figura 3.8: Supercomputador Tianhe-1A3
Figura 3.9: Clúster de GPUs MinoTauro del BSC4
investigación de excelencia en materias de energı́a y medio ambiente, ası́ como en múltiples tecnologı́as
de vanguardia y en algunas áreas de investigación básica.
El clúster de GPUs de CETA se compone de dos subsclústers de GPUs (llamados comúnmente
clúster Tesla y clúster Fermi), donde cada uno cuenta con GPUs pertenencientes a las generaciones
Tesla y Fermi de NVIDIA. El clúster Tesla está compuesto de 17 nodos de cómputo y está destinado
al desarrollo y pruebas de programas, ası́ como para el aprendizaje de uso del clúster. Por otro lado, el
clúster Fermi está compuesto de 32 nodos de cómputo y está dedicado a la producción cientı́fica. Ambos
entornos usan una red de comunicaciones de tipo Infiniband. El clúster Tesla también es denominado
entorno de Test y el clúster Fermi entorno de Producción. Las figuras 3.11 y 3.12 muestran en detalle
los elementos del clúster y su disposición fı́sica.
Cada nodo del clúster está compuesto del siguiente equipamiento:
2 x Quad Core Intel Xeon 2,26 GHz.
24 GB SDRAM DDR3 1333MHz ECC.
500 GB SATA.
2 Nvidia Tesla C1060 (mitad de un TESLA S1070), para los nodos del entorno de Test y 2
Nvidia Tesla C2050 (mitad de un S2050) o 2 Nvidia Tesla C2070 (mitad de un S2070) para los
nodos del entorno de Producción.
Para la gestión y planificación de los trabajos que se envı́an al clúster se utiliza el software Simple
Linux Utility for Resource Management (SLURM). SLURM es un software de fuentes abiertas, tolerante a fallos y de alta escalabilidad orientado a clústers de computadores basados en Linux. Define
un conjunto de colas o entornos que agrupan los recursos del clúster (ver figura 3.10), permitiendo la
asignación de diferentes permisos y prioridades por cada entorno a los usuarios del clúster.
4 Fuente:
http://www.bsc.es/plantilla.php?cat id=44
3.3. EL CLÚSTER DE GPUS DE CETA-CIEMAT
23
Figura 3.10: Arquitectura del entorno HPC de CETA-CIEMAT (Imagen cedida por el Dr. Abel F.
Paz, Responsable de Infraestructura de CETA-CIEMAT)
El clúster de GPUS de CETA-CIEMAT es un clúster semi-homogéneo, ya que todos los nodos de
cómputo funcionan con el mismo sistema operativo (CentoOS 6.2 de 64 bits). El espacio de almacenamiento de usuario está basado en el sistema de ficheros distribuido LUSTRE. Soporta el uso de
MPI, utilizando el sabor MVAPICH 1.8 (implementación de MPI optimizada para redes Infiniband)
y CUDA en su versión 4.1. Los usuarios acceden al clúster a través de una máquina de login (loginhpc.ceta-ciemat.es), que contiene una gran variedad de compiladores ası́ como librerı́as de cálculo
cienfı́fico. Desde este nodo se compilan los programas y se envı́an al clúster para su ejecución.
Actualmente el clúster está siendo utilizado por diferentes grupos de investigación nacionales e
internacionales de diferentes disciplinas como Genómica, Fı́sica de Altas Energı́as, Dinámica de Fluidos
y Análisis de Imágenes Hiperespectrales, entre otras. En esta lı́nea de investigación, hay que comentar
24
CAPÍTULO 3. ARQUITECTURAS PARALELAS CONSIDERADAS
que el desarrollo y pruebas de las diferentes versiones paralelas del algoritmo PPI para clúster de
GPUs se han llevado a cabo satisfactoriamente utilizando la infraestructura de CETA-CIEMAT.
Figura 3.11: Disposición de los elementos hardware del clúster Tesla de GPUs de CETA-CIEMAT
(Imagen cedida por el Dr. Abel F. Paz, Responsable de Infraestructura de CETA-CIEMAT)
3.3. EL CLÚSTER DE GPUS DE CETA-CIEMAT
25
Figura 3.12: Disposición de los elementos hardware del clúster Fermi de GPUs de CETA-CIEMAT
(Imagen cedida por el Dr. Abel F. Paz, Responsable de Infraestructura de CETA-CIEMAT)
26
CAPÍTULO 3. ARQUITECTURAS PARALELAS CONSIDERADAS
Capı́tulo 4
Método
En este capı́tulo se describe el algoritmo Pixel Purity Index también conocido como PPI. Este
algoritmo es un conocido método de extracción de endmembers en imágenes hiperespectrales y multiespectrales. Este algoritmo ha sido seleccionado para este trabajo por su sencillez de implementación y
su elevado coste computacional. En capı́tulos posteriores se describen las diferentes implementaciones
paralelas para clúster de computadores, tarjetas GPU y clúster de GPUs utilizadas para el análisis de
rendimiento.
4.1.
Pixel Purity Index
El algoritmo Pixel Purity Index o PPI es uno de los algoritmos de selección de pı́xeles puros o
endmembers más conocidos. El algoritmo PPI [7] fue desarrollado por Boardman, Kruse y Green
en 1993 y posteriormente fue incorporado al software ENVI de Exelis Visual Information Solutions
(inicialmente desarrollado por Better Solutions Consulting, LLC).
El algoritmo parte de la generación de un conjunto amplio de vectores aleatorios N-dimensionales
llamados skewers. Cada punto de la imagen hiperespectral se proyecta en cada skewer y aquellos pı́xeles
que correspondan a los extremos en la dirección de dicho skewer son selecionados como candidatos a
firma espectral pura. Según crece el tamaño del conjunto de skewers, el número de pı́xeles seleccionados
también aumenta y algunos de los pı́xeles seleccionados previamente vuelven a serlo. Finalizado el
proceso para cada skewer, aquellos pı́xeles que han sido más veces seleccionados como candidatos, o
dicho en otras palabras, aquellos con mayor ı́ndice de pureza, son considerados como firmas espectrales
puras.
PPI pertenece al conjunto de los métodos interactivos, es decir, que necesita intervención del
usuario, y es el más representativo. Como se ha indicado anteriormente, su objetivo es localizar aquellos
puntos de la imagen que son espectralmente más puros. Se basa en la suposición de que los puntos
extremos del conjunto de pı́xeles son los mejores candidatos para ser utilizados como endmembers.
Los parámetros del algoritmo son los siguientes:
Una imagen multiespectral o hiperespectral a procesar.
El número de iteraciones a realizar, esto es, el tamaño del conjunto de skewers a generar.
Un valor umbral para seleccionar los pı́xeles puros.
Los siguientes pasos describen el funcionamiento del algoritmo:
1. Inicialmente, el algoritmo asigna un ı́ndice de pureza a todos los pı́xeles de la imagen. El contador
de selección de candidato como endmember se inicializa a 0 para cada pı́xel.
2. Posteriormente se genera un skewer o divisor. Es un vector unitario aleatorio cuyo objetivo es
particionar el conjunto de pı́xeles de la imagen.
3. Una vez generado el skewer, se proyectan todos los pı́xeles de la imagen sobre éste, identificando
los puntos extremos en la dirección definida por el vector unitario. El ı́ndice de pureza de los
pı́xeles seleccionados se incrementa en 1.
27
28
CAPÍTULO 4. MÉTODO
4. Se repiten los pasos del punto 2 al punto 3 tantas veces como indique el parámetro de entrada
número de iteraciones.
5. Una vez ejecutadas todas las iteraciones, se obtiene como resultado una imagen de pureza formada por los ı́ndices asociados a cada pı́xel de la imagen.
Figura 4.1: Selección de los pı́xeles extremos para un conjunto de skewers en el algoritmo PPI
6. En este momento, se aplica el parámetro de entrada valor umbral, seleccionando aquellos pı́xeles
de la imagen cuyo ı́ndice de pureza asociado es mayor que el valor umbral. Estos pı́xeles seleccionados son etiquetados como puros. La figura 4.1 muestra la selección de los pı́xeles extremos
para un caso sencillo con tres skewers y seleccionando aquellos pı́xeles cuyo ı́ndice de pureza es
mayor que 0.
7. Los pı́xeles seleccionados se cargan en una herramienta intereactiva llamada N-dimensional Visualizer, incluı́da en ENVI, la cual permite realizar diagramas de dispersión de los primeros
autovectores obtenidos tras la aplicación de una reducción de dimensionalidad (transformación
MNF) sobre los datos originales.
8. Finalmente, utilizando el N-dimensional Visualizer, el usuario escoge manualmente aquellos
pı́xeles o grupos de pı́xeles de la imagen que aparecen como extremos en proyecciones sucesivas, identificando un subconjunto de ellos que se etiquetarán como endmembers. En el caso de
seleccionar un grupo de pı́xeles, el valor del endmember se calculará a partir del espectro medio.
Una descripción analı́tica del algoritmo se describe a continuación [28]. Las entradas se definirı́an
como:
Un cubo de datos multiespectral o hiperespectral con N dimensiones.
El tamaño del conjunto de vectores aleatorios que se van a generar durante la ejecución K.
Un valor umbral de corte tv , utilizado para seleccionar como endmembers aquellos pı́xeles que
han sido seleccionados como extremos al menos tv veces durante la ejecución del algoritmo.
Y los pasos del algoritmo quedarı́an de la siguiente manera:
1. Generación de skewers: Produce un conjunto de K vectores generados aleatoriamente {skewerj }K
j=1
2. Proyecciones de los extremos : Para cada skewerj , toda la muestra de pı́xeles fi del conjunto
de datos original F se proyecta sobre el skewerj mendiante el cálculo del producto escalar para
encontrar los pı́xeles de muestra que son extremos (máximo y mı́nimo). De esta forma se obtiene
un conjunto de extremos para el skewerj que se denota por Sextrema (skewerj ). El producto
escalar se calcula de la forma |fi · skewerj |.
4.1. PIXEL PURITY INDEX
29
A pesar del hecho de que diferentes skewers skeweri y skewerj pueden generar conjuntos de
extremos diferentes Sextrema (skeweri ) y Sextrema (skewerj ), es muy probable que una misma
muestra de vectores aparezca en más de un conjunto de extremos. Para hacer frente a este
situación se define la función lS (x) la cual denota la pertenencia de un elemento x para un
conjunto particular S. Esta función se define por la función 4.1
(
lS (fi ) =
1
0
si x ∈ S
si x ∈
/S
(4.1)
3. Cálculo de las puntuaciones PPI: Utilizando la función 4.2, se calcula la puntuación PPI
asociada a un vector de la muestra fi (número de veces que un pixel dado ha sido seleccionado
como extremo)
NP P I (fi ) = ΣK
j=1 ISextrema (skewer)j (fi )
(4.2)
La parte del algoritmo PPI que es más costosa computacionalmente hablando es la descrita en el
paso 2 (Proyecciones de los extremos), pero es muy adecuada para ser paralelizada, ya que no hay
dependencia de datos entre iteraciones.
Por último, se ha de comentar que el algoritmo PPI contiene etapas totalmente automatizadas,
como la fase de generación de la imagen de pureza, pero se hace necesaria una etapa interactiva final en
la que el usuario debe seleccionar manualmente aquellos pı́xeles que quiere utilizar como endmembers.
El usuario no conoce de antemano cuál es el número apropiado de endmembers a seleccionar, por
lo que el conocimiento a priori de la imagen es muy conveniente. Este hecho y la aleatoriedad de la
generación de los skewers representan los principales inconvenientes de esta metodologı́a [22].
En el siguiente capı́tulo se describen las diferentes implementaciones paralelas del algoritmo PPI
desarrolladas para un clúster de computadores, tarjetas GPUs y para clúster de computadores equipados con tarjetas GPUs.
30
CAPÍTULO 4. MÉTODO
Capı́tulo 5
Implementaciones paralelas
En este capı́tulo se presentan las diferentes versiones de implementaciones paralelas desarrolladas
para el algoritmo de extracción de firmas espectrales puras Pixel Purity Index descrito en el capı́tulo
anterior. Primeramente se describe la implementación paralela desarrollada para un clúster de computadores con el fin de acelerar la versión secuencial de dicho algoritmo. Además, se describe el problema
del particionamiento de datos y el paralelismo adoptado, presentando algunos ejemplos prácticos que
permiten analizar los pasos seguidos en el proceso de paralelización. A continuación, se explica la
versión paralela de PPI para GPUs, comentando las funciones que se ejecutan en el dispositivo o kernels desarrollados y el esquema de pararelismo adoptado. Para finalizar se presenta la implementación
desarrollada para el clúster de GPUs de CETA-CIEMAT, un clúster de computadores que contiene
dos tarjetas GPU por nodo de cómputo.
5.1.
Implementación de PPI para un clúster de computadores
En este apartado se analizan la implementación de PPI realizada para clúster de computadores,
prestando especial atención al esquema de paralelismo utilizado y a la comunicación entre los nodos
de cómputo. Además, debido a que los algoritmos de análisis hiperespectral para esta arquitectura
paralela se basan generalmente en el reparto de los datos a procesar entre los nodos del clúster, se
presentan las diferentes estrategias de particionamiento que pueden adoptarse, destacando sus ventajas
e inconvenientes.
5.1.1.
Estrategias de particionamiento de datos hiperespectrales
El problema de particionamiento de datos hiperespectrales para procesamiento en paralelo se ha
explorado en diferentes aproximaciones en la literatura reciente [26]. En la mayor parte de los casos, el
particionamiento de datos está asociado a un patrón de algoritmo paralelo maestro-esclavo o masterworker, en la que un proceso, el maestro o master, se encarga de realizar el particionamiento de los
datos hiperespectrales y repartirlos entre el resto, los esclavos o slaves, los cuales se encargan de
procesarlos. Una vez que el esclavo finaliza su tarea, genera un resultado parcial que envı́a de vuelta
al maestro. Cuando éste ha recopilado los datos parciales de cada uno de los esclavos, se encarga de
procesarlos y combinarlos para generar un resultado global.
Teniendo en cuenta este patrón de procesamiento, a continuación se describen tres tipos de particionamiento de datos considerados en el presente trabajo a la vez que se presentan sus ventajas e
incovenientes. Para finalizar se justifica la elección de uno de los tipos propuestos como modelo base
para el desarrollo de las implementaciones paralelas descritas a lo largo del capı́tulo.
1. Particionamiento espectral. Este tipo de particionamiento divide el cubo de datos hiperespectrales en subvolúmenes, cada uno de los cuales resulta de seccionar el cubo con planos
paralelos al plano formado por los ejes X e Y , correspondientes a lı́neas y muestras respectivamente. Esto provoca que cada subvolumen contenga información de todos los pı́xeles de la
imagen, de forma que la información espectral asociada a un mismo pı́xel puede encontrarse
almacenada en dos o más procesos o nodos [ver figura 5.1 (a)]. Aplicando este tipo de particionamiento, el procesamiento de un único pı́xel de la imagen requiere la comunicación entre los
procesos mencionados debido a que la información espectral se encuentra dispersa entre varios
procesadores de la arquitectura.
31
32
CAPÍTULO 5. IMPLEMENTACIONES PARALELAS
Figura 5.1: Estrategias de particionamiento de imágenes hiperespectrales. (a) Particionamiento espectral. (b) Particionamiento espacial. (c) Particionamiento hı́brido.
2. Particionamiento espacial. Este tipo de particionamiento divide el cubo de datos hiperespectrales en bloques de pı́xeles, cada uno de los cuales resulta de seccionar el cubo con planos
paralelos al plano formado por los ejes X y Z, correspondientes a lı́neas y bandas respectivamente. Esto provoca que cada bloque contenga toda la información espectral relativa a un
subconjunto de pı́xeles de la imagen contiguos en el dominio espacial [ver figura 5.1 (b)]. Aplicando este tipo de particionamiento, el procesamiento de un único pı́xel de la imagen no requiere
comunicación entre procesos debido a que todos los valores espectrales se encuentran localizados
en un mismo procesador de la arquitectura.
3. Particionamiento hı́brido. Este tipo de particionamiento resulta de aplicar conjuntamente
los dos tipos de particionamiento anteriores: el cubo de datos hiperespectrales queda dividido en
subvolúmenes, cada uno de ellos integrando una partición de la imagen en el dominio espacial
y a su vez la información espectral asociada a un pı́xel de dicho subvolumen puede encontrarse
dispersa en dos o más procesadores (ver figura 5.1 (c)).
Dada las caracterı́stidas del algoritmo PPI y para aprovechar su paralelismo inherente, se ha optado
por un particionamiento de datos de tipo espacial, debido principalemente a los siguientes motivos:
Primeramente, el particionamiento espacial se adapta de manera natural a la paralelización de
los algoritmos de procesamiento basados en ventana deslizante, al almacenarse en una misma
unidad de proceso todos los valores espectrales de pı́xeles contiguos en el dominio espacial.
Otra razón fundamental para seleccionar este tipo de división de los datos espectrales viene dada
por la forma de trabajar del algoritmo PPI. Tal y como se ha descrito en el capı́tulo anterior,
el algoritmo calcula en cada iteración el valor de la proyección de cada pı́xel de la imagen
sobre un vector unitario y aleatorio o skewer. El particionamiento espacial permite reducir
sensiblemente las comunicaciones entre los diferentes procesos o nodos de la arquitectura al
encontrarse almacenados todos los valores espectrales para un pı́xel dado en la misma unidad de
proceso. El particionamiento espectral o hı́brido involucra comunicaciones inter-proceso a nivel
de pı́xel, incrementando significativamente el coste total asociado a las comunicaciones, lo que
se traduce en un menor rendimiento en paralelo y en problemas de escalabilidad según aumenta
el número de nodos de cálculo de la arquitectura.
Para terminar, una razón fundamental para la selección del particionamiento espacial es la
posibilidad de reutilizar el código y de mejorar la portabilidad de los algoritmos paralelos implementados a diferentes arquitecturas. En la mayor parte de las aplicaciones, es altamente
deseable poder reutilizar los códigos serie a la hora de desarrollar versiones paralelas, debido
principalmente a la complejidad de algunas técnicas de análisis. Por ello, el particionamiento
espacial permite un paralelismo de grano fino al facilitar la aplicación de un algoritmo paralelo
a diferentes porciones de datos que contienen toda la información espectral, permitiendo que la
5.1. IMPLEMENTACIÓN DE PPI PARA UN CLÚSTER DE COMPUTADORES
33
transformación del código serie a paralelo sea mucho más sencilla que aplicando otro de los tipos
de particionamiento descritos anteriormente.
En el siguiente apartado se explica la aplicación del particionamiento espacial como parte de la
paralelización del algoritmo PPI.
5.1.2.
Detalle de la implementación
La implementación paralela del algoritmo PPI para clúster de computadores implementa el patrón
maestro-esclavo de comunicación entre los procesos explicado anteriormente, paralelizando el procesamiento de la imagen entre los nodos esclavos para disminuir el tiempo de ejecución del algoritmo.
El maestro realiza la división de la imagen aplicando un particionamiento de espacial de datos, de tal
forma que todos los valores espectrales de los pı́xeles de cada fragmento asignado se encuentren en
un mismo nodo esclavo y se evite establecer una comunicación con otro nodo, lo que penalizarı́a en el
tiempo de ejecución.
Los parámetros del algoritmo son los mismos que los de la versión secuencial descrita en el apartado 4.1:
Una imagen hiperespectral de entrada F .
El tamaño del conjunto de vectores unitarios aleatorios o skewers K a generar.
La salida del algoritmo es una imagen resultado R que almacena en cada coordenada espacial
R(x, y) el número de veces que dicho pı́xel ha sido seleccionado como posible endmember por el
algoritmo.
A continuación se expone paso por paso de esta versión paralela del algoritmo PPI:
1. El procesador maestro lee el fichero de cabecera en formato ENVI header format (HDR) que
describe el fichero que contiene la imagen hiperespectral F . De este fichero obtiene la siguiente
información:
num bands: Número de bandas que contiene la imagen de entrada.
num lines: Número de lı́neas que contiene la imagen de entrada para cada banda.
num samples: Número de muestras (pı́xeles) por cada lı́nea de la imagen de entrada.
data type: Parámetro que identifica el tipo de representación. Están soportados los valores
1 (entero de 16 bits), 4 (coma flotante de 32 bits) y 5 (coma flotante 64 bits).
byte order: Describe el orden de los bytes en los tipos de datos. 0 describe la codificación
Least Significant Byte First o LSF (sistemas DEC y Microsoft) y 1 describe la codificación
Most Significant Byte First o MSF (resto de sistemas - SUN, SGI, IBM, HP, etc.).
Una vez leı́do el fichero de cabecera, el nodo maestro lee el fichero que contiene la imagen
hiperespectral e intenta distribuirlos de forma balanceada entre los nodos esclavos (él mismo
incluı́do). Para ello se calcula el resto de la división entre el número de lı́neas de la imagen
(num lines) y el número de procesos (num processes) (ver fórmula 5.1).
c = num lines % num processes
(5.1)
Si el resultado no es 0, se reparten las lı́neas entre los primeros c procesos.
2. El proceso maestro genera un número de vectores unitarios aleatorios del tamaño del parámetro
de entrada s. Cada vector tendrá un tamaño del número de bandas num bandas de la imagen
de entrada. Para la generación de los vectores aleatorios se utiliza el generador de números
aleatorios Mersenne-Twister [25] distribuido en la librerı́a GNU Scientific Library (GSL) [13].
El código 5.1 muestra cómo se generan los vectores aleatorios.
34
CAPÍTULO 5. IMPLEMENTACIONES PARALELAS
gsl_rng * r ;
if (( r = gsl_rng_alloc ( gs l_ r ng _m t1 9 93 7 ) ) == NULL ) {
printf ( " ERROR : Could not create random number generator \ n " ) ;
exit (1) ;
}
// Set seed
gsl_rng_set (r , time ( NULL ) * getpid () ) ;
for ( i = 0; i < num_skewers ; i ++) {
for ( j = 0; j < num_bands ; j ++) {
skewers_data [ i * num_bands + j ] = g s l _ r n g _ u n i f o r m _ i n t (r , SHRT_MAX ) ;
}
}
gsl_rng_free ( r ) ;
Código 5.1: Generación aleatoria de los skewers
Una vez generado el conjunto de skewers, se realiza una operación de distribución o broadcast
a todos los procesos esclavos para que tengan el conjunto de skewers generado. El código 5.2
muestra el código MPI utilizado para la distribución de los skewers.
MPI_Bcast ( skewers_data , skewers_data_size , MPI_FLOAT , 0 , MPI_C OMM_WORL D ) ;
Código 5.2: Broadcasting de los skewers
3. En este momento todos los procesos tienen los datos necesarios para ejecutar el algoritmo PPI
localmente. El código del algoritmo es el mismo código que el código secuencial, pero utilizando
como imagen fuente el bloque de la imagen recibido. Una vez que se ha ejecutado el algoritmo, el
proceso envı́a de vuelta al proceso maestro el resultado parcial obtenido tras ejecutar el algoritmo
PPI.
El nodo maestro, una vez ejecutado el algoritmo PPI localmente (también actúa como esclavo) efectúa una operación de recolección de resultados (gathering). El cuadro de código 5.3
ejemplifica la función MPI utilizada para el envı́o del resultado al proceso maestro.
MPI_Gather ( local_results , num_skewers * 6 , MPI_FLOAT , gathered_results ,
num_skewers * 6 , MPI_FLOAT , 0 , MPI_C OMM_WOR LD ) ;
Código 5.3: Recolección de los resultados locales
4. Una vez que el nodo maestro obtiene los resultados parciales de la ejecución del algoritmo en cada
uno de los nodos esclavos se realiza el proceso de generación del resultado final del algoritmo.
Para cada skewer se han de comparar los máximos y mı́nimos locales obtenidos para cada bloque
de imagen distribuido. Se seleccionarán aquellos pı́xeles con el mayor pmax (x, y) y menor valor
pmin (x, y). El nodo maestro generará finalmente una imagen resultado R de una sola banda y
para cada máximo y mı́nimo obtenido incrementará en 1 el valor del pı́xel en la imagen resultado.
Tras la ejecución del algoritmo, la imagen resultado contendrá para cada pı́xel el número de veces
que ha sido seleccionado como endmember.
En resumen, los pasos a seguidos en la ejecución de la implementación en paralelo del algoritmo
PPI son los siguientes:
1. La imagen original se distribuye en particiones entre los diferentes procesadores. Cada procesador
debe recibir un volumen de datos proporcional a sus caracterı́sticas.
2. Un nodo (maestro) se encarga del reparto de la carga y de la recolección de los resultados
parciales.
3. El resto de nodos (esclavos) ejecutan el algoritmo PPI en su versión secuencial para su bloque
y el conjunto de skewers recibido.
La figura 5.2 representa el proceso de particionamiento de datos para PPI de forma sencilla.
Esta versión del algoritmo servirá de base para la implementación paralela del algoritmo PPI para
el clúster de GPUs de CETA-CIEMAT. El cuerpo del algoritmo será el mismo, conservando el esquema
de particionamiento de datos (espacial) y el patrón maestro-esclavo de comunicación entre nodos. La
diferencia fundamental reside en la delegación de la ejecución del algoritmo PPI a la(s) GPU(s) de
cada nodo de procesamiento. La versión del algoritmo PPI que se ejecutará se describe en el apartado
siguiente.
5.2. IMPLEMENTACIÓN PARALELA DE PPI PARA GPUS
35
Figura 5.2: Particionamiento de datos en el algoritmo PPI
5.2.
Implementación paralela de PPI para GPUs
En este apartado se describe la implementación paralela del algoritmo PPI en su versión para
GPU. Esta implementación sigue un patrón diferente a la de clústers presentada en el apartado
anterior, debido principalmente a que la GPU es un sistema de memoria compartida y no es necesario
invertir demasiado tiempo en la comunicación entre las unidades de procesamiento. En este sentido,
se muestran los detalles de esta implementación, incluyendo fragmentos de código que describen las
acciones más relevantes en cada paso.
Cabe destacar que en esta implementación no se implementa un patrón de comunicación maestroesclavo al uso, dado que no existe un nodo de procesamiento que reparta los datos y recolecte y procese
los resultados como en la implementación anterior. Se podrı́a decir que en la implementación GPU es
el proceso que se ejecuta en la CPU el que actúa de maestro, enviando a la GPU, que en este caso serı́a
el esclavo, los datos para la ejecución del algoritmo. Tras su ejecución, la GPU devuelve los resultados
parciales a la CPU para que ésta proceda a la generación del resultado final.
Al igual que en la versión paralela de PPI para clústers, el algoritmo PPI para GPU tiene como
entradas una imagen hiperespectra F y el tamaño del conjunto de skewers K a generar. A continuación
se enumeran los pasos que realiza esta implementación del algoritmo:
1. El proceso de la CPU procede a la lectura de la imagen tal y como se realiza en la implementación
para clústers de computadores. Tras la lectura del fichero la imagen hiperespectral se encuentra
en una estructura en la memoria de la CPU y se han obtenido los datos relativos al número de
bandas (num bands), número de lı́neas (num lines) y número de muestras (num samples).
2. La generación de los skewers se realiza de la misma manera que en la versión de clúster de
computadores. Para la generación de los números aleatorios se utiliza la implementación del
algoritmo de Mersenne-Twister que proporciona la librerı́a GSL. Este paso se podrı́a haber
realizado en la GPU, utilizando la implementación de Mersenne-Twister para GPU que se
porporciona en el CUDA SDK [2]. La justificación a no haberse utilizado dicha implementación
se debe al hecho de poder reutilizar el mayor porcentaje de código posible de la implementación
para clústers.
3. La imagen hiperespectral F se envı́a a la GPU para su almacenamiento en la memoria global.
Hay que tener en cuenta que para imágenes de gran tamaño (>4GB) habrı́a que realizar un
particionamiento de la imagen antes de enviarla a la GPU. Esto es debido a que las GPUs
actuales tienen una capacidad limitada de memoria dedicada (4GB para la C1060 y 6GB para
la C2070) y se producen errores al intentar reservar un espacio de memoria tan grande con
cudaMalloc. Tras el envı́o de la imagen se procede al envı́o a la GPU del conjunto de skewers
generados.
36
CAPÍTULO 5. IMPLEMENTACIONES PARALELAS
cudaMalloc (( void **) & d_image_chunk , ( chunk_size * num_samples * num_bands *
sizeof ( float ) ) ) ;
cudaMalloc (( void **) & d_skewers_data , ( num_skewers * num_bands * sizeof ( float
)));
// host -> device copy
cudaMemcpy ( d_image_chunk , image_chunk , chunk_size * num_samples * num_bands *
sizeof ( float ) , c u d a M e m c p y H o s t T o D e v i c e ) ;
cudaMemcpy ( d_skewers_data , skewers_data , num_skewers * num_bands * sizeof (
float ) , c u d a M e m c p y H o s t T o D e v i c e ) ;
Código 5.4: Copia de la imagen hiperespectral a la memoria de la GPU
El código 5.4 muestra las instrucciones CUDA para la copia de la imagen y del conjunto de
skewers a la memoria global de la GPU.
4. Una vez que la GPU tiene los datos necesarios para ejecutar el algoritmo PPI, se procede a
su ejecución. Para ello, cada hilo de la GPU ejecutará un fragmento de código o kernel que
calculará las proyecciones de un skewer asignado a todos los pı́xeles de la imagen hiperespectral.
El identificador del skewer asignado para cada hilo de ejecución vendrá dado por el código
5.5 y para su cálculo se utilizan los identificadores de bloque y de hilo dentro del bloque que
proporciona la GPU.
int idx = blockDim . x * blockIdx . x + threadIdx . x ;
while ( idx < num_skewers ) {
...
idx += num_skewers
}
Código 5.5: Cálculo de la selección de skewer para cada kernel
Si el número de skewers es mayor al número total de hilos que se ejecutarán en la GPU, se
calculará el número restante de skewers para seleccionar y los hilos con identificador más bajo
ejecutarán de nuevo el kernel para el nuevo skewer. El código 5.6 muestra el código que ejecuta
el cálculo del algoritmo PPI como kernel en la GPU.
int idx = blockDim . x * blockIdx . x + threadIdx . x ;
while ( idx < num_skewers ) {
float min = FLT_MAX ;
float max = FLT_MIN ;
float dot_product = 0.0;
for ( int k = 0; k < num_lines ; k ++) {
for ( int j = 0; j < num_samples ; j ++) {
dot_product = dotProduct (& skewers [ idx ] , & image [ k * num_samples
* num_bands + j * num_bands ] , num_bands ) ;
if ( dot_product > max ) {
max = dot_product ;
local_results [ idx * 6 + 0] = k ; // maxX
local_results [ idx * 6 + 1] = j ; // maxY
local_results [ idx * 6 + 2] = dot_product ;
}
if ( dot_product < min ) {
min = dot_product ;
local_results [ idx * 6 + 3] = k ; // minX
local_results [ idx * 6 + 4] = j ; // minY
local_results [ idx * 6 + 5] = dot_product ;
}
}
}
idx += num_skewers
}
Código 5.6: Código del kernel que implementa el algoritmo PPI para GPU
5. Tras el cálculo de los resultados del algoritmo PPI en la GPU, se devuelve a la CPU una
estructura que almacena por cada skewer los pı́xeles de la imagen hiperespectral con los valores
máximo y mı́nimo de la proyección. La CPU realiza un procesado final para generar la imagen
resultado R de una sola banda, cuyo valor para cada pı́xel es el número de veces que dicho pı́xel
5.3. IMPLEMENTACIÓN PARALELA DE PPI PARA UN CLÚSTER DE GPUS
37
ha sido seleccionado como candidato a endmember. Este proceso es el mismo que el realizado en
la versión paralela del algoritmo para clústers.
Resumiendo, los pasos seguidos para la ejecución del algoritmo paralelo PPI en su versión GPU
son los siguientes:
1. La imagen original se distribuye en su totalidad a la GPU.
2. La GPU actúa como esclavo ejecutando el algoritmo de forma paralela, de forma que cada hilo
de ejecución calcula la proyección de todos los pı́xeles de la imagen para un skewer dado.
3. Una vez finalizada la ejecución del algoritmo en la GPU, la CPU recibe los resultados y se
procesan para generar la imagen resultado.
Esta versión paralela del algoritmo servirá de base, junto con la versión para clúster de computadores para la implementación de PPI para el clúster de GPU de CETA-CIEMAT. El códido del
kernel que se ejecuta en la GPU será el que se ejecute en cada GPU de cada uno de los nodos de
cómputo del clúster de GPUs. El siguiente apartado describe en detalle esta implementación hı́brida
del algoritmo PPI.
5.3.
Implementación paralela de PPI para un clúster de GPUs
En los apartados anteriores hemos dado una visión detallada de las implementaciones paralelas del
algoritmo PPI en sus versiones para clúster de computadores y para GPUs. Este apartado describe
una implementación mixta para el clúster de GPUs de CETA-CIEMAT, descrito en el apartado 3.3
del capı́tulo 3. Recordemos que este clúster de computadores está compuesto por dos subclústers o
entornos. Éstos son:
Test: formado por 17 nodos de cálculo, 8 cores de CPU por nodo y 2 GPUs Nvidia Tesla C1060
(media S1070) por nodo.
Producción: formado por 32 nodos de cálculo. Éstos se dividen en 16 nodos de cálculo, con 8
cores de CPU y 2 GPUs Nvidia Tesla C2050 (media S2050) por nodo y otros 16 compuestos por
12 cores de CPU y 2 GPUs Nvidia Tesla C2070 (media S2070).
En esta versión del algoritmo PPI paralelo para clúster de GPUs se adopta el esquema de comunicación entre nodos maestro-esclavo implementado en la versión para clústers, con la particularidad
de que no es la CPU de los nodos esclavos la que realiza la ejecución del algoritmo PPI localmente,
sino que se delega la ejecución del algoritmo a la(s) GPU(s) del propio nodo. En este caso el código
ejecutado en la GPU es el presentado en el apartado anterior. A continuación se enumeran los pasos
de la ejecución del algoritmo para el clúster de GPUs:
1. Un nodo maestro se encarga de la lectura de la imagen hiperespectral de entrada F y del
particionamiento de la misma, siguiendo el esquema de particionamiento espacial descrito en el
apartado 5.1.1 de este capı́tulo, y de repartir los bloques resultantes entre el resto de nodos. En
este caso el nodo maestro también procesará un bloque de la imagen de entrada para que no
quede ocioso durante la ejecución local del algoritmo por los esclavos. Tal y como se hace en
la versión de clúster de computadores, el reparto de los bloques es balanceado, siendo todos los
bloques de tamaño similar.
En esta ocasión no se ha tenido en cuenta las capacidades de cómputo de los nodos de CPU a la
hora de hacer el reparto de la imagen de entrada, pues para cada entorno del clúster de GPUs
de CETA-CIEMAT puede afirmarse que es un clúster homogéneo, es decir, que todos los nodos
de cálculo tienen la misma capacidad de cómputo.
2. El nodo maestro genera posteriormente los vectores unitarios aleatorios (skewers) y realiza una
operación de broadcasting o reparto entre el resto de nodos para que cada uno de los nodos
esclavos tenga los skewers localmente.
3. Una vez que los nodos esclavos han recibido el fragmento de la imagen hiperespectral de entrada
a procesar y el conjunto de skewers, ambos se envı́an a la GPU para que ésta pueda ejecutar el
algoritmo PPI. El código que se ejecutará en cada una de las GPUs es el implementado en la
versión paralela para GPU y se muestra en el código 5.6 del apartado 5.2 del presente capı́tulo.
38
CAPÍTULO 5. IMPLEMENTACIONES PARALELAS
4. Una vez finalizada la ejecución del algoritmo los nodos esclavos reciben los resultados generados
por la(s) GPU(s). Esta salida contiene, para cada skewer del conjunto de skewers, las coordenadas espaciales (x, y) de los pı́xeles cuyos valores de proyección a cada skewer son máximo o
mı́nimo junto con sus valores del proyección calculados. Además, las coordenadas son relativas
al tamaño del fragmento asignado de la imagen original, dado que el nodo esclavo desconoce la
distribución de bloques realizada por el maestro al resto de nodos esclavos. Como ocurre en la
implementación para clústers, el nodo maestro, una vez ejecutado el algoritmo PPI localmente
vı́a su(s) GPU(s) asociada(s) (recordemos que éste también actúa como esclavo) efectúa una
operación de recolección de resultados o gathering. El código 5.3 del apartado 5.1.2 del presente
capı́tulo muestra el código MPI utilizado para el envı́o del resultado al nodo maestro.
5. Para finalizar el nodo maestro procesa los resultados parciales recibidos de cada esclavo y selecciona para cada skewer aquellos pı́xeles con valor máximo y mı́nimo de entre los candidatos
recibidos de cada nodo esclavo y se genera la imagen resultado R.
Esta versión del algoritmo se ha implementado también en su versión multiGPU. En este caso,
cada nodo de procesamiento recibe el bloque completo de la imagen hiperespectral a procesar, y se
dividen el número de skewers entre el número de GPUs de las que conste el nodo (en el caso del clúster
de CETA-CIEMAT serı́an 2). En este caso no se ha realizado otro tipo de particionamiento de los
datos de entrada para evitar la comunicación entre los nodos, que sı́ implican un coste significativo si
se realiza de una GPU a otra. Finalmente la CPU de cada nodo recibe los resultados de cada GPU y
los agrega para construir el resultado final que se enviará al nodo maestro.
Capı́tulo 6
Resultados experimentales
En este capı́tulo se realiza un análisis de los resultados experimentales de las pruebas ejecutadas
para las implementaciones del algoritmo PPI descritas en el capı́tulo anterior. En el primer apartado se
presentan los parámetros de entrada para las pruebas realizadas en cada experimento y los entornos
de pruebas. Seguidamente, se comenta la evolución de la implementación de PPI para clústers de
GPUs, desde la versión inicial, que no tiene en cuenta el rendimiento, hasta la versión final, que utiliza
dos tarjetas GPU simultáneamente para reducir el tiempo de ejecución de dicho algoritmo. Como
cierre del capı́tulo, se realiza una comparativa entre las implementaciones secuencial, para clúster de
computadores, GPUs y clúster de GPUs, analizando los resultados de cada implementación para las
métricas obtenidas.
6.1.
Descripción de las pruebas realizadas
Este apartado presenta las pruebas realizadas a las diferentes implementaciones desarrolladas del
algoritmo PPI dentro del marco de este trabajo. Primeramente se muestran los parámetros de entrada
del algoritmo para todas las versiones desarrolladas y seguidamente se describen los entornos de ejecución de las pruebas realizadas. Para finalizar, se presentan las diferentes configuraciones adicionales
necesarias para cada evolución concreta del algoritmo.
6.1.1.
Parámetros del algoritmo PPI
En el capı́tulo 4 se describe en detalle el algoritmo PPI por lo que esta sección se centrará en la
enumeración de los parámetros que dicho algoritmo tienen como entrada. A saber:
1. Una imagen hiperespectral F .
2. El número de iteraciones del algoritmo o tamaño de vectores aleatorios o skewers a generar K.
3. Un valor de umbral de corte tv , utilizado para seleccionar aquellos pı́xeles de la imagen con un
ı́ndice de pureza mayor que valor del umbral.
Cabe comentar que para todas las pruebas se va a seleccionar un valor de umbral igual a 1. Esto
quiere decir que todos los pı́xeles con ı́ndice de pureza 1, es decir, que hayan sido seleccionados al
menos una sola vez como candidatos a endmember, aparecerán en la imagen resultado de la ejecución
del algoritmo R.
De importancia es saber también que en todas las pruebas ejecutadas se han utilizado imágenes
reales obtenidas por el sensor AVIRIS, operado por el Jet Propulsion Laboratory de NASA y disponibles de manera abierta en su página web1 . Se han realizado pruebas con un total de tres imágenes
de diferente tamaño que ha permitido analizar el rendimiento del algoritmo acorde al tamaño de los
datos de entrada: la primera de pequeño tamaño (decenas de MBs), la segunda de un tamaño mediano
(cientos de MBs) y una tercera de gran tamaño (varios GBs). Se ha considerado relevante el tamaño
de la imagen hiperespectral dado que los sensores de observación remota están en continua evolución,
alcanzando progresivamente resoluciones espaciales mayores y trabajando en un mayor número de
bandas espectrales.
1 http://aviris.jpl.nasa.gov/alt
locator/
39
40
CAPÍTULO 6. RESULTADOS EXPERIMENTALES
La primera imagen (ver figura 6.1) fue adquirida por el sensor AVIRIS en 1995 sobre la región
denominada Cuprite, en el estado de Nevada, Estados Unidos. Es una imagen ampliamente utilizada
en la literatura y se caracteriza porque se manifiestan singularidades que permiten discriminar entre
una amplia gama de minerales calizos. La tabla 6.1 resume las caracterı́sticas de la imagen de Cuprite.
Número de lı́neas
Número de muestras
Número de bandas
Tipo de archivo
Orden de bytes
Tipo de dato
Tamaño
350
350
188
ENVI Standard (BIP)
LSF
Entero 16 bits
Aprox. 44 MB
Tabla 6.1: Caracterı́sticas de la imagen hiperespectral AVIRIS, capturada en 1995 sobre la región
minera de Cuprite, En Nevada (Estados Unidos)
Figura 6.1: Imagen real AVIRIS perteneciente a la región minera de Cuprite, en Nevada (Estados
Unidos)
La segunda imagen utilizada fue tomada también por el sensor AVIRIS en 2008 (ver figura 6.2).
Corresponde al Lago St. Clair, en Michigan (Estados Unidos), en su frontera con Canadá. Esta imagen
ha sido seleccionada por la presencia de zonas de agua, vegetación y zonas habitadas. La tabla 6.2
resume las caracterı́sticas de dicha imagen.
Número de lı́neas
Número de muestras
Número de bandas
Tipo de archivo
Orden de bytes
Tipo de dato
Tamaño
738
703
224
ENVI Standard (BIP)
MSF
Entero 16 bits
Aprox. 222 MB
Tabla 6.2: Caracterı́sticas de la imagen hiperespectral AVIRIS, capturada en 2008 sobre la región del
lago St. Clair, en Michigan (Estados Unidos)
La tercera imagen, también capturada por el sensor AVIRIS, pertenece al Parque Nacional de
Yellowstone, en el estado de Wyoming (Estados Unidos) y data del año 2009. Esta imagen ha sido
seleccionada por su gran tamaño (aprox. 4 GB). La tabla 6.3 resume las caracterı́sticas de dicha
imagen.
El segundo parámetro de entrada del algoritmo es el tamaño de conjunto de skewers K. Para la
realización de las pruebas se ha seleccionado un valor de K igual a 15.360, partiendo de la configuración
6.1. DESCRIPCIÓN DE LAS PRUEBAS REALIZADAS
41
Figura 6.2: Imagen real AVIRIS perteneciente la región del lago St. Clair, en Michigan (Estados
Unidos)
Número de lı́neas
Número de muestras
Número de bandas
Tipo de archivo
Orden de bytes
Tipo de dato
Tamaño
11.491
777
224
ENVI Standard (BIP)
MSF
Entero 16 bits
Aprox. 3,8 GB
Tabla 6.3: Caracterı́sticas de la imagen hiperespectral AVIRIS, capturada en 2009 sobre el Parque
Nacional de Yellowstone, en Wyoming (Estados Unidos)
del algoritmo encontrada en anteriores trabajos seleccionados [35]. Básicamente dicho valor de K hace
que encaje perfectamente con la configuración de ejecución del código que se lanzará en las GPUs y
que se detallará más adelante.
El uso de este valor del tamaño del conjunto de skewers junto con la imagen AVIRIS Cuprite
nos permitirá comparar los resultados de rendimiento obtenidos por la implementación del algoritmo
PPI para clúster de GPUs con resultados publicados anteriormente de las versiones secuencial y
GPU[35, 36].
Continuando con la descripción de los parámetros de entrada de las diferentes implementaciones
de PPI, adicionalmente existen parámetros especı́ficos dependientes de la arquitectura utilizada. Estos
parámetros se listan a continuación:
Número de nodos: Número de nodos de cómputo en los que se ejecutará en algoritmo. Este
parámetro es necesario para las implementaciones para clúster y clúster de GPUs. Para las
pruebas este valor variará de 1 a 15 nodos.
Número de bloques: Corresponde a la cantidad de bloques de GPU a utilizar. El cálculo
del número de bloques sigue la fórmula 6.1, de tal forma que cada hilo de la GPU ejecute una
iteración del algoritmo. Dependiendo de la implementación de PPI y de la arquitectura (Tesla
o Fermi), este número variará entre 30 y 60 para alcanzar la máxima ocupación de la GPU y
ası́ maximizar el rendimiento.
No de bloques = Tamaño del conjunto de skewers (K) / No de hilos por bloque
Este parámetro es especı́fico de las implementaciones que utilizan GPUs.
(6.1)
42
CAPÍTULO 6. RESULTADOS EXPERIMENTALES
Figura 6.3: Imagen real AVIRIS perteneciente al Parque Nacional de Yellowstone, en Wyoming (Estados Unidos)
Número de hilos por bloque: Este parámetro hace referencia al número de hilos por bloque
de GPU. Se configura también de cara a maximizar la ocupación de la GPU y ası́ maximizar
su rendimiento. En arquitecturas Tesla, como por ejemplo la del modelo C1060 Nvidia, el lı́mite
está en 512 hilos por bloque. En arquitectura Fermi y posteriores, como las C2050 y C2070 de
Nvidia, este número se incrementa hasta 1.024. En nuestras pruebas variará de 256 a 512, según
la implementación de algoritmo.
En el siguiente apartado se describen las pruebas realizadas a las diferentes implementaciones
desarrolladas del algoritmo PPI para clúster de GPUs.
6.2. DESARROLLO DE PPI PARA EL CLÚSTER DE GPUS
6.1.2.
43
Entornos de pruebas
Tras la descripción de los parámetros de las diferentes implementaciones del algoritmo PPI sujetas
a estudio, se procede a la exposición de los entornos de ejecución de las pruebas realizadas. Como
se viene indicando a lo largo de esta memoria, los resultados que se presentan en este documento se
han obtenido utilizando el clúster de GPUs de CETA-CIEMAT, cuya arquitectura y composición se
describieron en detalle en el capı́tulo 3.
Recordemos, no obstante, que el clúster de GPUs de CETA-CIEMAT se divide en dos entornos de
ejecución de trabajos:
Entorno de Test: Este entorno consta de 17 nodos de cómputo, cada uno de ellos equipado con
2 GPUs Nvidia C1060 (S1070). Este entorno está destinado al aprendizaje del envı́o de trabajos
del clúster y las para pruebas de versiones paralelas de algoritmos en desarrollo.
Entorno de Producción: Este entorno consta de 32 nodos de cómputo destinados a la producción cientı́fica. Este entorno consta de 16 nodos de cómputo equipados cada uno con 2 GPUs
Nvidia C2050 (S2050) y otros 16 nodos equipados con 2 GPUs Nvidia C2070 (S2070) por nodo.
Estos 32 nodos se pueden utilizar de forma conjunta o separada por nodos 2050 y 2070.
Tal y como se comenta en el apartado anterior, se han realizado pruebas con configuraciones para
cada entorno (Test y Producción) desde 1 a 15 nodos. El principal motivo por el que no se han
realizado pruebas con un mayor número de nodos ha sido el de no acaparar el uso del clúster. Dentro
de las pruebas lanzadas para cada configuración de ejecución del algoritmo se miden los siguientes
tiempos:
Image Retrieval Time (IRT): Tiempo de recuperación de la imagen de entrada.
Skewers Generation Time (SKT): Tiempo de generación de los vectores aleatorios.
Broadcasting Time (BT): Tiempo de diseminación del conjunto de skewers a los nodos
esclavos.
Scatter Time (ScT): Tiempo de reparto de fragmentos de la imagen de entrada entre los
nodos esclavos.
Computing Time (CT): Tiempo de ejecución del algoritmo en cada nodo de cálculo. Este
tiempo incluye el tiempo de copiado de los datos de entradas a la GPU, el tiempo de ejecución
del algoritmo en la GPU y el tiempo de recolección de los resultados.
Gathering Time (GT): Tiempo de recolección de los resultados parciales de cada nodo esclavo.
Post-Processing Time (PPT): Tiempo de procesamiento de los resultados parciales y de
generación del resultado final del algoritmo.
Total Time (TT): Tiempo total de ejecución del algoritmo.
6.2.
Desarrollo de PPI para el clúster de GPUs
Esta sección está destinada a la descripción de la evolución del desarrollo de la implementación
paralela del algoritmo PPI parar clúster de GPUs. En total se han realizado seis implementaciones,
desde la versión inicial, que no cuenta con ninguna optimización, hasta la versión final que hace uso
de varias tarjetas GPU simultáneamente.
6.2.1.
Implementación sin optimizaciones
La primera implementación de PPI para el clúster de GPU se desarrolló con la premisa principal
de tener una versión del algoritmo funcionando en un clúster de GPUs, sin tener en cuenta ninguna
configuración orientada a reducir el tiempo de ejecución del algoritmo.
Tal y como se comenta en el apartado 5.3 del capı́tulo 5, esta implementación parte de las implementaciones para clúster de computadores y de GPU existentes anteriormente. De la primera se ha
mantenido el esquema de comunicación entre los nodos de procesamiento. Existe un proceso maestro,
44
CAPÍTULO 6. RESULTADOS EXPERIMENTALES
que se encarga de la lectura de la imagen hiperespectral de entrada y de calcular el reparto balanceado de la misma entre el resto de nodos. El proceso maestro también se encarga de la generación de
los skewers, que posteriormente también reparte. Una vez que cada nodo tiene los datos de entrada
necesarios (fragmento de la imagen y conjunto de skewers), procede a la ejecución del algoritmo PPI
localmente. Cuando el algoritmo se ha ejecutado en cada nodo, el proceso maestro recolecta los resultados parciales obtenidos por cada uno de ellos, elaborando la salida final del algoritmo. Por otro
lado, la versión para GPU aporta el core del algoritmo para su ejecución en una GPU a las que tiene
acceso. Cada proceso esclavo delega la ejecución del algoritmo a la GPU, quien recibe los datos de
entrada, ejecuta su trabajo y devuelve los resultados para que sean enviados posteriormente al nodo
maestro.
El código 6.1 muestra el fragmento de código fuente que se ejecuta en la GPU. Este fragmento
de código será el que evolucione entre las diferentes versiones posteriores del algoritmo, con vistas a
reducir el tiempo de ejecución.
int idx = blockDim . x * blockIdx . x + threadIdx . x ;
while ( idx < num_skewers ) {
float min = FLT_MAX ;
float max = FLT_MIN ;
float dot_product = 0.0;
for ( int k = 0; k < num_lines ; k ++) {
for ( int j = 0; j < num_samples ; j ++) {
dot_product = dotProduct (& skewers [ idx * num_bands ] , & image [ k *
num_samples * num_bands + j * num_bands ] , num_bands ) ;
if ( dot_product > max ) {
max = dot_product ;
local_results [ idx * 6 + 0] = k ; // maxX
local_results [ idx * 6 + 1] = j ; // maxY
local_results [ idx * 6 + 2] = dot_product ;
}
if ( dot_product < min ) {
min = dot_product ;
local_results [ idx * 6 + 3] = k ; // minX
local_results [ idx * 6 + 4] = j ; // minY
local_results [ idx * 6 + 5] = dot_product ;
}
}
}
idx += num_skewers
}
Código 6.1: Código del kernel del algoritmo PPI para la implementación sin optimizaciones
Este código o kernel es ejecutado por cada hilo de la GPU. La configuración de lanzamiento es de
30 bloques con 512 hilos de ejecución en cada uno con lo que se consiguen 30 × 512 = 15360 hilos de
ejecución, uno para cada skewer. La tabla 6.4 muestra la ocupación de configuración de la GPU para
una tarjeta versión 1.3, como las Nvidia C1060 del entorno de Test del clúster de CETA-CIEMAT.
En este caso la ocupación de la tarjeta es del 100 %. Por lo general, una mayor ocupación conlleva una
mejora del rendimiento del algoritmo, aunque no en todos los casos. Con esta misma configuración de
bloques e hilos se obtiene en una tarjeta 2.0, como las Nvidia C2050 y C2070 del entorno de Producción
del clúster de CETA-CIEMAT, una ocupación del 67 % (ver tabla 6.5). Este dato para esta versión
no es relevante, dado que en esta ocasión no está orientada a la obtención del mayor rendimiento.
Dato que mejorará en las sucesivas versiones orientadas a la reducción del tiempo de ejecución del
algoritmo.
Hilos por bloque
Registros por hilo
Memoria compartida por bloque (bytes)
Ocupación de cada multiprocesador
512
11
56
100 %
Tabla 6.4: Datos de ocupación de la GPU para la implementación MPI-CUDA sin optimizaciones del
algoritmo PPI para el entorno de Test del clúster de CETA-CIEMAT
Una vez que se ha descrito la implementación desarrollada, se pasará a realizar una comparativa
entre los resultados obtenidos por la versión del algoritmo PPI para clúster de GPUs y los resultados
obtenidos por el software comercial ENVI. Dicha comparativa surge con el ánimo de comprobar si
6.2. DESARROLLO DE PPI PARA EL CLÚSTER DE GPUS
Hilos por bloque
Registros por hilo
Memoria compartida por bloque (bytes)
Ocupación de cada multiprocesador
45
512
23
0
67 %
Tabla 6.5: Datos de ocupación de la GPU para la implementación MPI-CUDA sin optimizaciones del
algoritmo PPI para el entorno de Producción del clúster de CETA-CIEMAT
esta versión del algoritmo PPI para clúster de GPUs se puede aplicar a la práctica diaria del análisis
de imágenes hiperespectrales.
Como se comentó en el capı́tulo 4, el algoritmo PPI pertenece al conjunto de métodos interactivos, dado que se hace necesaria una etapa interactiva final en la que el usuario debe seleccionar
manualmente aquellos pı́xeles que quiere utilizar como firmas espectrales puras o endmembers y, consecuentemente, el conocimiento a priori que éste tenga de la imagen resultará muy útil.
Para comprobar la efectividad del algoritmo se utilizará la imagen capturada por el sensor AVIRIS
sobre la región minera de Cuprite, en el estado de Nevada (Estados Unidos). Esta imagen se caracteriza
porque en ella se manifiestan singularidades que permiten discriminar entre una amplia gama de
minerales de tipo calizo.
Una forma adecuada y bastante ilustrativa de comprobar la efectividad de una versión de PPI es
comprobar visualmente los resultados obtenidos de la ejecución de dicho algoritmo con los resultados
que ofrece ENVI para un caso de aplicación real como la detección de minerales. Respecto a la
implementación de PPI que integra ENVI, cabe destacar que ésta aplica un proceso denominado
Fast Pixel Purity Index [11] que permite incrementar el número de pı́xeles que se seleccionan en
cada proyección como candidatos a firma espectral pura. Esta singularidad la hace diferente de la
especificación establecida por la versión inicial del algoritmo [7] que indica que solamente se seleccionan
aquellos pı́xeles cuya proyección es máxima o mı́nima sobre el vector aleatorio.
A continuación se muestran los resultados del algoritmo PPI obtenidos tras ejecutar las implementaciones para clúster de GPUs y ENVI (ver figura 6.4).
(a) Resultados ENVI
(b) Resultados clúster de GPUs
Figura 6.4: Resultados visuales obtenidos de la ejecución del algoritmo PPI para las versiones de ENVI
y clúster de GPUs sobre la imagen Cuprite
A la vista de estos resultados, cabe destacar que ambas imágenes son muy similares, presentando
regiones de candidatos a firmas espectrales puras en coordenadas espaciales casi coincidentes, lo cual
permite afirmar que ambas versiones son comparables y que es posible encontrar el mismo conjunto
de firmas espectrales puras. Dado que los resultados son prácticamente los mismos, podemos afirmar
que la versión del algoritmo PPI para clúster de GPUs es válida para su uso en la práctica diaria
del análisis de imágenes hiperespectrales. Por otro lado y a modo de ejemplo, La figura 6.5 presenta
algunos de los minerales que se pueden detectar en la imagen resultado de la ejecución del algoritmo
46
CAPÍTULO 6. RESULTADOS EXPERIMENTALES
para la imagen de Cuprite. El cuadrado verde señala la localización de la Kaolinita, la situación de
la Alunita se destaca en azul y en naranja se ubica la Calcita, presentándose en la figura 6.6 la firma
espectral de dichos minerales.
(a) Resultados ENVI
(b) Resultados clúster de GPUs
Figura 6.5: Ejemplo de algunos de los minerales detectados en la imagen resultado de la ejecución de
PPI sobre la imagen Cuprite
(a) Kaolinita (verde)
(b) Alunita (azul)
(c) Calcita (naranja)
Figura 6.6: Firmas espectrales de los minerales detectados en la imagen resultado de la ejecución de
PPI para clúster de GPUs sobre la imagen Cuprite
Para continuar con el estudio de la efectividad del algoritmo PPI presentado en esta sección, se
presentan además los resultados obtenidos de la ejecución del algoritmo para la imagen del Lago St.
Clair. Al contrario que en el caso anterior, esta imagen ha sido seleccionada aleatoriamente de entre
las publicadas por el Jet Propulsion Laboratory de NASA principalmente por su tamaño y por la
presencia de agua, vegetación y edificaciones entre otros elementos, y no ha sido tan estudiada en la
literatura reciente como la imagen de Cuprite.
La figura 6.7 muestra los resultados obtenidos por la ejecución del algoritmo PPI en sus versiones
para clúster de GPUs y ENVI. En esta ocasión, se puede comprobar visualizando los resultados que
ENVI ha seleccionado un mayor número de pı́xeles como candidatos a endmember que la versión para
clúster de GPUs, debido principalmente a la implementación Fast PPI, que selecciona un número
mayor de pı́xeles en cada iteración. Aun ası́, ambas imágenes son muy similares, seleccionando pı́xeles
en coordenadas casi coincidentes, tal y como ocurrı́a con los resultados de la imagen anterior. En
dicha figura se han resaltado algunas zonas con presencia de agua (en azul), bancos de arena (en
naranja) y vegetación (en verde). Cabe comentar que no nos es posible presentar con mayor detalle
estos resultados por el desconocimiento de la imagen al no contar con datos de verdad-terreno.
Con respecto a las pruebas con la imagen de mayor tamaño, correspondiente a Yellowstone, no se
ha podido realizar una ejecución de PPI con el software ENVI porque dicha imagen provoca un error
de ejecución y, por consiguiente, no se puede realizar la comparación visual de los resultados al no
contar con una de las imágenes necesarias para dicho fin.
6.2. DESARROLLO DE PPI PARA EL CLÚSTER DE GPUS
(a) Resultados ENVI
47
(b) Resultados clúster de GPUs
Figura 6.7: Resultados visuales obtenidos de la ejecución del algoritmo PPI para las versiones de ENVI
y clúster de GPUs sobre la imagen Lago St. Clair
Para finalizar con el análisis de la efectividad del algoritmo, y a modo de conclusión, se puede
afirmar que la implementación del algoritmo PPI para clúster de GPUs es una buena alternativa a las
implementaciones existentes como la incluida en ENVI, fundamentado tras haberse comprobado que
puede ser utilizada en casos reales de análisis de imágenes hiperespectrales.
Dejando a un lado la efectividad del algoritmo, se pasa al estudio del rendimiento que ofrece. A
continuación se presentan las mediciones de tiempo y las gráficas asociadas de los resultados obtenidos
de la ejecución del algoritmo en el entorno de Producción de CETA-CIEMAT. En cada gráfica se
representa la evolución del tiempo de ejecución del algoritmo en cada nodo (CT) y el tiempo total del
algoritmo (TT) y para ejecuciones de 1 a 16 nodos para con las tres imágenes de entrada: Cuprite,
Lago St. Clair y Yellowstone.
La tabla 6.6 muestra el promedio de los resultados medidos en segundos para cada configuración
de número de nodos de cálculo y la imagen de entrada Cuprite. La gráfica 6.8a representa la evolución
del tiempo de ejecución del algoritmo en cada nodo (CT) y el tiempo total del algoritmo (TT) para
cada configuración.
IRT
0,007466
0,005778
0,008936
0,005108
0,005872
0,005722
0,005783
0,001496
0,003714
0,006049
0,003841
0,005920
0,004940
0,005839
0,005716
SKT
0,098670
0,096527
0,098125
0,101290
0,096295
0,095356
0,096302
0,096338
0,096112
0,096368
0,095777
0,096344
0,096601
0,096368
0,096300
BT
0,000021
0,008008
0,010607
0,013208
0,014514
0,014878
0,015449
0,016772
0,017010
0,018203
0,018029
0,018605
0,018767
0,019017
0,019635
ScT
0,065842
0,067687
0,074246
0,076521
0,075650
0,074696
0,076539
0,079188
0,078945
0,081345
0,079236
0,079365
0,079926
0,079987
0,081071
CT
343,879915
174,709909
118,781294
90,742096
73,657719
63,115902
54,367685
48,164924
43,778489
39,611804
36,565600
34,351460
31,930619
29,959470
29,239362
GT
343,880037
174,843165
118,781774
90,742674
73,952397
63,228940
54,532515
48,687444
43,936143
40,253398
37,340465
34,831334
32,554513
30,703032
29,466519
PPT
0,000086
0,000153
0,000198
0,000259
0,000271
0,000336
0,000390
0,000479
0,000549
0,000612
0,000689
0,000770
0,000849
0,000929
0,001012
TT
344,059276
175,028680
118,982667
90,946680
74,153451
63,429148
54,736143
48,886653
44,140178
40,465447
37,545533
35,042957
32,765289
30,916052
29,680364
Tabla 6.6: Resultados de ejecución (en sg.) de la implementación sin optimizaciones del algoritmo PPI
para clúster de GPUs (Imagen: Cuprite)
48
CAPÍTULO 6. RESULTADOS EXPERIMENTALES
(a) Gráfica de CT y TT (en sg.)
(b) Gráfica de speedup
Figura 6.8: Gráficas de la implementación sin optimizaciones del algoritmo PPI para clúster de GPUs
(Imagen: Cuprite)
Como se puede observar, con esta primera versión se ha conseguido procesar la imagen Cuprite
en un tiempo menor a 30 segundos utilizando 15 nodos de cálculo. Dada la evolución de la gráfica,
no se prevé que se puedan alcanzar tiempos mucho menores con un mayor número de nodos, siendo
debido principalmente al tamaño de la imagen (aprox. 44 MB). Esto se ve claramente en la gráfica de
speedup, cuyo crecimiento no aumenta de forma lineal en relación al número de nodos.
La tabla 6.7 y las gráficas 6.9a y 6.9b muestran el promedio de los resultados medidos en segundos
y las gráficas asociadas para cada configuración de número de nodos de cálculo y la imagen de entrada
Lago St. Clair.
IRT
0,002542
0,003506
0,001745
0,001518
0,001624
0,002574
0,002549
0,003651
0,004518
0,003418
0,006078
0,005709
0,006008
0,005934
0,003697
SKT
0,122611
0,120154
0,117872
0,117741
0,118098
0,119728
0,114798
0,119554
0,117937
0,114695
0,114959
0,113392
0,114950
0,114741
0,114778
BT
0,000029
0,009649
0,013125
0,015572
0,016780
0,018758
0,018530
0,020695
0,020349
0,020803
0,020788
0,021230
0,022057
0,022108
0,021808
ScT
0,328790
0,352597
0,369838
0,370279
0,375730
0,372674
0,366866
0,373793
0,383687
0,401043
0,400755
0,403661
0,413443
0,386402
0,390773
CT
1682,914922
844,719698
564,085151
424,301137
340,638141
280,996522
248,948807
214,010589
190,348702
175,613142
161,405213
148,692089
136,931735
127,406702
120,701931
GT
1682,915040
845,837891
564,554586
424,301872
340,678577
281,971433
249,328818
214,177324
191,033256
176,158855
161,406591
148,693567
137,035074
128,028677
120,703738
PPT
0,000090
0,000161
0,000199
0,000246
0,000292
0,000346
0,000382
0,000483
0,000567
0,000622
0,000691
0,000770
0,000850
0,000917
0,000997
TT
1683,373763
846,329213
565,062664
424,812375
341,196782
282,492184
249,838687
214,703762
191,569801
176,707793
161,960920
149,250247
137,603646
128,571139
121,246150
Tabla 6.7: Resultados de ejecución (en sg.) de la implementación sin optimizaciones del algoritmo PPI
para clúster de GPUs (Imagen: Lago St. Clair )
A la vista de los resultados vemos como la escalabilidad del algoritmo mejora con el aumento del
tamaño de la imagen. Para estas configuraciones (de 1 a 15 nodos), el speedup del algoritmo crece de
forma casi lineal, alcánzandose valores de casi el 14x de mejora de la ejecución de 15 nodos frente a la
de 1 nodo. Esto se debe principalmente a que el tiempo de las transferencias de los datos de entrada
y demás comunicaciones pierden peso frente al tiempo de ejecución del algoritmo.
Por último, se presentan los resultados obtenidos para la ejecución del algoritmo que nos ocupa con
la imagen de mayor tamaño: Yellowstone. La tabla 6.8 muestra el promedio de los tiempos medidos
para cada fase del algoritmo y las gráficas 6.10a y 6.10b representan la evolución del tiempo de
ejecución (CT), el tiempo total (TT) y el speedup, para la misma configuración de ejecución que los
casos anteriores.
A primera vista de los resultados se observa que el tiempo de ejecución del algoritmo para un nodo
es muy pequeño en relación al resto de ejecuciones. Esto es debido a que la GPU no ha permitido
la reserva de memoria para un tamaño de imagen tan grande, abortando la ejecución del algoritmo.
Esto a su vez se debe a que, aunque la GPU disponga de memoria suficiente para alojar la imagen
6.2. DESARROLLO DE PPI PARA EL CLÚSTER DE GPUS
(a) Gráfica de CT y TT (en sg.)
49
(b) Gráfica de speedup
Figura 6.9: Gráficas de la implementación sin optimizaciones del algoritmo PPI para clúster de GPUs
(Imagen: Lago St. Clair )
IRT
0,002139
0,007377
0,002374
0,003407
0,004616
0,004000
0,004720
0,002914
0,005917
0,001506
0,003692
0,005748
0,003897
0,002603
0,003471
SKT
0,119449
0,116187
0,113286
0,114167
0,120276
0,116124
0,113344
0,113354
0,113305
0,113079
0,113619
0,113122
0,113118
0,113626
0,113367
BT
0,000022
0,009560
0,012856
0,015207
0,017174
0,017986
0,018532
0,018849
0,020438
0,021222
0,021155
0,021318
0,021902
0,021854
0,022719
ScT
4,961460
5,630827
5,410332
6,870268
7,420957
7,439791
7,325346
7,201049
6,988009
7,048699
7,104953
7,128804
7,164687
7,238491
6,877310
CT
5,766046
14575,538538
9723,635413
7296,974268
5845,612390
4881,273283
4176,625554
3648,802645
3252,257260
2934,371958
2668,094073
2447,168522
2257,754746
2092,317722
1954,929733
GT
5,766228
14601,182773
9738,133839
7302,139137
5847,861562
4881,274071
4183,655707
3659,390417
3257,402571
2935,358991
2668,250562
2447,169969
2257,756324
2092,319388
1954,931492
PPT
0,000087
0,000166
0,000194
0,000238
0,000296
0,000361
0,000403
0,000490
0,000548
0,000619
0,000706
0,000760
0,000859
0,000927
0,001004
TT
11,059273
14607,533542
9744,291464
7309,712133
5856,008346
4889,466504
4191,692540
3667,297256
3265,101265
2943,106586
2676,098618
2455,051376
2265,799866
2100,265150
1962,553448
Tabla 6.8: Resultados de ejecución (en sg.) de la implementación sin optimizaciones del algoritmo PPI
para clúster de GPUs (Imagen: Yellowstone)
(a) Gráfica de CT y TT (en sg.)
(b) Gráfica de speedup
Figura 6.10: Gráficas de la implementación sin optimizaciones del algoritmo PPI para clúster de GPUs
(Imagen: Yellowstone)
en su memoria global, mayor que el tamaño de la imagen, es muy posible que no exista la memoria
contigua necesaria para almacenarla (solicitada por la llamada a la función cudaMalloc()).
Por este motivo, la gráfica del speedup (ver figura 6.10b) se ha calculado de acuerdo a la ejecución
con menor número de nodos (2 nodos), consiguiendo para la ejecución de 15 nodos una mejora aproximada del 7,5x. Extrapolando el resultado, podemos afirmar que el speedup total conseguido frente
a la versión de un solo nodo serı́a superior a 14x, muy cercano al speedup lineal (15x).
En resumen y a la vista de los resultados obtenidos para cada imagen, el factor de aceleración de
esta primera versión del algoritmo va mejorando según aumenta el tamaño de la imagen de entrada.
Además, se ha conseguido un speedup lineal para el caso de la imagen de mayor tamaño. Hay que
50
CAPÍTULO 6. RESULTADOS EXPERIMENTALES
destacar también que para esta imagen, se han producido errores durante la ejecución del algoritmo
para un solo nodo de computación, debido a que no se ha podido copiar la imagen a la memoria
dedicada de la GPU.
En la siguiente versión se intentará solucionar este problema con el uso de la caracterı́stica denominada Zero Copy de CUDA, que supone un acceso directo a la memoria de la CPU sin necesidad de
copiar la imagen a la memoria dedicada de la GPU.
6.2.2.
Implementación Zero Copy
La primera evolución de la implementación inicial del algoritmo PPI para clúster de GPUs va
orientada a corregir el error producido en la GPU cuando se intenta reservar memoria para la imagen
de Yellowstone. Esto es debido a que la llamada a la función cudaMalloc() que se utiliza en la
implementación inicial devuelve un error ya que no puede reservar un espacio de memoria contiguo
tan grande.
Para evitar la copia del fragmento de la imagen de la memoria del host a la memoria de la GPU se
ha utilizado la caracterı́stica denominada Zero Copy. Con esta técnica, se mapea un área de memoria
de la GPU con una zona de memoria del host no paginable, evitando la copia explı́cita de los datos.
La memoria del host debe ser no paginable o pinned, es decir, que no puede ser paginada a disco, para
acelerar las transferencias al no tener que hacerse comprobaciones referentes a la paginación. Para ello
se utiliza la función de CUDA cudaHostAllocMapped().
cudaSetDeviceFlags ( cudaDeviceMapHost );
cudaHostAlloc (( void **) & pm_image_chunk , ( chunk_size * num_samples * num_bands *
sizeof ( float ) ) , c u d a H o s t A l l o c W r i t e C o m b i n e d | c u d a H o s t A l l o c M a p p e d ) ;
cudaMemcpy ( pm_image_chunk , image_chunk , chunk_size * num_samples * num_bands *
sizeof ( float ) , c u d a M e m c p y H o s t T o H o s t ) ;
c u d a H o s t G e t D e v i c e P o i n t e r (& d_image_chunk , pm_image_chunk , 0) ;
Código 6.2: Cálculo de la selección de skewer para cada kernel
El código 6.2 muestra las lı́neas necesarias para realizar este proceso en CUDA. El primer paso es activar en el dispositivo el uso de memoria no paginada mediante la llamada a la función
cudaSetDeviceFlags() con el flag cudaDeviceMapHost. Hecho esto, se podrá reservar el espacio de
memoria no paginable mediante invocaciones a la función cudaHostAlloc(). En esta implementación
se han utilizado los flags cudaHostAllocMapped, que permite “notificar” al entorno de ejecución el
uso de una zona de memoria como mapeable entre el host y el dispositivo (en definitiva, que se va a
usar como Zero Copy), y cudaHostAllocWriteCombined, que omite el uso de las cachés L1 y L2 de
la CPU, permitiendo el acceso directo a la memoria RAM. Posteriormente se copia el contenido de la
imagen a la memoria no paginable y por último se crea una referencia en la GPU para tener acceso
desde el dispositivo. En cuanto al código a ejecutar en la GPU, éste no cambia respecto a la versión
anterior (ver código 6.3).
int idx = blockDim . x * blockIdx . x + threadIdx . x ;
while ( idx < num_skewers ) {
float min = FLT_MAX , max = FLT_MIN , dot_product = 0.0;
for ( int k = 0; k < num_lines ; k ++) {
for ( int j = 0; j < num_samples ; j ++) {
dot_product = dotProduct (& skewers [ idx * num_bands ] , & image [ k *
num_samples * num_bands + j * num_bands ] , num_bands ) ;
if ( dot_product > max ) {
max = dot_product ;
local_results [ idx * 6 + 0] = k ; // maxX
local_results [ idx * 6 + 1] = j ; // maxY
local_results [ idx * 6 + 2] = dot_product ;
}
if ( dot_product < min ) {
min = dot_product ;
local_results [ idx * 6 + 3] = k ; // minX
local_results [ idx * 6 + 4] = j ; // minY
local_results [ idx * 6 + 5] = dot_product ;
}
}
}
idx += num_skewers
}
Código 6.3: Código del kernel del algoritmo PPI para la implementación Zero Copy
6.2. DESARROLLO DE PPI PARA EL CLÚSTER DE GPUS
51
A continuación, se muestran los resultados de las pruebas realizadas para esta segunda implementación del algoritmo PPI para clúster de GPUs. Las configuraciones y los datos de entrada son los
mismos que en la versión inicial. Para estas pruebas se ha conservado la configuración de 30 bloques
con 512 hilos de ejecución cada uno, manteniendo la premisa de un hilo de ejecución por skewer. La
tabla 6.9 muestra la ocupación de esta segunda versión del algoritmo para las GPUs del entorno de
Producción. La ocupación continúa al 67 %.
Hilos por bloque
Registros por hilo
Memoria compartida por bloque (bytes)
Ocupación de cada multiprocesador
512
23
0
67 %
Tabla 6.9: Datos de ocupación de la GPU para la implementación MPI-CUDA Zero Copy del algoritmo
PPI para el entorno de Producción del clúster de CETA-CIEMAT
La tabla 6.10 muestra el promedio de los resultados medidos en segundos para cada configuración
de número de nodos de cálculo y la imagen de entrada Cuprite. Las gráficas 6.11a y 6.11b representan
la evolución del tiempo de ejecución del algoritmo en cada nodo (CT) y el tiempo total del algoritmo
(TT) ası́ como del speedup para cada configuración.
IRT
0,005613
0,005000
0,005083
0,004657
0,004939
0,005775
0,005894
0,003303
0,006029
0,005888
0,004857
0,003085
0,002307
0,002877
0,002971
SKT
0,097593
0,100252
0,096184
0,097622
0,097505
0,096411
0,095794
0,096202
0,096582
0,096546
0,095726
0,096460
0,096680
0,096360
0,096482
BT
0,000002
0,008054
0,010943
0,012967
0,013675
0,014079
0,015303
0,016754
0,016950
0,017506
0,017809
0,018333
0,018274
0,018044
0,019255
ScT
0,066733
0,074171
0,073975
0,075275
0,078830
0,077357
0,078238
0,079439
0,078743
0,079657
0,079033
0,078841
0,080682
0,080814
0,080902
CT
340,759616
174,724443
118,527903
91,378705
73,442751
63,846850
54,989670
49,081655
44,126817
40,069551
37,447870
35,657757
32,972948
30,673825
29,773322
GT
340,759732
174,985334
120,123084
91,577520
74,747782
63,973611
56,086529
49,585962
45,421145
40,906307
38,291077
36,056652
33,468409
31,587739
30,215363
PPT
0,000084
0,000158
0,000193
0,000262
0,000283
0,000383
0,000437
0,000502
0,000633
0,000620
0,000803
0,000852
0,001101
0,000922
0,001210
TT
340,936536
175,179630
120,316493
91,775458
74,951083
64,176326
56,290965
49,789107
45,629756
41,116369
38,498288
36,262089
33,674957
31,795756
30,425026
Tabla 6.10: Resultados de ejecución (en sg.) de la implementación Zero Copy del algoritmo PPI para
clúster de GPUs (Imagen: Cuprite)
(a) Gráfica de CT y TT (en sg.)
(b) Gráfica de speedup
Figura 6.11: Gráficas de la implementación Zero Copy del algoritmo PPI para clúster de GPUs (Imagen: Cuprite)
A la vista de los resultados de esta etapa para la primera imagen, se puede afirmar que no se ha
obtenido una mejora del tiempo de ejecución del algoritmo para la imagen de Cuprite, pero tampoco el
52
CAPÍTULO 6. RESULTADOS EXPERIMENTALES
uso de acceso directo a memoria host ha empeorado los resultados del algoritmo. Esto probablemente
viene dado por los mecanismos de cacheo de datos de la tarjeta GPU implementados en la arquitectura
Fermi, los cuales tratan de reducir al máximo las transferencias de memoria.
Por otro lado, los datos de la gráfica 6.11b nos muestran que para esta segunda implementación la
escalabilidad empeora ligeramente, obteniéndose un factor de aceleración inferior a 12x de la ejecución
para 15 nodos frente a la de 1 solo nodo.
La tabla 6.11 y las gráficas 6.12a y 6.12b muestran el promedio de los resultados medidos en
segundos y las gráficas asociadas para la imagen de entrada Lago St. Clair.
IRT
0,002610
0,004885
0,005645
0,006044
0,005730
0,003090
0,004931
0,004837
0,005452
0,002642
0,003322
0,006156
0,005950
0,004031
0,006022
SKT
0,119456
0,117834
0,117634
0,114526
0,114706
0,114812
0,114177
0,114627
0,114313
0,114446
0,115052
0,114588
0,114777
0,113935
0,114578
BT
0,000002
0,009521
0,012812
0,014966
0,016159
0,016930
0,017445
0,018705
0,019816
0,020343
0,020101
0,021278
0,021308
0,041220
0,021642
ScT
0,310544
0,367247
0,378820
0,382612
0,386493
0,385774
0,384678
0,384178
0,397159
0,397886
0,401576
0,402065
0,411273
0,386635
0,390141
CT
1681,069079
843,238162
564,876730
426,538869
342,878733
285,884617
248,252611
217,737151
192,627282
175,812533
162,411108
148,671750
136,169852
127,812292
120,788521
GT
1681,069193
844,528266
566,889622
428,034216
344,323565
287,720566
248,535986
218,620947
194,100704
177,143451
162,412449
148,807031
137,803295
129,077415
121,773408
PPT
0,000087
0,000156
0,000206
0,000251
0,000326
0,000378
0,000542
0,000527
0,000549
0,000755
0,001114
0,001204
0,000857
0,001230
0,001319
TT
1681,506842
845,035675
567,413802
428,562247
344,856770
288,249343
249,067529
219,153517
194,648119
177,687649
162,962069
149,364141
138,369482
129,633940
122,319136
Tabla 6.11: Resultados de ejecución (en sg.) de la implementación Zero Copy del algoritmo PPI para
clúster de GPUs (Imagen: Lago St. Clair )
(a) Gráfica de CT y TT (en sg.)
(b) Gráfica de speedup
Figura 6.12: Gráficas de la implementación Zero Copy del algoritmo PPI para clúster de GPUs (Imagen: Lago St. Clair )
De manera similar a lo ocurrido con la implementación inicial para esta imagen de entrada, el
factor de aceleración conseguido para la imagen del Lago St. Clair ha mejorado, alcanzando un valor
muy próximo a 14x. En este caso la diferencia con respecto a los speedups alcanzados para la primera
versión es muy pequeña. En cuanto al tiempo de ejecución, el mejor resultado (versión de 15 nodos)
ha empeorado en más de 1 segundo respecto a la primera implementación, posiblemente debido al
mayor movimiento de datos entre el host y la GPU.
Por último, se presentan los resultados medidos para el procesamiento de la imagen de Yellowstone.
Dados los resultados para las dos imágenes de menor tamaño, se puede determinar a priori que esta
versión mejorará el cuanto a speedup, pero puede que empeore en cuanto a tiempo de ejecución. Los
datos se presentan en la tabla 6.12 y las gráficas 6.13a y 6.13b.
Tal y como se comentó anteriormente, los resultados obtenidos del procesamiento de la imagen
Yellowstone han confirmado la mejora del factor de aceleración respecto a las ejecuciones con las
imágenes de menor tamaño. Como ocurrió con la versión inicial, se ha conseguido un speedup lineal.
En cuanto al tiempo de ejecución, en contra con lo afirmado anteriormente, ha disminuido 30 segundos
6.2. DESARROLLO DE PPI PARA EL CLÚSTER DE GPUS
IRT
0,001432
0,005772
0,006223
0,005669
0,011909
0,006029
0,005811
0,001720
0,005850
0,004941
0,005888
0,005288
0,002029
0,005939
0,004008
SKT
0,114679
0,121186
0,120642
0,114923
0,114950
0,120580
0,114981
0,114288
0,114937
0,114470
0,114480
0,114675
0,114467
0,114968
0,114481
BT
0,000002
0,009676
0,012811
0,015088
0,016499
0,016734
0,018201
0,019526
0,020080
0,020789
0,019682
0,021040
0,021658
0,023319
0,022307
ScT
5,230289
5,677227
5,666692
6,792180
7,373056
7,496450
7,198692
7,258234
7,052949
7,086271
7,161734
7,205575
7,212340
7,294426
6,947605
CT
28710,449690
14350,617940
9626,155269
7207,478735
5759,512698
4820,486999
4119,450682
3616,152097
3207,720680
2888,539941
2625,830895
2405,140376
2221,554608
2063,074039
1927,449961
53
GT
28710,474150
14418,722470
9626,155737
7218,682973
5775,036039
4820,487800
4124,393175
3616,153587
3210,328402
2889,458959
2629,822069
2411,145821
2225,625693
2067,114146
1930,864148
PPT
0,000102
0,000162
0,000239
0,000237
0,000281
0,000486
0,000374
0,000746
0,000548
0,000596
0,000819
0,000884
0,000840
0,000918
0,000996
TT
28715,856490
14424,579010
9632,005186
7225,660245
5782,595961
4828,158814
4131,774424
3623,592535
3217,566989
2896,729635
2637,172386
2418,564595
2233,016808
2074,597593
1937,997324
Tabla 6.12: Resultados de ejecución (en sg.) de la implementación Zero Copy del algoritmo PPI para
clúster de GPUs (Imagen: Yellowstone)
(a) Gráfica de CT y TT (en sg.)
(b) Gráfica de speedup
Figura 6.13: Gráficas de la implementación Zero Copy del algoritmo PPI para clúster de GPUs (Imagen: Yellowstone)
respecto a la versión inicial, procesándose la imagen en 32 minutos aproximadamente, lo cual no
resulta muy coherente. Este hecho puede ser debido a diversas causas, desde una gestión diferente de
los accesos respecto a la memoria global, hasta el que el movimiento de datos entre el host y la GPU
y el procesamiento de la imagen se coordinan mejor que en la versión anterior. Debido a que no se ha
experimentado una mejora sustancial en el tiempo de ejecución del algoritmo, no se investigará dicho
suceso en profundidad para centrar el esfuerzo en otro tipo de mejoras.
Cabe destacar que con esta implementación ya no aparece el problema del error de reserva de
memoria que impedı́a la ejecución del algoritmo para un solo nodo. Aún ası́, por cuestiones de rendimiento, el uso de acceso directo a la memoria del host no es recomendable para tarjetas GPU con
memoria dedicada, recomendándose solo para tarjetas GPU con memoria compartida con la CPU o
en los casos en los que los datos de entrada no puedan almacenarse en la memoria de la GPU y se
realicen pocos accesos a memoria (read once / write once).
En el siguiente apartado se desestima el uso de Zero Copy memory, dado que el problema solamente
surge para ejecuciones en un nodo de cómputo, y se implementa el uso de los registros de la GPU
para mejorar los tiempos de procesamiento.
6.2.3.
Implementación con uso de memoria local
Tras comprobar que el uso de memoria Zero Copy soluciona el problema de almacenamiento de
datos de gran tamaño en la GPU, se procede a evolucionar la versión inicial con vistas a disminuir el
tiempo de ejecución del algoritmo PPI. En la programación GPU, una de las principales razones que
afectan al rendimiento de un algoritmo es el patrón de acceso a memoria. Las GPUs proporcionan
mecanismos para disminuir los accesos a bloques de memoria contiguos realizados por los threads de
54
CAPÍTULO 6. RESULTADOS EXPERIMENTALES
un mismo bloque [2]. Ası́ mismo, la arquitectura Fermi implementa una jerarquı́a de caché de dos
niveles, la cual se presenta en el apartado 3.2.1 del capı́tulo 3, orientada a reducir el tiempo de acceso
a la memoria DRAM del dispositivo.
En la primera versión, presentada en el apartado 6.2.1 del presente capı́tulo, los accesos a memoria
global para leer los pı́xeles de la imagen de entrada son a las mismas posiciones de memoria, dado que
todos los hilos leen la misma imagen. Eso provoca que se produzcan aciertos de caché y se reduzca
el tiempo de acceso a estos datos. Por el contrario, cada hilo debe acceder a una zona de memoria
diferente donde se encuentra el skewer que necesita para calcular las proyecciones con cada pı́xel de
la imagen. En este caso, como no hay coincidencias de lectura de datos, se producen fallos de caché y
como consecuencia el rendimiento del algoritmo empeora. Este comportamiento no deseado será el
que intentará corregir la versión del algoritmo basada en memoria local o local memory.
La memoria local de la GPU es un espacio privado de memoria que es único para cada hilo de
la GPU. Su almacenamiento fı́sico real se produce en la memoria global del dispositivo y consecuentemente tiene los mismos tiempos de acceso que ésta, pero la GPU la gestiona de manera diferente.
Primeramente, el alineamiento de los datos almacenados en este tipo de memoria se realiza para favorecer las lecturas en bloque (coalescentes) para hilos contiguos de la CPU. Además, el dispositivo
prioriza el almacenamiento de los datos de memoria local a la caché de primer nivel L1 para reducir
el número de accesos a la memoria global.
La idea que mueve esta versión del algoritmo paralelo PPI es la de almacenar el skewer con el
que trabaja un hilo en la memoria privada del mismo, de tal forma que cambie el patrón de acceso a
los valores del vector aleatorio y se consiga una mejora del rendimiento. La primera intención de esta
versión era el almacenamiento del vector de skewers en los registros de la GPU, los cuales tienen un
coste de acceso despreciable, pero el tamaño del vector aleatorio (224 × 4 bytes = 896 bytes) no hacı́a
viable esta idea dado que el número de registros asignados a un hilo de la GPU está limitado a 63
como máximo (debido a una restricción del número de bits de direccionamiento [4]) y el número de
registros requeridos por el skewer es de 896 bytes/4 bytes por registro = 224.
Cabe destacar que es muy importante hacer un uso de los registros de la GPU limitado debido
principalmente a que si se supera la cantidad máxima por hilo de ejecución afectará al porcentaje
de ocupación de la GPU y muy probablemente al rendimiento. Las GPUs del entorno de Producción
del clúster de CETA-CIEMAT tienen un total de 32.768 registros y permiten un total de 1.536 hilos
por multiprocesador. Este hecho limita a un máximo de 32768/1536 = 21, 3 registros por hilo para
alcanzar la ocupación máxima.
El código 6.4 muestra la declaración de un array en la memoria local de la GPU, de tamaño
máximo 224, suficiente para alojar el vector aleatorio. Como se puede observar, no es necesario el uso
de ningún modificador ni directiva para la declaración de una variable local.
float skewer [224];
// Copy a skewer a local memory
for ( short k = 0; k < num_bands ; k ++) {
skewer [ k ] = skewers [ idx * num_bands + k ];
}
Código 6.4: Declaración de un array en memoria local de la GPU (registros) para el almacenamento
del skewer con el que trabajará el hilo de ejecución
La tabla 6.13 muestra los datos de ocupación de la GPU de esta versión del algoritmo. Como se
puede observar, se hace uso de 22 registros por hilo, provocando que la ocupación de la GPU no esté al
100 %. En esta ocasión se ha modificado la configuración de ejecución a 60 bloques de 256 hilos por
bloque, lo que supone un aumento de la ocupación al 83 %.
Hilos por bloque
Registros por hilo
Memoria compartida por bloque (bytes)
Ocupación de cada multiprocesador
256
22
0
83 %
Tabla 6.13: Datos de ocupación de la GPU para la implementación MPI-CUDA local memory del
algoritmo PPI para el entorno de Producción del clúster de CETA-CIEMAT
En cuanto al cuerpo del kernel (ver Código 6.5), el único cambio significativo está relacionado con
el uso del array local skewer para el almacenamento del vector aleatorio que se utilizará durante el
cálculo de la proyección (producto escalar) de cada pı́xel de la imagen sobre dicho vector.
6.2. DESARROLLO DE PPI PARA EL CLÚSTER DE GPUS
55
int idx = blockDim . x * blockIdx . x + threadIdx . x ;
while ( idx < num_skewers ) {
float skewer [224];
// Copy a skewer a local memory
for ( short k = 0; k < num_bands ; k ++) {
skewer [ k ] = skewers [ idx * num_bands + k ];
}
float min = FLT_MAX ;
float max = FLT_MIN ;
float dot_product = 0.0;
for ( int k = 0; k < num_lines ; k ++) {
for ( int j = 0; j < num_samples ; j ++) {
dot_product = dotProduct ( skewer , & image [ k * num_samples * num_bands + j
* num_bands ] , num_bands ) ;
if ( dot_product > max ) {
max = dot_product ;
local_results [ idx * 6 + 0] = k ; // maxX
local_results [ idx * 6 + 1] = j ; // maxY
local_results [ idx * 6 + 2] = dot_product ;
}
if ( dot_product < min ) {
min = dot_product ;
local_results [ idx * 6 + 3] = k ; // minX
local_results [ idx * 6 + 4] = j ; // minY
local_results [ idx * 6 + 5] = dot_product ;
}
}
}
idx += num_skewers ;
}
Código 6.5: Código del kernel del algoritmo PPI para la implementación local memory
A continuación se muestran los resultados obtenidos de la ejecución de esta versión de PPI para
las tres imágenes.
La tabla 6.14 muestra el promedio de los resultados medidos en segundos ejecuciones de 1 a 15
nodos y la imagen de entrada Cuprite. Las gráficas 6.14a y 6.14b representan la evolución del tiempo
de ejecución del algoritmo en cada nodo (CT) y el tiempo total del algoritmo (TT) ası́ como del
speedup para cada configuración.
IRT
0,005101
0,004546
0,005061
0,004993
0,004838
0,004909
0,005328
0,004650
0,005125
0,004728
0,004370
0,004978
0,004749
0,004516
0,005100
SKT
0,098678
0,099765
0,098564
0,098323
0,096915
0,096133
0,096188
0,095941
0,096407
0,096248
0,095983
0,095870
0,096411
0,095691
0,096448
BT
0,000022
0,009976
0,010836
0,012567
0,013854
0,014897
0,015393
0,016424
0,017327
0,018085
0,023903
0,018486
0,018559
0,018518
0,019882
ScT
0,061240
0,066934
0,069347
0,072766
0,075090
0,073440
0,074382
0,075370
0,076165
0,077415
0,077184
0,077182
0,077846
0,078339
0,078548
CT
23,036714
14,448204
11,438934
10,264137
9,381146
8,675665
8,130888
8,131217
7,821537
7,710534
7,582804
7,554543
7,317478
7,173489
6,920080
GT
23,036820
14,639335
11,933519
10,714850
9,859819
9,237495
8,891306
8,631233
8,439901
8,244788
8,120437
7,951359
7,927773
7,830721
7,729951
PPT
0,000086
0,000155
0,000192
0,000237
0,000280
0,000325
0,000384
0,000453
0,000534
0,000617
0,000687
0,000765
0,000832
0,000909
0,000976
TT
23,208729
14,826948
12,124826
10,911214
10,058303
9,435137
9,091374
8,832101
8,643854
8,450503
8,330652
8,157887
8,135422
8,038347
7,940828
Tabla 6.14: Resultados de ejecución (en sg.) de la implementación local memory del algoritmo PPI
para clúster de GPUs (Imagen: Cuprite)
A la vista de los resultados obtenidos se puede apreciar que se ha reducido de forma notable el
tiempo de ejecución del algoritmo, pasando de los 30 segundos de la versión inicial a los apenas 8
56
CAPÍTULO 6. RESULTADOS EXPERIMENTALES
(a) Gráfica de CT y TT (en sg.)
(b) Gráfica de speedup
Figura 6.14: Gráficas de la implementación local memory del algoritmo PPI para clúster de GPUs
(Imagen: Cuprite)
segundos que tarda la ejecución de la versión descrita en este apartado para 15 nodos. Esta reducción
notable del tiempo de ejecución afecta al speedup conseguido, que apenas alcanza el 2,5x para el
tiempo total de ejecución, principalmente provocado por el coste de las transferencias de datos entre
los nodos de cómputo en primer lugar y en segundo lugar por el de las transferencias entre el host y
el dispositivo. Se ha calculado el tiempo de ejecución del kernel en la GPU y es de 1, 29 sg., frente a
los 22, 19 sg. calculados para la versión inicial del algoritmo que no implementaba optimizaciones.
Tras presentar los resultados obtenidos para la imagen de Cuprite, se muestran a continuación
aquellos obtenidos para la imagen del Lago St. Clair. La tabla 6.15 muestra el promedio de los tiempos
de ejecución para configuraciones de 1 a 15 nodos y posteriormente las figuras 6.15a y 6.15b ilustran
la evolución del tiempo de cómputo (CT) y el tiempo total (TT) según evoluciona el número de nodos
de cómputo, ası́ como la evolución del speedup para dichas configuraciones. Dados los resultados
obtenidos para la imagen más pequeña, cabrı́a esperar también una notable mejora de rendimiento
para la imagen del Lago St. Clair.
IRT
0,003719
0,004849
0,003828
0,002143
0,004362
0,004364
0,004412
0,002041
0,005047
0,004423
0,004682
0,005437
0,003935
0,004707
0,002842
SKT
0,121321
0,120804
0,120770
0,120860
0,119432
0,118761
0,118925
0,118898
0,114452
0,114559
0,114609
0,114734
0,114598
0,114100
0,114798
BT
0,000026
0,009528
0,012839
0,015241
0,016289
0,017503
0,018343
0,019459
0,020021
0,021114
0,020731
0,021749
0,021294
0,022275
0,022932
ScT
0,309108
0,375402
0,365294
0,380260
0,378752
0,394136
0,382319
0,376856
0,396691
0,398375
0,400935
0,403094
0,409218
0,383360
0,388511
CT
93,201709
49,118143
34,574901
27,892955
23,358827
20,223921
18,328444
16,907292
15,478415
14,766224
13,964797
13,280844
12,761645
12,020751
11,829046
GT
93,201821
49,153271
34,699710
27,990033
23,783166
20,871107
18,944631
17,348269
15,907097
14,993860
14,232090
13,525592
13,155483
12,671629
12,243934
PPT
0,000090
0,000161
0,000206
0,000246
0,000293
0,000347
0,000399
0,000458
0,000542
0,000625
0,000688
0,000759
0,000849
0,000925
0,000999
TT
93,642087
49,671612
35,210487
28,514849
24,310824
21,414485
19,477920
17,872652
16,453214
15,542197
14,783668
14,082083
13,714948
13,206913
12,782979
Tabla 6.15: Resultados de ejecución (en sg.) de la implementación local memory del algoritmo PPI
para clúster de GPUs (Imagen: Lago St. Clair )
Tal y como se esperaba, el tiempo de ejecución de esta versión del algoritmo también se ha reducido
de forma notable respecto a las versiones anteriores, bajando de los 2 minutos que tardaba la versión
inicial para 15 nodos a los aproximadamente 13 segundos de ésta para la imagen de tamaño medio.
A la vista de las gráficas de rendimiento, el speedup del algoritmo mejora frente al obtenido para la
imagen de Cuprite, alcanzando una mejora del 7x debida principalmente a que las comunicaciones
entre nodos y la transferencia entre host y GPU pierden peso frente al tiempo empleado en la ejecución
del algoritmo. Si se sigue esta tendencia, la ejecución para la imagen de entrada de Yellowstone será la
que alcance un mayor factor de aceleración y también verá reducido significativamente el tiempo de
ejecución.
6.2. DESARROLLO DE PPI PARA EL CLÚSTER DE GPUS
(a) Gráfica de CT y TT (en sg.)
57
(b) Gráfica de speedup
Figura 6.15: Gráficas de la implementación local memory del algoritmo PPI para clúster de GPUs
(Imagen: Lago St. Clair )
Siguiendo el esquema de presentación de resultados utilizado a lo largo de esta memoria, la tabla
6.16 presenta el promedio de los tiempos de ejecución medidos para cada uno de los parámetros
descritos en el apartado 6.1.2 del presente capı́tulo y las figuras 6.16a y 6.16b muestran la evolución
de los tiempos de ejecución y del speedup según aumenta el número de nodos de cómputo utilizados.
IRT
0,004491
0,004753
0,004310
0,004867
0,004299
0,004465
0,004419
0,004053
0,004449
0,004926
0,005443
0,003794
0,004394
0,004390
0,002909
SKT
0,120952
0,120826
0,120770
0,118830
0,120946
0,118683
0,114942
0,114759
0,114756
0,114766
0,114614
0,114438
0,114184
0,114633
0,114631
BT
0,000026
0,009431
0,012805
0,015365
0,016337
0,017854
0,018821
0,019254
0,019887
0,020198
0,020656
0,022006
0,021748
0,022366
0,021991
ScT
5,047203
5,439158
5,225850
6,965751
7,270667
7,314724
7,205072
7,065163
7,024875
7,093697
7,156510
7,201065
7,237853
7,281797
6,925390
CT
5,701569
756,793811
503,848671
380,497205
305,191945
255,139061
220,607593
193,779202
173,153925
156,300174
142,844738
130,888048
121,699176
113,330393
105,938751
GT
5,701641
756,794192
504,717033
380,497804
305,192636
255,180258
220,608767
193,780601
173,155453
156,301425
142,846084
130,889500
121,700737
113,332079
105,940529
PPT
0,000090
0,000163
0,000205
0,000242
0,000294
0,000346
0,000392
0,000458
0,000542
0,000625
0,000693
0,000763
0,000844
0,000920
0,000987
TT
10,909211
762,411248
510,126280
387,639080
312,648455
262,676779
227,995265
201,028339
180,362056
163,578063
150,187122
138,274753
129,123323
120,801127
113,048970
Tabla 6.16: Resultados de ejecución (en sg.) de la implementación local memory del algoritmo PPI
para clúster de GPUs (Imagen: Yellowstone)
(a) Gráfica de CT y TT (en sg.)
(b) Gráfica de speedup
Figura 6.16: Gráficas de la implementación local memory del algoritmo PPI para clúster de GPUs
(Imagen: Yellowstone)
Al igual que ocurrı́a con la imagen de Lago St. Clair, esta versión del algoritmo PPI ha reducido
también el tiempo de ejecución respecto a las versiones anteriores, siendo el menor tiempo de ejecución
el alcanzado por la configuración de 15 nodos. Esto significa que se ha conseguido procesar una imagen
de 4 GB en menos de 2 minutos de tiempo. Además, se ha conseguido un speedup del 7x respecto
58
CAPÍTULO 6. RESULTADOS EXPERIMENTALES
a la versión que utiliza 2 nodos, puesto que, como ocurrı́a en la versión inicial, el procesamiento de
ésta imagen en un solo nodo de cómputo provoca errores al no poderse almacenar dicha imagen en la
memoria del dispositivo. Extrapolando los datos podemos afirmar que se consiguirı́a un speedup en
torno al 12,5x respecto a la versión de un solo nodo.
6.2.4.
Implementación con optimizaciones de compilación
En la implementación descrita en el apartado anterior se introdujo un cambio en la gestión de los
skewers que provocó una reducción notable del tiempo de ejecución del algoritmo PPI, destacando
especialmente el procesamiento de la imagen Yellowstone que alcanzó una reducción de más del 80 %
en el tiempo total de ejecución. Aun ası́, la ocupación de la GPU no alcanzaba el 100 %, por lo que
en esta cuarta versión se intentará alcanzar una ocupación total del dispositivo de cara a reducir aún
más el tiempo de ejecución.
Para ello, partiendo de la información proporcionada por las gráficas de la herramienta CUDA
Occupancy Calculator se identifica que mediante una reducción a 20 del número de los registros por
thread de la GPU, el cual asciende a 22 en la versión local memory, se puede conseguir una ocupación
del 100 % de la GPU. Para conseguir este fin, se utilizará el parámetro que proporciona el compilador
de CUDA --maxrregcount, que limita el número máximo de registros por thread que utilizará la
GPU. Esta opción funciona de la siguiente manera: si el número de registros introducido como lı́mite
es múltiplo de 4 se usará ese valor y en caso contrario se establecerá como lı́mite el múltiplo de 4
mayor más próximo.
Aplicando esta premisa a nuestro problema, se establece el número de registros a utilizar a 16. No
se ha seleccionado un valor mayor que sea múltiplo de 4 a efectos de evaluar cómo varı́a el rendimiento
con una diferencia más amplia. Además, se vuelve a recuperar la configuración de 30 bloques con 512
hilos cada uno dado que esta configuración también produce un 100 % de ocupación. La tabla 6.17
muestra la configuración para esta versión.
Hilos por bloque
Registros por hilo
Memoria compartida por bloque (bytes)
Ocupación de cada multiprocesador
512
16
0
100 %
Tabla 6.17: Datos de ocupación de la GPU para la implementación MPI-CUDA con optimizaciones
de compilación del algoritmo PPI para el entorno de Producción del clúster de CETA-CIEMAT
En cuanto al código del kernel que se ejecutará en la GPU, no varı́a respecto a la versión local
memory descrita en la versión anterior (ver código 6.5 del apartado 6.2.3).
Adicionalmente a la reducción del número de registros y dado que la implementación del kernel
no utiliza memoria compartida, se procede al aumento de la capacidad de la memoria caché L1 para
propiciar un aumento de aciertos de caché que permita reducir el número de accesos a memoria
global de la GPU y, por lo tanto, mejorar el rendimiento del algoritmo. Para ello se introduce como
modificación el código 6.6. Esta configuración, aplicada antes de la invocación del kernel, solicita a
la GPU el aumento de tamaño de la caché L1 a 48KB, en lugar de los 16KB asignados por defecto,
en detrimento del tamaño asignado a la memoria compartida de bloque que se ajusta a 16KB. La
función cudaFuncSetCacheConfig() permite configurar programáticamente para un kernel dado la
preferencia de uso de memoria compartida o caché L1. El flag cudaFuncCachePreferL1 indica la
preferencia por la segunda opción.
c u d a F u n c S e t C a c h e C o n f i g ( " ppi " , c u d a F u n c C a c h e P r e f e r L 1 ) ;
Código 6.6: Código que permite el aumento del tamaño de la caché L1 de la GPU
La tabla 6.18 presenta los resultados obtenidos con esta versión del algoritmo para la imagen
Cuprite. Como ocurre en la versión anterior basada en local memory, no se manifiesta una reducción
del tiempo total de ejecución del algoritmo, debido principalmente a la penalización que introducen
las transferencias de datos entre la CPU y la GPU y la comunicación entre los nodos de cómputo. En
cuanto al factor de aceleración, el algoritmo evoluciona de manera similar al anterior, consiguiendo
una mejora ligeramente superior (>3x), pero continuando con la pobre escalabilidad del algoritmo
para imágenes de pequeño tamaño.
6.2. DESARROLLO DE PPI PARA EL CLÚSTER DE GPUS
IRT
0,004272
0,004055
0,003893
0,003262
0,003219
0,002674
0,002918
0,002817
0,002532
0,002969
0,002993
0,003364
0,003365
0,003656
0,004502
SKT
0,100712
0,100920
0,100094
0,097691
0,096945
0,098698
0,098385
0,096385
0,096208
0,096315
0,096402
0,096283
0,096184
0,096338
0,096468
BT
0,000002
0,008010
0,010844
0,012914
0,014038
0,015284
0,015604
0,016883
0,017303
0,017963
0,018132
0,018521
0,019343
0,018548
0,019332
ScT
0,064539
0,071268
0,073554
0,075971
0,077773
0,078009
0,078140
0,078589
0,078771
0,080012
0,079498
0,079320
0,080325
0,080244
0,080908
CT
24,496807
15,597140
12,334444
10,987662
9,766403
9,076478
8,718414
8,639395
8,160504
8,006253
7,796685
7,331805
7,596470
7,148420
7,242082
59
GT
24,496924
15,831477
12,711785
11,271803
10,269583
9,539273
9,235675
8,954391
8,632493
8,466980
8,288210
8,047796
8,001797
7,971463
7,835678
PPT
0,000087
0,000162
0,000200
0,000241
0,000287
0,000343
0,000404
0,000475
0,000554
0,000624
0,000691
0,000776
0,000857
0,000923
0,001001
TT
24,672050
16,021618
12,907177
11,467695
10,467982
9,739874
9,437225
9,155953
8,834029
8,671907
8,493088
8,253444
8,209347
8,179566
8,047227
Tabla 6.18: Resultados de ejecución (en sg.) de la implementación con optimizaciones de compilación
del algoritmo PPI para clúster de GPUs (Imagen: Cuprite)
(a) Gráfica de CT y TT (en sg.)
(b) Gráfica de speedup
Figura 6.17: Gráficas de la implementación con optimizaciones de compilación del algoritmo PPI para
clúster de GPUs (Imagen: Cuprite)
En el caso de la imagen del Lago St. Clair, el tiempo total de ejecución es similar al de la versión
descrita en el apartado anterior. De hecho, los resultados obtenidos son ligeramente peores, debido
principalmente al fenómeno denominado desbordamiento de registros o register spilling [37]. Este
fenómeno ocurre cuando el número de registros máximos establecidos para cada thread es insuficiente
para el kernel que se va a ejecutar. Esto se detecta con la salida de la compilación del código fuente si el
flag -Xptxas=-v está activado. Este desborde provoca que los datos que no se han podido almacenar
en los registros se almacenen en memoria local, con tiempos de accesos mayores, provocando una
caı́da del rendimiento. Este factor también ocurrı́a en el procesamiento de la imagen Cuprite, pero se
camuflaba con la penalización por las transferencias de datos entre host y dispositivo.
(a) Gráfica de CT y TT (en sg.)
(b) Gráfica de speedup
Figura 6.18: Gráficas de la implementación con optimizaciones de compilación del algoritmo PPI para
clúster de GPUs (Imagen: Lago St. Clair )
60
IRT
0,005766
0,003949
0,003354
0,003585
0,003916
0,004093
0,004852
0,004644
0,003294
0,002645
0,004747
0,003410
0,004425
0,004371
0,004054
CAPÍTULO 6. RESULTADOS EXPERIMENTALES
SKT
0,119411
0,119093
0,119802
0,117978
0,117239
0,115712
0,115354
0,114592
0,114661
0,114748
0,114685
0,114418
0,114579
0,114354
0,114557
BT
0,000002
0,009499
0,012754
0,015095
0,016693
0,017405
0,018444
0,019518
0,019313
0,020892
0,020548
0,021689
0,021613
0,022287
0,022265
ScT
0,315346
0,349727
0,367835
0,377176
0,389263
0,390930
0,382179
0,382582
0,398379
0,400883
0,404565
0,405705
0,408605
0,384867
0,388705
CT
102,720709
53,709227
37,831152
29,917336
25,106306
21,935792
19,688626
18,198350
16,778827
15,708724
14,736118
14,039456
13,378398
12,911301
12,712763
GT
102,720824
53,952885
38,226190
30,347664
25,562380
22,304449
20,157002
18,450896
17,012494
16,063433
15,191168
14,450360
13,755763
13,276968
12,867922
PPT
0,000088
0,000158
0,000199
0,000244
0,000287
0,000337
0,000401
0,000466
0,000554
0,000626
0,000694
0,000768
0,000854
0,000929
0,000999
TT
103,168611
54,441920
38,737827
30,868831
26,097683
22,841261
20,687371
18,981789
17,556516
16,610837
15,746574
15,005667
14,315817
13,813935
13,408644
Tabla 6.19: Resultados de ejecución (en sg.) de la implementación con optimizaciones de compilación
del algoritmo PPI para clúster de GPUs (Imagen: Lago St. Clair )
En cuanto al factor de aceleración conseguido para esta imagen de entrada, éste aumenta a aproximadamente un 8x, superior al conseguido para la misma imagen y la versión del algoritmo anterior.
Esto sólo indica que el algoritmo escala ligeramente mejor, pero el tiempo de ejecución total empeora.
Finalmente, para el procesamiento de la imagen más grande, Yellowstone, se consiguen los resultados expuestos en la tabla 6.20. En esta ocasión sı́ se percibe notablemente el empeoramiento del
tiempo de ejecución del algoritmo provocado por el register spilling dado que la ejecución más rápida,
correspondiente a la configuración de 15 nodos, es aproximadamente un 10 % más lenta que la versión
basada en local memory.
IRT
0,002804
0,004687
0,003829
0,003450
0,005021
0,004408
0,004499
0,004645
0,004167
0,004959
0,003865
0,004782
0,003480
0,003860
0,004119
SKT
0,117270
0,118609
0,116119
0,118544
0,118947
0,116944
0,114463
0,114452
0,114308
0,114780
0,114726
0,114786
0,114587
0,114519
0,114636
BT
0,000002
0,009424
0,012638
0,014911
0,016461
0,017628
0,018178
0,019169
0,019840
0,020801
0,020530
0,021579
0,021645
0,021768
0,022150
ScT
5,728717
5,059573
5,311343
6,972659
7,198395
7,202100
7,131761
6,923381
7,054056
7,111845
7,162059
7,192657
7,218305
7,294218
6,938815
CT
6,076623
826,619394
556,067588
417,029938
334,175347
281,098572
241,236472
211,685312
190,421293
171,752177
156,435695
144,534062
133,441804
124,812662
116,897165
GT
6,076696
831,547152
558,279981
418,844816
335,369278
281,895375
242,634762
212,607251
190,479745
171,916446
156,691119
144,535503
133,506242
124,814328
116,898942
PPT
0,000087
0,000158
0,000196
0,000241
0,000285
0,000329
0,000379
0,000452
0,000543
0,000607
0,000706
0,000803
0,000837
0,000914
0,001026
TT
11,959669
836,774550
563,760637
425,993195
342,746721
289,277675
249,941800
219,707373
197,716695
179,212621
164,037294
151,914091
140,907340
132,295992
124,025086
Tabla 6.20: Resultados de ejecución (en sg.) de la implementación con optimizaciones de compilación
del algoritmo PPI para clúster de GPUs (Imagen: Yellowstone)
Resumiendo los resultados obtenidos, las variaciones de la configuración de la GPU que se han
introducido en esta versión no han dado los resultados esperados. Lejos de reducir el tiempo de ejecución del algoritmo, hemos provocado un comportamiento no deseado que ha empeorado los resultados.
Para la siguiente versión, se eliminarán las mejoras introducidas en esta versión y se implementará una
solución que haga uso de la memoria compartida de bloque o shared memory, una memoria a la que
tienen acceso todos los hilos de un mismo bloque y de acceso muy rápido. Por otro lado, el fenómeno
de register spilling no siempre significa una caı́da del rendimiento, por lo que en versiones sucesivas
se impondrá un lı́mite de 20 registros por hilo para alcanzar la máxima de ocupación en la GPU.
6.2. DESARROLLO DE PPI PARA EL CLÚSTER DE GPUS
(a) Gráfica de CT y TT (en sg.)
61
(b) Gráfica de speedup
Figura 6.19: Gráficas de la implementación con optimizaciones de compilación del algoritmo PPI para
clúster de GPUs (Imagen: Yellowstone)
6.2.5.
Implementación basada en memoria compartida
Continuando con la evolución de la implementación del algoritmo PPI para clúster de GPUs, este
apartado describe una nueva implementación basada en el uso de la memoria compartida por bloque o
shared memory. Esta memoria es muy rápida en comparación con la memoria global de la GPU, pero
por contra tiene un tamaño limitado (de 16 KB a 48 KB). El uso de memoria compartida pretende
reducir las transferencias de memoria mediante la copia y compartición de un conjunto de pı́xeles de
la imagen entre todos los hilos de un bloque. Cabe recordar que la jerarquı́a de memoria que ofrece
CUDA se describió en el apartado 3.2.1 del capı́tulo 3.
Para que una variable se almacene en memoria compartida o shared memory debe añadirse en
su declaración el modificador de tipo introducido por CUDA llamado shared . Tal y como se
describe en el apartado 3.2.2 del capı́tulo 3, este modificador provoca que la variable asociada resida
en memoria compartida y sea accesible por todos los hilos de un mismo bloque durante el tiempo de
vida de éste. El código 6.7 presenta la declaración de un array llamado sm pixels, que actuará como
caché programática para que todos los hilos de un bloque accedan a un conjunto de pı́xeles de la
imagen a procesar que se han almacenado previamente en dicho array, evitando que cada hilo de un
bloque acceda directamente a la memoria global. El resto del kernel, que se muestra en el código 6.9
debe adaptarse para implementar la copia de los pı́xeles al vector sm pixels y posteriormente calcular
las proyecciones al skewer asignado partiendo de los datos almacenados en éste. Cabe destacar el uso
que se realiza de la función syncthreads() para establecer dos puntos de sincronización entre los
hilos de un bloque a lo largo del kernel, a saber:
El primer punto de sincronización se establece para que los hilos no accedan al espacio de
memoria compartida antes de la copia de los pı́xeles de la imagen a procesar.
El segundo punto de sincronización se establece para que no se actualice el contenido del array
de memoria compartida con nuevos pı́xeles antes de que finalice el cálculo de la proyección de
los pı́xeles actuales al skewer por los hilos del bloque.
El tamaño del array sm pixels viene dado por el número de pı́xeles que puede almacenar, almacenado en una constante llamada N pixels, y por sus respectivos valores espectrales, indicado por la
variable num bands, de ahı́ que su tamaño sea de N pixels * num bands (ver código 6.7).
__shared__ float sm_pixels [ N_Pixels * num_bands ];
Código 6.7: Declaración de un array en memoria compartida
El número de pı́xeles que se podrá almacenar en la memoria compartida está limitado por el
tamaño máximo de dicha memoria que se asigna a cada bloque. Según la información que aporta la
herramienta CUDA Occupancy Calculator, para una configuración de 512 hilos por bloque de GPU y
20 registros por hilo, los datos de ocupación son los mostrados en la tabla 6.21.
62
CAPÍTULO 6. RESULTADOS EXPERIMENTALES
Hilos activos por multiprocesador
Warps activos por Multiprocesador
Bloques activos por Multiprocesador
Ocupación de cada multiprocesador
1.536
48
3
100 %
Tabla 6.21: Datos de ocupación de la GPU para la implementación MPI-CUDA basada en memoria
compartida utilizados para el cálculo del tamaño del array a almacenar en dicho nivel de la jerarquı́a
de memoria
A la vista de estos datos, solamente 3 bloques estarán activos de forma simultánea en cada multiprocesador de la GPU, por lo que el lı́mite superior que se establece para el tamaño de la memoria compartida asignada a cada bloque será de un tercio del tamaño total disponible, el cual, dicho en cifras,
es de 49152/3 = 16384 bytes. Sabiendo que cada pı́xel de la imagen ocupa 224 × 4 bytes = 896 bytes,
el tamaño del array de memoria compartida será de b16384/896c = 18 pı́xeles. Por consiguiente los
datos de ocupación de esta versión del algoritmo serán los mostrados en la tabla 6.22.
Hilos por bloque
Registros por hilo
Memoria compartida por bloque (bytes)
Ocupación de cada multiprocesador
512
20
16.128
100 %
Tabla 6.22: Datos de ocupación de la GPU para la implementación MPI-CUDA basada en memoria
compartida del algoritmo PPI para el entorno de Producción del clúster de CETA-CIEMAT
Continuando con la descripción del kernel implementado para esta versión del algoritmo PPI,
cabe destacar que el proceso de la copia de los pı́xeles al array sm pixels, mostrado en el código
6.8, se realiza de forma paralela y favoreciendo la lectura de posiciones de memoria contiguas por
hilos contiguos de un bloque (coalescencia). Como CUDA optimiza este tipo de lecturas para que se
realicen en bloque y de una vez y la imagen está codificada en formato BIP [1], lo que significa que los
valores espectrales de un mismo pı́xel en resolución espacial están almacenados de forma contigua en la
imagen, para copiar un pı́xel al array sm pixels de forma paralela se utilizarán los 224 primeros hilos
de un bloque, uno para cada valor espectral. Dado que estos hilos accederán a posiciones de memoria
contiguas se realizará una lectura en bloque y se evitará la serialización de las transferencias a memoria
para la copia del pı́xel. La introducción del bucle while se debe a que se ha querido implementar una
versión genérica que funcione para tamaños de bloque menores al número de bandas de la imagen. En
este caso, un mismo hilo copiarı́a dos valores espectrales al array de memoria compartida.
// Copy pixels to SM
int smidx = threadIdx . x ;
while ( smidx < num_bands ) {
for ( i = 0; i < N_Pixels ; i ++) {
sm_pixels [ i * num_bands + threadIdx . x ] = image [( k * N_Pixels + i ) *
num_bands + threadIdx . x ];
}
smidx += blockDim . x ;
}
Código 6.8: Declaración de un array en memoria compartida
Por último, y para terminar la descripción del kernel, se ha cambiado la estructura de almacenamiento de los resultados parciales del algoritmo y en esta ocasión no se almacenan por separado
las coordenadas espaciales (x, y) en la estructura que almacena dichos resultados parciales. En esta
ocasión y por simplicidad a la hora de procesar los pı́xeles, se almacena el ı́ndice de la pseudomatriz,
el cual sigue la fórmula 6.2.
i = x × num samples + y
(6.2)
Finalmente, el código completo del kernel para esta versión del algoritmo se muestra en el código
6.9.
6.2. DESARROLLO DE PPI PARA EL CLÚSTER DE GPUS
63
int idx = blockDim . x * blockIdx . x + threadIdx . x ;
__shared__ float sm_pixels [ N_Pixels * num_bands ];
if ( idx < num_skewers ) {
float min = FLT_MAX , max = FLT_MIN , dot_product = 0.0;
for ( int k = 0; k < num_lines * num_samples / N_Pixels ; k ++) {
// Copy pixels to SM
int smidx = threadIdx . x ;
while ( smidx < num_bands ) {
for ( int i = 0; i < N_Pixels ; i ++) {
sm_pixels [ i * num_bands + threadIdx . x ] = image [( k * N_Pixels + i ) *
num_bands + threadIdx . x ];
}
smidx += blockDim . x ;
}
__syncthreads () ;
for ( int i = 0; i < N_Pixels ;
dotProduct (& skewers [ idx ] ,
dot_product ) ;
if ( dot_product > max ) {
max = dot_product ;
local_results [ idx * 4
local_results [ idx * 4
}
if ( dot_product < min ) {
min = dot_product ;
local_results [ idx * 4
local_results [ idx * 4
}
}
__syncthreads () ;
i ++) {
& sm_pixels [ i * num_bands ] , num_bands , &
+ 0] = k * N_Pixels + i ; // pixel
+ 1] = dot_product ;
+ 2] = k * N_Pixels + i ; // pixel
+ 3] = dot_product ;
}
}
Código 6.9: Código del kernel del algoritmo PPI para la implementación basada en memoria
compartida
Una vez descrito el código de esta versión del algoritmo PPI para clúster de GPUs que hace
uso de memoria compartida, se presentan los resultados obtenidos para las tres imágenes habituales.
Comenzando por la imagen Cuprite, la tabla 6.23 muestra el promedio de los valores medidos en las
ejecuciones realizadas para esta versión del algoritmo, con configuraciones de ejecución de 1 a 15 nodos
de cómputo y seguidamente las figuras 6.20a y 6.20b muestran las gráficas de evolución del tiempo de
cómputo (CT), del tiempo total de ejecución (TT) y del speedup según aumenta el número de nodos
de cómputo utilizados.
IRT
0,005262
0,005218
0,004950
0,004678
0,004728
0,003985
0,004224
0,003773
0,003133
0,004008
0,003993
0,002806
0,003309
0,003316
0,003804
SKT
0,098404
0,098699
0,097655
0,094231
0,093506
0,094902
0,094168
0,093351
0,093561
0,093341
0,093346
0,093504
0,093481
0,094660
0,093281
BT
0,000022
0,007945
0,010878
0,012992
0,014321
0,014957
0,015527
0,016503
0,016958
0,017809
0,017821
0,018348
0,018862
0,018189
0,019453
ScT
0,065236
0,071415
0,072741
0,076078
0,078608
0,076517
0,076589
0,078980
0,078724
0,080042
0,079544
0,079505
0,080159
0,079800
0,080709
CT
22,780076
14,614350
11,736442
10,535370
9,673711
9,109504
8,535719
8,327568
8,100804
7,669839
7,594869
7,626984
7,637773
7,392742
7,431989
GT
22,780158
14,863156
12,190816
10,858870
9,951118
9,432804
9,037139
8,741591
8,459683
8,390138
8,153650
7,996942
7,917867
7,937044
7,803767
PPT
0,000083
0,000148
0,000196
0,000231
0,000281
0,000333
0,000381
0,000446
0,000531
0,000611
0,000681
0,000750
0,000831
0,000895
0,000976
TT
22,955662
15,053010
12,384140
11,054094
10,149510
9,630272
9,235051
8,941845
8,659118
8,593363
8,356860
8,198552
8,121969
8,141672
8,010301
Tabla 6.23: Resultados de ejecución (en sg.) de la implementación basada en memoria compartida del
algoritmo PPI para clúster de GPUs (Imagen: Cuprite)
64
CAPÍTULO 6. RESULTADOS EXPERIMENTALES
(a) Gráfica de CT y TT (en sg.)
(b) Gráfica de speedup
Figura 6.20: Gráficas de la implementación basada en memoria compartida del algoritmo PPI para
clúster de GPUs (Imagen: Cuprite)
Según se observa en los resultados, el tiempo de ejecución del algoritmo no ha disminuido respecto
a versiones anteriores, pero tampoco empeora notablemente el tiempo de ejecución de la versión
que hasta ahora arroja mejores resultados (local memory). Esto se debe principalmente a que la
memoria compartida no deja de ser una caché controlada por el usuario que, además, comparte chip
con la memoria caché L1, teniendo los mismos tiempos de acceso. Este uso de memoria compartida
sı́ hubiese tenido más repercusión en el tiempo de ejecución para arquitecturas anteriores como la
Tesla. Actualmente, con la jerarquı́a de caché que implementa la arquitectura Fermi, el uso de shared
memory no es indispensable para disminuir el rendimiento. En esta ocasión el speedup es mejor que
en la versión local memory, alcanzando un factor de casi 3x frente al 2,5x de ésta última.
Tras los resultados obtenidos para la imagen de 44 MB, se muestran los resultados para la imagen
del Lago St. Clair. Las gráficas 6.21a y 6.21b representan la evolución del tiempo de ejecución del
algoritmo en cada nodo (CT) y el tiempo total del algoritmo (TT) ası́ como del speedup para cada
configuración utilizada. Los resultados medidos se muestran en la tabla 6.24.
Como cabı́a de esperar, los resultados obtenidos para esta imagen son similares a los mejores resultados obtenidos anteriormente para las implementaciones anteriores, volviendo a romper la barrera
de los 13 segundos en el procesamiento de la imagen utilizando 15 nodos de cómputo. En cuanto al
speedup alcanzado por esta versión del algoritmo se mantiene en 7x, pudiéndose ver claramente cómo
este valor comienza a curvarse para las configuraciones que utilizan mayor número de nodos.
IRT
0,004420
0,005210
0,005560
0,004449
0,005387
0,005346
0,004683
0,005096
0,004585
0,004979
0,003160
0,003974
0,004646
0,003807
0,004383
SKT
0,116810
0,115256
0,113412
0,115071
0,114137
0,116393
0,111495
0,111325
0,111195
0,111182
0,111646
0,111429
0,112449
0,111173
0,111731
BT
0,000025
0,009399
0,012691
0,015234
0,016257
0,017084
0,018059
0,019212
0,019536
0,020336
0,020427
0,021534
0,021533
0,022079
0,021788
ScT
0,301233
0,344011
0,375907
0,388081
0,382678
0,379939
0,375616
0,383012
0,391983
0,401689
0,406319
0,404548
0,412874
0,384849
0,388802
CT
93,368136
49,169154
34,924499
27,400518
23,373792
20,339352
18,484162
17,029876
15,725369
14,466571
13,945115
13,188010
12,639809
12,351217
11,765032
GT
93,368219
49,643279
35,318050
27,864872
23,856888
20,784989
18,897697
17,368439
15,997474
15,156156
14,427424
13,690499
13,048524
12,655579
12,330921
PPT
0,000079
0,000146
0,000190
0,000240
0,000288
0,000338
0,000417
0,000430
0,000541
0,000620
0,000684
0,000747
0,000829
0,000895
0,000957
TT
93,797492
50,124564
35,834759
28,395555
24,384787
21,313475
19,416531
17,896629
16,534284
15,704594
14,977763
14,241529
13,610668
13,188123
12,868784
Tabla 6.24: Resultados de ejecución (en sg.) de la implementación basada en memoria compartida del
algoritmo PPI para clúster de GPUs (Imagen: Lago St. Clair )
A la vista de los resultados anteriores, parece ser que los valores que se obtendrán para la imagen
de mayor tamaño serán similares a los obtenidos por la implementación local memory, quedándo la
duda de si se volverá a bajar de los 2 minutos de tiempo para procesar la imagen de los 4 GB. Los
tiempos medidos para esta imagen se presentan en la tabla 6.24 y la evolución de los tiempos y el
speedup frente al número de nodos se ilustra en las figuras 6.21a y 6.21b.
6.2. DESARROLLO DE PPI PARA EL CLÚSTER DE GPUS
(a) Gráfica de CT y TT (en sg.)
65
(b) Gráfica de speedup
Figura 6.21: Gráficas de la implementación basada en memoria compartida del algoritmo PPI para
clúster de GPUs (Imagen: Lago St. Clair )
IRT
0,003944
0,003320
0,005074
0,004407
0,004547
0,004706
0,003989
0,004461
0,005583
0,005238
0,003606
0,004530
0,004721
0,005198
0,003925
SKT
0,115504
0,116279
0,114303
0,113276
0,113289
0,111320
0,114212
0,111377
0,111928
0,111284
0,111164
0,111405
0,113174
0,111576
0,111090
BT
0,000028
0,009476
0,012651
0,015229
0,016282
0,017472
0,018407
0,019188
0,019729
0,020596
0,020408
0,021266
0,021185
0,022011
0,022076
ScT
4,896240
5,392947
5,332101
7,033414
7,046309
7,153001
7,243374
6,999897
7,052209
7,078813
7,137345
7,175165
7,210193
7,275668
6,929979
CT
6,036655
752,254284
505,087797
379,299165
304,481140
254,845478
219,296014
193,593828
172,677596
156,328352
142,493207
130,631165
121,443850
112,807819
106,152012
GT
6,036707
753,106313
505,299801
380,183461
304,905104
255,065870
219,387866
193,594958
172,678770
156,329267
142,565007
130,666563
121,529069
112,809042
106,153305
PPT
0,000077
0,000150
0,000191
0,000236
0,000280
0,000328
0,000380
0,000426
0,000530
0,000619
0,000666
0,000719
0,000793
0,000850
0,001023
TT
11,088650
758,664694
510,802390
387,385765
312,125213
262,392399
226,808726
200,772298
179,914066
163,591343
149,880308
138,022905
128,924151
120,270764
113,266530
Tabla 6.25: Resultados de ejecución (en sg.) de la implementación basada en memoria compartida del
algoritmo PPI para clúster de GPUs (Imagen: Yellowstone)
(a) Gráfica de CT y TT (en sg.)
(b) Gráfica de speedup
Figura 6.22: Gráficas de la implementación basada en memoria compartida del algoritmo PPI para
clúster de GPUs (Imagen: Yellowstone)
De nuevo, tal y como se predijo, los resultados obtenidos para esta esta imagen de entrada son
similares a los de la versión local memory, rompiendo de nuevo la barrera de los 2 minutos y procesando la imagen en 113 segundos. El speedup alcanzado con esta versión tampoco destaca frente
al alcanzado anteriormente, superando por poco el factor 7x respecto a la ejecución de dos nodos
(extrapolando unos 12,5x).
En este punto parece que no se ha conseguido continuar con la mejora del tiempo de ejecución,
principalmente porque los cambios introducidos no han supuesto un gran avance dado que la arquitectura Fermi se ha diseñado para corregir muchos de los pitfalls de las versiones anteriores de la
arquitectura. En la siguiente implementación se aborda el problema de manera diferente, intentando
mejorar el rendimiento mediante la adición de un nuevo nivel de paralelismo: el uso de varias GPUs.
66
6.2.6.
CAPÍTULO 6. RESULTADOS EXPERIMENTALES
Implementación multiGPU
Desde la versión inicial, las versiones del algoritmo PPI para clúster de GPUs se han focalizado en
reducir el tiempo de ejecución del algoritmo mediante técnicas basadas en la optimización de uso de la
GPU comenzando por el uso de la memoria local del dispositivo, pasando por ajustes de compilación
y finalizando por la explotación de los diferentes niveles de la jerarquı́a de memoria. Cierto es que
desde la mejora notable del tiempo de ejecución introducida en la implementación basada en memoria
local no se ha conseguido continuar con esta tendencia de evolución en las versiones posteriores, por
lo que en esta ocasión se abordará el problema de manera diferente.
Como se describe en el apartado 3.3 del capı́tulo 3, cada nodo de cómputo del clúster de GPUs de
CETA-CIEMAT está equipado con dos GPUs. Hasta el momento solamente se habı́a utilizado una de
ellas pero en la implementación a la que está dedicada esta sección se paralelizará el algoritmo PPI en
un nivel más, repartiendo la carga de cada nodo de cómputo entre las GPUs que posee dicho clúster.
El esquema de paralelización será el mismo que el de versiones anteriores, suponiendo que ambas
GPUs trabajan como una sola, pero el doble de grande. Hasta ahora, cada hilo de la GPU se encargaba
de calcular las proyecciones de los pı́xeles de la imagen de entrada sobre un skewer que se le habı́a
asignado. En esta implementación, se dividirá el conjunto de skewers en dos, y cada GPU calculará las
proyecciones de la imagen a procesar sobre la mitad del conjunto de skewers que se le ha asignado, lo
que a efectos prácticos funciona como si de una de GPU con el doble de capacidad se tratase. Cierto es
que se podrı́a haber dividido la imagen y posteriormente aunar los resultados, pero eso hubiese forzado
a realizar una etapa adicional de generación intermedia de resultados para determinar cuáles de los
pı́xeles de cada fragmento de la imagen asignado a cada GPU serı́an seleccionados como candidatos
finales a endmember.
La implementación multiGPU se basa en la implementación de la sección anterior basada en el
uso de memoria compartida o shared memory. La configuración de hilos y bloques es la misma, y el
número de pı́xeles a almacenar en memoria compartida no cambia (18 pı́xeles), dado que las dos GPUs
de cada nodo de cómputo son iguales. Por lo tanto, los datos de ocupación obtenidos se mantienen de
la versión anterior y se muestran en la tabla 6.26.
Hilos por bloque
Registros por hilo
Memoria compartida por bloque (bytes)
Ocupación de cada multiprocesador
512
20
16.128
100 %
Tabla 6.26: Datos de ocupación de la GPU para la implementación MPI-CUDA multiGPU del algoritmo PPI para el entorno de Producción del clúster de CETA-CIEMAT
La implementación multiGPU del algoritmo se basa en la duplicación de las acciones que se realizan
para invocar al kernel de las versiones anteriores. CUDA proporciona la función cudaSetDevice(),
que acepta como parámetro del ı́ndice de la GPU que se va a utilizar en cada momento, cuya misión
es la de seleccionar el dispositivo con el que se quiere trabajar. En nuestro caso, como solamente hay
dos GPUs por nodo, se realizarán invocaciones a dicha función con los parámetros 0 y 1.
Puede parecer poco probable que un dispositivo esté equipado con dos GPUs, pero es un hecho
que cada vez es más frecuente. Las tarjetas graficas de los últimos portátiles suelen tener dos GPUs,
una integrada de potencia suficiente para el trabajo diario de un usuario medio, y una segunda más
potente, que se utiliza cuando se ejecutan aplicaciones más exigentes como juegos y aplicaciones
de edición de video entre otras, todo con la misión de alargar el tiempo de uso de la baterı́a. En
cuanto a supercomputación, las tarjetas de la gama de NVidia Tesla que comienzan con S suelen estar
compuestas por entre dos y cuatro tarjetas GPUs.
El código 6.10 describe la invocación de un kernel para la GPU con identificador 1 de uno de
los nodos de cómputo del clúster. Primeramente se selecciona el dispositivo a utilizar con la llamada a cudaSetDevice() para posteriormente comenzar con la reserva de memoria en el dispositivo y la trasferencia de datos del host a la GPU mediante el uso de las funciones cudaMalloc() y
cudaMemcpy() para finalizar con la invocación del kernel ppi(). Cabe destacar que se hace uso de
la función cudaFuncSetCacheConfig() con el flag cudaFuncCachePreferShared para indicarle a la
GPU nuestra preferencia por el uso de memoria compartida frente a la caché L1. Una vez invocado el
kernel, se podrı́a cambiar de dispositivo, dado que esta acción solamente se puede realizar cuando se
realizan llamadas ası́ncronas de funciones CUDA, como por ejemplo la invocación de un kernel. Si el
dispositivo estuviese ocupado con una operación bloqueante no se podrı́a realizar el cambio de GPU.
6.2. DESARROLLO DE PPI PARA EL CLÚSTER DE GPUS
67
Cabe destacar respecto al código en esta ocasión que la invocación del kernel ppi() se realiza
pasándole la mitad del conjunto de skewers, de ahı́ que la estructura d skewers data1 se “rellene”
con la segunda mitad del conjunto de skewers &skewers data[(num skewers / 2) * num bands].
cudaSetDevice (1) ;
// Device memory p o i n t e r s
float * d _image_c hunk1 ;
float * d_ s ke we rs _ da ta 1 ;
float * d _ l o c a l _ r e s u l t s 1 ;
cudaMalloc (( void **) & d_image_chunk1 ,
( chunk_size * num_samples * num_bands *
sizeof ( float ) ) ) ;
cudaMalloc (( void **) & d_skewers_data1 , ( num_skewers * num_bands * sizeof ( float ) ) )
;
cudaMalloc (( void **) & d_local_results1 , ( num_skewers * 2 * sizeof ( float ) ) ) ;
// host -> device copy
cudaMemcpy ( d_image_chunk1 ,
image_chunk ,
chunk_size * num_samples * num_bands *
sizeof ( float ) , c u d a M e m c p y H o s t T o D e v i c e ) ;
cudaMemcpy ( d_skewers_data1 , & skewers_data [( num_skewers / 2) * num_bands ] , (
num_skewers / 2) * num_bands * sizeof ( float ) , c u d a M e m c p y H o s t T o D e v i c e ) ;
cudaMemcpy ( d_local_results1 , local_results , num_skewers * 2 * sizeof ( float ) ,
cudaMemcpyHostToDevice );
c u d a F u n c S e t C a c h e C o n f i g ( " ppi " , c u d a F u n c C a c h e P r e f e r S h a r e d ) ;
// PPI kernel e x e c u t i o n
ppi <<< num_bloques , num_hilos > > >( d_image_chunk1 , d_skewers_data1 , d_local_results1
, chunk_size , num_samples , num_bands , num_skewers / 2) ;
Código 6.10: Código de la invocación del kernel del algoritmo PPI para una GPU en la implementación
multiGPU
Una vez que se han invocado ambos kernels se tiene que establecer un punto de sincronización
para que ambos dispositivos terminen sus tareas antes de recoger los resultados. Esta acción se realiza mediante la llamada a la función proporcionada por CUDA cudaDeviceSynchronize() en cada
dispositivo (ver código 6.11)
// Device 1 p r e v i o u s l y s e l e c t e d
c u d a D e v i c e S y n c h r o n i z e () ;
cudaSetDevice (0) ;
c u d a D e v i c e S y n c h r o n i z e () ;
Código 6.11: Sincronización de los dispositivos en la implementación multiGPU del algoritmo PPI
Para finalizar, se deben recolectar los resultados parciales generados por cada GPU. Esta recolección es muy sencilla, dado que simplemente éstos se deben copiar adecuadamente en la estructura que
se devolverá al nodo maestro. Los resultados de la GPU 0 se almacenarán en la primera mitad de
la estructura que almacena los resultados (local results) y los de la GPU 1 se almacenarán en la
segunda mitad. El proceso de recolección de resultados para el dispositivo 1 se muestra en el código
6.12.
cudaSetDevice (1) ;
// device -> host copy
cudaMemcpy (& local_results [ num_skewers * 2] , d_local_results1 , num_skewers * 2 *
sizeof ( float ) , c u d a M e m c p y D e v i c e T o H o s t ) ;
// Free memory
cudaFree ( d _s ke w er s_ da t a1 ) ;
cudaFree ( d_image _chunk1 ) ;
cudaFree ( d _ l o c a l _ r e s u l t s 1 ) ;
Código 6.12: Recolección de los resultados de una GPU en la implementación multiGPU
Una vez descrito el código se presentan los resultados obtenidos para las imágenes habituales.
Comenzando por la imagen Cuprite, la tabla 6.27 muestra el promedio de los tiempos medidos para
cada uno de los parámetros descritos en el apartado 6.1.2 y las figuras 6.23a y 6.23b muestran las
gráficas de evolución del tiempo de cómputo (CT) y el tiempo total (TT) de ejecución, ası́ como el
speedup, para las configuraciones ejecutadas de 1 a 15 nodos.
68
CAPÍTULO 6. RESULTADOS EXPERIMENTALES
IRT
0,006409
0,005415
0,004714
0,005132
0,004603
0,005060
0,005135
0,005378
0,004209
0,004241
0,005212
0,004618
0,005581
0,004976
0,005046
SKT
0,096049
0,096511
0,094594
0,094273
0,096524
0,093576
0,094045
0,093725
0,093919
0,093545
0,093454
0,093843
0,093700
0,093973
0,093635
BT
0,000002
0,007996
0,010657
0,012737
0,014094
0,014964
0,015625
0,016348
0,016988
0,017822
0,018066
0,024836
0,018551
0,018637
0,025065
ScT
0,443146
0,067120
0,070123
0,072812
0,075562
0,073651
0,074613
0,076068
0,076698
0,077848
0,077813
0,077357
0,078124
0,078435
0,079037
CT
15,793712
11,375779
9,734920
8,873116
8,265920
8,017330
8,041177
8,100983
7,720451
7,847921
7,552571
7,540006
7,260395
7,078283
6,973607
GT
15,793785
11,723104
10,303225
9,436983
9,015941
8,880147
8,601562
8,647567
8,716753
8,602033
8,494860
8,292043
8,370715
8,339936
8,141262
PPT
0,000076
0,000142
0,000188
0,000231
0,000287
0,000325
0,000387
0,000431
0,000530
0,000591
0,000660
0,000738
0,000796
0,000857
0,000907
TT
16,347264
11,907246
10,490626
9,631075
9,214113
9,075537
8,799135
8,848130
8,916897
8,803820
8,698847
8,502028
8,577265
8,546037
8,354137
Tabla 6.27: Resultados de ejecución (en sg.) de la implementación multiGPU del algoritmo PPI para
clúster de GPUs (Imagen: Cuprite)
(a) Gráfica de CT y TT (en sg.)
(b) Gráfica de speedup
Figura 6.23: Gráficas de la implementación multiGPU del algoritmo PPI para clúster de GPUs (Imagen: Cuprite)
A la vista de los resultados se puede comprobar que el tiempo de ejecución para la imagen de
Cuprite no ha mejorado. Esto es debido a que el tiempo de procesamiento de la imagen es muy
pequeño (aproximadamente 1 sg.) respecto del tiempo de transferencia de los datos de entrada entre
la CPU y los dispositivos. El tiempo empeora respecto a las versiones anteriores porque en esta ocasión
se realiza una copia de los datos de entrada por cada GPU. Este comportamiento del algoritmo deberı́a
cambiar según aumente el tamaño de la imagen dado que el procesamiento de la imagen tomará peso
con respecto a las comunicaciones.
A continuación se muestran los resultados obtenidos para la imagen del Lago St. Clair. La tabla
6.28 presenta el promedio de los tiempos de ejecución medidos para cada uno de los parámetros
descritos en el apartado 6.1.2 del presente capı́tulo y las figuras 6.24a y 6.24b muestran la evolución
de los tiempos de ejecución y del speedup.
En esta ocasión se ha conseguido reducir el tiempo de ejecución obtenido por las versiones anteriores
del algoritmo, siendo éste de apenas 11 sg. para la configuración de ejecución que utiliza 15 nodos de
cálculo. El speedup conseguido no es muy bueno ya que apenas alcanza el factor 5x.
Para finalizar con la presentación de las pruebas, a continuación se incluyen los resultados obtenidos
para la imagen de Yellowstone. Los datos medidos y las gráficas generadas se detallan en la tabla 6.29
y las figuras 6.25a y 6.25b respectivamente.
Al igual que en el caso de la imagen del Lago St. Clair, se ha conseguido reducir el tiempo de
ejecución del algoritmo para la imagen más grande, llegándose a procesar en poco más de 1 minuto
(67 sg.). Esto es debido a que el grueso del tiempo de cómputo se debe al procesamiento de la
imagen en lugar que a las transferencias de datos como ocurrı́a en la imagen de Cuprite. En cuanto
al speedup conseguido es menor que en las versiones anteriores del algoritmo, alcanzándose un factor
de aceleración de poco más de 6x respecto a la ejecución de dos nodos (extrapolando no alcanzarı́a
6.2. DESARROLLO DE PPI PARA EL CLÚSTER DE GPUS
IRT
0,006436
0,005324
0,004581
0,005628
0,005631
0,004706
0,005861
0,005091
0,004802
0,005363
0,003899
0,005253
0,004506
0,005976
0,004926
SKT
0,116302
0,116349
0,115191
0,111039
0,112410
0,114535
0,114400
0,111301
0,111134
0,111431
0,111558
0,111432
0,111268
0,111469
0,111206
BT
0,000002
0,009385
0,012753
0,014791
0,016506
0,017540
0,018292
0,019552
0,019702
0,020586
0,020831
0,021458
0,021757
0,022317
0,022328
ScT
0,311541
0,353297
0,376247
0,377138
0,382188
0,386792
0,374357
0,382294
0,393246
0,397855
0,401974
0,404582
0,408799
0,382669
0,389060
CT
53,010888
29,594654
22,086820
18,264652
15,940279
13,991949
13,408163
12,695689
11,659171
11,265264
10,727219
10,498291
10,049843
10,070015
9,824852
69
GT
53,010970
30,054039
22,697393
18,883179
16,439741
14,699043
13,927808
13,146160
12,513935
12,032946
11,727650
11,318091
10,903699
10,918805
10,658089
PPT
0,000078
0,000148
0,000193
0,000231
0,000282
0,000337
0,000382
0,000420
0,000545
0,000609
0,000665
0,000741
0,000895
0,000887
0,000958
TT
53,462331
30,546396
23,214768
19,400933
16,965877
15,231295
14,450857
13,673939
13,052215
12,578863
12,275116
11,871989
11,459992
11,453097
11,197010
Tabla 6.28: Resultados de ejecución (en sg.) de la implementación multiGPU del algoritmo PPI para
clúster de GPUs (Imagen: Lago St. Clair )
(a) Gráfica de CT y TT (en sg.)
(b) Gráfica de speedup
Figura 6.24: Gráficas de la implementación multiGPU del algoritmo PPI para clúster de GPUs (Imagen: Lago St. Clair )
IRT
0,004765
0,004829
0,004821
0,004712
0,005245
0,005303
0,004257
0,005388
0,004453
0,005200
0,004817
0,004294
0,003639
0,003179
0,004085
SKT
0,115346
0,115492
0,113272
0,111370
0,112329
0,111157
0,111370
0,111551
0,111483
0,111300
0,111163
0,111898
0,111355
0,111411
0,111874
BT
0,000002
0,009512
0,012670
0,014534
0,016562
0,017592
0,018763
0,019235
0,019945
0,021122
0,027526
0,021577
0,021346
0,022161
0,022592
ScT
4,968464
5,007724
5,243812
6,739466
7,232359
7,137247
7,175867
6,923678
7,022828
7,094025
7,147466
7,176949
7,212339
7,279546
6,922418
CT
6,287983
401,900796
270,236191
203,789313
165,335666
137,943963
119,424813
105,774022
94,853668
86,393971
78,968023
73,132041
67,696651
63,763476
59,463695
GT
6,288034
401,901125
270,236587
203,789783
165,336192
138,196509
119,437964
105,939544
94,908862
86,394878
78,968999
73,236507
67,884871
63,883725
59,692932
PPT
0,000077
0,000148
0,000191
0,000237
0,000277
0,000323
0,000369
0,000422
0,000542
0,000603
0,000685
0,000726
0,000812
0,000862
0,000929
TT
11,422122
407,079036
275,654485
210,696289
172,743685
145,508139
126,786683
113,045920
102,110127
93,669184
86,304342
80,595950
75,278965
71,343455
66,799286
Tabla 6.29: Resultados de ejecución (en sg.) de la implementación multiGPU del algoritmo PPI para
clúster de GPUs (Imagen: Yellowstone)
los 10x).
En este punto podemos considerar satisfactorios los resultados obtenidos para procesar este tipo de
70
CAPÍTULO 6. RESULTADOS EXPERIMENTALES
(a) Gráfica de CT y TT (en sg.)
(b) Gráfica de speedup
Figura 6.25: Gráficas de la implementación multiGPU del algoritmo PPI para clúster de GPUs (Imagen: Yellowstone)
imágenes, llegando al punto de haber conseguido procesar una imagen de 4 GB en apenas un minuto. Probablemente se pueda optimizar esta implementación multiGPU para conseguir una reducción
mejor, pero se propondrá para un trabajo futuro.
En el siguiente apartado se realizará una comparativa de los mejores resultados obtenidos con la
implementación para clústers de GPU frente a implementaciones para otras arquitecturas.
6.3.
Comparativa frente a otras implementaciones
Una vez que se ha desarrollado la implementación del algoritmo PPI para un clúster de GPUs y
tienen los resultados de ejecución para el conjunto de imágenes reales capturadas por el sensor AVIRIS
procedemos a comparar los tiempos de ejecución con los obtenidos para la versión secuencial, para
clústers de computadores y tarjetas GPUs con el ánimo de estudiar cómo evolucionan los tiempos de
ejecución y los factores de aceleración.
Los parámetros de entrada serán los mismos que se han utilizado para la ejecución de las pruebas
anteriores. A modo de recordatorio se enumeran a continuación:
Una imagen hiperespectral de entrada: Se ejecutarán las pruebas para las tres imágenes del sensor
AVIRIS pertenecientes a las regiones de Cuprite, Lago St. Clair y Yellowstone.
Un número de iteraciones o tamaño del conjunto de skewers: Este número se establecerá a
15.360 para que coincida con las pruebas ejecutadas anteriormente.
Una configuración de número de bloques e hilos de GPU : Estos parámetros solamente son necesarios para las versiones que utilizan GPUs y se establecen para maximizar la ocupación del
dispositivo y, consecuentemente, mejorar el rendimiento. El número de bloques se establece a
30 y el de hilos a 512.
En cuanto a las opciones de compilación utilizadas, todas las versiones del algoritmo se han compilado con la opción -O3, el cual establece el nivel de optimización del binario generado al máximo.
La plataforma utilizada para las pruebas ha sido el clúster de GPUs de CETA-CIEMAT.
En primer lugar se comparan los tiempos de ejecución obtenidos para las versiones del algoritmo
antes mencionadas utilizando la imagen de entrada Cuprite. La tabla 6.30 presenta los resultados en
segundos para cada una de las versiones sujetas a estudio junto con el factor de aceleración obtenido
respecto de la versión secuencial.
Tiempo (en sg.)
Factor de aceleración
Secuencial
1319,944515
1x
Clúster
92,411848
14,28x
GPUs
25,810000
51,14x
Clúster de GPUs
8,354137
157,99x
Tabla 6.30: Comparativa de resultados obtenidos para las versiones secuencial, clúster de computadores, GPUs y clúster de GPUs en el procesamiento de la imagen Cuprite
A la vista de los resultados se puede afirmar que la versión que mejor factor de aceleración obtiene
es la implementación para clústers de GPUs con un factor de 158x. Cabe destacar también que la
versión para GPUs consigue procesar la imagen de Cuprite en menos de un minuto. Por otro lado, la
6.3. COMPARATIVA FRENTE A OTRAS IMPLEMENTACIONES
71
versión para clúster de computadores, aún utilizando 15 nodos de cálculo, procesa la imagen en más
de 90 segundos.
Tras los buenos resultados obtenidos para la imagen más pequeña, se procede a presentar los
resultados obtenidos para la imagen de tamaño mediano, correspondiente al Lago St. Clair. Se espera
que el factor de aceleración mejore debido a que el tiempo medido para la imagen Cuprite se ve
altamente influenciado por la transferencia de datos y la comunicación entre nodos, como se describe
en el apartado anterior. Los tiempos medidos para cada una de las implementaciones y el factor de
aceleración calculado se muestran en la tabla 6.31.
Tiempo (en sg.)
Factor de aceleración
Secuencial
5018,109371
1x
Clúster
282,842483
17,74x
GPUs
91,340000
54,94x
Clúster de GPUs
11,197010
448,17x
Tabla 6.31: Comparativa de resultados obtenidos para las versiones secuencial, clúster de computadores, GPUs y clúster de GPUs en el procesamiento de la imagen Lago St. Clair
Como era de esperar, el factor de aceleración para la versión de clúster de GPUs vuelve a aumentar
448,17x, debido principalmente a que el mayor tamaño de la imagen del Lago St. Clair permite hacer
notar el uso de dos GPUs para el procesamiento de dicha imagen. Cabe destacar también que el resto
de factores de aceleración también aumenta.
Por último se presentan los resultados obtenidos para la imagen de mayor tamaño, perteneciente
al Parque Yellowstone. A priori los resultados deberı́an mostrar un aumento del factor de aceleración,
tal y como ocurrı́a con la imagen del Lago St. Clair. Los resultados obtenidos para cada versión del
algoritmo y sus respectivos factores de aceleración se presentan en la tabla 6.32.
Tiempo (en sg.)
Factor de aceleración
Secuencial
83316,717722
1x
Clúster
5834,629652
14,27x
GPUs
N/A
N/A
Clúster de GPUs
66,799286
1262,37x
Tabla 6.32: Comparativa de resultados obtenidos para las versiones secuencial, clúster de computadores, GPUs y clúster de GPUs en el procesamiento de la imagen Yellowstone
En esta ocasión, la implementación del algoritmo PPI para clúster de GPUs ha alcanzado el valor
máximo de factor de aceleración, siéndo éste de 1262,37x. Esto quiere decir que se ha conseguido
procesar una imagen que el algoritmo secuencial procesa en 23 horas en menos poco más de 1 minuto.
Este resultado aporta mucho valor dado que con la implementación del algoritmo PPI para clúster de
GPUs se acelerarı́a notablemente el procesamiento de grandes volúmenes de datos hiperespectrales y
se evitarı́a que parte de esos datos acabasen almacenados o desechados sin que se pudiese trabajar
con ellos.
Por otro lado, el procesamiento de la imagen de Yellowstone no ha sido posible en la GPU porque, al
igual que ocurrı́a con las implementaciones para clúster de GPUs que usaban un solo nodo de cómputo,
la memoria de la ésta no ofrecı́a espacio suficiente para almacenar la imagen en dicho dispositivo.
En este punto, finalizada la presentación y el análisis de los resultados experimentales para las
diferentes arquitecturas paralelas consideradas y a la vista del buen rendimiento obtenido por la versión
de PPI para clúster de GPUs podemos seguir afirmando que ésta resulta una buena alternativa a las
implementaciones existentes como la incluı́da en ENVI para el análisis de imágenes hiperespectrales
reales.
En el siguiente capı́tulo se resumen las conclusiones obtenidas a partir del trabajo realizado y se
presentan una serie de propuestas de trabajo futuro para una posible continuación de esta lı́nea de
investigación.
72
CAPÍTULO 6. RESULTADOS EXPERIMENTALES
Capı́tulo 7
Conclusiones y trabajo futuro
A lo largo de esta memoria se ha presentado la evolución del desarrollo de una versión del algoritmo
de extracción de firmas espectrales puras PPI para un clúster de GPUs. Además se ha realizado un
estudio comparativo de las diferentes evoluciones de dicho algoritmo, comenzando por la versión
inicial, la cual no implementa ningún mecanismo de optimización del rendimiento, y finalizando por la
implementación que hace uso de varias tarjetas GPUs simultáneamente. Además se ha realizado una
comparativa de tiempos de ejecución con otras implementaciones del algoritmo, véase, una versión
secuencial, otra para un clúster de computadores y una tercera para GPUs. Para todas las pruebas
realizadas se ha utilizado un conjunto de imágenes reales de diferentes tamaños, moviéndonos en un
rango de tamaño de imagen desde decenas de Megabytes hasta varios Gigabytes, capturadas por el
sensor AVIRIS del Jet Propulsion Laboratory de NASA.
Como resultado se ha obtenido un estudio detallado de la aplicación de una arquitectura de última
generación de computación de alto rendimiento como es un clúster de GPUs para el procesamiento de
análisis hiperespectrales, realizando una contribución al estado del arte en la materia dada la reciente
aparición de este tipo de infraestructuras. Las principales aportaciones del presente estudio pueden
resumirse en un conjunto de contribuciones que se presentan a continuación:
Tras el análisis de los resultados obtenidos por la implementación del algoritmo PPI para clúster
de GPUs, obteniéndose factores de aceleración superiores a 1200x para el procesamiento de
imágenes de gran tamaño respecto su versión secuencial, podemos afirmar que a dı́a de hoy los
clúster de GPUs pueden ser aplicados de forma satisfactoria en el procesamiento de imágenes
hiperespectrales. Esta arquitectura de cómputo puede ser muy adecuada para procesar datos
almacenados en repositorios digitales, pudiéndose obtener información de datos históricos muy
relevantes para disciplinas como la meteorologı́a, medio ambiente, estudios demográficos y biologı́a entre otros.
A lo largo de este trabajo, se ha realizado un estudio de diferentes técnicas de optimización de
rendimiento para la computación GPU, intentando aprovechar al máximo el modelo de ejecución
y de memoria que implementan las tarjetas de NVidiaTM , pudiendo afirmar que esta compañı́a
está realizando un gran esfuerzo en la optimización automática de rendimiento de aplicaciones
para GPUs, especialmente en lo relacionado con las operaciones con la memoria, para descargar
de esta tarea a los desarrolladores.
Ası́ mismo, se ha conseguido aprovechar las capacidades de cómputo de los nodos del clúster de
computación de CETA-CIEMAT al implementar un algoritmo que es capaz de trabajar con las
dos GPUs instaladas cada uno de dichos nodos.
Además, tal y como se ha comentado a lo largo de esta memoria, el acceso a recursos hı́bridos
de cómputo como los clústers de GPUs es una opción relativamente sencilla, debido principalmente
a que estas infraestructuras son cada vez más comunes por su moderado coste económico y a que los
proveedores de recursos computacionales en la nube como Amazon permiten la configuración de un
clúster de estas caracterı́sticas pagando solamente por el uso realizado del mismo. De hecho, durante
la escritura de esta memoria Amazon ha publicado que sus instancias de GPUs para clústeres ya están
disponible en su centro de datos localizado en Irlanda a un precio de 2,36 Dólares la hora.
73
74
CAPÍTULO 7. CONCLUSIONES Y TRABAJO FUTURO
Para finalizar el capı́tulo se propone una serie de posibles tareas que permitirán continuar la lı́nea
de trabajo presentada en esta memoria:
Implementar otros algoritmos de extracción de endmembers no interactivos, como OSP y NFINDR, con vistas a automatizar el procesamiento de datos históricos hiperespectrales sin la
intervención de un usuario.
Evolucionar la implementación multiGPU del algoritmo PPI para soportar un número indeterminado de GPUs, de diferente potencia computacional, aplicando técnicas de computación
heterogénea al paradigma de la computación multiGPU.
Evaluar las prestaciones del algoritmo PPI para clúster de computadores de cara a otras arquitecturas paralelas no estudiadas en este trabajo como los sistemas de memoria compartida.
Determinar el grado de influencia de los generadores de números aleatorios en los resultados
del algoritmo PPI, dado que se ha comprobado durante este trabajo que los resultados cambian
según el generador utilizado.
Como conclusión final, comentar que los resultados de las pruebas realizadas para la fundamentación de esta memoria han superado las expectativas iniciales y que éste es un campo que no queda
cerrado a su futura investigación, fin para el cual se han señalado algunos pasos propuestos a seguir
en el futuro.
Bibliografı́a
[1] Extendable
Image
Formats
for
ArcView
GIS
(http://downloads.esri.com/support/whitepapers/other /eximgav.pdf).
July 1999. Page 8.
3.1
ESRI
and
3.2
White Paper.
[2] NVIDIA CUDA Programming Guide 4.2. NVidia Corporation, 2012.
[3] MPICH library for message passing. http://www-unix.mcs.anl.gov/mpi/mpich/.
[4] CUDA and Fermi update. NVidia Corporation, Virtual Summer School of Computational Science
and Engineering 2012. https://www.youtube.com/watch?v=za8 KNN2-fQ
[5] G. Amdahl. Validity of the single processor approach to achieving large- scale computing capabilities. AFIPS Conference Proceedings, 40:483–485, 1967.
[6] C.A. Bateson, B. Curtis, “A method for manual endmember selection and spectral unmixing,”
Remote Sensing of Environment, vol. 55, pp.229–243, 1996.
[7] J. W. Boardman, F. A. Kruse, and R. O. Green. Mapping target signatures via partial unmixing
of aviris data. In Proceedings JPL Airborne Earth Science Workshop, pages 23–26, Pasadena,
California, 1995.
[8] R. Brightwell, L. Fisk, D. Greenberg, T. Hudson, M. Levenhagen, A. Maccabe, and R. Riesen.
Massively parallel computing using commodity components. Parallel Computing, 26:243–266, 2000.
[9] C.-I. Chang. Hyperspectral imaging: Techniques for spectral detection and classification. Kluwer
Academic/Plenum Publishers: New York., 2003.
[10] C.-I. Chang. Estimation of number of spectrally distinct signal sources in hyperspectral imagery.
IEEE Transactions on Geoscience and Remote Sensing, 42(3):608–619, 2004.
[11] C.-I Chang and A. Plaza. A Fast Iterative Algorithm for Implementation of Pixel Purity Index.
IEEE Geoscience and Remote Sensing Letters, vol. 3, no. 1, pp. 63- 67, January 2006.
[12] M. Flynn. Some computer organizations and their effectiveness. IEEE Transactions on Computers, 21(9):948–960, September 1972.
[13] M. Galassi et al, GNU Scientific Library Reference Manual (2nd Ed.), ISBN 0954161734, 2006
http://www.gnu.org/software/gsl/
[14] A. F. H. Goetz and B. Kindel. Comparison of unmixing result derived from aviris, high and
low resolution, and Hydice images at Cuprite, NV. In Proceedings IX NASA/JPL Airborne Earth
Science Workshop, Pasadena, California, 1999.
[15] R. O. Green and J. Boardman. Exploration of the relationship between information content and
signal-to-noise ratio and spatial resolution in aviris spectral data. In Proceedings IX NASA/JPL
Airborne Earth Science Workshop, Pasadena, California, 2000.
[16] R. O. Green, M. L. Eastwood, C. M. Sarture, T. G. Chrien, M. Aronsson, B. J. Chippendale, J. A.
Faust, B. E. Pavri, C. J. Chovit, M. Solis, M. R. Olah, and Orlesa Williams. Imaging spectroscopy
and the airborne visible/infrared imaging spectrometer (aviris). Remote Sensing of Environment,
65:227–248, 1998.
75
76
BIBLIOGRAFÍA
[17] J. C. Harsanyi and C.-I. Chang, Hyperspectral image classification and dimensionality reduction:
An orthogonal subspace projection. IEEE Transactions on Geoscience and Remote Sensing, vol.
32, no. 4, pp. 779–785.
[18] G. Healey and D. Slater. Models and methods for automated material identification in hyperspectral imagery acquired under unknown illumination and atmospheric conditions. IEEE Transactions
on Geoscience and Remote Sensing, vol. 37, pp. 2706-2717, 1999.
[19] D. Landgrebe. Multispectral Data Analysis, A Signal Theory Perspective. Springer Hoboken, NJ,
1998.
[20] D. Landgrebe. Hyperspectral image data analysis. IEEE Signal Processing Magazine, 19(1):17–28,
2002.
[21] A. Lastovetsky and J. Dongarra. High-Performance Heterogeneous Computing. New York: Wiley,
2009.
[22] D. Lavenier, E. Fabiani, S. Derrien, C. Wagner. Systolic array for computing the pixel purity
index (PPI) algorithm on hyper spectral images. SPIE Conference on Imaging Spectrometry, San
Diego, CA, USA, 2001.
[23] F. Liu, F. Seinstra, and A. Plaza. Parallel hyperspectral image processing on multi-cluster systems. SPIE Journal of Applied Remote Sensing, 2011.
[24] E. Lusk, N. Doss, and A. Skjellum. A high-performance, portable implementation of the MPI
message passing interface standard. Parallel Computing, 22:789–828, 1996.
[25] M. Matsumoto and T. Nishimura. 1998. Mersenne twister: a 623-dimensionally equidistributed
uniform pseudo-random number generator. ACM Trans. Model. Comput. Simul. 8, 1 (January
1998), 3-30.
[26] A. F. Paz. Diseño e implementación de algoritmos paralelos de análisis de imágenes hiperespectrales en tarjetas gráficas programables. Tesis doctoral. Universidad de Extremadura, 2011.
[27] R.M. Pérez, P. Martı́nez, A. Plaza, P.L. Aguilar. Systolic Array Methodology for a Neural Model
to Solve the Mixture Problem. Neural Networks and Systolic Array Design. Edited by D. Zhang
and S.K. Pal. World Scientific, 2002.
[28] A. Plaza, C.-I Chang. Clusters Versus FPGA for Parallel Processing of Hyperspactral Imagery.
The International Journal of High Performance Computing Applications, vol. 22 – no. 1 – pp.1-7,
2008.
[29] A. Plaza, P. Martı́nez, R.M. Pérez, J. Plaza. Spatial/Spectral Endmember Extraction by Multidimensional Morphological Operations. IEEE Transactions on Geoscience and Remote Sensing,
vol. 40, no. 9, pp. 2025-2041, 2002.
[30] A. Plaza, J. Plaza, and A. Paz. Parallel heterogeneous CBIR system for efficient hyperspectral image retrieval using spectral mixture analysis. Concurrency and Computation: Practice &
Experience, 9:1138–1159, June 2010.
[31] A. Plaza, J. Plaza, and D. Valencia. Impact of platform heterogeneity on the design of parallel
algorithms for morphological processing of high-dimensional image data. The Journal of Supercomputing, 40(1):81–107, 2007.
[32] A. Plaza, J. Plaza, D. Valencia. AMEEPAR: Parallel Morphological Algorithm for Hyperspectral
Image Classification in Heterogeneous Networks of Workstations.” Lecture Notes in Computer
Science, vol. 3391, pp. 888-891, 2006.
[33] A. Plaza, D. Valencia, J. Plaza and C.-I Chang. Parallel Implementation of Endmember Extraction Algorithms from Hyperspectral Data. IEEE Geoscience and Remote Sensing Letters, vol. 3,
no. 3, pp. 334-338, July 2006.
[34] H. Ren, C.-I Chang, Automatic spectral target recognition in hyperspectral imagery. IEEE Transactions on Aerospace and Electronic Systems, vol. 39, no. 4, pp. 1232-1249, 2003.
BIBLIOGRAFÍA
77
[35] S. Sanchez y A. Plaza. Implementación paralela del algoritmo Pixel Purity Index para análisis
hiperespectral en GPUs. Jornadas de Paralelismo, Congreso Español de Informática (CEDI’2010),
Valencia, Spain, 2010.
[36] S. Sanchez.Implementación de algoritmos de análisis hiperespectral en tarjetas gráficas programables (GPUs). Trabajo Fin de Máster MUIT-TINC. Universidad de Extremadura, Julio 2010.
[37] J. Sanders and E. Kandrot. CUDA by Example: An Introduction to General-Purpose GPU Programming. Addison-Wesley Educational Publishers Inc; First edition. ISBN 0131387685. 2010.
[38] R. A. Schowengerdt. Remote Sensing: Models and Methods for Image Processing. Academic Press:
London, 1997.
[39] J. Setoain, M. Prieto, C. Tenllado, A. Plaza, F. Tirado. Parallel Morphological Endmember
Extraction Using Commodity Graphics Hardware. IEEE Geoscience and Remote Sensing Letters,
vol. 43, no. 3, pp. 441-445, 2007.
[40] V. S. Sunderam. PVM: A framework for parallel distributed computing. Concurrency and Computation: Practice & Experience, 2(4):315–339, December 1990.
[41] B. Thai, G. Healey, D. Slater. Invariant subpixel material identification in AVIRIS imagery. Proc.
JPL AVIRIS workshop, JPL Publication 99-17, 1999.
78
BIBLIOGRAFÍA
Publicaciones del candidato
Presentaciones en congresos:
• S. Garcı́a, J. M. Franco, C. Suárez, G. Dı́az and A. Plaza. Developing a portlet for the GISELA Science Gateway to process hyperspectral images. Joint GISELA-CHAIN Conference,
Mexico City, 2012.
• J. M. Franco and A. Plaza. Parallel implementation of the Pixel Purity Index algorithm
for GPU clusters. 27th IEEE International Parallel & Distributed Processing Symposium,
Boston, Massachusetts, 2013. (Pendiente de aceptación).
79
Descargar