Reading Self-supervised Single-view 3D Reconstruction via Semantic Consistency

论文地址:https://arxiv.org/abs/2003.06473

作者:Xueting Li, Sifei Liu, Kihwan Kim, Shalini De Mello, Varun Jampani, Ming-Hsuan Yang, and Jan Kautz

发表: ECCV 2020

链接: https://github.com/NVlabs/UMR


如果你去做这个任务,会怎么做?作者做的方法和你想的有什么差异?

Why:

  1. 在3d重建模任务中,同时预测形状、相机位置和材质是一个很大的问题,因为它内在的不确定性。
  2. 现有方法都需要借助各种手段:3D层面的监督、2D语义关键点、shading(这是什么?)、特定类别的3D template 、多视角等等。这些方法需要大量人力,所以很难广泛应用。
  3. 人类会直觉感知到一个物体包括各个部分,比如鸟有两只腿、两个翅膀、一个头,从而识别物体。类似的,cv受此启发,也可以将一个物体定义为多个可变形的部分的集合。

What:

  1. 仅需要单张图片+轮廓mask,利用语义一致性,实现自监督3D重建模
  2. 思路:1. 每个物体可以看作由可变形的部分组成;2. 对同一类型的不同物体,它们的每一部分在语义上都是一致的
  3. 通过自监督学习大量同类的图片,可以建立重建的mesh模型与图片之间的语义一致性。这样在同时预测形状、相机位置和材质的时候,可以降低模糊性。
  4. 第一个做到不需要特定类别的template mesh模型或者语义关键点,就可以从单视角图像中实现3d重建模。因此,这个方法可以推广到各种物体类别,而不需要类别的标签

读前疑问:

How:

模型

image-20220122145159190
image-20220122145159190
  1. (a)是原始图片。需要同一类别的大量图片一起作为输入
  2. (b)用SCOPS模型(另一篇工作),对图像进行语义分割的结果。这个模型也是自监督的
  3. (c)标准语义 uv map(Canonical semantic uv map):
    1. 理论上,同一类物体的mesh模型,尽管各自都有不同的形状,但每个点的语义含义都是一致的。
    2. 因此,根据前一步生成的大量语义分割结果,可以生成一张对应这个类别的Canonical语义uv map。
  4. (d)由前一步生成的Canonical语义uv map,可以得到重建的mesh模型表面的点对应的语义标签
  5. 橘色箭头:这个就是语义一致性了,它鼓励2D图像和3D模型之间的语义标签相互一致。这样,就可以解决前面提到过的在3D重建模的时候的“相机-形状不确定性”这个难题

具体方法

CMR是baseline

  1. 用三个decoder \(D_{shape}\ D_{camera}\ D_{texture}\) 同时预测mesh模型的形状、相机和材质
    1. 形状 \(V=\tilde V + \Delta V\),其中 $V $ 是某类物体的template mesh模型,\(\Delta V\) 是预测出来的点的偏移量
    2. 相机pose \(\theta\) 是 weak perspective transformation (?)
    3. 材质 \(I_{flow}\) 是 UV flow,是将输入图片到UV空间的映射,然后它可以被一个已经定义好的函数\(\phi\)映射到mesh模型的表面的每一个点
  2. 但是CMR需要人工标注的关键点作为输入,这篇论文主要就是把它去掉了。去掉之后呢,会出现相机+形状同时预测时Ambiguity的问题,所以就想方设法解决这个问题。
image-20220122160143711
image-20220122160143711

语义一致性:解决相机+形状同时预测时的Ambiguity

也就是Fig 3中红色框的部分。

  1. 语义部件不变性 semantic part invariance:

    1. 对于2D图像,用SCOPS(自监督co-part语义分割,另一篇论文的方法)可以很准确地对物体各个部分进行分割
    2. 对于3D mesh,每个点的语义含义是固定不变的,就算每个物体会有各自的形变
  2. 语义一致性

    1. image-20220124121618081

      从Fig 4 (i) 可以看到,如果没有语义一致性,mesh模型中原本对应头的顶点被当作了翅膀尖,这样错误的变形对应了错误的相机pose。这就是相机+形状同时预测时的Ambiguity。

    2. 前面已经提到过,可以为每个具体类别生成一张标准语义 uv map(Canonical semantic uv map)。这里,就可以让 每个物体的2D语义分割结果 与 标准语义 uv map 保持一致性,从而让3D模型的每个语义部件跟2D图像里相应的位置有对应关系。这样可以很好地解决相机-形状Ambiguity问题。

通过SCOPS实现2D图像中部件的分割

image-20220124114332065

SCOPS 是自监督的方法,从一类物体的大量图片中发掘共同的语义部件。Fig 10第二行就是它的结果。后面还会提到,通过本文的方法,还可以反过来提升SCOPS的结果:利用生成的标准语义UV map作为伪标注反过来进行监督。

通过标准语义uv map实现3D模型中部件的分割
  1. 已经有了:

    1. 模型学到的texture flow \(I_{flow}\)可以将输入图片映射到UV空间,然后它可以被一个已经定义好的函数\(\phi\)映射到mesh模型的表面的每一个点
    2. 通过SCOPS生成的图像 \(i\) 的语义分割结果 \(P^i\in R^{H\times W\times N_p}\), 其中H和W是长和宽, \(N_p\) 是语义部件数量
  2. 这样的话,通过模型的 \(I_{flow}\) 就可以把2D的语义分割结果 \(P^i\) 映射到 UV 空间,把这个称为 语义UV map

  3. 理论上来说,同一类别的所有物体都应该得到同一个语义UV map,因为 1. 根据语义部件不变性,mesh模型的每个顶点对应的语义部件都是固定不变的 2. UV map和3d mesh 中的点又是通过\(\Phi\)映射的关系,每个顶点对应的UV map上的坐标也是不变的。

  4. 但是因为SCOPS + \(I_{flow}\) 的误差,各个物体生成的语义UV map事实上很不一样。所以这里提出了对 标准语义UV map \(\bar P_{uv}\) 的估计方法:

    1. 通过某种方法选择出训练集中效果比较好的子集 \(\mathcal{U}\),对它们的结果进行加和,

      选择样本的方式

      1. 首先选择最好的那一个样本,即 perceptual distance(3D投影到2D的图像与原始RGB图像的知觉距离?)最小的
      2. 然后选择K个跟这个最好的样本最接近的样本,即它们的语义UV map最接近

      公式如下:

    2. \[ \bar P_{uv}=\frac{1}{|\mathcal{U}|}\sum_{i\in \mathcal{U}}I^i_{flow}(P^i) \]

      其中 \(I^i_{flow}(P^i)\) 就是通过 \(I_{flow}\) 映射语义分割结果 \(P^i\) 得到的 语义UV map。

2D 和 3D 间的语义一致性
  1. 基于概率的约束 Probability-based constraint

    1. \[ L_{sp}=||P^i-\mathcal{R}(\Phi (\bar P_{uv});\theta^i)||^2 \]

      标准语义UV map \(\bar P_{uv}\) 由预定义好的函数 \(\Phi\) 映射到 3D mesh表面,然后采用预测好的相机pose \(\theta^i\) ,用可微分渲染 \(\mathcal{R}\) 将3D模型渲染到2D,然后将结果与对应的由SCOPS生成的部件分割概率图 \(P^i\) 做均方误差。

    2. 注:这个由SCOPS生成的图像分割结果 \(P^i\) 是概率数值的形式

    3. 经验性地选择了采用均方误差MSE,比 KullbackLeibler divergence 效果好

  2. 基于顶点的约束 Vertex-based constraint

    1. 让3D模型投影回2D之后,被分类到某个语义part的顶点仍然处在图像中该part对应的区域

    2. \[ L_{sv}=\sum^{N_p}_{p=1} \frac{1}{|\bar V_p|}Chamfer(\mathcal{R}(\bar V_p;\theta^i),Y_p^i) \]

      其中,\(\bar V_p\) 是已经学好的某类物体的template mesh中属于部件p的那部分,\(Y_p^i\)是原始2D图像中属于部件p的那部分,\(N_p\) 是语义部件数量。

    3. 用Chamfer distance是因为投影后的顶点和原始的像素点并不是严格一对一对应的关系

    4. 用某类物体的template mesh,就可以让网络学相机pose;反之,假如用单个具体物体的mesh的话,网络就仅仅会对3D物体的形状进行扭曲,不会学到正确的相机pose了【我有点不理解为啥】

渐进的训练方法EM

  1. 之所以要用渐进式训练,是因为

    1. 需要3D重建模网络首先学会一个大体上可用的texture encoder \(I_{flow}\),然后才能生成标准语义UV map,
    2. 这样还能先生成对应具体类别的template mesh,一方面加速网络的收敛,一方面可以用在前面提到的基于顶点的约束中。
  2. 但是,如果直接把template mesh和重建模模型全都一起学习的话,效果不好;所以就提出了:EM训练步骤(expectation-maximization期望最大化?),就是先固定一部分学习另一部分。

    1. E:固定标准语义UV map和template(初始是球体),训练重建模网络。200轮。

      loss包括:

      1. 3D投影到2D的图像与gt剪影的 IoU ✖️ -1

      2. 3D投影到2D的图像与原始RGB图像的 perceptual distance(知觉距离?)

      3. 前面提到的基于概率的约束和基于顶点的约束

      4. 材质循环一致性 Texture cycle consistency:

        1. image-20220124182432533
          image-20220124182432533

          学习texture flow的时候最大的问题:颜色相似的3D mesh的面会被对应到错误的2D图像的像素点上

        2. 这是一个cycle:强制预测出来的texture flow(2D to 3D)和相机投影(3D to 2D)二者一致。

        3. 首先定义了\(\mathcal{C}_{in}^j\)\(\mathcal{C}_{out}^j\)分别是输入图像中被映射到三角形面\(j\)的一定数量像素点的几何中心,和从三角形面\(j\)渲染回2D图像时对应的一定数量像素点的几何中心。公式如下: \[ \mathcal{C}_{in}^j = \frac{1}{N_c}\sum^{N_c}_{m=1}\Phi(I_{flow}(\mathcal{G}^m))_j; \\ \mathcal{C}_{out}^j = \frac{\sum^{H\times W}_{m=1}\mathcal{W}_j^m\times \mathcal{G}^m}{\sum^{H\times W}_{m=1}\mathcal{W}_j^m} \] 其中,\(\mathcal{G}^m\)是投影图像的标准坐标网格(包含了像素的坐标\((u,v)\)值),\(\Phi\)是UV map,\(I_{flow}\)把像素映射到3D mesh的面\(j\)上;\(N_c\)是对应到面\(j\)的像素点的数量;\(\mathcal{W}\)是可微分渲染时生成的概率map,每个\(\mathcal{W}_j^m\)表示面 j 被投影到像素 m 上的概率。

          • 把重建模mesh模型渲染成2D图像,用的是 Soft Rasterizer,而不是CMR中用的 Neural Mesh Renderer,因为前者可以提供概率map,供texture cycle consistency使用
        4. 那么,材质循环一致性就是让\(\mathcal{C}_{in}^j\)接近 \(\mathcal{C}_{out}^j\)\[ L_{tcyc} = \frac{1}{|F|}\sum^{|F|}_{j=1}||\mathcal{C}_{in}^j-\mathcal{C}_{out}^j||^2_F \]

      5. 还有写在附录里的两个loss:

        1. graph Laplacian constraint 来鼓励mesh表面平滑【从pixel-mesh中来的】
        2. edge regularization 来惩罚大小不规则的面 代码里似乎是flatten loss
      6. 还有写在附录里的对抗训练loss

    2. M:利用训练好的重建模网络,更新template(从球体开始)和标准语义UV map。

      1. template一开始是球体,然后每训练K轮,对它进行一次更新: \[ \bar V_t=\bar V_{t-1} + D_{shape}(\frac{1}{|\mathcal{Q}|}\sum_{i\in \mathcal{Q}}E(I^i)) \] \(V_{t}\)\(V_{t-1}\)是更新前后的template,I是输入的图片,经过E生成3D属性,D是形状 encoder。Q是经过某种方式选择出来的部分样本。

        选择样本的方式

        1. 首先选择最好的那一个样本,即与ground truth轮廓的IoU最小的
        2. 然后选择K个跟这个最好的样本最接近的样本,即这些样本的gt轮廓与最好的样本的gt轮廓的IoU越小则越接近
      2. 这样的话,template \(V_t\) 就是选出来的样本的平均形状

    3. 整个训练过程会包括两轮,每轮都包括一个E和一个M。(两轮分别就是代码中的train_s1 train_s2。)在E中,训练200 epoch 重建模网络,然后在M中用训练好的网络更新template和标准语义UV map。注意在第一轮中(一轮包括一个E和M),只训练重建模网络,而没有语义一致性约束。

实验

  1. 数据集:PASCAL3D+中的车和摩托车、CUB-200-2011中的鸟、ImageNet中的马 斑马 牛、OpenImages中的企鹅
  2. 局限性:
    1. 依赖于SCOPS提供语义分割,有时候语义分割不准确的话结果就不好
    2. 比较少见的相机pose很难
    3. 细节性的地方效果不好,比如正在飞的鸟的两个翅膀、斑马的腿等

Questions

  1. 为什么要stage2 ?

    1. 这两个 stage的主要区别就是:stage1的时候没有用语义一致性约束,在stage2才加上。因为一开始texture flow encoder效果并不好,avg_uv也不准确,所以干脆先不用。所以分成s1和s2,最主要的就是因为在s1训练完之后,重建模网络已经大体可以用了,这时候就可以调用avg_uv.py来生成标准语义UV map,供s2的时候语义一致性用。
    2. 附录里说,从效果上来看,2个stage比1个效果要好,且已经足够好了,有这张图对比了一下:image-20220127171646865
  2. avg_uv 就是学 seg map -> uv map的么?

    1. seg map -> uv map这个过程是重建模网络中texture flow这个部分做的事情
    2. avg_uv就是论文里说的 标准语义 uv map(Canonical semantic uv map):
      1. 理论上,同一类物体的mesh模型,尽管各自都有不同的形状,但每个点的语义含义都是一致的
      2. 因此,对于某一类物体的大量图像数据集(比如鸟),可以生成一张对应这整个类别的avg_uv
      3. 利用这个avg_uv,相当于是给整个类别的template打上了语义标签,后续计算语义一致性约束的时候可以用。
      4. 这个avg_uv的计算过程:
        1. 首先用SCOPS(另一篇工作,无监督的)生成所有图像的语义分割结果seg map,然后用重建模网络学到的texture flow映射成uv map
        2. 选择效果最好的一部分instances,对它们的uv map取平均,得到avg_uv
  3. paper 里面 有说固定camera 学shape? 那代码里有fix camera预测么?

    我好像没有读到paper里有具体说到固定camera学shape耶……

    论文里提到要解决camera-shape一起学时的ambiguity的问题,但不是固定一个学另一个,而是利用avg_uv来实现语义一致性:让 每个物体的2D seg uv map 与 avg_uv 保持一致性,从而让3D模型的每个语义部件跟2D图像里相应的位置有对应关系。

    image-20220124121618081

    从这张图里可以看到,如果没有语义一致性,mesh模型中原本对应头的顶点被当作了翅膀尖,这样的camera就是错误的,错误的camera又造成了错误的shape。而有了语义一致性,就能利用语义让camera 更准确,这样就能跟着提升shape

  4. 按照他的说法, 先是feature avg 然后 decode 出 average shape。那么这个feature就要学好一点,否则平均容易成球形。那么这个feature 还有其他loss在上面么?比如我们smr 上还有 consistency loss 但是加在 delta_vertice上?他有加在feature上么?否则不能确保这个 feature avg 了以后 还有意义

    我可能没有懂这个问题耶……学长说的是不是计算category level 的 template这个步骤呢?我觉得这个步骤里面保证效果好的方式有这几点比较关键:

    1. 更新category level 的 template是从M步骤才开始进行的;在此之前,E步骤中会在固定template的前提下,单独训练重建模网络200轮,这个过程中的loss还是挺多的,除了语义一致性没有用以外,其他的loss都用了,包括论文里提出的texture cycle consistency,还有附录里提到的graph Laplacian constraint、edge constraint等等
    2. 计算average template的时候,并不是用了所有数据,而是选择了最好的一部分instances:
      1. 首先选择最好的那一个instance,即与ground truth mask的IoU最小的
      2. 然后选择K个跟这个最好的样本最接近的样本,即这些样本的gt mask与最好的样本的gt mask的IoU越小则越接近
  5. 代码里面还放了一些 external的code,有用到么?

    1. 一个是SoftRas,用来把重建模mesh模型渲染成2D图像。论文里提到用它而不是CMR中用的 Neural Mesh Renderer,是因为它可以提供概率map,供texture cycle consistency使用
    2. 另一个是Neural Mesh Renderer,备选的renderer
    3. 再就是PerceptualSimilarity,用来计算了perceptual loss