分享

GPU 编程:CUDA 和 Python 中的实际示例

 技术的游戏 2023-05-23 发布于广东


什么是 GPU 编程?

GPU 计算是使用图形处理单元 (graphics processing unit) 来执行曾经由中央处理单元 (central processing unit) 处理的高度并行的独立计算。

GPU 编程是一种在 GPU 加速器上运行高度并行的通用计算的方法。

虽然过去的 GPU 专为计算机图形设计,但如今它们也被广泛用于通用计算。除了图形渲染,GPU 驱动的并行计算现在还用于科学建模、机器学习和其他需要并行化的工作。

CPU 与 GPU 计算差异

中央处理器 (CPU) 是延迟优化的通用处理器,旨在按顺序处理各种不同的任务,而图形处理单元 (GPU) 是吞吐量优化的专用处理器,专为高端并行设计计算。

您是否需要 GPU 加速器的问题归结为您要解决的问题的具体情况。CPU 和 GPU都有不同的优势领域,了解它们的局限性会让你在决定是否为你的项目使用 GPU 编程时做得更好。

GPU 编程 API

GPU 根据图元理解计算问题。如今,有多种可用的编程框架可以在幕后为您操作这些原语,因此您可以专注于更高级别的计算概念。

CUDA

计算统一设备架构 (CUDA) 是 Nvidia 于 2006 年创建的并行计算平台和应用程序编程接口 (API),可直接访问 GPU 的虚拟指令集以执行计算内核。

内核是在 GPU 上运行的函数。当我们启动内核时,它做为一组线程执行。每个线程都映射到 GPU 上的单个 CUDA 内核,并对数据子集执行相同的操作。根据Flynn 的分类法,它是一种单指令多数据 (SIMD) 计算。

线程被分组为块,当内核启动时,它们被映射到一组相应的 CUDA 内核。块进一步分组为网格,每次内核启动都会创建一个网格。

CUDA 编程模型允许软件工程师使用支持 CUDA 的 GPU 在 C/C++ 和 Fortran 中进行通用处理,第三方包装器也可用于 Python、Java、R 和其他几种编程语言。CUDA 兼容从 G8x 系列开始的所有 Nvidia GPU,以及大多数标准操作系统。

OpenCL

虽然 CUDA 是专有框架,但 OpenCL 是由 Khronos Group 创建的跨异构平台并行编程的开放标准。OpenCL 与中央处理器 (CPU)、图形处理单元 (GPU)、数字信号处理器、现场可编程门阵列 (FPGA) 和其他处理器或硬件加速器协同工作。

OpenCL 用途极为广泛,已被科技行业巨头成功采用,包括 AMD、Apple、IBM、Intel、Nvidia、Qualcomm、Samsung 等。它基于 C/C++ 语言,第三方包装器也可用于 Python、Java、R、GO、JavaScript 等。

OpenACC

OpenACC 是一种用户驱动的基于指令的并行编程标准,专为有兴趣将其代码移植到各种异构高性能计算 (HPC) 硬件平台的科学家和工程师而设计。该标准是由用户为用户设计的。

OpenACC 旨在简化异构 CPU/GPU 硬件平台和架构的并行编程,其编程工作量比低级模型所需的工作量少得多。它支持 C/C++ 和 Fortran 编程语言。

使用 CUDA 和 Python 进行 GPU 编程

开始构建 GPU 加速程序有多种标准和多种编程语言,但我们选择了 CUDA 和 Python 来说明我们的示例。CUDA 是最容易上手的框架,Python 在科学、工程、数据分析和深度学习领域非常流行——所有这些都严重依赖并行计算。

即使在 Python 中,您也可以在不同的抽象层上进行 GPU 编程。如果您不需要较低抽象层可以提供的额外自定义和控制功能,那么从满足您的应用程序的最高抽象层开始是合理的。

让我们回顾一下在 Python 中使用 CUDA 的方法,从最高抽象级别开始一直到最低级别。

CUDA 用于专业库

如果您只想使用神经网络或任何其他深度学习算法,那么 Tensorflow 或 PyTorch 等专业深度学习库可能是您的正确选择。这些库可以在后台为您自动在 CPU 和 GPU 处理之间切换。

CUDA 做为直接替代品

如果您是使用 NumPy 和 SciPy 的科学家,优化 GPU 计算代码的最简单方法是使用 CuPy。它模仿大多数 NumPy 函数,并允许您简单地插入 NumPy 代码并将其替换为在 GPU 而不是 CPU 上处理的 CuPy 函数。
CUDA 用于自定义算法。

当您需要使用自定义算法时,您不可避免地需要深入抽象层次结构并使用 NUMBA。它绑定到 CUDA 并允许您在 Python 中编写自己的 CUDA 内核。通过这种方式,您可以仅使用 Python 非常接近 CUDA C/C++,而无需自己分配内存。

CUDA 做为 C/C++ 扩展

如果您想要对硬件进行最高级别的控制,例如手动内存分配、动态并行性或纹理内存管理,那么使用 C/C++ 是没有办法的。对于 Python 应用程序,最方便的方法是使用 PyCUDA 扩展,它允许您在 Python 字符串中编写 CUDA C/C++ 代码。

如何在 Ubuntu 20.04 上开始使用 CUDA for Python?

在 Ubuntu 20.04 上安装 CUDA

首先,您需要在具有支持 CUDA 的 GPU 的机器上安装 CUDA。要使用本地安装程序在 Ubuntu 20.04 上安装 CUDA 驱动程序,请按照以下说明操作:

wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/cuda-ubuntu2004.pin
sudo mv cuda-ubuntu2004.pin /etc/apt/preferences.d/cuda-repository-pin-600
wget https://developer.download.nvidia.com/compute/cuda/11.4.2/local_installers/cuda-repo-ubuntu2004-11-4-local_11.4.2-470.57.02-1_amd64.deb
sudo dpkg -i cuda-repo-ubuntu2004-11-4-local_11.2-470.57.02-1_amd64.deb
sudo apt-key add /var/cuda-repo-ubuntu2004-11-4-local/7fa2af80.pub
sudo apt-get update
sudo apt-get -y install cuda

安装 CuPy 库

接下来,我们需要安装一个 Python 库来使用 CUDA。如上所述,有许多方法可以在不同的抽象级别在 Python 中使用 CUDA。由于 NumPy 是 Python 数据科学生态系统的骨干库,我们将选择对其进行加速以进行本次演示。

使用 NumPy 的最简单方法是使用名为 CuPy 的插入式替换库,它在 GPU 上复制 NumPy 函数。您可以通过 pip 安装稳定版的 CuPy 源码包:

pip install cupy

编写脚本来比较 CPU 和 GPU

最后,您要确保 CuPy 在您的系统上运行良好,以及它能在多大程度上提高您的性能。为此,让我们编写一个简单的脚本来实现这一目的。

让我们导入 NumPy 和 CuPy 库,以及我们将用于基准处理单元的时间库。

import numpy as np
import cupy as cp
from time import time

接下来,让我们定义一个将用于基准测试的函数。

def benchmark_processor(arr, func, argument):  
start_time = time()
func(arr, argument) # your argument will be broadcasted into a matrix automatically
finish_time = time()
elapsed_time = finish_time – start_time
return elapsed_time

然后需要实例化两个矩阵:一个用于 CPU,一个用于 GPU。我们将为我们的矩阵选择 9999 x 9999 的形状。

# load a matrix to global memory
array_cpu = np.random.randint(0, 255, size=(9999, 9999))

# load the same matrix to GPU memory
array_gpu = cp.asarray(array_cpu)

最后,我们要运行一个简单的加法函数来确定 CPU 与 GPU 处理器的性能差异。

# benchmark matrix addition on CPU by using a NumPy addition function
cpu_time = benchmark_processor(array_cpu, np.add, 999)

# you need to run a pilot iteration on a GPU first to compile and cache the function kernel on a GPU
benchmark_processor(array_gpu, cp.add, 1)

# benchmark matrix addition on GPU by using CuPy addition function
gpu_time = benchmark_processor(array_gpu, cp.add, 999)

# determine how much is GPU faster
faster_processor = (gpu_time - cpu_time) / gpu_time * 100

并将结果打印到控制台。

print(f"CPU time: {cpu_time} seconds\nGPU time: {gpu_time} seconds.\nGPU was {faster_processor} percent faster")

在配备来自Cherry Servers GPU Cloud的 Nvidia Geforce GT1030 GPU 加速器的 Intel Xeon 1240v3 机器上运行此脚本后,我们确认整数加法在 GPU 上的运行速度快了许多倍。例如,当使用 10000x10000 矩阵时,GPU 运行整数加法的速度要快 1294 倍。

事实上,矩阵越大,您期望的性能提升就越高。

cuda-gpu-基准测试

图 1 – GPU 性能提升。

我们通过对 100x100、500x500、1000x1000、7500x7500 和 10000x10000 二维矩阵使用整数加法,比较了 CPU 与 GPU 的性能(以秒为单位)。当使用足够大的矩阵时,GPU 开始明显超过 CPU。

总结

  1. NVIDIA官方网站。https://developer./language-solutions

  2. Aliyun Servers GPU 服务器。https://www.aliyun.com/minisite/goods?userCode=69hiviin

  3. Cherry Servers GPU 服务器。https://www./?affiliate=1TO67IVM

如果您正在处理可以并行处理的大量数据,那么深入研究 GPU 编程可能是值得的。如您所见,使用 GPU 计算处理大型矩阵时性能显着提高。到一天结束时,如果您的应用程序可以利用并行计算,它可能会为您节省宝贵的时间和资源。

半熟不熟,慢慢就熟了。

    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多