C++中的高级GPU编程

48

我一直在寻找适用于C++的库/扩展,可以在高级别上进行基于GPU的处理。我不是GPU编程的专家,也不想深入了解。我有一个由具有虚拟函数的类组成的神经网络。我需要一个库,基本上为我执行GPU分配 - 在高级别上。有个人写了一篇关于名为GPU ++ 的系统的论文,它为您处理大部分GPU操作。我无法在任何地方找到代码,只有他的论文。

是否有人知道类似的库,或者有GPU ++的代码吗?像CUDA这样的库太底层了,不能处理我的大多数操作(至少不能不重写所有的过程和算法 - 我不想这样做)。


1
类似这样的东西可能吗?http://viennacl.sourceforge.net/viennacl-examples-vector.html - stardust
1
OpenACC http://www.openacc-standard.org/ 或者 Thrust https://developer.nvidia.com/thrust? - ShPavel
1
你可以尝试使用arrayfire,或者OpenCV GPU模块 - sgarizvi
1
投票关闭,建议使用工具。 - Ciro Santilli OurBigBook.com
@AndersonGreen,自那以后我已经改变了我的哲学观点,我现在相信我们永远不应该关闭任何事情。我相信在6个月后迁移是不可能的,唯一的选择是开一个新的问题。软件推荐可能会接受它。 - Ciro Santilli OurBigBook.com
8个回答

61

有许多专用于GPGPU编程的高级库。由于它们依赖于CUDA和/或OpenCL,因此必须明智选择(基于CUDA的程序将无法在AMD的GPU上运行,除非通过像gpuocelot这样的项目进行预处理)。

CUDA

您可以在NVIDIA website上找到一些CUDA库的示例。

  • Thrust:官方描述已经说明了:

Thrust是一个类似于C++标准模板库(STL)的并行算法库。 Thrust的高级接口大大提高了程序员的生产力,同时实现了GPU和多核CPU之间的性能可移植性。 与已建立的技术(如CUDA、TBB和OpenMP)的互操作性有助于与现有软件集成。

作为@Ashwin指出,Thrust的类似STL的语法使其成为开发CUDA程序时广泛选择的库。快速查看示例可了解如果决定使用该库,将编写的代码类型。NVIDIA的网站介绍了该库的关键特性。此外还提供了一份视频演示(来自GTC 2012)。
  • CUB:官方描述告诉我们:

CUB为CUDA编程模式的每个层提供最先进的可重用软件组件。它是一个灵活的协作线程块基元库和其他CUDA内核编程实用程序。

CUB提供设备级、块级和warp级并行基元,如并行排序、前缀扫描、约简、直方图等。

它是开源的,可在GitHub上获得。从实现的角度来看,它不是高级的(您可以在CUDA内核中开发),但提供了高级算法和例程。

  • mshadow:C++ / CUDA中轻量级CPU / GPU矩阵/张量模板库。

这个库主要用于机器学习,并依赖于表达式模板

从Eigen 3.3开始,现在可以在CUDA内核中使用Eigen的对象和算法。但是,为了确保不在CUDA内核中触发动态分配,只支持一部分功能。
OpenCL
请注意,OpenCL不仅支持GPGPU计算,还支持异构平台(多核CPU、GPU等)。
- OpenACC:该项目为GPGPU提供类似于OpenMP的支持。编译器和运行时API隐式地完成了大部分编程工作。您可以在他们的网站上找到sample code
The OpenACC应用程序接口描述了一组编译器指令,以指定要从主机CPU卸载到附加加速器的标准C、C++和Fortran中的循环和代码区域,从而提供跨操作系统、主机CPU和加速器的可移植性。
  • Bolt:类似于STL接口的开源库。

Bolt是一个针对异构计算进行优化的C++模板库。Bolt旨在为常见算法(如扫描、归约、转换和排序)提供高性能的库实现。Bolt接口是基于C++标准模板库(STL)建模的。熟悉STL的开发人员将会认识到许多Bolt API和自定义技术。

  • Boost.Compute:正如@Kyle Lutz所说,Boost.Compute为OpenCL提供了类似STL的接口。请注意,这不是官方的Boost库(尚未)。

  • SkelCL“是一个提供高级抽象的库,用于减轻现代并行异构系统的编程难度”。该库依赖于骨架编程,您可以在他们的研究论文中找到更多信息。

CUDA + OpenCL

  • ArrayFire是一个开源(曾经是专有的)GPGPU编程库。他们最初针对CUDA,但现在也支持OpenCL。您可以查看在线示例。 NVIDIA的网站提供了其关键特性的很好的摘要

补充信息

虽然这不是这个问题的范围,但其他编程语言也有类似的支持:

如果你需要进行线性代数(例如)或其他特定操作,CUDA和OpenCL也提供了专门的数学库(例如ViennaCL, CUBLAS, MAGMA等)。
同时注意,使用这些库并不会阻止你进行一些低级别的操作,如果你需要进行一些非常特定的计算。
最后,我们可以提到C++标准库的未来。已经有大量工作添加了并行支持,虽然目前仍是技术规范还没有正式发布,且我所知道的GPU没有被明确提到(尽管Thrust的开发者Jared Hoberock直接参与其中),但肯定存在使这成为现实的意愿。

4
考虑将此标记为正确答案吗? - lmat - Reinstate Monica
我使用Eigen来反转大矩阵,但仅比使用单线程代码运行快2倍。 - mathengineer
在撰写本文时,ArrayFire似乎是仍在维护的少数几个库之一,并且它似乎是最多才多艺的。 - Paschover
这需要更新为NVIDIA [MatX](https://github.com/NVIDIA/MatX),以及所有新的AMD ROCM替代品,如[rocThrust](https://github.com/ROCmSoftwarePlatform/rocThrust)。随着Intel GPGPU的出现,甚至可以包括OneAPI的内容。此外,还有SYCL和Kokkos试图普遍提高可移植性。 - paleonix

37

Thrust 库提供了容器、并行原语和算法。所有这些功能都以类似 STL 的语法进行封装。因此,如果您熟悉 STL,实际上可以仅使用 Thrust 编写整个 CUDA 程序,而无需编写单个 CUDA 内核。请查看快速入门指南中的简单示例,以了解使用 Thrust 可以编写的高级程序类型。


1
现在这才是我真正想要的。非常感谢你。 - goocreations
2
@Ashwin,现在有一个名为Bulk的Thrust的继任者。Jared Hoberock做了一个关于它的演讲。你对此有什么看法吗?从演讲中看起来,它似乎非常先进。 - The Vivandiere

15

看一下Boost.Compute。它提供了一个高级的、类似STL的接口,包括容器,如vector<T>和算法,如transform()sort()

它基于OpenCL构建,因此可以在大多数现代GPU和CPU上运行,包括NVIDIA、AMD和Intel的设备。


2
如果您正在寻找更高维度的容器并能在内核代码中传递和操作这些容器,我已经花费了过去几年时间开发ecudaAPI来协助我的科研项目(因此它已经过了测试)。希望它能填补一个需要的空白。以下是如何使用它的简要示例(这里使用了C++11特性,但ecuda将与预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;

}

我尽可能地让它直观易懂(通常只需用ecuda::替换std::即可)。如果你了解STL,那么ecuda应该能够做出你所期望的基于CUDA的C++扩展功能。


ecuda在调用以下函数时避免了内存传输。性能如何?它是否隐藏了复杂的内存分配和传输? - mathengineer

2

另一个高级库是VexCL——用于OpenCL的向量表达式模板库。它提供了直观的向量操作符号,并且在MIT许可证下可用。


1
cpp-opencl项目提供了一种简便的方式,使开发者能够轻松地编程GPU。它允许您直接在C++中实现数据并行性,而不是使用OpenCL。
请参见http://dimitri-christodoulou.blogspot.com/2014/02/implement-data-parallelism-on-gpu.html
源代码请参见https://github.com/dimitrs/cpp-opencl
请看下面的示例。parallel_for_each lambda函数中的代码在GPU上执行,其余部分在CPU上执行。更具体地说,“square”函数既在CPU上执行(通过调用std::transform),也在GPU上执行(通过调用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;
}

1
新的 OpenMP 版本4现在包括加速器卸载支持。
据我所知,GPU被视为加速器。

0

C++ AMP就是你正在寻找的答案。


2
寻找跨平台的解决方案。AMP似乎只适用于Windows系统。 - goocreations
微软和AMD发布了支持Linux的C++ AMP。C++AMP是一个高级库,它隐藏了OpenCL还是另一种解决方案? - mathengineer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接