常见问题与已知问题#

什么时候应该使用 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

以下是一些提高工作流程性能的更多技巧

  • 重塑数据使其成为长格式而不是宽格式(更多行,更少列)。这提高了 cuDF 在整个 GPU 上并行执行的能力!

  • 避免逐元素迭代和修改。如果可能,使用 pandas 函数一次性操作整个列,而不是编写计算和赋值的原始 for 循环。

  • 如果您的数据实际上是一个 n 维数组,有很多列,并且您打算进行大量的数学运算(例如矩阵相加),那么 CuPyNumPy 可能比 pandas 或 cudf.pandas 是更好的选择。数组库与 DataFrame 库的用例不同,并且会通过使用连续内存进行多维数组存储来获得最佳性能。使用 .values 方法将 DataFrame 或 Series 转换为数组。

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。此函数检查给定的对象是否是包装了 cudfpandas 对象的代理对象。以下是使用此 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.")

要分开检测 SeriesDataFrameIndexndarray 对象,您可以将类型名称作为第二个参数传入

  • 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 上的真正的 cudfpandas 对象。例如,这可以用于确保支持 cudfpandas 的 GPU 感知库在处理 cudf.pandas 对象时可以使用将数据保留在 GPU 上的 cudf 优化代码路径。否则,库可能会使用优化程度较低的 CPU 代码,因为它认为 cudf.pandas 对象是普通的 pandas dataframe。

可以使用以下方法检索实际的 cudfpandas 对象

  • 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 对象被转换为其底层 cudfpandas 类型,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