可微分渲染技术在理论上(‘Differentiable Monte Carlo Ray Tracing through Edge Sampling’)得到解决后,在实际中还存在两个问题,一个是边缘检测的性能问题,另一个问题则是内存消耗过大,很难满足复杂场景对内存的需求。RGL团队在2019和2020分别发表了三篇针对可微分渲染的论文,‘Mitsuba 2’提供了可微分渲染的框架,上一篇介绍的论文‘Reparameterizing Discontinuous Integrands’针对边界性能差的问题,而这一篇论文‘Radiative Backpropagation’针对内存消耗大这个问题。
首先,论文解释了reverse-mode下autodiff分为两个阶段:
接着,给出light transport的measurement function:
该公式中的
是ray space,A是相机的image plane,p是其中的一点,而ω则是对应点p的solid angle。同时,
对应的反方向(outgoing)是
,r(p,ω)对应反方向相交的最近的一点:
上面的介绍后,又要写一便rendering equation了:
上式求导:
推导也很直观,算是本论文第一个贡献,term 1对应当光源发生变化时,发射出的differential radiance,term 2则是碰到物体后,对应材质发生变化时,发射出的differential radiance,term 3对应differential radiance遇到物体后的散射现象:
同时,对应measurement function求导:
接着,我们用Q(emission term)来记录term1 term2:
用K(scattering operator)和G(propagation operator) :
这样,类似传统的光路,我们对differentiation进行如下的推导(Neumann):
在Veach的论文中,证明了G,K以及GS满足self-adjoint,于是有了如下结论:
如上公式证明,类似传统的光路是可逆的,differentiable radiance一样是可逆的,而这里,
是标量,而Q是向量,因此,从左侧计算时可以大量的变量,这就是本论文的核心思想,证明了传统光路和微分光路之间的相似性。同时,论文也提到了对边界的处理,尽管论文中并没有考虑该问题,但边界问题同样需要转化为对光路的求导,然后再使用该思路,两者并不矛盾。
上图是对应的代码实现,在radiative_backprop_sample函数中,我们用adjoint方法分别计算Q中的L_e和f_s相对于场景参数x的导数(emitter部分)。
如上是unbiased的算法,论文中还给出了两个biased的优化,论文中给出了评价是’worse is better’。
第一是对Q的近似解:
这里,默认L_i的值为1,记作biased(1),好处是原先的L_i的计算是recursive,需要多次迭代,这种近似可以中断迭代。虽然是近似值,但实验发现这样的效果反而更好,给出了理由是MC本身就存在噪音,在这个情况下,方向本身更重要,而数值准确度的意义不大。
第二处近似的原因是构建light path时,很多计算步骤在reverse中是可以复用的,这样可以节约大量的计算消耗。基于这个思考,论文中尝试把primal和adjoint两个步骤合并在一起:在第i次迭代时,使用的是上次迭代输出的目标值y来优化当前迭代的参数x,这样,当每次迭代中Jacobian变化不大时,这个近似解的效果也很好,同时节省了很多计算记作biased(2):
再给出了unbiased的算法和两个biased的优化后,就是如何在Mitsuba中实现该算法。通常,path tracing在GPU中都是采用wavefront的架构,论文中说,wavefront这种方式下,在求导的过程中,因为生成脚本的读写操作会消耗带宽(个人理解是CPU和GPU之间的带宽)和内存的latency产生的瓶颈,因此megakernel的方式更好一些,而且现代的GPU设计中,硬件优化也往往侧重于megakernel的方式(个人并不认同这个观点,也可能是我对论文理解有差错)。因此,论文在应用中,主要的问题是如何将Mitsuba 2中的wavefront架构,改造为megakernel。这里主要也是牵扯到如何处理emission term Q,我们需要让这个过程不需要访问auto diff相关的动态的数据结构。
首先,Mitsuba 2中采用了JIT技术,只有在触发了同步指令时,计算指令才会编译并执行。在这里做了一个小的改动,此时我们不执行指令,而是生成执行指令的字符串,这个字符出会绑定到场景中的物体中,当物体在intersection时再触发执行。这样完成了对primal过程的提取。使用类似的机制,我们需要把adjoint过程也提取出来,我们需要声明要进行auto diff的output的变量
以及对应的参数
,声明这是backward的方式(reverse-mode),最后通过record记录这个一个原子函数(enoki::scatter_add),该过程会将求导的结果累加到
。
最后是实验结论。
第一是validation
(a)场景是对Cornell box场景的颜色求导,(b)是环境光下,对一个heterogeneous volume求导,(c)是对一个木板的纹理求导,实验结果显示,该算法和其他方法的结果接近。
第二个是纹理的优化
上图的复杂场景中,初始是一个火星地图的纹理,在迭代优化后,计算出对应的地球纹理。
该实验中还对比了之前Mitsuba 2中的测试场景,给出了新的算法的性能对比。综上对比,可见新的算法每次迭代的优化效率不比原先的方式差,而在时间上有着显著优势。
第三个是性能对比
文中给出了使用unbiased的方法和biased的方法的时间消耗。
上图是四个场景中不同的方式相比Mitsuba 2的性能优化的程度。
总结
本论文基于光路求导可逆,提供了一种新的方法,该方法不需要记录中间状态的脚本,从而极大的减少了内存开销,并将性能最多优化了三个数量级。