IM-Net learning implicit field for generative shape modeling论文笔记

603 阅读5分钟

本文已参与「新人创作礼」活动, 一起开启掘金创作之路。

作者报告讲解:www.bilibili.com/video/BV1e7…

我之前看过作者的一个报告,他在里面讲了pointnet和imnet和后面一些工作的关系,但是现在找不到那个报告了。

在官网games-cn.org/previousweb… 直接搜zhiqin就是作者的报告

代码链接:github.com/Bailey-24/I…

IM-Net learning implicit field for generative shape modeling

概述: 传统的三维重建通过使用高分辨率的图像采集设备获取目标物体的二维特征,然后使用算法重建它的三维特征,但是算法重建的模型质量不高;针对以上问题,作者提出用隐式场来构建形状学习的生成模型,并引入 IM-NET 的隐式场解码器替换传统解码器进行表示学习和形状生成,IM-NET 输入是坐标点和形状的编码,输出一个布尔值,这个布尔值代表这个坐标点是否属于物体内部,IMNET在生成形状建模、插值和单视图三维重建等任务中取得较好的结果。

image.png

1. 前置知识

  • Deep Implicit Representation 深度隐式表示是一种将各种信号参数化的新方法。以图像为例,其最常见的表示方式为二维空间上的离散像素点。但是,在真实世界中,我们看到的世界可以认为是连续的,或者近似连续。于是,可以考虑使用一个连续函数来表示图像的真实状态,然而我们无从得知这个连续函数的准确形式,因此有人提出用神经网络来逼近这个连续函数,这种表示方法被称为“深度隐式表示” Deep Implicit Representation (DIR)。 举几个例子,图像、视频、体素,都能用 DIR 来表示,其数学表达如下:

image.png

对于图像,DIR 函数将二维坐标映射到rgb值。对于视频, DIR 函数将时刻 t 以及图像二维坐标xy映射到rgb值。对于一个三维形状, DIR 函数将三维坐标 xyz 映射到0或1,表示空间中的某一位置处于物体内部还是外部。当然还有其他形式,如NERF将xyz映射到rgb和sigma。总而言之,这个函数就是将坐标映射到目标值。一旦该函数确定,那么一个图像/视频/体素就确定了。

2. 算法原理

针对之前的算法生成的模型视觉质量不高的问题,本论文提出了用深度隐式表达来生成质量更高的模型。具体而言提出一个 implicit decoder,输入坐标点和 shape 的编码,输出0或1,表达这个坐标点属于物体内部还是外部。然后得到所有点组成的连续的零等值面,最后用 marching cubes 方法就能重建 mesh 表面。 下面介绍 implicit decoder 的网络结构,损失函数和如何训练。

  • 网络结构 因为算法本质是一个二进制分类问题,所以用多层感知机就能学得很好,也就是有足够的线性层就能逼近任意精度内的等值面。 原网络结构用到 skip connection,就是将上一层的特征与本层特征拼在一起,但是后面作者在代码上不用 skip connection,而且将本来 2048-1024 线性层换成 1024-1024-1024,而且最后不用 sigmoid,改用 clip ,原结构与修改后的结构图如下所示。

image.png

  • 损失函数 用均方误差作为损失函数,目标是缩小ground truth的值和网络预测每个点的值。

  • 训练技巧 为了输出质量更好的模型,作者使用 progressive training 技巧,也就是先用 16316^3的体素数据训练网络,然后用这个训练好的网络在32332^3的数据上训练,这样能够稳定训练过程和减少训练时间。

3. 算法实现

3.1 数据集

训练 implicit decoder需要point-value pairs数据进行监督学习。

  • 数据预处理 为了能够 progressive training,用 Hierarchical Surface Prediction算法获得不同分辨率的体素模型,然后在每种分辨率上采样点。 代码链接:github.com/Bailey-24/I…

3.2 核心代码

  • IM-AE网络结构 用auto-encoder架构,encoder用3D CNN进行编码,decoder就用 implicit decoder。
class generator(nn.Module):
	def __init__(self, z_dim, point_dim, gf_dim):
		super(generator, self).__init__()
		self.z_dim = z_dim
		self.point_dim = point_dim
		self.gf_dim = gf_dim
		self.linear_1 = nn.Linear(self.z_dim+self.point_dim, self.gf_dim*8, bias=True)
		self.linear_2 = nn.Linear(self.gf_dim*8, self.gf_dim*8, bias=True)
		self.linear_3 = nn.Linear(self.gf_dim*8, self.gf_dim*8, bias=True)
		self.linear_4 = nn.Linear(self.gf_dim*8, self.gf_dim*4, bias=True)
		self.linear_5 = nn.Linear(self.gf_dim*4, self.gf_dim*2, bias=True)
		self.linear_6 = nn.Linear(self.gf_dim*2, self.gf_dim*1, bias=True)
		self.linear_7 = nn.Linear(self.gf_dim*1, 1, bias=True)
		
	def forward(self, points, z, is_training=False):
		zs = z.view(-1,1,self.z_dim).repeat(1,points.size()[1],1)
		pointz = torch.cat([points,zs],2)

		l1 = self.linear_1(pointz)
		l1 = F.leaky_relu(l1, negative_slope=0.02, inplace=True)

		l2 = self.linear_2(l1)
		l2 = F.leaky_relu(l2, negative_slope=0.02, inplace=True)

		l3 = self.linear_3(l2)
		l3 = F.leaky_relu(l3, negative_slope=0.02, inplace=True)

		l4 = self.linear_4(l3)
		l4 = F.leaky_relu(l4, negative_slope=0.02, inplace=True)

		l5 = self.linear_5(l4)
		l5 = F.leaky_relu(l5, negative_slope=0.02, inplace=True)

		l6 = self.linear_6(l5)
		l6 = F.leaky_relu(l6, negative_slope=0.02, inplace=True)

		l7 = self.linear_7(l6)

		l7 = torch.max(torch.min(l7, l7*0.01+0.99), l7*0.01)
		
		return l7

3.3 实验结果

结果是用在16316^3体素训练200epoch,然后在32332^3体素训练200epoch,最后在64364^3体素训练200epoch后的网络进行测试的,测试时的分辨率是2563256^3,可以看出结果比论文的光滑度要低很多。

image.png

4. 心得体会

  • 训练数据很影响效果 因为这个数据集是作者在原来的 shapenet 数据集上进行预处理的,它比64364^3分辨率更高的体素模型,所以没办法训练更好分辨率的网络,所以结果不是很理想。
  • 训练时间好久 因为这个网络是需要对模型每个坐标点进行分类,所以训练时间很久。

5. 参考文献