Skip to content

GPU 支持 [公开测试版]

Polars 为使用 Lazy API 的 Python 用户提供了一个基于 NVIDIA GPU 的内存中、GPU 加速的执行引擎,使用的是 RAPIDS cuDF。此功能目前处于公开测试阶段,并且正在快速开发中。

系统要求

  • NVIDIA Volta™ 或更高版本的 GPU,具有 计算能力 7.0+
  • CUDA 11 或 CUDA 12
  • Linux 或 Windows Subsystem for Linux 2 (WSL2)

请参阅RAPIDS 安装指南以获取完整详情。

安装

您可以通过功能标志为Polars安装GPU后端,作为正常安装的一部分。

pip install polars[gpu]

注意

如果您有CUDA 11,安装行还需要NVIDIA包索引来获取CUDA 11包。

pip install --extra-index-url=https://pypi.nvidia.com polars cudf-polars-cu11

用法

使用惰性API 如常构建查询后,通过运行.collect(engine="gpu")而不是.collect()来请求启用GPU的执行。

import polars as pl

df = pl.LazyFrame({"a": [1.242, 1.535]})

q = df.select(pl.col("a").round(1))

result = q.collect(engine="gpu")
print(result)
shape: (2, 1)
┌─────┐
│ a   │
│ --- │
│ f64 │
╞═════╡
│ 1.2 │
│ 1.5 │
└─────┘

为了更详细地控制执行过程,例如在多GPU节点上指定使用哪个GPU,我们可以提供一个GPUEngine对象。默认情况下,GPU引擎将使用适用于大多数用例的配置。

q = df.select((pl.col("a") ** 4))

result = q.collect(engine=pl.GPUEngine(device=1))
print(result)
shape: (2, 1)
┌──────────┐
│ a        │
│ ---      │
│ f64      │
╞══════════╡
│ 2.379504 │
│ 5.551796 │
└──────────┘

它是如何工作的

当您使用GPU加速引擎时,Polars会创建并优化查询计划,并将其分派到基于RAPIDS cuDF的物理执行引擎,以在NVIDIA GPU上计算结果。最终结果将作为普通的CPU支持的Polars数据框返回。

GPU支持哪些内容?

GPU支持目前处于公开测试阶段,引擎正在快速发展。引擎目前支持许多核心表达式和数据类型,但并非全部。

由于表达式是可组合的,因此列出GPU上支持的完整表达式矩阵是不可行的。相反,我们提供了当前支持和未支持的高级表达式类别和接口列表。

支持

  • LazyFrame API
  • SQL API
  • 从CSV、Parquet、ndjson和内存中的CPU数据帧进行I/O操作。
  • 对数值、逻辑、字符串和日期时间类型的操作
  • 字符串处理
  • 聚合和分组聚合
  • 连接
  • 过滤器
  • 缺失数据
  • 连接

不支持

  • Eager DataFrame API
  • 流式API
  • 对分类、结构和列表数据类型的操作
  • 滚动聚合
  • 时间序列重采样
  • 时区
  • 折叠
  • 用户自定义函数
  • JSON、Excel 和数据库文件格式

我的查询是否使用了GPU?

GPU引擎的公开测试版发布意味着我们期望一切都能正常运行,但仍有一些我们正在处理的粗糙边缘。特别是Polars表达式API的完整广度尚未得到支持。通过回退到CPU,您的查询应该能够完成,但您可能不会观察到执行时间上的任何变化。有两种方法可以获取更多关于查询是否在GPU上运行的信息。

在详细模式下运行时,任何无法在GPU上执行的查询都会发出一个PerformanceWarning

df = pl.LazyFrame(
    {
        "key": [1, 1, 1, 2, 3, 3, 2, 2],
        "value": [1, 2, 3, 4, 5, 6, 7, 8],
    }
)

q = df.select(pl.col("value").sum().over("key"))


with pl.Config() as cfg:
    cfg.set_verbose(True)
    result = q.collect(engine="gpu")

print(result)
PerformanceWarning: Query execution with GPU not supported, reason: 
<class 'NotImplementedError'>: Grouped rolling window not implemented
# some details elided

shape: (8, 1)
┌───────┐
│ value │
│ ---   │
│ i64   │
╞═══════╡
│ 6     │
│ 6     │
│ 6     │
│ 19    │
│ 11    │
│ 11    │
│ 19    │
│ 19    │
└───────┘

要禁用回退,并在查询不受支持时让GPU引擎引发异常,我们可以传递一个适当配置的GPUEngine对象:

q.collect(engine=pl.GPUEngine(raise_on_fail=True))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/coder/third-party/polars/py-polars/polars/lazyframe/frame.py", line 2035, in collect
    return wrap_df(ldf.collect(callback))
polars.exceptions.ComputeError: 'cuda' conversion failed: NotImplementedError: Grouped rolling window not implemented

目前,仅报告了在GPU上执行失败的近因,我们计划扩展此功能以报告查询中所有不支持的操作。

测试

Polars 和 NVIDIA RAPIDS 团队运行全面的单元和集成测试,以确保 GPU 加速的 Polars 后端能够顺利运行。

每次提交到GPU引擎时,都会运行完整的Polars测试套件,以确保结果的一致性。

GPU引擎目前在启用CPU回退的情况下通过了99.2%的Polars单元测试。如果没有CPU回退,GPU引擎通过了88.8%的Polars单元测试。启用回退后,大约有100个失败的测试:其中大约40个由于调试输出不匹配而失败;有些情况下,GPU引擎产生了正确的结果但使用了不同的数据类型;其余的情况是我们未能正确确定查询不受支持,因此在运行时失败,而不是回退。

何时应该使用GPU?

根据我们的基准测试,当您的工作流主要由分组聚合和连接操作组成时,您最有可能在使用GPU引擎时观察到加速。相比之下,I/O密集型查询通常在GPU和CPU上表现出相似的性能。GPU通常比CPU系统拥有更少的内存,因此非常大的数据集可能会因为内存不足错误而失败。根据我们的测试,50-100 GiB的原始数据集(取决于工作流)适合拥有80GiB内存的GPU。

CPU-GPU 互操作性

CPU和GPU引擎都使用Apache Arrow列式内存规范,这使得在CPU和GPU之间快速移动数据成为可能。此外,一个引擎写入的文件可以被另一个引擎读取。

当使用GPU模式时,如果某些功能不被支持,您的工作流不会失败。当您运行 collect(engine="gpu")时,会检查优化后的查询计划,看它是否可以在 GPU上执行。如果不能,它将透明地回退到标准的Polars引擎并在 CPU上运行。

GPU 执行仅在 Lazy API 中可用,因此当查询执行完成时,物化的 DataFrames 将驻留在 CPU 内存中。

提供反馈

请在Polars的问题跟踪器上报告问题和缺失的功能。