Nvidia CUDA

NVIDIA CUDA (Compute Unified Device Architecture) es una plataforma de computación paralela y un modelo de programación desarrollado por NVIDIA. CUDA permite a los desarrolladores usar GPUs NVIDIA de alto rendimiento (Graphics Processing Units) para realizar tareas de computación de propósito general. A través de CUDA, los desarrolladores pueden aprovechar las potentes capacidades de computación de las GPUs para cálculos paralelos a gran escala, mejorando significativamente el rendimiento de las aplicaciones, especialmente en campos como la computación científica, el aprendizaje automático, el procesamiento de imágenes y la simulación física. CUDA soporta múltiples lenguajes de programación, como C, C++ y Python, y proporciona un rico conjunto de bibliotecas y herramientas para ayudar a los desarrolladores a lograr fácilmente la computación acelerada por GPU.

cuda logo

Fundamentos de programación CUDA

¿Cómo podemos invocar recursos de GPU en un programa para acelerar la ejecución del código? Usando CUDA, podemos administrar fácilmente miles de núcleos de computación dentro de la GPU. El modelo de programación CUDA es un modelo heterogéneo que requiere que la CPU y la GPU trabajen juntas. En la programación CUDA, los términos "host" y "device" se usan para distinguir los dispositivos donde se ejecuta el código.

  • Host: CPU y memoria del host
  • Device: GPU y memoria de video

Generalmente, el programa principal se carga en la CPU, luego copia los datos de inicialización a la GPU. La GPU completa los cálculos y copia los resultados de vuelta a la CPU.

Podemos usar un kernel en un programa CUDA para implementar el proceso anterior. En CUDA, un kernel se refiere a una función que, cuando se llama, hace que la GPU lance muchos hilos simultáneamente para ejecutar este kernel, logrando así paralelismo. Cada hilo ejecuta el kernel usando su ID de hilo para corresponder al índice de los datos de entrada, asegurando que cada hilo ejecute el mismo kernel pero procese datos diferentes.

La GPU tiene una vasta cantidad de núcleos de computación, y CUDA usa una estructura organizativa de dos niveles para administrar estos núcleos. Aquí hay tres conceptos en la programación CUDA que necesitan ser introducidos: Thread, Block y Grid.

  • Thread: Un programa paralelo CUDA es ejecutado por muchos hilos.
  • Block: Varios hilos se agrupan juntos para formar un bloque.
  • Grid: Múltiples bloques se organizan en una cuadrícula.

Nota: Los hilos dentro del mismo bloque pueden sincronizarse y comunicarse a través de memoria compartida.

cpu and gpu

En CUDA, cada hilo tiene un identificador único llamado ThreadIdx, que cambia dependiendo de la forma en que se divide el Grid y el Block.

Además, aquí hay una breve introducción al modelo de memoria CUDA, como se muestra en el diagrama a continuación. Cada hilo tiene su propia memoria local privada, mientras que cada bloque de hilos incluye memoria compartida que puede ser accedida por todos los hilos dentro del bloque, con una vida útil igual a la del bloque de hilos. Además, todos los hilos pueden acceder a la memoria global. También hay algunos espacios de memoria de solo lectura: memoria constante y memoria de textura. La estructura de memoria involucra la optimización del programa, que no se discutirá en detalle aquí.

cpu and gpu

Caso de demostración CUDA

Ahora, experimentemos la aceleración de GPU a través de un ejemplo simple. En este ejemplo, calcularemos la suma de dos vectores tanto en la CPU como en la GPU, y compararemos las velocidades de computación entre CPU y GPU.

Preparando el entorno de ejecución

El sistema operativo JetPack ya incluye el entorno de ejecución CUDA. Podemos verificar la versión de CUDA usando la herramienta jtop. Abra el terminal y ejecute jtop.

bash
jtop

jtop

Nota: Si jtop no está instalado en su sistema, consulte esta guía.

A continuación, usaremos Python para escribir código CUDA. Por lo tanto, necesitamos ejecutar el siguiente comando en el terminal para instalar Numba.

bash
pip install numba

Ejecutando el código de ejemplo

Paso 1: Cree un script de Python para este curso en el directorio raíz:

bash
mkdir -p ~/reComputer_J/3.4_CUDA
touch ~/reComputer_J/3.4_CUDA/add_compare.py

Paso 2: Abra VSCode en el directorio donde se encuentra el script:

bash
cd ~/reComputer_J/3.4_CUDA
code .

Paso 3: En la barra de navegación izquierda, podemos ver hello_world.py. Ingrese el siguiente código en el archivo python:

Haga clic para expandir el código
python
from numba import cuda, float32
import numpy as np
import time


@cuda.jit
def add_gpu(a, b, out):
  tx = cuda.threadIdx.x
  ty = cuda.blockIdx.x
  block_size = cuda.blockDim.x
  grid_size = cuda.gridDim.x
  start = tx + ty * block_size
  stride = block_size * grid_size

  for i in range(start, a.shape[0], stride):
      out[i] = a[i] + b[i]

def add_cpu(a, b, out):
  for i in range(a.shape[0]):    
      out[i] = a[i] + b[i]

def main():
  # Prepare test data
  n = 10000000
  a = np.arange(n).astype(np.float32)
  b = np.arange(n).astype(np.float32)
  out = np.empty_like(a)

  # 1. Test CPU computation time
  start = time.time()
  add_cpu(a, b, out)
  print("CPU Time Taken:", time.time()-start)

  # 2. Test GPU computation time
  # Copy data from host memory to device memory
  d_a = cuda.to_device(a)
  d_b = cuda.to_device(b)
  d_out = cuda.device_array_like(out)
  # Define the number of threads per block and the number of blocks
  threads_per_block = 256  
  blocks_per_grid = (n + threads_per_block - 1) // threads_per_block
  # Compute the result
  start_gpu = time.time()
  add_gpu[blocks_per_grid, threads_per_block](d_a, d_b, d_out)
  end_gpu = time.time()
  # Copy the result from device memory back to host memory
  d_out.copy_to_host(out)

  print("GPU Time Taken:", end_gpu-start_gpu)


if __name__ == "__main__":
  main()

Paso 4: Haga clic en el botón de ejecución para ver el resultado del script Python en el terminal.

launch vscode

De los resultados impresos en el terminal, se puede observar que la velocidad de computación de la GPU es más rápida.

Más tutoriales de aprendizaje CUDA

TutorialTipoDescripción
Getting Started with CUDA Programming(zh)DocumentoUn tutorial minimalista para comenzar con la programación CUDA en chino
CUDA C++ Programming GuideDocumentoLa guía de programación para el modelo y la interfaz de CUDA.