人工智能/深度学习

使用 CUDA 加速 Blender Python

模拟或 合成数据 生成是人工智能工具发展的一个重要趋势。传统上,这些数据集可用于解决低数据问题或边缘情况场景,而或许现在存在于可用的实际数据集中。

合成数据的新兴应用包括建立模型性能水平、量化适用领域,以及下一代系统工程,其中人工智能模型和传感器是串联设计的。

Picture of a ship next a representation of the ship’s phase map, which is composed of lines and colors.
图 1 。 船舶合成孔径雷达渲染: 相位图 ( left ) ,压缩图像 ( right ).

Blender 是生成这些数据集的一个常用且引人注目的工具。它是免费使用和开源的,但同样重要的是,它可以通过强大的 Python API 完全扩展。 Blender 的这一特性使其成为视觉图像渲染的一个有吸引力的选择。因此,它已被广泛用于此目的,有 18 +渲染引擎选项可供选择。

集成到 Blender 中的渲染引擎(如 Cycles )通常具有紧密集成的 GPU 支持,包括最先进的 NVIDIA RTX 支持。但是,如果在可视化渲染引擎之外需要高性能级别,例如合成 SAR 图像的渲染,那么 Python 环境对于实际应用程序来说可能过于迟缓。加速这段代码的一个选择是使用流行的 Numba 包将 Python 代码的部分预编译成 C 。然而,这仍有改进的余地,特别是在采用领先的 GPU 体系结构进行科学计算方面。

GPU 科学计算功能可直接从 Blender 中获得,允许使用简单的统一工具,利用 Blender 强大的几何体创建功能以及尖端计算环境。对于 blender2 . 83 +的最新变化,可以使用 CuPy (一个专门用于数组计算的 GPU 加速 Python 库)直接从 Python 脚本中完成。

根据这些想法,下面的教程将比较两种不同的加速矩阵乘法的方法。第一种方法使用 Python 的 Numba 编译器,而第二种方法使用 NVIDIA GPU-compute API, CUDA 。这些方法的实现可以在 rleonard1224/matmul GitHub repo 中找到,还有一个 Dockerfile ,它设置了 anaconda 环境,从中可以运行 CUDA – 加速的 Blender Python 脚本。

矩阵乘法算法

作为讨论用于加速矩阵乘法的不同方法的前奏,我们简要回顾了矩阵乘法本身。

对于两个矩阵的乘积[A \cdot B]为了更好地定义[A]必须等于[B].

  • [A]然后是一个矩阵[m]行和[n]列,即[m \times n]matrix.
  • [B]是一个[n \times p]matrix.
  • 产品[C = A \cdot B]结果是[m \times p]matrix.

如果[C],[A],和[B]使用数字 1 (即基于 1 的索引)进行索引,然后是的第 i 行和第 j 列中的元素[C],[C[i,j]],由以下公式确定:

[C[i,j] = \Sigma_{r = 1}^{n} A[i,r] \cdot B[r,j]]

麻木加速度

通过使用 Numba . jit decorator ,可以将 Numba 编译器应用于 Python 脚本中的函数。通过预编译到 C 中,在 Python 代码中使用 numba . jit decorator 可以显著减少循环的运行时间。由于直接转换为代码的矩阵乘法需要嵌套 for 循环,因此使用 numba . jit decorator 可以显著减少用 Python 编写的矩阵乘法函数的运行时间。 matmulnumba.py Python 脚本实现矩阵乘法并使用 numba . jit decorator 。

CUDA 加速度

在讨论使用 CUDA 加速矩阵乘法的方法之前,我们应该大致概述 CUDA 内核的并行结构。内核启动中的所有并行进程都属于一个网格。网格由块数组组成,每个块由线程数组组成。网格中的线程组成了由 CUDA 内核启动的基本并行进程。图 2 概述了这类并行结构的示例。

Picture of a grid arranged as a 2x2 matrix representing a CUDA kernel grid with each element of the matrix representing a CUDA block.
图 2 。 一个由 2 组成的 CUDA 核网格的并行结构× 2 块数组。每个块由一个 2 × 2 个线程阵列。

既然已经详细说明了 CUDA 内核启动的并行结构,那么在 matmulcuda.py Python 脚本中用于并行化矩阵乘法的方法可以描述如下。

假设以下由一个由块的二维数组组成的 CUDA 内核网格计算,每个块由线程的一维数组组成:

  • 矩阵积[C = A \cdot B]
    • [A]and[m \times n]matrix
    • [B]and[n \times p]matrix
    • [C]and[m \times p]matrix

此外,进一步假设如下:

  • 网格 x 维中的块数 ([\textrm{nblocksx}]) 大于或等于[m]([\textrm{nblocksx} \geq m]).
  • 网格 y 维中的块数 ([\textrm{nblocksy}]) 大于或等于[p]([\textrm{nblocksy} \geq p]).,
  • 每个块中的线程数 ([\textrm{nthreads}]) 大于或等于[n]([\textrm{nthreads} \geq n]).

矩阵积的元素[C = A \cdot B]可以通过为每个块分配一个元素的计算来并行计算[C],[C[i,j]].

您可以通过将指定给要执行的块的每个线程来获得进一步的并行增强[C[i,j]]分配,计算[n]和等于[C[i,j]].

为了避免竞争条件,这些[n]积和结果的赋值[C[i,j]]可以使用 CUDA atomicAdd 函数处理。 atomicAdd 函数签名由作为第一个输入的指针和作为第二个输入的数值组成。该定义将输入的数值与第一个输入所指向的值相加,然后将该和存储在第一个输入所指向的位置。

假设[C]初始化为零[\textrm{tid}(i,j)]表示属于块的线程的线程索引,其索引在块的网格中[[i,j]]. 上述平行排列可通过以下方程式进行总结:

[C[i,j] = \textrm{atomicAdd}(C[i,j], A[i, \textrm{tid}(i,j)] \cdot B[\textrm{tid}(i,j), j])]

图 3 总结了两个样本矩阵乘法的并行排列[2 \times 2].

Grid composed of blocks in a 2x2 grid, which parallelize the multiplication of two 2x2 matrices composed of ones.
图 3 .两个 2 的乘法的并行化方法× 2 个矩阵。每个块被分配两个矩阵乘积的一个元素,一个线程块中的线程并行地计算乘积,以确定分配给块的矩阵元素的值。

提速

图 4 显示了 CUDA 加速矩阵乘法相对于不同大小矩阵的 Numba 加速矩阵乘法的加速比。在该图中,绘制了加速比以计算两个[N \times N]两个矩阵的所有元素都等于一的矩阵。[N]范围从一百到一千,增量为一百。

One-dimensional plot showing increasing speedup of CUDA relative to Numba as the size of the matrices increases.
图 4 .两个 NxN 矩阵相乘时 CUDA 加速矩阵相乘相对于 Numba 加速矩阵相乘的加速比。

今后的工作

考虑到 Blender 作为计算机图形工具的作用,一个适用于 CUDA 加速的相关应用领域涉及到通过光线跟踪解决可见性问题。可见性问题可以概括如下: 相机存在于空间的某个点上,并且正在观察由三角形元素组成的网格。可见性问题的目标是确定哪些网格元素对摄影机可见,哪些网格元素被其他网格元素遮挡。

光线跟踪可以用来解决可见性问题。您试图确定其可见性的网格由[N]网格元素。那样的话,[N]可以生成以场景中的摄影机为原点的光线。这些端点位于[N]网格元素。

每条光线在不同的网格元素上都有一个端点。如果光线到达其端点时未被其他网格元素遮挡,则可以从摄影机中看到端点网格元素。图 5 显示了这个过程。

One face blocking another face from the viewpoint of a camera.
图 5 . 从相机向场景中的人脸发射的两条光线;一个面可见,另一个面被遮挡。

使用光线跟踪来解决可见性问题的本质使其成为[\mathcal{O}(N^{2})]作为直接计算实现时的问题。幸运的是, NVIDIA 开发了一个光线跟踪库,名为 NVIDIA OptiX ,它使用 GPU 并行性来实现显著的加速。在 Blender Python 环境中使用 NVIDIA OptiX 将带来实实在在的好处。

概括

这篇文章描述了两种不同的加速矩阵乘法的方法。第一种方法使用 Numba 编译器来减少 Python 代码中与循环相关的开销。第二种方法使用 CUDA 并行化矩阵乘法。速度比较证明了 CUDA 在加速矩阵乘法方面的有效性。

因为前面描述的 CUDA 加速代码可以作为 Blender Python 脚本运行,所以可以在 Blender Python 环境中使用 CUDA 加速任意数量的算法。这大大提高了 blenderpython 作为科学计算工具的有效性。

如果您有任何问题或意见,请在下面发表意见或联系我们 info @ rendered . ai .

Tags