如何使用Nvidia Kaolin和PyTorch将2D照片变成3D模型 - 3D深度学习教程

1,328 阅读18分钟

如果你读过我上一篇关于GANverse3D的文章,那么你可能会听说过DIB-R论文,我曾多次提到过它。这是2019年3D深度学习的一篇关键论文。

DIB-R论文介绍了一个改进的差分渲染器,作为解决深度学习中目前最时髦的问题之一的工具。

从单一的2D图像生成3D物体。

当DIB-R论文发布时,早在2019年,它还包括源代码。但不幸的是,它缺少运行该代码所需的机器学习模型。

来源。DIB-R Github页面

这让人相当失望,因为我真的想亲身尝试一下。

好消息是,我们现在可以亲身尝试DIB-R了,因为Nvidia已经发布了一个属于Nvidia Kaolin的PyTorch库,其中包括DIB-R,也就是DIB-R论文中使用的那个差分渲染器。

但最重要的是,这个库还包括一个教程,展示了DIB-R这个差分渲染器的功能。

当我第一次看到这个教程时,我必须承认,我并没有真正理解它。而且,我甚至不知道为什么首先需要一个差分渲染器。我甚至把差分渲染器和DIB-R论文中描述的神经网络混为一谈,后者能够从一张2D照片中生成一个3D物体。

它们实际上是两个不同的东西。

因此,在本教程中,我将逐步向你展示如何尝试DIB-R教程,同时我也将与你分享我对DIB-R和3D深度学习领域的认识。

什么是Nvidia Kaolin

Nvidia Kaolin不仅仅是PyTorch库。Nvidia Kaolin有两个主要组成部分。

  • Nvidia Omniverse Kaolin App,是由Nvidia创建的一个应用程序,通过提供3D数据集的可视化工具、生成合成数据集的手段,帮助3D深度学习研究人员,甚至还具有可视化模型在训练期间生成的3D输出的能力。
  • Nvidia Kaolin Library是一个PyTorch API,支持不同的3D表示方法,如点云、网格和体素网格,以及允许从一种表示方法转换到另一种表示方法的函数(kaolin.ops)。该库还包括DIB-R,微分渲染器(kaolin.render),从流行的3D数据集(如Shapenet)加载数据的函数,以及加载不同文件格式(如objusd)的3D模型的函数(kaolin.io)。创建3D检查点的API**(kaolin.visualize**),未来还有更多。

DIB-R教程

所需软件

为了能够运行DIB-R教程,你需要具备以下条件。

  • 硬件。Nvidia GPU
  • 操作系统。Windows或Linux

必要的软件。

  • Python 3.7
  • Pytorch 1.7.0
  • CUDA 11.2或以上
  • Nvidia Kaolin库
  • Nvidia Omniverse Launcher

使用Anaconda

通过使用Anaconda,我们可以减轻很多痛苦。通过Anaconda,我们可以很容易地安装多个版本的Python,而且通过使用虚拟环境,我们可以大大减少找到不兼容版本的库的几率。

如果你没有安装Anaconda,你可以按照这篇文章来完成Anaconda的设置

CUDA

在安装任何东西之前,请检查你是否安装了10.2或以上版本的CUDA。如果你没有,你可能想阅读我最近的一篇文章,其中我告诉你如何安装CUDA 11.2

创建Conda环境

让我们先为我们需要安装的一切创建一个Conda 环境。让我们把它叫做kaolin

$ conda create --name kaolin python=3.7

从Github下载Nvidia Kaolin

为了准备我们的设置,我们将从Github下载Nvidia Kaolin。

git clone --recursive 

使用哪个版本的Kaolin

Kaolin的安装说明告诉我们要将git分支切换到Kaolin的最新版本,截至今天为止是v0.9.0。不幸的是,0.9.0版本还不包括DIB-R教程。DIB-R教程只在主分支中。

出于这个原因,我们将直接从主分支进行Kaolin设置。

安装Pytorch 1.7.1

在我们安装Nvidia Kaolin之前,我们需要安装PyTorch。

为了使事情变得非常简单,让我们用Conda来安装Pytorch。

conda install pytorch==1.7.1 torchvision==0.8.2 torchaudio==0.7.2 -c pytorch

安装Nvidia Kaolin应用程序

在我们尝试运行DIB-R教程之前,虽然没有严格要求,但最好还是安装Nvidia Kaolin应用。

Nvidia Kaolin应用程序将帮助我们实现3D模型的可视化,在本例中是一个时钟,我们将用它来训练DIB-R。它还将帮助我们可视化更广泛的数据集,这个时钟就来自于此。

我们稍后还将使用这个工具为另一个3D资产生成更多的训练数据,我们将从厨房的数据集中挑选。

安装Nvidia Omniverse Laucher

在能够安装Nvidia Omniverse之前,我们首先需要下载并安装Nvidia Omniverse Launcher。下面的视频来自Nvidia,向你展示了具体的步骤。

从Nvidia Omniverse Launcher安装Nvidia Kaolin应用程序

现在Nvidia Omniverse已经安装完毕,我们可以安装Nvidia Kaolin应用。

让我们打开Nvidia Omniverse Launcher并选择EXCHANGE标签。

然后我们点击APPS并搜索Kaolin。然后你可以从这里下载并安装Omniverse Kaolin应用程序。

将DIB-R放入背景中

现在我们已经安装了所有的组件,我们已经准备好尝试DIB-R的教程了!

但在此之前,让我们简单地谈谈最近的GanVerse3DDIB-R 论文,以及它们之间的联系。

DIB-R论文的第一部分,Nvidia详细介绍了一种改进的差分渲染器的设计,称为DIB-R

资料来源。Chen等人,Nvidia(2019),DIB-R

在第二部分,DIB-R论文讨论了如何使用DIB-R这个差分渲染器来解决3D深度学习中的困难问题。训练一个能够从单一图像中预测3D物体形状、纹理和照明的模型。在这种情况下,该模型是使用ShapeNet和CUB鸟类数据集的数据训练的。

DIB-R论文结果与CMR论文的比较 - Chen等人,Nvidia(2019),DIB-R

在后续的GANVerse3D论文中,Nvidia上升了一个档次。
他们没有使用ShapeNet数据集和CUB鸟类数据集,而是使用了通过使用StyleGAN-R和一个新的GAN(称为DatasetGAN)生成的数据集。

资料来源:Zhang et al:Zhang等人,Nvidia(2020),GanVerse3D

StyleGAN-R,又称StyleGAN渲染器,与普通的StyleGAN一样,只是它的前四层被冻结,在已知相机位置的情况下,以不同的视角生成同一物体类别的图像。

**资料来源:Zhang et al:**Zhang等人,Nvidia(2020),GanVerse3D

**资料来源:Zhang等人,Nvidia(2020),GanVerse3D。**Zhang等人,Nvidia(2020),GanVerse3D

由Nvidia开发的GAN数据集, 然后被用来自动注释这些生成的图像中的每一张,直到像素级别(语义分割)。

这就是Nvidia在从二维照片转换后,能够对汽车等三维物体进行动画处理的原因。

资料来源:NvidiaZhang等人,Nvidia(2021),DatasetGAN

**资料来源。**Zhang等人,Nvidia(2021), DatasetGAN

DIB-R教程是关于什么的?

我们现在可以在Github上找到的DIB-R教程是关于向你展示DIB-R差分渲染器是如何工作的,以及它如何被用来从多个2D图像中恢复3D模型结构和纹理,作为一个纯优化问题。

但是,更重要的是,它不是什么。它不是一个关于如何使用DIB-R论文第二部分中描述的神经网络从单一2D图像中生成3D模型的教程。稍后,当我们浏览代码时,你会发现,它并没有使用神经网络。

DIB-R论文

现在,让我们来详细谈谈DIB-R的论文,因为这将有助于理解DIB-R教程。

将二维图像转换为原始三维场景的问题是传统计算机图形学的逆向问题,因此被称为 逆向图形

说起来容易做起来难,逆向图形是相当困难的,因为传统的渲染管道,如OpenGL、DirectX,从来没有被设计为允许恢复被渲染的3D场景。这些管道的开发是为了提高效率,它们包含大量的优化,这导致一些3D场景信息的丢失。

什么是差分渲染器

我认为有必要讨论一下什么是差异化渲染器,以及为什么需要它。

让我们想象一下,我们正试图自己解决这个计算机视觉问题,但不一定要用机器学习。

一张2D照片是一个3D场景的投影。三维场景是三维网格、顶点、面、纹理贴图和光源的集合,从一个相机或视角来看。为了简单起见,让我们把我们的三维场景限制在一个单一的三维物体。

如果我们能够恢复产生二维照片的原始三维场景,我们应该能够通过使用产生输入二维照片的相同视角将给定的三维物体投射到二维来验证它。

蛮力

为了重建我们的三维物体,蛮力方法是计算顶点、面、光源和纹理的每一种可能的组合,只要相机位置相同,这些组合在投射到二维时应产生与输入的二维图像相当的图像。这实质上是一个搜索问题。

但强行搜索的问题是,有无数个顶点、面、纹理图和光源的组合可以被创造出来。

所以我们不能用暴力解决这个问题。

基于梯度的方法

让我们尝试找到一个更聪明的方法吧

我们从一个初始网格开始,例如一个球体,它在拓扑学上与我们要恢复的三维物体相似,例如一个时钟,然后我们试着做一些改变,使我们塑造的这个球体与时钟相似,这样做怎么样?

我们可以在不同层次上进行改变。

  • 通过移动顶点来改变输入网格的几何形状
  • 改变纹理中的颜色
  • 改变输入的灯光

如果你想一想,这就类似于一个三维建模艺术家会做的事情。他们总是会选择一个与他们试图重建的三维物体相似的基础几何体。

关键的一点是,如果我们对球体的几何形状做了改变,那么我们希望几何形状与目标几何形状趋同或背离,纹理和光源也是如此。

为了验证我们是否在收敛,我的意思是,越来越接近目标形状,在本例中是一个时钟,在每一步,我们需要使用与输入的2D图像类似的视角,将我们的成型球体投射到2D,并验证我们是否越来越接近。

光栅化

但是,休斯顿,我们有一个问题,为了从3D场景转换到2D,我们需要使用一个图形渲染管道。

在传统的计算机图形管道中,光栅化技术被用来将3D场景渲染到2D场景中。

在将三维图像投射到二维平面、光栅化三角形和对像素进行着色的过程中,由于图形管道中使用的算法,会有信息损失。这些损失的问题是,它们在图像中引入了不连续。

这意味着经常对几何图形进行细微的改变可能根本不会导致不同的图像。或者更糟的是,图像会突然改变,让我们离目标2D图像更远。这是一个不...不...

由于这两个问题,我们没有办法知道该往哪个方向去搜索。这使得从2D照片中恢复原始3D场景变得非常困难。

差分渲染器来拯救

因此,我们似乎需要设计自己的渲染管道,也就是差分渲染器。

这个新的渲染管道将保证,对于输入的3D物体的每一个变化,投射的2D图像像素都会有一个保证的变化,而且这个变化对于每个像素来说都是一个渐进的变化。

此外,每个生成的像素都将有导数,可以用来确定,我是说,反推,对每个像素的最终值有贡献的原始输入。

幸运的是,我们不需要重新发明车轮。DIB-R就是一个我们可以使用的差分渲染器!

DIB-R - 微分渲染器

DIB-R是一个微分渲染器,它使用可微分栅格化算法来模拟像素值。它有两种分配像素值的方法。一种用于前景像素,另一种用于背景像素。

前景像素

对于前景像素,论文中说。

在这里,与标准渲染不同的是,一个像素的值是从覆盖它的最近的面开始分配的,我们把前景栅格化当作顶点属性的内插[4]。对于每一个前景像素,我们都要进行Z-缓冲测试[6],并将其分配给最接近的覆盖面。每个像素都只受这个面的影响。

差别化的说明 - Chen等人,Nvidia(2019),DIB-R

因此,综上所述,前景像素被计算为最近的三个相邻顶点的内插,使用和每个顶点的权重,其中Ii是像素强度。

Chen等人,Nvidia(2019),DIB-R

背景像素

对于背景像素,即没有被三维物体的任何面覆盖的像素,像素值是根据该像素到最近的面的距离计算的。

其他差分渲染器

需要强调的是,DIB-R并不是第一个也是唯一一个差分渲染器。它是一个改进的差分渲染器,是基于2014年的OpenDR的想法,还有 SoftRas-Mesh,它提出了一个与DIB-R类似的差分渲染器。

差分渲染器比较--Chen等人,Nvidia(2019),DIB-R

我们如何从一张图片中生成一个3D模型和纹理?

所以我只提到了我们能看到的东西。那我们看不到的东西呢?当然,如果我只有一张时钟正面的图片,它怎么能搞清楚时钟背面的东西呢?
解决办法是通过幻觉。让我解释一下。

目前,机器学习中唯一能想象事物的是GAN(生成对抗网络)。

因此,我们也可以用GANs来生成3D物体和一个纹理,这不应该是一个惊喜。

DIB-R的论文在第二部分描述了使用编码器-解码器架构的GAN来预测3D模型的顶点位置、几何形状、颜色/纹理,并使用2D监督,使用差分渲染器。

回到DIB-R教程

但DIB-R教程并没有使用GAN或任何神经网络。相反,它只是一个简单的演示,说明我们如何使用DIB-R差分渲染器,结合PyTorch来解决一个优化问题,即从同一物体的多个视图中反复恢复3D几何和纹理,在这种情况下,就是一个时钟

是时候运行教程了!

DIB-R教程的目的是展示如何使用DIB-R这个差分渲染器来重建一个三维物体的三维几何和纹理,比如时钟,它是皮克斯的厨房数据集的一部分。这个数据集是一个3D物体的集合,你通常会在厨房里找到这些物体,皮克斯已经友好地将其开源。

你可以在厨房数据集中找到的时钟被选中,因为它是一个相对简单的物体,没有拓扑孔。

生成训练数据

首先,我们使用NvidiaKaolin应用程序,从不同的视角生成时钟的2D图像数据集,在这种情况下,总共有100个不同的视角。

对于每个**视点,**我们生成一个RGB图像,一个分割掩码,以及一个额外的元数据JSON文件,其中包含相机参数,如焦点、光圈、焦距等。

一个由Nvidia Kaolin生成的数据集中的时钟的例子图像

预计每个不同视角都会看到的文件

加载训练数据

为了加载训练数据,我们使用torch.utils.DataLoader,这是PyTorch的一个类,用于将数据集加载到内存中,准备用于GPU。请注意,我们将pin_memory设置为True,这将自动将数据集加载到钉住的内存中,一旦训练开始,这将更快地传输到GPU内存中。

另外,我们使用kal.io.render.import_synthetic_view 方法来加载训练数据集中的每张图片,此外,它还加载每张图片的语义掩码文件和包含相机参数的元数据json。

num_views = len(glob.glob(os.path.join(rendered_path,'*_rgb.png')))

加载球体模板

接下来,我们加载一个obj格式的球体。这个球体将在训练中被塑造成与时钟相似的样子。

Blender中球体模板的视图

在训练过程中,我们不打算改变球体的拓扑结构,例如添加任何孔。

准备损失和正则器

现在,在Jupyter笔记本的这一部分,我们设置了损失函数。这些损失函数有两个目的。

  • 用来了解我们与地面真相的差距有多大。我们的地面实况将是在不同位置的相机拍摄的时钟的不同视图。
    我们使用图像L1损失,它是预测图像和地面真相图像之间的绝对差异。
    此外,我们还计算掩码损失,这是一个测量预测的软掩码与我们时钟的地面实况分割掩码相交(IoU)的程度。
  • 作为正则器使用,以惩罚任何具有自相交面的几何体,并鼓励平滑度。在这种情况下,我们使用Laplacian loss和flat loss。这些都是常用的平滑度正则器。
loss = (

神经三维网格渲染器,Kato等人。

海豚的三维形状重建,使用和不使用平滑度正则器。
**左图:目标海豚中心。**三维重建,使用平滑度正则器 右:不使用

设置优化器

本教程选择了Adam作为训练期间使用的优化算法。

optim  = 

在训练过程中,亚当优化算法将把顶点、纹理图和顶点移动作为可学习的参数。

vertice_shift似乎是一个参数,用于在训练期间移动球体的所有顶点。
这就是为什么在训练的每一步,我们都要调用recenter_vertices方法,该方法将顶点和vertices_shift参数作为输入。

def

训练

在训练中,教程总共运行了40个epochs。每个历时有100步,这是我们为时钟拍摄的视图的数量。

在第0个历时中,我们从一个球体开始,这个球体是我们先前在笔记本中加载的。球体的顶点被存储在顶点 中**,** 球体的初始纹理图被存储在texture_map中**。**

在每一步中,我们使用DIB-R差分渲染器将正在成型的三维球体渲染为二维,并将纹理应用于其上,使用的相机位置和参数与用于地面实况时钟的相机相同。

然后在每一步结束时,我们计算出损失。

loss = (

最后我们更新网格。

### Update the mesh ###

这两行代码是必不可少的。

  • loss.backward()计算梯度,我是说我们正在优化的每个参数的数值变化。optim.step()根据这些梯度来更新参数。这就是所说的反向传播的意思。

请注意,在训练过程中,对于每个epoch,我们也在拍摄球体随时间变化的快照。我们稍后将使用Nvidia Kaolin应用程序将其可视化。

可视化训练

最后一个代码块只是为了显示最终的形状,即球体被塑造成一个时钟的样子。

一旦你运行它,你应该得到一个类似的结果!

在这个阶段,我们应该能够使用Nvidia Kaolin应用程序查看训练的时间推移。观看我的这个教程的视频,看看如何做到这一点。

希望这篇文章是有用的,你现在明白了为什么需要一个差分渲染器,以及为什么它对3D深度学习如此重要。

编码愉快!

资源

研究论文

Yuxuan Zhang, Wenzheng Chen, Huan Ling, Jun Gao, Yinan Zhang, Antonio Torralba, Sanja Fidler
IMAGE GANS MEET DIFFERENTIABLE RENDERING FOR INVERSE GRAPHICS AND INTERPRETABLE 3D NEURAL RENDERING
arxiv.org/pdf/2010.09…

Wenzheng Chen, Jun Gao*, Huan Ling*, Edward J. Smith*, Jaakko Lehtinen, Alec Jacobson, Sanja Fidler
学习用基于插值的可分辨渲染器预测三维物体
nv-tlabs.github.io/DIB-R/

Yuxuan Zhang, Huan Ling, Jun Gao, Kangxue Yin, Jean-Francois Lafleche, Adela Barriuso, Antonio Torralba, Sanja Fidler
DatasetGAN: Efficient Labeled Data Factory with Minimal Human Effort
arxiv.org/pdf/2104.06…

Shunyu Yao, Tzu Ming Hsu, Jun-Yan Zhu, Jiajun Wu, Antonio Torralba, Bill Freeman, and Josh Tenenbaum
通过反向图形进行3D感知的场景操作。在神经信息处理系统的进展中,
arxiv.org/pdf/1808.09…

Matthew M. Loper和Michael J. Black
OpenDR: An Approximate Differentiable Renderer
files.is.tue.mpg.de/black/paper…

Paul Henderson, Vittorio Ferrari
学习生成和重建三维网格,只用二维监督
arxiv.org/pdf/1807.09…

Shunyu Yao, Tzu Ming Hsu, Jun-Yan Zhu, Jiajun Wu, Antonio Torralba, Bill Freeman, and Josh Tenenbaum
通过反向图形进行3D感知的场景操作。In Advances in neural information processing systems,
arxiv.org/pdf/1808.09…

网站

Nvidia Kaoolin Github页面
github.com/NVIDIAGameW…

视频

3D深度学习播放列表