谈谈DeepSDF中AutoDecoder

内容同步发表于 知乎科创论坛

假装有个封面图

前阵子读了一篇关于三维重建的论文,是Facebook团队联合华盛顿大学发表在CVPR2019上的。这一论文尝试用神经网络去近似SDF函数(将在后面进行简述),进而重建三维模型。

在阅读过程中我对其中的AutoDecoder概念产生了一定兴趣,特此将一些随想记录下来。

在谈论AutoDecoder之前,我想先用最少的文字说说这个传说中のDeepSDF

用最简单易懂的语言来说,对于一个已知的三维模型,SDF(Signed Distance Function)就是一个三维空间中的函数,输入一个坐标点p_0 = (x_0, y_0, z_0),返回该点到三位模型表面的距离。同时这个距离是有符号的,一般来说,对于模型外面的点,距离为正,而模型内部的点则为负。或者从观察者的角度,如果点在表面面向观察者的一侧,则为正,在背离观察者的一侧,则为负。

引用DeepSDF论文官方的兔兔说明一下:


SDF函数

各个方法对于SDF函数的存储往往是离散的,比如将三维空间是做一系列的“体素”(类比二维空间的“像素”),每个体素中存储一个SDF值,之后尝试用体素中等于或接近零的部分重建一个三维表面。

而DeepSDF论文呢,则尝试将SDF解析为一个连续的函数。虽然文章把这一点作为一个创新提出(包括将模型表面视作SDF回归的决策边界),其实我觉得这个很早应该就有人想到了,因为根本上来讲,SDF本来就应该是一个连续函数才对,只是受制于各种原因,我们无法为每个三维物体写出这个连续函数的完整形式。这也就是DeepSDF的思路,用神经网络这个“万能插值机”去近似这一函数。

事实上我之前也想过这个方向,也相信许多人尝试过这个思路。不过就像大多数DeepLearning落地的应用一样,真正需要做的工作在于如何科学地编码输入输出,以及如何Encapsulate你自己的领域知识到神经网络的结构和训练过程当中去

文章一开始提出了一个显而易见的结构,就是直接拿个神经网络,输入坐标,输出SDF值,然后对每一个三维模型单独训练,充分发挥“插值机”的原始作用。不过显然,这种方法在现实中是很难应用的,因为对于每个新模型都要训练一个新神经网络,实在是太低效太不Generalizablism了,那么自然地,为了发挥深井网络Generalizability的优势,团队自然而然想到了使用一个Latent Vector去表示三维模型的原始形态,于是新的神经网络就变成了,给定一个用来表示三维模型的Latent Vector,附带一个用以查询的坐标点,返回这个坐标点所在位置的SDF值。

具体的神经网络结构和LossFunction的设计就不详述了,非常Straight forward,扫一眼论文就明白。

众所周知(并不)获得一个原始输入数据的Latent Vector Representation,大家最喜欢的方法之一就是训练一个AutoEncoder。然而DeepSDF则使用了一个稍有不同的东西,他们叫做AutoDecoder,故名思义,就是一个不训练Encoder的Decoder。

这里我想吐个大嘈,他们的论文说了一大堆不要Encoder的理由,比如AutoEncoder大家一般都只用一半而把另一半另一半扔掉什么的,说来说去没说到点上。强烈怀疑他们组提出使用AutoDecoder架构的人和最后执笔写论文的人沟通不畅。我自己读下来的感觉是,AutoDecoder的选用本质上是一个在FeedForward过程的速度,和数据本身潜在的复杂度和变数之间的取舍(如果我的理解有错,欢迎指正)

下面简单讲一下这个传说中の AutoDecoder:

AutoEncoder结构

如图所示,标准AutoEncoder的架构大体上是,一个输入,若干层(称为Encoder)之后有一个关键的瓶颈层(Code),瓶颈层后面若干层(称为Decoder)之后有一个和输入层长得一样的输出层。训练的时候努力让输出等于(甚至优于——比如修复类任务)输入,最后训练出来的瓶颈层,就是对输入数据的一种更紧凑的压缩,也叫做关于原始数据的Latent Vector。Latent Vector往往包含了原始数据最关键的那些信息,更加便于提取特征,等等等等。

而DeepSDF则提出,我们可以不要Encoder部分,而直接取用Decoder部分

这就很TM诡异了,如果我只有一个Decoder,我怎么知道哪个Latent Vector对应原始输入呢?

官方给出的示意图长这样:


Auto-encoder vs Auto-decoder对比

Hmm...不是很好懂,没错,不仅这图不太好懂,论文里的描述也乱七八糟,不过且慢,容我再画一张图:

Auto Decoder

这张图里,我们加入了一个额外的输入X \equiv 1,称为第0层,而 Code 层则是一个纯 Linear 层,那么第 0 层对 Code 层的权重W_0即是我们要的 Latent Vector。

另外,Decoder 不必是解码成原始数据的样子,而是只要解码成目标函数的输出(比如SDF值)就好了。

那么对于DeepSDF来说,其结构事实上可以理解成:

  1. 第 0 层是一个恒为1的输入,
  2. Code 层和要查询的(x,y,z)一起输入到后面的深度神经网络
  3. 最后输出SDF函数

而这个训练过程则是:

  1. 对每个模型i,初始化一个独立的Latent Vector v_i (嗯,原论文用z表示Latent Vector,不过为了避免和空间坐标点(x,y,z)产生迷惑,我在这里用v代替了)
  2. 然后对于每个((x,y,z),\text{sdf})^i样本,选择该Vector作为到Code层的权重,即W^i_{(0\to\text{code})} = z_i^\top
  3. 再对整个神经网络(包含W^i_{(0\to\text{code})})进行训练。

这样子训练下来,每个训练样本都渐渐就训练出了自己的Latent Vector,而Decoder则学习到了对每个Latent Vector,如何匹配其要查询的(x,y,z)对应的sdf值。

可是既然这样,每个训练数据训练出了自己独立的Latent Vector,那么面对新的数据(比如测试数据集)该怎么办?论文里轻描淡写了一个\text{argmin}_v,可是这个\text{argmin}是怎么做的呢?难道还是对每个新数据重新训练一番?!

这里不得不吐槽一下,这个项目不仅论文抓不住重点,代码也写得乱七八糟,读得人晕头转向,重建的核心部分居然还存在# TODO: why is this needed这样的注释。我准备过一阵子专门针对机器学习界软件工程基础薄弱,代码凌乱不堪的现象开一篇文章。

于是带着迷惑我又去看了一遍这个项目的源码,然后发现还真的(差不多)是这样 。。。

不过比起直接用(x,y,z)作为输入的那个版本,这个版本在面对新数据t的时候,锁定了整个Decoder,也就是说保持(v, (x,y,z)) \to \text{sdf value} 的映射不变,而只训练新的v_t^\top = W^t_{(0\to\text{code})},大大减少了需要训练的参数数量。并且因为Decoder经过之前的训练,已经包含了关于训练数据的先验知识,所以这次Latent Vector训练的收敛将会十分迅速。

其实这里面我有一个小小的疑惑,为什么不保留论文最开始的结构(只输入(x,y,z)),但是对于每个不同的模型,独立训练输入层对第一个隐藏层的权重,这样输入层对第一个隐藏层的变换可以视作一个“Latent Function”(对应“Latent Vector”的概念),将(x,y,z)的值变换为该模型对应的,隐空间下该点的特征。这样一来,神经网络的参数数量能够减少,并且也能够更好地表达Latent Coding和空间坐标之间的耦合关系。这一方面的比较和分析,如果有时间,我也有可能会去做一做。

所以,答案是,AutoDecoder的结构不能像AutoEncoder一样面对新数据时只需要一个Forward过程,而是需要根据后面的Decoder中隐含的先验知识,进行少量的训练,以找到一个Latent Code出来。

那么问题来了,为什么要使用一个无法进行实时推断而是每次都要训练的AutoDecoder来代替原有的AutoEncoder呢?

一个不那么具备说服力(但是论文里似乎确实提出了)的理由是,因为Decoder不必还原原始数据,而可以是近似目标函数,所以训练出来的Latent Vector,对于我们目标函数所需要的信息会更加友好。但是仔细想一想就会发现,如果我们直接使用原始数据进行输入,构建一个神经网络,然后在某一隐藏层拼接上(x,y,z)查询。那么训练之后,我们就可以得到一个在预测时只需要Forward过程而无需再训练的神经网络,而被拼接了(x,y,z)的那一层也就可以视作Latent Vector。

所以……用AutoDecoder的深层原因到底是什么?

于是我去费劲巴拉地又读了一遍他们的代码,着重看了看Reconstruction部分,想办法搞明白这个神经网络到底在做什么之后,谜题便渐渐解开了。

首先,这个模型在重建的时候到底在干什么?这个问题在我读论文和代码的时候一度困扰了我很久,尤其是在我看到这个预期输出是SDF Value的神经网络在 Test - Evaluation 阶段,依然在测试数据集中包含SDF Value进行训练。进一步捋顺之后我反应过来他们在神经网络中的那一步Evaluation,实际上是在衡量这个神经网络能构造出一个多好的Latent Vector来近似测试数据集中的SDF Value,而不是尝试计算Reconstruct Error。而在真正的表面重建过程中,这个收敛出来的Latent Vector将和任意输入坐标(x,y,z)一起得出一个SDF Value,进而实现任意精度的重建。

那么问题就逐渐明朗了,DeepSDF在做的事情,其实是对于有限精度采样的SDF数据,在包含先验知识的Decoder的帮助下,回归出一个连续的SDF函数,从而实现将有穷精度的数据转换成任意精度的查询器,以便进行精细重建。

返回来看这个AutoDecoder在测试数据上的训练过程(即寻找Latent Vector的过程),我们发现,可以将一个模型的所有采样点作为一个完整的epoch,而不是把单个模型的全部采样数据一股脑输入进去。这么做的好处是什么呢?

  1. 如果是AutoEncoder,为了得到代表一整个模型的Latent Vector,我们将不得不想办法统一模型原始数据的分辨率(比如每三个神经元代表一个采样点,那么一个模型最多只能有input_size / 3个采样点)。而对于AutoDecoder,一个模型对应的采样数量只影响其epoch的大小,而不会影响单个输入本身的尺寸,所以AutoDecoder的架构支持对每个输入模型有任意数量的采样点。
  2. 另一个非常重要的是,对于模型的采样点,一个显著的特征就是它是Orderless的,即你交换任意两个采样点的顺序,也不应当影响最终输出的结果。传统的神经网络结构并不是很善于解码orderless vector的输入,但是如果我们不将整个模型的所有采样点编码为一个巨大的input vector,而是将每个采样点作为一个input vector,整个模型的所有采样点作为一个epoch去训练,那么我们就可以应对这种orderless的特征了。

综上,我们可以得到AutoDecoder结构与AutoEncoder以及论文最开始提出的(x,y,z) \to \hat{\text{SDF}}结构(下面简称xyz结构)进行比较:

  1. AutoDecoder vs xyz结构:
    • 对于新的模型,可以比xyz更快速地收敛成一个可靠的查询器
    • 经过训练的Decoder包含了来自训练数据集的先验知识,使得对于SDF的回归并不是单纯地“插值”操作,而是考虑了模型本身附带的意义而进行的合理补全。
  2. AutoDecoder vs AutoEncoder
    • AutoDecoder能够处理任何尺寸的采样数据,而不必像AutoEncoder那样将一个模型的全部采样点包含在一个定长的input vector中
    • AutoDecoder将单独的Input Vector转换成Epoch的操作,使得采样的顺序能够被很好地解耦,适合处理orderless的采样数据
    • 相比AutoEncoder来说,AutoDecoder面对每一个新数据时都需要一个训练过程来找到合适的Latent Vector,无法在需要相对实时的领域应用

到这里,AutoDecoder的具体合适的应用场景,可谓呼之即出了。

不过最后我想说一个自己的疑惑,不知道大家怎么看待:

将单个模型的所有采样数据作为一个Epoch而非一整个Input Vector去获取Latent Vector的这一操作,是否因为神经网络的Independence Assumption而丢失了邻接节点的互相影响呢?

鄙人不才,没想到足够的支持或者否定,还希望大家讨论点拨

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,332评论 5 475
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,930评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,204评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,348评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,356评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,447评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,862评论 3 394
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,516评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,710评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,518评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,582评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,295评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,848评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,881评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,121评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,737评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,280评论 2 341

推荐阅读更多精彩内容

  • 五、Deep Learning的基本思想 假设我们有一个系统S,它有n层(S1,…Sn),它的输入是I,输出是O,...
    dma_master阅读 1,614评论 1 2
  • 查看原文 1 简介 Deep Learning最简单的一种方法是利用人工神经网络的特点,人工神经网络(ANN)本身...
    JinkeyAI阅读 6,731评论 0 4
  • AIOps探索:基于VAE模型的周期性KPI异常检测方法 作者:林锦进 前言 在智能运维领域中,由于缺少异常样本,...
    AIOPstack阅读 4,472评论 2 4
  • 激活函数(Activation Function) 为了让神经网络能够学习复杂的决策边界(decision bou...
    御风之星阅读 5,106评论 0 8
  • 关于借钱真是一个含糊的问题,很多人说绝不能借钱给朋友,很对。但是生活中朋友就是相互帮助的,信任的。当一个人借钱的时...
    兀升山阅读 504评论 2 4