常见问题#

Warp 与其他用于 GPU 编程的 Python 项目(例如:Numba、Taichi、cuPy、PyTorch 等)有什么关系?#

Warp 的灵感来自许多这些项目,并且与 Numba 和 Taichi 密切相关,它们都将内核编程暴露给 Python。这些框架映射到传统的 GPU 编程模型,因此许多高级概念都是相似的,但是存在一些功能和实现差异。

与 Numba 相比,Warp 支持的 Python 子集较小,但提供内核程序的自动微分,这对于机器学习很有用。与 Numba 和 Taichi 不同,Warp 使用 C++/CUDA 作为中间表示,这使得实现和公开底层例程以及利用内核中现有的 C++ 库变得方便。此外,Warp 内置了数据结构,以支持几何处理(网格、稀疏体积、点云、USD 数据)作为一流的公民,这些数据结构在其他运行时中未公开。

Warp 不提供像 PyTorch 和 JAX 那样的完整的基于张量的编程模型,但旨在通过数据共享机制(例如 __cuda_array_interface__)与这些框架很好地协同工作。对于很好地映射到张量的计算(例如:神经网络推理),使用这些现有工具是有意义的。对于具有大量稀疏性、条件逻辑、异构工作负载(例如我们在模拟和图形中经常遇到的那些)等问题,基于内核的编程模型(如 Warp 中的编程模型)通常更方便,因为用户可以控制单个线程。

有哪些使用 Warp 的项目示例?#

Warp 是否支持所有 Python 语言?#

不,Warp 支持 Python 的一个子集,该子集可以很好地映射到 GPU。 我们的目标是不存在任何性能悬崖,以便用户可以期望内核始终如一地表现良好,接近本机代码。 不支持的概念示例包括无法很好地映射到 GPU 的动态类型、列表推导式、异常、垃圾回收等。

我应该在什么时候调用 wp.synchronize()#

对于新用户来说,一个常见的困惑来源是何时需要调用 wp.synchronize()。 答案是“几乎从不”! 同步非常昂贵,通常应避免,除非必要。 Warp 自然会处理操作之间的同步(例如:内核启动、设备内存复制)。

例如,以下不需要手动同步,因为转换为 NumPy 会自动同步

# run some kernels
wp.launch(kernel_1, dim, [array_x, array_y], device="cuda")
wp.launch(kernel_2, dim, [array_y, array_z], device="cuda")

# bring data back to host (and implicitly synchronize)
x = array_z.numpy()

唯一 需要手动同步的情况是将副本异步复制回 CPU,例如

# copy data back to cpu from gpu, all copies will happen asynchronously to Python
wp.copy(cpu_array_1, gpu_array_1)
wp.copy(cpu_array_2, gpu_array_2)
wp.copy(cpu_array_3, gpu_array_3)

# ensure that the copies have finished
wp.synchronize()

# return a numpy wrapper around the cpu arrays, note there is no implicit synchronization here
a1 = cpu_array_1.numpy()
a2 = cpu_array_2.numpy()
a3 = cpu_array_3.numpy()

有关异步操作的更多信息,请参阅 并发文档同步指南

当你对像 wp.abs(x) 这样的函数进行微分时会发生什么?#

非平滑函数,例如 \(y=|x|\)\(x=0\) 处没有唯一的梯度,而是在该点具有所谓的次梯度,它正式上是该点方向导数的凸包。 Warp(以及大多数自动微分框架)处理这些点的方式是从该集合中选择任意梯度,例如:对于 wp.abs(),它将任意选择原点处的梯度为 1.0。 你可以在 warp/native/builtin.h 中找到这些函数的实现。

大多数优化器(尤其是利用随机性的优化器)对从次梯度中使用哪个梯度的选择不敏感,但也有例外。

Warp 是否支持多 GPU 编程?#

是的!自 0.4.0 版本以来,我们支持在单个进程中分配、启动和复制多个 GPU 之间的数据。 我们遵循 PyTorch 的命名约定,并使用诸如 cuda:0cuda:1cpu 等别名来标识单个设备。 有关更多信息,请参见 设备 文档。

Warp 应用程序也可以使用 mpi4py 在多个 GPU 上并行化。 如果 mpi4py 是针对支持 CUDA 的 MPI 安装构建的,则 GPU 上的 Warp 数组可以直接传递到 MPI 调用。

我应该切换到 Warp 而不是 IsaacGym/PhysX 吗?#

Warp 不能替代 IsaacGym、IsaacSim 或 PhysX——虽然 Warp 提供了一些物理模拟功能,但主要面向需要可微物理的开发人员,而不是功能齐全的物理引擎。 Warp 还与 IsaacGym 集成,非常适合执行诸如强化学习的奖励和观察计算之类的辅助任务。

为什么不支持在内核外部对 Warp 数组进行赋值?#

为了获得最佳性能,读取和写入位于 GPU 上的数据只能在 Warp CUDA 内核中执行。 否则,在 Python 范围内对单个元素的访问(例如 array[i] = 1.0)将需要速度慢到令人难以接受的设备同步和复制。

我们建议从其他本机数组(Python 列表、NumPy 数组等)初始化 Warp 数组,或通过启动内核来设置其值。

对于用给定值填充数组的常见用例,我们还支持以下形式

  • wp.full(8, 1.23, dtype=float):初始化一个新的 8 个浮点值数组,设置为 1.23

  • arr.fill_(1.23):将现有浮点数组的内容设置为 1.23

  • arr[:4].fill(1.23):将现有浮点数组的前四个值设置为 1.23

如何直接联系 Warp 团队?#

对于错误报告、功能请求和技术问题,我们建议使用 GitHub Issues

Warp 团队还会监控公共 Omniverse Discord 服务器上的 #warp 论坛。

对于不适合 GitHub Issues 或 Discord 的查询,请发送电子邮件至 warp-python@nvidia.com