MILES MACKLIN, PRINCIPAL ENGINEER, NVIDIA
Warp 最初是作为可微分物理模拟的编译器后端而编写的。
未来将有更广泛的关注点,包括:
* 几何处理:例如,OmniGraph 节点收缩包络。
* 物理模拟:例如,海洋形变器、粒子物理。
* 强化学习研究:例如,IsaacGym、奖励函数建模。
* 合成数据生成:例如,图像处理。
* 可微分模拟:例如,药物发现、机器人技术。
import warp as wp
@wp.kernel
def integrate(x: wp.array(dtype=wp.vec3),
v: wp.array(dtype=wp.vec3),
f: wp.array(dtype=wp.vec3),
w: wp.array(dtype=float),
gravity: wp.vec3,
dt: float):
# thread id
tid = wp.tid()
x0 = x[tid]
v0 = v[tid]
f_ext = f[tid]
inv_mass = w[tid]
# Semi-implicit Euler step
v1 = v0 + (f_ext * inv_mass + gravity) * dt
x1 = x0 + v1 * dt
x[tid] = x1
v[tid] = v1
# Kernel launch
wp.launch(integrate, dim=1024, inputs=[x, v, f, w], device="cuda")
概括为“模拟的 Shadertoy”。
考虑一个点到三角形最近点的函数,包含复杂的条件逻辑和多个提前退出。
@wp.func
def triangle_closest_point(a: wp.vec3, b: wp.vec3, c: wp.vec3, p: wp.vec3):
ab = b - a
ac = c - a
ap = p - a
d1 = wp.dot(ab, ap)
d2 = wp.dot(ac, ap)
if (d1 <= 0.0 and d2 <= 0.0):
return wp.vec3(1.0, 0.0, 0.0)
bp = p - b
d3 = wp.dot(ab, bp)
d4 = wp.dot(ac, bp)
if (d3 >= 0.0 and d4 <= d3):
return wp.vec3(0.0, 1.0, 0.0)
vc = d1 * d4 - d3 * d2
v = d1 / (d1 - d3)
if (vc <= 0.0 and d1 > 0.0 and d3 < 0.0):
return wp.vec3(1.0 - v, v, 0.0)
cp = p - c
d5 = wp.dot(ab, cp)
d6 = wp.dot(ac, cp)
vc = d1 * d4 - d3 * d2
v = d1 / (d1 - d3)
if (vc <= 0.0 and d1 > 0.0 and d3 < 0.0):
return wp.vec3(1.0 - v, v, 0.0)
cp = p - c
d5 = wp.dot(ab, cp)
d6 = wp.dot(ac, cp)
v = (d4 * d5 - d1 * d6) / ((d4 - d6) * (d5 - d1) - d5 * d6 + d3 * d1)
if (d6 > 0.0 and d5 <= d6):
return wp.vec3(0.0, 0.0, 1.0)
vb = d5 * d2 - d1 * d6
w = d2 / (d2 - d6)
if (vb <= 0.0 and d2 > 0.0 and d6 < 0.0):
return wp.vec3(1.0 - w, 0.0, w)
va = d3 * d6 - d5 * d4
w = (d3 - d5) / ((d4 - d6) * (d5 - d1) - d5 * d6 + d3 * d1)
if (va <= 0.0 and d4 - d3 > 0.0 and d5 - d6 > 0.0):
return wp.vec3(0.0, w, 1.0 - w)
denom = 1.0 / (va + vb + vc)
v = vc * denom
w = vb * denom
return wp.vec3(1.0 - v - w, v, w)
对于张量框架,处理这类问题存在以下困难:
* 需要手动将条件语句转换为条件选择/掩码。
* 内核融合不可靠且不透明。
* 对分散写入/原子累加的支持不佳。
下表比较了 Warp 与其他几种框架的功能:
该流程包括:
1. Python 代码(带有 @wp.kernel 装饰器)通过 AST 遍历。
2. 生成 .cpp, .cu, .hlsl 文件。
3. 这些文件通过 MSVC/GCC、NVRTC、FXC 编译器编译。
4. 生成 .dll, .so, .ptx 文件。
5. 编译过程利用 Kernel Cache。
6. 最终由 Python 通过 wp.launch() 导入并执行。
Python AST -> SSA -> CUDA。
状态存储在寄存器中。
内核融合是隐式的。
支持调试。
@wp.func
def simple(a : float, b : float):
return wp.sin(a) + a*b
// generated code
float simple(
float var_a,
float var_b)
{
// primal vars
float var_0;
float var_1;
float var_2;
// forward pass
var_0 = wp::sin(var_a);
var_1 = wp::mul(var_a, var_b);
var_2 = wp::add(var_0, var_1);
return var_2;
}
vec2, vec3, vec4, mat22, mat33, mat44, quat, transform。wp.array 类型管理,支持 __array_interface__, __cuda_array_interface__。wp.from_torch(), wp.to_torch()。wp.add_builtin() 注册原生函数。// forward mode
inline CUDA_CALLABLE vec3 cross(vec3 a, vec3 b)
{
vec3 c;
c.x = a.y*b.z - a.z*b.y;
c.y = a.z*b.x - a.x*b.z;
c.z = a.x*b.y - a.y*b.x;
return c;
}
// reverse mode (optional)
inline CUDA_CALLABLE void adj_cross(
vec3 a,
vec3 b,
vec3 adj_a,
vec3 adj_b,
vec3 adj_ret)
{
adj_a = cross(b, adj_ret);
adj_b = cross(a, adj_ret);
}
# register
add_builtin("cross", input_types={"x": vec3, "y": vec3}, value_type=vec3, ...)
wp.Tape() 的使用示例。tape 记录内核启动。tape.backward()。tape.gradients{} 中获取。tape = wp.Tape()
with tape:
wp.launch(kernel=kernel_1, dim=dim, inputs=[a], outputs=[b], device=device)
wp.launch(kernel=kernel_2, dim=dim, inputs=[b], outputs=[c], device=device)
wp.launch(kernel=kernel_3, dim=dim, inputs=[c], outputs=[l], device=device)
# run backward
tape.backward(loss=l)
# gradients of loss w.r.t inputs
print(tape.gradients[a])
布料模拟利用了以下技术:
* Bridson et al. 提出的弯曲模型。
* Neo-Hookean FEM 弹性模型。
* 内置的网格查询功能,包括 wp.mesh_query_point() 和 wp.mesh_query_ray()。
* 针对动态网格的 SDF 接触。
* 快速 GPU BVH 重建。
* 能够实现 60k 粒子对比 32k 三角形在 0.25ms 内完成模拟。
颗粒材料模拟的特点包括:
* 内置哈希网格原语,包括 wp.hash_grid_query_point() 和 wp.hash_grid_query_next()。
* 快速的最近邻查询。
* 使用 200 行 Python 代码实现了 DEM(离散元方法)。
* 可模拟 128k 粒子,每帧约 10ms。
进一步地,颗粒材料模拟还支持:
* 将 DEM 与形变网格碰撞结合。
* 来自 USD 的时间采样动画。
* 处理凝聚力(Cohesion)和身体粘附(adhesion to body)。
* 可模拟 512k 粒子,每帧约 40ms。
海洋模拟由以下组件构成:
* 由 Stefan Jeschke 开发的 Ocean deformer (omni.ocean)。
* 基于水面小波的程序网格位移。
* 参考来源:[Jeschke 2018]。
数字人变形器功能包括:
* 由 Edy Susanto Lim 开发的 Shrink-wrap deformer。
* 利用核射线投射(ray-cast)技术将眼睑投影到眼球上。
* 通过 OmniGraph 管道驱动。
系统支持 OpenVDB,具体包括:
* 支持 NanoVDB 稀疏体。
* 非常适用于窄带 SDF 碰撞。
* 提供简单易用的 API,例如:
* wp.volume_sample_world(vol, xyz)
* wp.volume_sample_local(vol, uvw)
* wp.volume_lookup(vol, ijk)
* wp.volume_transform(vol, xyz)
* wp.volume_transform_inv(vol, xyz)
布料求解器的基准测试基于以下实现:
Warp 对 CUDA 图提供了原生支持,通过以下 API 实现:
wp.capture_begin()wp.capture_end()wp.capture_launch()这带来了启动开销 > 10 倍的减少。
Warp 与 Omniverse 的集成方式如下:
* 通过 omni.warp 扩展暴露功能。
* 将 Warp 列为扩展的依赖项。
* 通过 import warp 即可开始编写核函数 (kernels)。
将 OmniGraph 与 Warp 结合使用具有以下优势:
* 非常适合编写 Python OmniGraph 节点。
* 实现超快的迭代时间。
* 支持 Ctrl-S 热重载 (Hot Reload),使得 JIT 编译在 < 1s 内完成。
* 扩展附带了示例,包括:
* 波动方程求解器
* 布料模拟
* 粒子模拟
在第31页,标题为“ITERATION TIMES”,展示了一个包含3D模拟软件界面和代码编辑器的截图。左侧的软件界面显示了一个波浪形表面上的球体,实时帧率为102 Hz。界面还显示了系统资源信息:NVIDIA GeForce RTX 3090 GPU使用了2 GB,可用20 GB;主机内存使用了17 GB,可用128 GB。右侧是Python代码,其中包含对cupy和numpy库的引用,并定义了一个CUDA内核,用于处理“wave_solver”逻辑。这页幻灯片强调了迭代过程的效率和速度,展示了在NVIDIA Omniverse或类似环境中进行实时物理模拟及其背后的Python/CUDA代码。
第32页的标题为“SUMMARY”,总结了之前介绍的关键特性:
第33页的标题为“JOIN OMNIVERSE DEVELOPER DAYS”,介绍了NVIDIA GTC大会上与Omniverse相关的特色演讲和特别活动:
特色演讲
* 为Omniverse制作连接器 [S41592]
* Lou Rohan, Connect Engineer, NVIDIA
深入研究Omniverse的微服务构建 [S41593]
如何构建Omniverse套件的扩展和应用程序 [S41591]
使用Omniverse Replicator进行合成数据生成 [S41581]
Warp:面向GPU模拟的高性能Python框架 [S41599]
特别活动与交流
开发者专题:物理模拟新纪元 [SE2312]
分组会议:使用NVIDIA Kaolin进行3D深度学习研究 [SE42115]
开发者专题:在Omniverse上构建您自己的微服务 [SE2306]
开发者专题:构建Omniverse扩展和应用程序 [SE2305]
与Omniverse专家见面:材料与渲染技术 [SE2310]
会议日期:3月21-24日, 2022 | http://www.nvidia.com/GTC
第34页是NVIDIA的品牌宣传图片,展示了一个抽象的绿色螺旋形图案,背景为黑色,左下角是NVIDIA的标志。