Kit de supervivencia con GPU para la era de la IA
(journal.hexmos.com)- El desarrollo de IA ya no puede depender solo de la ejecución secuencial típica de la CPU; para manejar bien el rendimiento de entrenamiento e inferencia, hay que entender el modelo de procesamiento masivo en paralelo de la GPU
- Una CPU, por lo general, tiene entre 2 y 16 núcleos en equipos de consumo y destaca en tareas de un solo hilo y con bifurcaciones condicionales, mientras que una GPU, con miles de núcleos pequeños, resulta ventajosa para operaciones matriciales, procesamiento de imágenes y deep learning
- AWS ofrece entornos de ejecución con GPU como P3/P4, P5/Inf1, G4 y Amazon SageMaker; p3.2xlarge cuesta $3.06 por hora, p5.48xlarge $98.32 y g4dn.xlarge alrededor de $0.526
- CUDA de NVIDIA permite a los desarrolladores manejar directamente el flujo de ejecución en paralelo, desde la asignación de memoria en GPU y la copia de datos hasta la ejecución de kernels y la compilación
- Los ejemplos de suma de arreglos, generación de Mandelbrot y una CNN para clasificar gatos y perros muestran cómo dividir bucles secuenciales en hilos de GPU; en Mandelbrot, el tiempo baja de 4.07 segundos en CPU a 0.0046 segundos en GPU
Por qué no basta con saber solo de CPU
- Muchos desarrolladores han aprendido a programar y resolver problemas con un enfoque centrado en la CPU, pero la CPU funciona en esencia apoyándose en una arquitectura secuencial
- Una CPU tradicional ejecuta instrucciones de forma lineal y optimiza unos pocos núcleos potentes para el rendimiento de un solo hilo
- Cuando hay que procesar varias tareas al mismo tiempo, el costo de atenderlas una por una crece debido al enfoque de ejecución secuencial
- Es posible mejorar el rendimiento con multithreading, pero la filosofía de diseño base de la CPU sigue estando más cerca de la ejecución secuencial
Modelos de IA y procesamiento en paralelo
- Las arquitecturas modernas de IA, como Transformer, mejoran el rendimiento del entrenamiento aprovechando el procesamiento en paralelo
- Mientras que una RNN opera de forma secuencial, un Transformer como GPT puede procesar varias palabras al mismo tiempo, lo que mejora la eficiencia del entrenamiento y la capacidad del modelo
- El entrenamiento en paralelo hace posibles modelos más grandes, y los modelos más grandes sientan la base para producir mejores resultados
- El paralelismo no solo se aplica al procesamiento de lenguaje natural, sino también al reconocimiento de imágenes
- AlexNet es un ejemplo de cómo procesar varias partes de una imagen al mismo tiempo para identificar patrones
- Debido a que la CPU está diseñada en torno al rendimiento de un solo hilo, le resulta difícil distribuir y ejecutar de manera eficiente la gran cantidad de cómputo paralelo que exigen los modelos de IA complejos
Cómo la GPU reduce los cuellos de botella
- La GPU está diseñada con una estructura que usa muchos núcleos pequeños y especializados en lugar de los núcleos grandes y potentes de la CPU
- El paralelismo de la GPU se luce especialmente en cargas de trabajo donde se repite masivamente el mismo tipo de operación, como el renderizado gráfico y los cálculos matemáticos complejos
- Frameworks de deep learning como TensorFlow están optimizados para aprovechar el rendimiento de la GPU y acelerar el entrenamiento y la inferencia de modelos
- El entrenamiento de redes neuronales incluye muchas operaciones matriciales, y la GPU destaca al paralelizarlas gracias a su gran cantidad de núcleos
Diferencias de rol entre CPU y GPU
-
CPU
- La CPU está diseñada con enfoque en el procesamiento secuencial, por lo que destaca en tareas que ejecutan un flujo de instrucciones de manera lineal
- Es adecuada para cómputo de propósito general, tareas del sistema y procesamiento de algoritmos complejos con bifurcaciones condicionales
- Una CPU de consumo suele tener una cantidad relativamente baja de núcleos, normalmente en el rango de 2 a 16 núcleos
- Cada núcleo puede procesar de forma independiente su propio conjunto de instrucciones
-
GPU
- La GPU está diseñada con una arquitectura paralela, por lo que es eficiente para manejar muchas subtareas al mismo tiempo
- Es ventajosa para renderizado gráfico, cálculos matemáticos complejos y ejecución de algoritmos paralelizables
- Divide el trabajo en unidades paralelas más pequeñas para procesar múltiples operaciones de forma simultánea
- Los núcleos de una GPU suelen contarse por miles y se organizan en streaming multiprocessors (SMs) o estructuras similares
- Es adecuada para tareas que manejan muchos datos al mismo tiempo, como procesamiento de imagen y video, deep learning y simulaciones científicas
Entornos con GPU que puedes elegir en AWS
- AWS ofrece varias instancias con GPU que pueden usarse para tareas como machine learning
-
Instancias GPU de propósito general
-
Instancias optimizadas para inferencia
- La inferencia es el proceso de introducir datos en tiempo real en un modelo de IA ya entrenado para hacer predicciones o resolver tareas
- P5 e Inf1 están orientadas a inferencia de machine learning, donde importan la baja latencia y la eficiencia en costos
- p5.48xlarge cuesta $98.32 por hora y ofrece 8 GPU NVIDIA H100, cada una con 80 GB de memoria, para un total de 640 GB de memoria de video
-
Instancias optimizadas para gráficos
- Las G4 instances están diseñadas para manejar tareas intensivas en gráficos
- Los desarrolladores de videojuegos pueden usar instancias G4 para renderizar gráficos 3D para juegos
- g4dn.xlarge cuesta $0.526 por hora y usa 1 GPU NVIDIA T4 con 16 GB de memoria
-
Servicio administrado de machine learning
- Amazon SageMaker es un servicio administrado para machine learning que brinda acceso a instancias basadas en GPU como P3, P4 y P5
- SageMaker es adecuado para organizaciones que quieren empezar con machine learning sin administrar directamente la infraestructura subyacente
- También se ofrece por separado la documentación de precios de Amazon SageMaker
Uso básico de NVIDIA CUDA
- CUDA es una plataforma de computación paralela y un modelo de programación desarrollado por NVIDIA, que permite ejecutar aplicaciones más rápido aprovechando aceleradores GPU
- Los ejemplos muestran el flujo de desarrollo con CUDA: asignación de memoria en GPU, copia de datos, ejecución del kernel y recuperación de resultados
-
Flujo de instalación
- Descarga el base installer y el driver installer desde CUDA
- Agrega las siguientes variables de entorno al archivo
.bashrcde tu carpeta personalexport PATH="/usr/local/cuda-12.3/bin:$PATH"export LD_LIBRARY_PATH="/usr/local/cuda-12.3/lib64:$LD_LIBRARY_PATH"
- Ejecuta los siguientes comandos
sudo apt-get install cuda-toolkitsudo apt-get install nvidia-gds
- Reinicia el sistema para aplicar los cambios
-
Comandos útiles de verificación
lspci | grep VGA: identifica y enumera las GPU del sistemanvidia-smi: proporciona información detallada sobre uso, temperatura y memoria de las GPU NVIDIAsudo lshw -C display: muestra información de los controladores de pantalla, incluidas las tarjetas gráficasinxi -G: muestra información del subsistema gráfico, incluida la GPU y la pantallasudo hwinfo --gfxcard: se usa para consultar información detallada sobre la tarjeta gráfica del sistema
Paralelizar la suma de arreglos con CUDA
- La suma de arreglos es un problema adecuado para explicar la paralelización con GPU
- Los arreglos de ejemplo son
A = [1,2,3,4,5,6],B = [7,8,9,10,11,12]y el resultado esC = [8,10,12,14,16,18] - En el enfoque con CPU, la suma se realiza recorriendo uno por uno los elementos del arreglo
- A medida que crecen los datos, aumenta el tiempo del enfoque secuencial, mientras que la GPU puede ejecutar al mismo tiempo operaciones como
1+7,2+8y3+9 - El ejemplo en CUDA usa un archivo de kernel
.cu__global__indica una función kernel que se ejecuta en la GPUvectorAddrecibe tres punteros enterosa,bycy realiza la suma de vectoresthreadIdx.xobtiene el índice del hilo actual- Cada hilo guarda la suma del elemento correspondiente en
c[i]
- La función
mainsigue el orden de asignación de memoria en GPU, copia de datos, ejecución del kernel y copia del resultadocudaMallocasigna en la GPU la memoria paracudaA,cudaBycudaCcudaMemcpycopiaaybdel host a la GPUvectorAdd <<<1, sizeof(a) / sizeof(a[0])>>>ejecuta el kernel- El vector resultado
cudaCse copia de la GPU al host
- Para compilar y ejecutar se usa el comando
nvcc - Se proporciona el código completo
Uso de GPU para generar imágenes en Python
- La generación del conjunto de Mandelbrot consiste en crear patrones visuales complejos a partir del comportamiento de números en una ecuación específica, y es una tarea intensiva en recursos
- El ejemplo en Python basado en CPU recorre cada píxel para calcular el valor de Mandelbrot, y tarda 4.07 segundos en generar una imagen de 1024×1536
- La versión acelerada con GPU usa la biblioteca Numba
- El decorador
@jitrealiza compilación Just-In-Time para convertir código Python en código máquina cuda.jitse usa para crearmandel_gpu, y se especificadevice=Truepara que se ejecute en la GPUmandel_kernelse ejecuta en una GPU CUDA y distribuye la generación de Mandelbrot entre hilos de GPU
- El decorador
create_fractal_gpurealiza la asignación de memoria en GPU, la configuración de hilos y bloques, la ejecución del kernel, la sincronización y la copia de resultados- Usa
threadsperblock = (16, 16) cuda.synchronize()espera a que termine el trabajo de la GPUd_image.copy_to_host(image)copia el resultado al lado de la CPU
- Usa
- El tiempo de ejecución en GPU es de 0.0046 segundos, mucho más rápido que el código basado en CPU
- Se proporciona el código completo
Entrenar una red neuronal para clasificar gatos y perros con GPU
- Para mostrar cómo se usa la GPU en IA, se utiliza como ejemplo una red neuronal que distingue entre gatos y perros
- Los prerrequisitos son CUDA y TensorFlow
- TensorFlow puede instalarse con
pip install tensorflow[and-cuda] - El dataset usado es Kaggle Dogs vs. Cats
- Después de descargarlo, se organizan las imágenes de gatos y perros en subcarpetas separadas dentro de la carpeta de entrenamiento
- TensorFlow puede instalarse con
- El modelo usa una red neuronal convolucional (CNN)
- pandas y numpy se usan para manipulación de datos
Sequentialse usa para apilar capas de la red neuronal de forma linealConvolution2D,MaxPooling2D,DenseyFlattenson capas que componen la CNNImageDataGeneratorse utiliza para aumento de datos en tiempo real durante el entrenamiento
- Los datos de entrenamiento se cargan con
ImageDataGenerator- A los datos de entrenamiento se les aplica
rescale=1./255,shear_range=0.2,zoom_range=0.2,horizontal_flip=True - Las imágenes de entrada se configuran con tamaño
(64, 64), batch size 32 y modo de clasificación binaria
- A los datos de entrenamiento se les aplica
- La estructura de la CNN se compone de capas convolucionales, max pooling, flatten, capas Dense y una salida sigmoid
- El modelo se compila con el optimizador
adam, la pérdidabinary_crossentropyy la métricaaccuracy - El entrenamiento se ejecuta con
epochs=25yvalidation_steps=2000, y se guarda en un archivo.h5conclassifier.save('trained_model.h5') - El código de inferencia carga
trained_model.h5, convierte la imagen a(64, 64)y, si la predicción es de 0.5 o más, imprimedog; de lo contrario,cat - Se proporciona el código completo
El alcance del uso de GPU
- En la era de la IA, es difícil ignorar las capacidades de la GPU, y los desarrolladores necesitan entender mejor su potencial
- A medida que se pasa de algoritmos secuenciales a algoritmos paralelizados, la GPU se convierte en una herramienta para acelerar cálculos complejos
- La capacidad de procesamiento en paralelo de la GPU es especialmente ventajosa para manejar grandes datasets y arquitecturas complejas de redes neuronales en tareas de IA y machine learning
- La GPU se usa más allá del machine learning tradicional, en investigación científica, simulaciones y trabajos intensivos en datos
- La capacidad de procesamiento en paralelo se aprovecha para resolver problemas en campos diversos como descubrimiento de fármacos, modelado climático y simulaciones financieras
1 comentarios
Opiniones en Hacker News
El código de este artículo está mal. No se llama a ningún kernel CUDA: https://github.com/RijulTP/GPUToolkit/blob/f17fec12e008d0d37...
El 90% del tiempo que el código compilado con JIT dedica a “calcular” el conjunto de Mandelbrot no se va en el cálculo real, sino en compilar la función.
Si quieres aprender CUDA correctamente, implementar multiplicación de matrices es un buen ejercicio, y hay tutoriales útiles en https://cnugteren.github.io/tutorial/pages/page1.html y https://siboehm.com/articles/22/CUDA-MMM.
Toma vectores de punto flotante de 32 bits X e Y, y un escalar A; multiplica cada X[i] por A y luego lo suma a Y[i]: https://developer.nvidia.com/blog/six-ways-saxpy/
Aunque afirma que “todo desarrollador debería saberlo”, en realidad parece más un artículo sobre cómo se usan las GPU en IA. La mayoría de los desarrolladores no son desarrolladores de IA, ni interactúan directamente con IA ni usan GPU de forma directa.
Además, casi no trata los gráficos 3D, que son la razón central por la que existen las GPU.
Tener conocimientos básicos también ayuda a entender mejor las historias de “IA” que se le venden al gerente.
La actitud de “no necesito saber nada de áreas vecinas” es algo que veía seguido en la escuela. En administración de sistemas, mis compañeros decían que no hacía falta saber programación, pero se necesitaba scripting; en la escuela de desarrollo de software decían que no hacía falta saber redes, pero unos años después DevOps apareció por todas partes en las ofertas de empleo.
Si el artículo tiene unas 1500 palabras, incluso leyéndolo como estudio toma alrededor de 12 minutos; y aunque pases unas 2 horas ejecutando los ejemplos de código, no es una gran inversión. Claro, eso supone que el artículo sea una buena introducción.
curl. Sigo siendo desarrollador embebido, pero desde entonces aprendí bastante de backend, frontend e infraestructura, y parece muy probable que en los próximos años ocurra algo parecido en toda la industria con la IA.Creo que la razón por la que Python domina en IA es que la relación Python-C se parece a la relación CPU-GPU.
Las GPU tienen muy buen rendimiento, pero son difíciles de programar directamente, así que la gente las usa mediante llamadas a APIs de alto nivel como PyTorch.
C también tiene buen rendimiento, pero es difícil de programar, así que se usa Python como una capa de abstracción sobre C.
No está claro que la gente tenga que entender las GPU con tanta profundidad. Menos aún si no se mete de lleno en el entrenamiento u operación de IA; y si la ley de Moore termina y el multithreading se convierte en la principal vía para mejorar velocidad, es muy probable que aparezcan nuevos lenguajes adaptados al paradigma de programación paralela. Mojo parece el punto de partida.
Algo diseñado para que, desde cálculos repetitivos simples, todas las instrucciones aprovechen inteligentemente y en paralelo todos los núcleos de CPU por detrás, y que las tareas posibles se envíen a la GPU.
Me pregunto si ya hubo intentos así, o si siquiera es posible.
La explicación de que “cuando la CPU se encuentra con varias tareas, asigna recursos para procesar cada tarea una por una” es demasiado simplista. Hasta me hace desear que las CPU todavía fueran así de simples.
Es válido que el artículo se concentre en el modelo de programación, pero desde el punto de vista del rendimiento, decir que “la CPU ejecuta instrucciones de forma secuencial” es básicamente incorrecto. Los pipelines ejecutan instrucciones en paralelo, también existe SIMD, y varios núcleos pueden trabajar juntos sobre el mismo problema.
La gran diferencia es que la CPU usa mucho silicio y energía para manejar el flujo de control de manera eficiente al ejecutar un solo hilo, mientras que la GPU destina esos recursos a más unidades de cómputo y ejecuta muchísimos hilos para ocultar el flujo de control y las latencias de memoria.
Decir que la CPU es buena para código serial y la GPU para código paralelo es cierto hasta cierto punto, pero es una aproximación bastante burda. Si asumimos un presupuesto de energía similar, de cientos de watts, una CPU tiene alrededor de 100 “núcleos” que ejecutan tareas independientes una por una, incluyendo hyper-threading, y oculta la latencia de memoria mediante predicción de saltos y pipelining
Una GPU tiene alrededor de 100 “unidades de cómputo”, y cada unidad ejecuta de forma intercalada unas 80 tareas independientes, ocultando la latencia de memoria al ejecutar la siguiente instrucción de otra tarea
La terminología es bastante confusa, y es probable que una CPU tenga unidades vectoriales de 256 bits de ancho y una GPU unidades vectoriales de 2048 bits de ancho, pero si uno toma un poco de distancia, ambas arquitecturas se ven bastante parecidas
Podrían llamarlo Xeon Chi
La mayoría de los lenguajes de programación están diseñados para procesamiento secuencial, como una CPU, mientras que Erlang/Elixir están diseñados para la paralelización, como una GPU; viéndolo así, me pregunto si Nx / Axon despegarán: https://github.com/elixir-nx/
Hace falta una guía de compra. Quiero saber cuánto hay que gastar como mínimo y cuál es la mejor opción para cada rango de presupuesto. El problema es que esa información cambia de vez en cuando, y no sé si existe algún recurso que se mantenga actualizado
https://colab.google/
https://www.kaggle.com/docs/notebooks
https://www.paperspace.com/gradient/free-gpu
¿Volvimos otra vez a los artículos clickbait del estilo “lo que todo desarrollador debería saber”?
Me gusta que aborden la complejidad de frente, y como tengo cierto conocimiento tanto de los métodos cuantitativos como de los detalles cualitativos de áreas como el hardware de computadoras, agradezco los textos que explican bien los detalles de un campo
Por ejemplo, es otra discusión si todos los programadores deberían conocer “What every programmer should know about memory”, pero un buen programador debería tener una idea de cómo funciona realmente una computadora. La idea clave que uno puede llevarse de ese texto, la localidad, suele aparecer de forma natural en buen código que es rápido, fácil de seguir y adecuado al problema
Es un buen artículo, pero las instancias AWS P5, junto con P4d y P4de, están claramente orientadas al entrenamiento, no a la inferencia. Los tipos de instancia más adecuados para inferencia son G4dn y G5, que usan GPU T4 y A10G, respectivamente
Soy casi principiante en programación de GPU, pero este artículo me pareció entretenido. Me sorprende que hayamos avanzado tanto como para poder entrenar con tanta facilidad una red neuronal simple de “perro o gato”