常见问题与已知问题#
什么时候应该使用 cudf.pandas
,什么时候应该直接使用 cuDF 库?#
cudf.pandas
是让 pandas 代码在 GPU 上运行的最快、最简单的方式。但是,在某些情况下应该考虑直接使用 cuDF 库。
cuDF 实现了 pandas API 的一个子集,而
cudf.pandas
会根据需要自动回退到 pandas。如果您的代码可以只使用 cuDF 支持的操作,那么直接使用 cuDF 将会受益于性能提升。cuDF 提供了一些 pandas 没有的函数和方法。例如,cuDF 有一个用于处理列表状数据的
.list
访问器。如果您需要访问 cuDF 中的附加功能,则需要直接使用 cuDF 包。
它与 pandas 的匹配程度有多高?#
您可以使用 100% 的 pandas API,并且大多数情况下工作方式与 pandas 完全相同。
cudf.pandas
针对整个 pandas 单元测试套件进行了测试。目前,我们通过了 187,000 多个单元测试中的 93%,目标是达到 100%。测试失败通常是因为边缘情况以及 cuDF 和 pandas 之间的一些行为差异。您可以在已知限制中了解更多关于这些边缘情况的信息
我们还运行夜间测试,跟踪 cudf.pandas
与其他第三方库之间的交互。参见第三方库兼容性。
如何判断 cudf.pandas
是否处于活动状态?#
无论 cudf.pandas
是否在使用,您都不必以不同的方式编写任何代码。您应该使用 pandas
,一切都应该能正常工作。
但在测试和开发中的少数情况下,您可能希望明确验证 cudf.pandas
是否处于活动状态。为此,请在您的代码中打印 pandas 模块并查看输出;它应该看起来像这样
%load_ext cudf.pandas
import pandas as pd
print(pd)
<module 'pandas' (ModuleAccelerator(fast=cudf, slow=pandas))>
哪些函数将在 GPU 上运行?#
通常,cudf.pandas
将加速 cuDF API 中的所有功能在 GPU 上运行。也有一些例外。例如,某些函数由 cuDF 进行 GPU 加速,但不支持所有的关键词参数组合。在不支持关键词参数的情况下,cuDF 无法提供 GPU 加速,cudf.pandas
将回退到 CPU。
评估哪些函数在 GPU 上运行的最准确方法是在使用 cudf.pandas
性能分析功能时运行代码。分析器将指示哪些函数在 GPU / CPU 上运行。为了提高性能,请尝试只使用可以在 GPU 上完全运行的功能。这有助于减少回退到 CPU 所需的内存传输次数。
如何提高使用 cudf.pandas
的工作流程性能?#
大多数工作流程在使用 cudf.pandas
后会看到显著的性能提升。然而,有时事情可能会比预期慢。首先,重要的是要注意 GPU 擅长处理大量数据的并行计算。对于小数据量,GPU 可能比 CPU 慢,因为数据传输有开销。cuDF 在处理大量行数据时能达到最高性能。根据算法、数据类型和其他因素,粗略来说,cudf.pandas
在数据量超过 10,000 - 100,000 行的工作流程中表现出色。大小为几个千兆字节和/或有数百万行的数据集非常适合 cudf.pandas
。
以下是一些提高工作流程性能的更多技巧
Does cudf.pandas
是否与第三方库兼容?#
cudf.pandas
与众多流行的第三方库进行了测试。cudf.pandas
不仅能正常工作,还能加速这些库中的 pandas 操作。作为我们 CI/CD 系统的一部分,我们目前正在测试与以下 Python 库的常见交互
库 |
状态 |
---|---|
cuGraph |
✅ |
cuML |
✅ |
Hvplot |
✅ |
Holoview |
✅ |
Ibis |
✅ |
Joblib |
❌ |
NumPy |
✅ |
Matplotlib |
✅ |
Plotly |
✅ |
PyTorch |
✅ |
Seaborn |
✅ |
Scikit-Learn |
✅ |
SciPy |
✅ |
Tensorflow |
✅ |
XGBoost |
✅ |
请查阅已知限制部分,了解预期无法工作的内容及其原因。
可以将 cudf.pandas
与 Dask 或 PySpark 一起使用吗?#
cudf.pandas
目前并非为分布式或外存计算 (OOC) 工作流程设计。如果您正在寻找用于数据处理的加速 OOC 和分布式解决方案,我们推荐 Dask 和 Apache Spark。
Dask 和 Apache Spark 都支持通过基于配置的接口进行加速计算。Dask 允许您配置 dataframe 后端以使用 cuDF(在这篇博客中了解更多),而 RAPIDS Accelerator for Apache Spark 为 Spark 提供了一个类似的基于配置的插件。
如何判断对象是否是 cudf.pandas
代理对象?#
要确定对象是否是 cudf.pandas
代理对象,可以使用 is_proxy_instance
API。此函数检查给定的对象是否是包装了 cudf
或 pandas
对象的代理对象。以下是使用此 API 的示例
from cudf.pandas import is_proxy_instance
obj = ... # Your object here
if is_proxy_instance(obj, pd.Series):
print("The object is a cudf.pandas proxy Series object.")
else:
print("The object is not a cudf.pandas proxy Series object.")
要分开检测 Series
、DataFrame
、Index
和 ndarray
对象,您可以将类型名称作为第二个参数传入
is_proxy_instance(obj, pd.Series)
: 检测对象是否是cudf.pandas
代理Series
。is_proxy_instance(obj, pd.DataFrame)
: 检测对象是否是cudf.pandas
代理DataFrame
。is_proxy_instance(obj, pd.Index)
: 检测对象是否是cudf.pandas
代理Index
。is_proxy_instance(obj, np.ndarray)
: 检测对象是否是cudf.pandas
代理ndarray
。
如何访问底层的 GPU 或 CPU 对象?#
在使用 cudf.pandas
代理对象时,有时需要获取驻留在 GPU 或 CPU 上的真正的 cudf
或 pandas
对象。例如,这可以用于确保支持 cudf
和 pandas
的 GPU 感知库在处理 cudf.pandas
对象时可以使用将数据保留在 GPU 上的 cudf
优化代码路径。否则,库可能会使用优化程度较低的 CPU 代码,因为它认为 cudf.pandas
对象是普通的 pandas
dataframe。
可以使用以下方法检索实际的 cudf
或 pandas
对象
as_gpu_object()
: 此方法从代理对象中返回cudf
对象。as_cpu_object()
: 此方法从代理对象中返回pandas
对象。
如果在代理数组上调用 as_gpu_object()
,它将返回一个 cupy
数组;如果调用 as_cpu_object
,它将返回一个 numpy
数组。
以下是使用这些方法的示例
# Assuming `proxy_obj` is a cudf.pandas proxy object
cudf_obj = proxy_obj.as_gpu_object()
pandas_obj = proxy_obj.as_cpu_object()
# Now you can use `cudf_obj` and `pandas_obj` with libraries that are cudf or pandas aware
请注意,如果 cudf.pandas
对象被转换为其底层 cudf
或 pandas
类型,cudf.pandas
代理将不再控制它们。这意味着 GPU 和 CPU 类型之间的自动转换以及从 GPU 到 CPU 功能的自动回退将不会发生。
是否存在已知限制?#
有几个您应该注意的已知限制
由于回退涉及从 GPU 到 CPU 再返回的数据复制,Pandas 对象的值可变性并非总是保证的。您应遵循 pandas 的建议,优先使用不可变操作。
出于性能原因,连接 (joins) 和基于连接的操作当前未实现,以保持与标准 pandas 相同的行顺序。
cudf.pandas
不兼容直接使用import cudf
,而是旨在用于基于 pandas 的工作流程。使用“常规” pandas 序列化的对象无法反序列化 (unpickling):您必须在启用
cudf.pandas
的情况下对对象进行序列化,才能在启用cudf.pandas
时对其进行反序列化。在 CPU 回退期间,可以访问全局变量,但不能修改它们。
%load_ext cudf.pandas import pandas as pd lst = [10] def udf(x): lst.append(x) return x + lst[0] s = pd.Series(range(2)).apply(udf) print(s) # we can access the value in lst 0 10 1 11 dtype: int64 print(lst) # lst is unchanged, as this specific UDF could not run on the GPU [10]
cudf.pandas
(以及一般的 cuDF)仅与 pandas 2 兼容。cudf 24.02 版本是最后一个支持 pandas 1.5.x 的版本。为了让
cudf.pandas
生成一个鸭子类型 (ducktypes) 为 NumPy 数组的代理数组,我们创建了一个实际上继承numpy.ndarray
的代理类型。我们可以使用 isinstance 检查来验证这一点。%load_ext cudf.pandas import pandas as pd import numpy as np arr = pd.Series([1, 1, 2]).unique() # returns a proxy array isinstance(arr, np.ndarray) # returns True, where arr is a proxy array
由于代理类型鸭子类型 (ducktypes) 为 NumPy 数组,NumPy 函数可能会尝试通过 NumPy C API 访问内部成员,例如数据缓冲区。然而,我们的代理机制旨在在 Python 层面代理函数调用,这与这些类型的访问不兼容。为了处理这些情况,我们执行了一个急切的设备到主机 (DtoH) 复制,这会正确设置数据缓冲区,但会增加创建代理数组时的额外耗时。在前面的示例中,创建
arr
就执行了这种隐式的 DtoH 传输。通过这种方法,我们还可以与
torch
等第三方库兼容。import torch x = torch.from_numpy(arr)
可以强制在 CPU 上运行吗?#
要在 CPU 上运行您的代码,只需在不激活 cudf.pandas
的情况下运行,将使用“常规 pandas”。
如有需要,在使用 cudf.pandas
进行测试或基准测试时,可以禁用 GPU 加速。为此,请设置 CUDF_PANDAS_FALLBACK_MODE
环境变量,例如
CUDF_PANDAS_FALLBACK_MODE=1 python -m cudf.pandas some_script.py