在 Python 数据科学领域,pandas 长期以来一直是直观数据操作和分析的首选库。但是,随着数据量的增长,CPU 受限的 pandas 工作流可能会成为瓶颈。
这就是 cuDF 及其 pandas 加速器模式 cudf.pandas
的用武之地。此模式可尽可能使用 GPU 加速操作,并无缝回退至 CPU 以执行不受支持的操作。此方法的基本支柱是 cudf.pandas
分析器,该分析器可用于了解与 CPU 相比,GPU 上执行的代码量。
在本文中,我们将讨论 cudf.pandas
分析器是什么,如何使用它,以及为什么它对于理解和优化加速 pandas 工作负载至关重要。
cudf.pandas 分析器概述
Jupyter 和 IPython 中提供的 cudf.pandas.profile
magic 命令是一种分析工具,可实时分析 pandas 式代码。启用 cudf.pandas
扩展后,分析器将报告每个操作的执行设备 (GPU 或 CPU),并统计特定函数或方法的触发次数。
通过捕获这些数据,您可以快速确定以下内容:
- 哪些操作在 GPU 上完全加速。
- 哪些操作返回到 CPU 上的 pandas。
- 潜在瓶颈或不必要的数据传输可能潜伏在何处。
启用分析器
首先,在 Notebook 中加载 cudf.pandas
扩展程序,就像加载其他 IPython 魔术一样:
%load_ext cudf.pandas
import pandas as pd
从这里开始,您可以开始编写 pandas 代码,例如读取 CSV、合并 DataFrames 或运行 groupbys,并让 cudf.pandas
自动决定如何在 GPU 上加速这些代码,或者在需要时使用 CPU。
分析的实际应用
使用 cudf.pandas
分析器的方法有以下几种:
- 使用单元级分析器
- 使用线条分析器
- 使用命令行中的 profiler
使用单元级分析器
在 Jupyter 或 IPython 中,您可以逐单元激活分析:
%%cudf.pandas.profile
df = pd.DataFrame({'a': [0, 1, 2], 'b': [3, 4, 3]})
df.min(axis=1)
out = df.groupby('a').filter(lambda group: len(group) > 1)
单元完成后,您将看到一个输出,其中分解了与 CPU 相比在 GPU 上运行的操作、每个操作的调用次数,以及用于发现性能瓶颈的便捷摘要。
Total time elapsed: 0.256 seconds
3 GPU function calls in 0.170 seconds
1 CPU function calls in 0.009 seconds
Stats
┏━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━━━━━┓
┃ Function ┃ GPU ncalls ┃ GPU cumtime ┃ GPU percall ┃ CPU ncalls ┃ CPU cumtime ┃ CPU percall ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━━━━━━┩
│ DataFrame │ 1 │ 0.031 │ 0.031 │ 0 │ 0.000 │ 0.000 │
│ DataFrame.min │ 1 │ 0.137 │ 0.137 │ 0 │ 0.000 │ 0.000 │
│ DataFrame.groupby │ 1 │ 0.001 │ 0.001 │ 0 │ 0.000 │ 0.000 │
│ DataFrameGroupBy.filter │ 0 │ 0.000 │ 0.000 │ 1 │ 0.009 │ 0.009 │
└─────────────────────────┴────────────┴─────────────┴─────────────┴────────────┴─────────────┴─────────────┘
Not all pandas operations ran on the GPU. The following functions required CPU fallback:
- DataFrameGroupBy.filter
To request GPU support for any of these functions, please file a Github issue here: https://github.com/rapidsai/cudf/issues/new/choose.
DataFrameGroupBy.filter
未在 GPU 上加速,因此您可以看到表中的一次 CPU 调用需要 0.025 秒。
使用线条分析器
要更深入地了解单元中每一行的执行情况,请运行以下代码示例:
%%cudf.pandas.line_profile
df = pd.DataFrame({'a': [0, 1, 2], 'b': [3, 4, 3]})
df.min(axis=1)
out = df.groupby('a').filter(lambda group: len(group) > 1)
在这里,profiler 逐行显示执行细节,以便更轻松地发现导致 CPU 回退或性能降低的特定代码行。
Total time elapsed: 0.244 seconds
Stats
┏━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━━━━━┓
┃ Line no. ┃ Line ┃ GPU TIME(s) ┃ CPU TIME(s) ┃
┡━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━━━━━━┩
│ 2 │ df = pd.DataFrame({'a': [0, 1, 2], 'b': [3, 4, 3]}) │ 0.004833249 │ │
│ │ │ │ │
│ 3 │ df.min(axis=1) │ 0.006497159 │ │
│ │ │ │ │
│ 4 │ out = df.groupby('a').filter(lambda group: len(group) > 1) │ 0.000599624 │ 0.000347643 │
│ │ │ │ │
└──────────┴────────────────────────────────────────────────────────────────┴─────────────┴─────────────┘
使用命令行中的 profiler
您还可以通过传递 --profile
参数从命令行运行 cudf.pandas
分析器。
以下是 demo.py
的内容:
import pandas as pd
s = pd.Series([1, 2, 3])
s = (s * 10) + 2
print(s)
运行以下命令:
python -m cudf.pandas –-profile demo.py
您将看到 profile stats 输出:
Total time elapsed: 0.852 seconds
4 GPU function calls in 0.029 seconds
0 CPU function calls in 0.000 seconds
Stats
┏━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━━━━━┓
┃ Function ┃ GPU ncalls ┃ GPU cumtime ┃ GPU percall ┃ CPU ncalls ┃ CPU cumtime ┃ CPU percall ┃
┡━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━━━━━━┩
│ Series │ 1 │ 0.002 │ 0.002 │ 0 │ 0.000 │ 0.000 │
│ OpsMixin.__mul__ │ 1 │ 0.011 │ 0.011 │ 0 │ 0.000 │ 0.000 │
│ OpsMixin.__add__ │ 1 │ 0.008 │ 0.008 │ 0 │ 0.000 │ 0.000 │
│ object.__str__ │ 1 │ 0.008 │ 0.008 │ 0 │ 0.000 │ 0.000 │
└──────────────────┴────────────┴─────────────┴─────────────┴────────────┴─────────────┴─────────────┘
分析为何重要
在 GPU 加速方面,并非所有功能都能自动获得支持。某些操作 (例如某些尚未在 GPU 上实现的 Python 级函数、自定义 lambdas 或 DataFrame 方法) 可能会触发 CPU 回退。
分析器可帮助您精确查看这些回退的出现位置。借助这些知识,您可以调整工作流程、重写某些函数,或调查需要改进的潜在领域:
- 重写受 CPU 限制的运算: 某些用户定义的函数或运算可能会进行修改,使其对 GPU 更加友好。
- 留意频繁的数据传输 :CPU 和 GPU 之间的过多数据传输可能会抵消加速所带来的收益。识别这些对更大限度地提高速度至关重要,因为重复的 GPU 操作序列和 CPU 操作通常会导致昂贵的数据传输。
- 及时了解最新动态:cuDF 不断添加功能 (并弥合与 pandas 之间的差距)。
了解哪些方法目前受 CPU 限制,有助于您跟踪未来的改进。
结束语
pandas 用户体验是现代数据科学的核心,但扩展到大型数据集通常会对 CPU 性能造成压力。
借助 cudf.pandas
,您可以尽可能使用 GPU 的速度获得相同的直观 API,并为不受支持的操作提供自动 CPU 回退。cudf.pandas
分析器是了解此混合 CPU/GPU 生态系统的关键,可突出显示加速机会,并帮助您优化代码以实现最佳性能。
在您的数据项目中尝试一下。通过分析代码并识别 CPU 回退,您可以快速突破 pandas 的极限,而无需离开其熟悉的 API 的舒适性。
如果您遇到希望通过 GPU 加速的 API,请在 /rapidsai/cudf GitHub 存储库中 打开 GitHub 问题 。