supported - Programación de GPU de alto nivel en C++
gpu programming cuda tutorial (8)
He estado buscando bibliotecas / extensiones para C ++ que permitan el procesamiento basado en GPU en un alto nivel. No soy un experto en programación de GPU y no quiero profundizar demasiado. Tengo una red neuronal que consta de clases con funciones virtuales. Necesito una biblioteca que básicamente haga la asignación de GPU por mí, en un nivel alto. Hay un tipo que escribió una tesis sobre un sistema llamado GPU ++ que hace la mayoría de las cosas de GPU por ti. No puedo encontrar el código en ningún lado, solo su tesis.
¿Alguien sabe de una biblioteca similar, o alguien tiene el código para GPU ++? Las bibliotecas como CUDA tienen un nivel demasiado bajo y no pueden manejar la mayoría de mis operaciones (al menos no sin volver a escribir todos mis procesos y algoritmos, lo que no quiero hacer).
C ++ AMP es la respuesta que estás buscando.
El proyecto cpp-opencl proporciona una manera de hacer que las GPU de programación sean fáciles para el desarrollador. Le permite implementar el paralelismo de datos en una GPU directamente en C ++ en lugar de usar OpenCL.
Consulte http://dimitri-christodoulou.blogspot.com/2014/02/implement-data-parallelism-on-gpu.html
Y el código fuente: https://github.com/dimitrs/cpp-opencl
Vea el ejemplo a continuación. El código en la función lambda de parallel_for_each se ejecuta en la GPU, y todo el resto se ejecuta en la CPU. Más específicamente, la función "cuadrada" se ejecuta tanto en la CPU (a través de una llamada a std :: transform) como en la GPU (a través de una llamada a compute :: parallel_for_each).
#include <vector>
#include <stdio.h>
#include "ParallelForEach.h"
template<class T>
T square(T x)
{
return x * x;
}
void func() {
std::vector<int> In {1,2,3,4,5,6};
std::vector<int> OutGpu(6);
std::vector<int> OutCpu(6);
compute::parallel_for_each(In.begin(), In.end(), OutGpu.begin(), [](int x){
return square(x);
});
std::transform(In.begin(), In.end(), OutCpu.begin(), [](int x) {
return square(x);
});
//
// Do something with OutCpu and OutGpu …..........
//
}
int main() {
func();
return 0;
}
Hay muchas bibliotecas de alto nivel dedicadas a la programación de GPGPU. Dado que dependen de CUDA y / o OpenCL, tienen que ser elegidos con inteligencia (un programa basado en CUDA no se ejecutará en las GPU de AMD, a menos que pase por un paso de procesamiento previo con proyectos como gpuocelot ).
CUDA
Puede encontrar algunos ejemplos de bibliotecas CUDA en el website NVIDIA.
- Thrust : la descripción oficial habla por sí misma.
Thrust es una biblioteca de algoritmos paralelos que se asemeja a la Biblioteca de plantillas estándar de C ++ (STL). La interfaz de alto nivel de Thrust mejora en gran medida la productividad del programador al tiempo que permite la portabilidad del rendimiento entre las GPU y las CPU multinúcleo. La interoperabilidad con tecnologías establecidas (como CUDA, TBB y OpenMP) facilita la integración con el software existente.
Como señaló @Ashwin , la sintaxis similar a STL de Thrust hace que sea una biblioteca ampliamente elegida al desarrollar programas CUDA. Un vistazo rápido a los ejemplos muestra el tipo de código que escribirá si decide utilizar esta biblioteca. El sitio web de NVIDIA presenta las developer.nvidia.com/thrust de esta biblioteca. También está disponible una presentación en video (de GTC 2012).
- CUB : la descripción oficial nos dice:
CUB proporciona componentes de software reutilizables de última generación para cada capa del modo de programación CUDA. Es una biblioteca flexible de primitivas de subprocesos cooperativos y otras utilidades para la programación del kernel CUDA.
Proporciona primitivas paralelas en todo el dispositivo, en todo el bloque y en la deformación, como la ordenación en paralelo, la exploración de prefijos, la reducción, el histograma, etc.
Es de código abierto y está disponible en GitHub . No es de alto nivel desde el punto de vista de la implementación (se desarrolla en los núcleos CUDA), pero proporciona algoritmos y rutinas de alto nivel.
- mshadow : biblioteca de plantillas de matriz / tensor de CPU / GPU ligeras en C ++ / CUDA.
Esta biblioteca se utiliza principalmente para el aprendizaje automático y se basa en plantillas de expresión .
- Eigen : se ha agregado soporte para CUDA con una nueva clase Tensor en la versión 3.3 . Es usado por Google en TensorFlow , y todavía es experimental.
A partir de Eigen 3.3, ahora es posible usar los objetos y algoritmos de Eigen dentro de los núcleos CUDA. Sin embargo, solo se admite un subconjunto de funciones para asegurarse de que no se active ninguna asignación dinámica dentro de un kernel CUDA.
OpenCL
Tenga en cuenta que OpenCL hace más que la computación GPGPU, ya que admite plataformas heterogéneas (CPU de múltiples núcleos, GPU, etc.).
- openacc-standard.org : este proyecto proporciona soporte similar a OpenMP para GPGPU. Una gran parte de la programación se realiza implícitamente por el compilador y la API en tiempo de ejecución. Puede encontrar un código de muestra en su sitio web.
La Interfaz de Programa de Aplicación de OpenACC describe una colección de directivas de compilación para especificar bucles y regiones de código en el estándar C, C ++ y Fortran que se descargarán de una CPU host a un acelerador adjunto, proporcionando portabilidad a través de sistemas operativos, CPU host y aceleradores.
- Bolt : biblioteca de código abierto con interfaz similar a STL.
Bolt es una biblioteca de plantillas C ++ optimizada para computación heterogénea. Bolt está diseñado para proporcionar implementaciones de biblioteca de alto rendimiento para algoritmos comunes como escanear, reducir, transformar y clasificar. La interfaz de Bolt se modeló en la Biblioteca de plantillas estándar de C ++ (STL). Los desarrolladores familiarizados con el STL reconocerán muchas de las API de Bolt y las técnicas de personalización.
Boost.Compute : como dijo @Kyle Lutz , Boost.Compute proporciona una interfaz similar a STL para OpenCL. Tenga en cuenta que esta no es una biblioteca oficial de Boost (todavía).
SkelCL "es una biblioteca que proporciona abstracciones de alto nivel para la programación aliviada de los modernos sistemas heterogéneos paralelos". Esta biblioteca se basa en la programación de esqueletos , y puede encontrar más información en sus trabajos de investigación .
CUDA + OpenCL
- ArrayFire es una biblioteca de programación GPGPU de código abierto (que solía ser propietaria). Primero se enfocaron en CUDA, pero ahora también admiten OpenCL. Puedes consultar los examples disponibles en línea. El sitio web de NVIDIA proporciona un buen resumen de sus características clave.
Información complementaria
Aunque esto no está realmente en el alcance de esta pregunta, también existe el mismo tipo de soporte para otros lenguajes de programación:
- Python : PyCUDA para CUDA, Clyther y PyOpenCL para OpenCL. Hay una pregunta dedicada de para esto.
- Java : JCuda para CUDA, y para OpenCL, puede consultar esta otra pregunta .
Si necesita hacer álgebra lineal (por ejemplo) u otras operaciones específicas, también están disponibles bibliotecas de matemáticas dedicadas para CUDA y OpenCL (por ejemplo, CUBLAS , CUBLAS , MAGMA , etc.).
También tenga en cuenta que el uso de estas bibliotecas no le impide realizar algunas operaciones de bajo nivel si necesita realizar algún cálculo muy específico.
Finalmente, podemos mencionar el futuro de la biblioteca estándar de C ++. Ha habido un extenso trabajo para agregar soporte de paralelismo. Esta es todavía una especificación técnica , y las GPU no se mencionan explícitamente como AFAIK (aunque Jared Hoberock de NVIDIA, desarrollador de Thrust, está directamente involucrado), pero la voluntad de hacer esto una realidad definitivamente está ahí.
La biblioteca Thrust proporciona contenedores, primitivos paralelos y algoritmos. Toda esta funcionalidad está muy bien envuelta en una sintaxis similar a STL. Por lo tanto, si está familiarizado con STL, puede escribir programas completos de CUDA usando solo Thrust, sin tener que escribir un solo núcleo de CUDA. Mire los ejemplos simples en la Guía de inicio rápido para ver el tipo de programas de alto nivel que puede escribir usando Thrust.
La nueva versión 4 de OpenMP ahora incluye soporte de descarga de acelerador.
Las GPU AFAIK son consideradas como aceleradoras.
Otra biblioteca de alto nivel es VexCL , una biblioteca de plantillas de expresiones vectoriales para OpenCL. Proporciona una notación intuitiva para operaciones vectoriales y está disponible bajo la licencia MIT.
Si está buscando contenedores de mayor dimensión y la capacidad de pasar y manipular estos contenedores en el código del kernel, he pasado los últimos años desarrollando el API de ecuda para ayudar en mis propios proyectos de investigación científica (por lo que se ha sometido a la pasos). Esperemos que pueda llenar un nicho necesario. Un breve ejemplo de cómo se puede usar (las características de C ++ 11 se usan aquí, pero ecuda funcionará bien con los compiladores pre-C ++ 11):
#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <vector>
#include <ecuda/ecuda.hpp>
// kernel function
__global__
void calcColumnSums(
typename ecuda::matrix<double>::const_kernel_argument mat,
typename ecuda::vector<double>::kernel_argument vec
)
{
const std::size_t t = threadIdx.x;
auto col = mat.get_column(t);
vec[t] = ecuda::accumulate( col.begin(), col.end(), static_cast<double>(0) );
}
int main( int argc, char* argv[] )
{
// allocate 1000x1000 hardware-aligned device memory matrix
ecuda::matrix<double> deviceMatrix( 1000, 1000 );
// generate random values row-by-row and copy to matrix
std::vector<double> hostRow( 1000 );
for( std::size_t i = 0; i < 1000; ++i ) {
for( double& x : hostRow ) x = static_cast<double>(rand())/static_cast<double>(RAND_MAX);
ecuda::copy( hostRow.begin(), hostRow.end(), deviceMatrix[i].begin() );
}
// allocate device memory for column sums
ecuda::vector<double> deviceSums( 1000 );
CUDA_CALL_KERNEL_AND_WAIT(
calcColumnSums<<<1,1000>>>( deviceMatrix, deviceSums )
);
// copy columns sums to host and print
std::vector<double> hostSums( 1000 );
ecuda::copy( deviceSums.begin(), deviceSums.end(), hostSums.begin() );
std::cout << "SUMS =";
for( const double& x : hostSums ) std::cout << " " << std::fixed << x;
std::cout << std::endl;
return 0;
}
Lo escribí para que fuera lo más intuitivo posible (generalmente tan simple como reemplazar std :: con ecuda: :). Si conoce STL, ecuda debe hacer lo que lógicamente espera que haga una extensión de C ++ basada en CUDA.
Echa un vistazo a Boost.Compute . Proporciona una interfaz similar a STL de alto nivel que incluye contenedores como vector<T>
y algoritmos como transform()
y sort()
.
Está construido en OpenCL lo que permite que se ejecute en la mayoría de las GPU y CPU modernas, incluidas las de NVIDIA, AMD e Intel.