3 月 19 日下午 2 点,锁定 NVIDIA AI 网络中文专场。立即注册观看
数据科学

适用于数据科学的 GPU 加速入门

在数据科学领域,运营效率是处理日益复杂和大型数据集的关键。GPU 加速已成为现代工作流程的关键,可显著提高性能。

RAPIDS 是由 NVIDIA 开发的一套开源库和框架,旨在使用 GPU 以尽可能减少代码更改来加速数据科学流程。RAPIDS 提供用于数据操作的 cuDF 、用于机器学习的 cuML 和用于图形分析的 cuGraph 等工具,可实现与现有 Python 库的无缝集成,使数据科学家更容易实现更快、更高效的处理。

本文分享了从 CPU 数据科学库过渡到 GPU 加速工作流程的技巧,特别适合经验丰富的数据科学家。

在桌面或云基础架构上设置 RAPIDS

开始使用 RAPIDS 非常简单,但它确实有几个依赖项。推荐的方法是遵循官方的 RAPIDS 安装指南 ,该指南提供了详细的本地安装说明。您有多种安装框架的路径:通过 pip install、Docker 镜像,或通过 Conda 等环境。要在云环境中设置 RAPIDS,请参阅 RAPIDS 云部署指南 。安装前,请检查安装页面上的 CUDA 版本和受支持的 RAPIDS 版本,确保兼容性。

适用于 pandas 的 cuDF 和 GPU 加速

RAPIDS 的一个优势在于其模块化架构,使用户能够采用专为 GPU 加速工作流程设计的特定库。其中,cuDF 作为一款功能强大的工具脱颖而出,可从基于 pandas 的传统工作流程无缝过渡到 GPU 优化的数据处理流程,并且无需更改代码。

首先,请确保在导入 pandas 之前启用 cuDF 扩展,以便在 GPU 上执行数据导入和剩余操作。通过使用 %load_ext cudf.pandas 加载 RAPIDS 扩展程序,您可以轻松地将 cuDF DataFrame 集成到现有工作流程中,从而保留熟悉的 pandas 语法和结构。

与 pandas 类似, cuDF pandas 支持不同的文件格式,例如 .csv、.json、.pickle、.paraquet,因此支持 GPU 加速的数据操作。

以下代码是如何启用 cudf.pandas 扩展名并连接两个 .csv 文件的示例:

%load_ext cudf.pandas
import pandas as pd 
import cupy as cp 
 
train = pd.read_csv('./Titanic/train.csv') 
test = pd.read_csv('./Titanic/test.csv') 
concat = pd.concat([train, test], axis = 0) 

通过加载 cudf.pandas 扩展程序,无需更改或重写代码,即可在 GPU 上执行熟悉的 pandas 操作,例如过滤、分组和合并。cuDF 加速器与 pandas API 兼容,可确保从 CPU 到 GPU 的平稳过渡,同时大幅提高计算速度。

target_rows = 1_000_000
repeats = -(-target_rows // len(train))  # Ceiling division
train_df = pd.concat([train] * repeats, ignore_index=True).head(target_rows)
print(train_df.shape)  # (1000000, 2)

repeats = -(-target_rows // len(test))  # Ceiling division
test_df = pd.concat([test] * repeats, ignore_index=True).head(target_rows)
print(test_df.shape)  # (1000000, 2)

combine = [train_df, test_df]


(1000000, 12)
(1000000, 11)
filtered_df = train_df[(train_df['Age'] > 30) & (train_df['Fare'] > 50)] 
grouped_df = train_df.groupby('Embarked')[['Fare', 'Age']].mean() 
additional_info = pd.DataFrame({ 
	'PassengerId': [1, 2, 3], 
	'VIP_Status': ['No', 'Yes', 'No'] 
  }) 
merged_df = train_df.merge(additional_info, on='PassengerId', 
how='left')

解码性能:CPU 和 GPU 运行时指标的实际应用

在数据科学中,性能优化不仅涉及速度,还涉及了解计算资源的利用方式。其中包括分析运营如何利用 CPU 和 GPU 架构、识别效率低下问题,以及实施旨在提高工作流程效率的策略。

%cudf.pandas.profile 等性能分析工具通过详细检查代码执行情况发挥着关键作用。以下执行结果会对每个函数进行分解,并区分在 CPU 上处理的任务与在 GPU 上加速的任务:

%%cudf.pandas.profile
train_df[['Pclass', 'Survived']].groupby(['Pclass'], 
as_index=False).mean().sort_values(by='Survived', ascending=False)
        Pclass    Survived
0         1        0.629592
1         2        0.472810
2         3        0.242378

                         Total time elapsed: 5.131 seconds
                         5 GPU function calls in 5.020 seconds
                         0 CPU function calls in 0.000 seconds

                                       Stats

+------------------------+------------+-------------+------------+------------+-------------+------------+
| Function           | GPU ncalls  | GPU cumtime | GPU percall | CPU ncalls | CPU cumtime | CPU percall |
+------------------------+------------+-------------+------------+------------+-------------+------------+
| DataFrame.__getitem__ | 1          | 5.000       | 5.000      | 0          | 0.000       | 0.000      |
| DataFrame.groupby     | 1          | 0.000       | 0.000      | 0          | 0.000       | 0.000      |
| GroupBy.mean          | 1          | 0.007       | 0.007      | 0          | 0.000       | 0.000      |
| DataFrame.sort_values | 1          | 0.002       | 0.002      | 0          | 0.000       | 0.000      |
| DataFrame.__repr__    | 1          | 0.011       | 0.011      | 0          | 0.000       | 0.000      |
+------------------------+------------+-------------+------------+------------+-------------+------------+

这种粒度有助于查明无意中恢复到 CPU 执行的操作,这是由于不受支持的 cuDF 函数、不兼容的数据类型或次优内存处理而常见的情况。识别这些问题至关重要,因为此类回退会严重影响整体性能。如需详细了解此加载程序,请参阅 Mastering cudf.pandas Profiler for GPU Acceleration

此外,您可以使用 Python magic 命令,如 %%time%%timeit,来启用特定代码块的基准测试,以便直接比较 pandas(CPU)和 cuDF 加速器(GPU)之间的运行时。这些工具可让您深入了解通过 GPU 加速实现的效率提升。通过使用 %%time 进行基准测试,可以清楚地比较 CPU 和 GPU 环境之间的执行时间,从而凸显通过并行处理实现的效率提升。

%%time 
 
print("Before", train_df.shape, test_df.shape, combine[0].shape, combine[1].shape) 
 
train_df = train_df.drop(['Ticket', 'Cabin'], axis=1) 
test_df = test_df.drop(['Ticket', 'Cabin'], axis=1) 
combine = [train_df, test_df] 
 
print("After", train_df.shape, test_df.shape, combine[0].shape, combine[1].shape) 
CPU output:
Before (999702, 12) (999856, 11) (999702, 12) (999856, 11)
After  (999702, 10) (999856, 9)  (999702, 10) (999856, 9)

CPU times: user 56.6 ms, sys: 8.08 ms, total: 64.7 ms

Wall time: 63.3 ms
GPU output:
Before (999702, 12) (999856, 11) (999702, 12) (999856, 11)
After  (999702, 10) (999856, 9)  (999702, 10) (999856, 9)

CPU times: user 6.65 ms, sys: 0 ns, total: 6.65 ms

Wall time: 5.46 ms

%%time 示例可将执行时间提高 10 倍,将墙面时间从 CPU 上的 63.3 毫秒 (ms) 缩短到 GPU 上的 5.46 毫秒。这凸显了使用 cuDF pandas 进行 GPU 加速在大规模数据操作中的效率。您可以使用 %%timeit 获得更多见解,它执行重复执行来测量性能指标中的一致性和可靠性。

%%timeit  
 
for dataset in combine: 
	dataset['Title'] = dataset.Name.str.extract(' ([A-Za-z]+)\\.', expand=False) 
 
pd.crosstab(train_df['Title'], train_df['Sex']) 
CPU output:
1.11 s ± 7.49 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
GPU output:
89.6 ms ± 959 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

在 GPU 加速方面,%%timeit 示例将性能提升了 10 倍,将运行时间从 CPU 上的每循环 1.11 秒缩短到 GPU 上的每循环 89.6 毫秒。这凸显了 cuDF pandas 在密集型数据操作中的效率。

验证 GPU 利用率 

在处理不同的数据类型时,请务必验证您的系统是否有效利用了 GPU。您可以使用熟悉的 type 命令来区分 NumPy 和 CuPy 数组,检查数组是在 CPU 还是 GPU 上处理。

type(guess_ages)
cupy.ndarray

如果输出为 np.array,则数据将在 CPU 上处理。如果输出为 cupy.ndarray,则数据将在 GPU 上处理。此快速检查可确保您的工作流程按预期利用 GPU 资源。

其次,只需使用 print 命令,即可确认是否正在利用 GPU,并确保正在处理 cuDF DataFrame。输出指定使用的是 fast 路径 (cuDF) 还是 slow 路径 (pandas)。这种简单的检查提供了一种验证 GPU 是否处于活动状态以加速数据操作的简单方法。

print(pd)
<module 'pandas' (ModuleAccelerator(fast=cudf, slow=pandas))>

最后,可以使用 df.info 等命令检查 cuDF DataFrame 的结构,并确认计算已通过 GPU 加速。这有助于验证操作是在 GPU 上运行,还是回退至 CPU。

train_df.info()
<class 'cudf.core.dataframe.DataFrame'>

RangeIndex: 1000000 entries, 0 to 999999
Data columns (total 9 columns):
 #   Column   Non-Null Count   Dtype   
---  ------   --------------   -----   
 0   Survived 1000000 non-null  int64   
 1   Pclass   1000000 non-null  int64   
 2   Sex      1000000 non-null  int64   
 3   Age      1000000 non-null  float64 
 4   SibSp    1000000 non-null  int64   
 5   Parch    1000000 non-null  int64   
 6   Fare     1000000 non-null  float64 
 7   Embarked 997755 non-null   object  
 8   Title    1000000 non-null  int64   
dtypes: float64(2), int64(6), object(1)
memory usage: 65.9+ MB

结束语 

通过 cuDF pandas 等工具,RAPIDS 可实现从基于 CPU 的传统数据工作流到 GPU 加速处理的无缝过渡,从而显著提高性能。通过利用 %%time%%timeit 等功能以及 %%cudf.pandas.profile 等分析工具,您可以测量和优化运行时效率。通过 typeprint(pd)df.info 等简单命令检查 GPU 利用率,可确保工作流程有效利用 GPU 资源。

要尝试本文中详述的数据操作,请查看 随附的 Jupyter Notebook

如需了解有关 GPU 加速的数据科学的更多信息,请参阅“ 10 分钟了解数据科学:在 RAPIDS cuDF 和 CuPy 库之间过渡 ”以及“ RAPIDS cuDF 即时将 pandas 在 Google Colab 上的运行速度提高 50 倍 ”。

加入我们的 GTC 2025 大会,并报名参加 Data Science Track ,获得更深入的见解。推荐的会议包括:

要积累有关 RAPIDS 的专业知识,请查看 GTC 上的以下实战研讨会:

 

标签