尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

无监督单目深度估计:左右一致性如何用双目几何约束训练模型

无监督单目深度估计:左右一致性如何用双目几何约束训练模型 读深度估计论文就像给相机配眼镜刚开始觉得能对上就行后来才发现度数和瞳距才是命门。在无监督单目深度估计这个方向上有一篇绕不过去的经典工作用Left-Right Consistency左右一致性做训练约束的那篇论文。我第一次读它时还没意识到这套思路会深刻影响后面一大批自监督深度估计方案——大家逐步发现没有深度真值完全可以用左眼右眼之间的几何关系来互相约束训练结束后只输入单张图照样能输出一张很稳的视差图。这篇笔记就围绕这个方法展开适合正在入门无监督深度估计、以及打算在项目里复现和改造这类模型的人。1. 真值是个奢侈品但左右眼是免费的真值1.1 监督方案的天花板与无监督的破局点做单目深度估计这几年我最深刻的体会是障碍从来不在网络结构而在真值。如果我们走老路——监督学习就需要每一个输入图像都有对应的像素级深度真值。室外场景里想要密集的深度真值往往得靠激光雷达但雷达点云投影到图像后是稀疏的近处密、远处疏而且车辆、行人边缘经常被遮挡采集完还要花大力气做插值和对齐。室内倒是可以用结构光传感器可一旦搬到开放环境量程和光照又会让你怀疑人生。换句话说大规模高质量深度真值是典型的奢侈品。正是这种成本焦虑逼出了无监督方向。破局点是与其花大价钱获取深度真值不如重新想一下“深度”这个变量从哪里来。一个很自然的便宜来源是双目立体图像对。两台相机固定基线、标定生产同一空间点在左右图上的位置差异就是视差而视差和深度是代数关系。两个视角之间天然存在几何约束不需要人工标注。但这里有个难解的地方如果只是要在训练时用左右图做立体匹配传统立体匹配算法已经做了几十年为什么还要神经网络因为目标不一样。传统立体重建要求在推理时也同时拿到左右图而单目深度估计希望在推理阶段只有一个摄像头、一张图的情况下仍然能从过往数据中学到“深度长什么样”的先验。也就是说左右图对只是训练阶段的免费几何真值网络的最终输出能力是单目场景下的深度估计。1.2 立体对、视差与单目网络的奇怪组合要理解左右一致性先得把“视差”这个概念聊透。在理想的双目相机模型里左右相机只存在水平方向的基线位移那么空间点投影到左右两幅图像时同一行的水平坐标会有一个偏移。这个偏移量叫视差d近处的物体视差大远处的物体视差小。由相机焦距f和基线长度B深度z f * B / d直接换算。于是有了一个非常好的近似如果某个像素的预测视差是对的那么把这个像素按照视差移动到右图对应的位置取到的颜色应当和左图原像素几乎一致。如果视差预测偏了取到的颜色会错得离谱。于是深度预测问题变成了图像重建问题预测视差图把一张原图按视差重投影成另一张图然后比较重建图和目标图像之间有多像。这个方法的核心思想就是用左右图的“互相可解释性”替代深度真值。网络在学什么它本质上在学一个能同时满足两件事的视差图一是把左图重投影成右图时像二是把右图重投影成左图时像。两条重投影路径如果都能走得通那么这张视差图基本上就是几何上自洽的。正是这个自洽约束让网络在没有真值的情况下也能产生相当干净的深度图。2. 网络在学什么一张视差图与一条可微重投影通道2.1 结构上的一处关键设计同时看左右却只输出一对视差看原论文的结构时我第一个注意到的是输入不是单张图。网络训练时输入的是左图和右图拼在一起的6通道图像输出端则同时输出两个通道左视差图D_l和右视差图D_r。这在当时看来是个很反直觉的做法——既然目标是单目深度估计为什么训练时还要把右图喂进去原因恰恰就在“左右一致性”里。如果网络只输出左视差那它只是从右图重投影左图网络完全可以钻空子它对右图不认识所以只学会了“从右图采样出一个像左图的结果”却不一定真的理解几何。而同时输出左右两套视差再把两套视差之间的几何一致性作为额外损失等于逼着网络同时从两个方向理解立体关系。左视差和右视差不再是两个独立的预测而是互为镜像、互相校验的同一个三维结构的两种投影。这种共享编码器的做法还有一个附带好处左右两个视差图共享同一个特征空间不会出现左眼学一套、右眼学一套的分裂局面。后来很多复现把它改成双分支共享编码器的结构效果大体一致但核心思想没有变——左右几何一致性必须被写进损失函数里而不是指望网络自己领悟。2.2 为什么输出的是视差而不是深度论文里最值得琢磨的设计选择是让网络输出视差图而不是直接回归深度图。第一个原因是尺度问题。深度值的变化范围非常大从贴近镜头的几十厘米到远处的几百米直接回归深度网络在近处和远处的误差尺度完全不一样。而视差是归一化的像素位移数值范围小且线性更容易落入神经网络偏爱的激活区间。第二个原因是形式匹配。左右重投影约束天然定义在视差上重投影时使用的就是“某个像素移动了多少像素”而不是“这个点有多远”。在视差空间里写重投影损失不需要关心相机内参也不需要每次计算前把深度换算成视差。但有一个代价绕不开视差图恢复出来的深度天然带着尺度的模糊性。单张图像本身没有绝对尺度一个近的小物体和一个远的大物体可以投影成同样大小。好在左右图训练时用了真实的立体基线网络在训练中接触过真实的像素位移量所以当测试相机的内参、基线和训练相机一致时输出的深度能接近度量尺度。一旦换成另一套相机的配置深度尺度就需要重新标定。这个坑我在实际测模型时踩过后面细说。2.3 可微重投影是这个方法能训练起来的最后一块拼图前面说“按视差去另一张图采样”听起来简单真正实现时有个技术门槛采样必须是可微的否则网络拿不到梯度。普通图像采样是按整数坐标取像素比如(x, y)取源图坐标但预测出的视差是浮点数x - d大概率不是整数坐标。如果直接用四舍五入取整梯度根本传不过去。论文使用的方案是双线性采样——一种可微的插值方式。采样点周围的四个像素按距离权重加权求和权重对坐标的导数是可以计算的于是误差信号能顺利回传到视差图上。可以把这个过程想象成在老板的Excel表里用公式而不是数值只要你改一个单元格所有依赖它的单元格都会自动更新结果。双线性采样就是那个“公式通道”它让整个网络变成一个大号的、可微的“视图合成器”输入左右图中间是预测视差输出为重建图重建图与真实图之间的误差一路透过采样公式传回视差预测层。这一步是整个方法能训练起来的决定性细节。如果采样不可微再精妙的左右一致性损失都只能看不能用。很多初学者复现时最容易卡住的地方也在这里拿grid_sample或自定义双线性采样时必须确保采样网格坐标的单位、方向与视差定义一致否则训练时看起来在下降实际重建图早就歪了。3. 三个损失函数一起工作从“重建像”到“几何一致”原文最大的贡献是把无监督深度估计的训练目标拆成了三个互相咬合的损失光度一致性损失、视差平滑损失、左右一致性损失。三者不是简单相加而是各管一个层面的“不变量”。3.1 光度一致性损失先把重建图长成原图的样子第一个损失是重投影后的图像和目标图像之间的外观匹配损失。最常见的组合是 L1 损失加 SSIM结构相似性指数。公式上大概长这样appearance_loss 0.85 * (1 - SSIM(重建图, 目标图)) / 2 0.15 * L1(重建图, 目标图)为什么要两个一起用L1 对颜色整体偏移敏感但容易忽视局部纹理结构SSIM 对亮度变化更鲁棒更关注梯度结构但单独用 SSIM 又容易出现颜色整体漂移。两个加权组合后在光照变化和传感器噪声下要稳得多。论文把 SSIM 权重定在 0.85这个数值我当时没在意后来在不同数据集上调参才发现0.85 左右确实是一个很难被推翻的甜点位——因为它恰好保持了边缘锐度又不过度惩罚亮度偏差。这个损失隐含的假设是场景是朗伯体、左右相机光照一致、场景静止。满足这些条件的像素重建误差越小视差越可信。问题在于现实场景几乎处处违反这些假设车窗反光、运动物体、边界遮挡。所以后面所有自监督深度模型的工作重心几乎都压在“怎么处理这些违反假设的像素”上。3.2 边缘感知平滑损失把噪声梯度从深度图里清出去如果只有光度损失网络会在纹理稀疏的区域摆烂。想一想纯色墙壁、天空或者路面——从重建的角度看这些区域任何视差值都能找到相似颜色损失几乎给出零梯度。于是网络会随机输出剧烈的视差抖动表现为深度图上密集的噪声斑块。解决办法是给视差图加平滑损失惩罚视差图在 x、y 方向的一阶梯度强迫它尽量平缓。但直接全图拉平很笨会把物体边缘的真实深度断裂也抹掉。所以论文给平滑损失加了一个用输入图像梯度做成的权重smooth_loss |∂D/∂x| * exp(-|∂I/∂x|) |∂D/∂y| * exp(-|∂I/∂y|)意思是输入图像边缘处梯度大视差可以剧烈变化输入图像平坦处梯度小视差必须平滑。这个设计很聪明它把“深度边缘”和“图像边缘”做了弱关联既不惩罚真实边界又能清理平坦区域的噪声。实操上有一个隐蔽细节输入图像梯度的权重需要detach也就是不要让这个权重本身参与梯度回传。原因是网络为了降低平滑损失会反过来修改输入图像梯度的利用方式导致图像纹理被错误抑制。这一步我在复现时漏掉过结果训练中期路面出现了一大片纹理异常排查了很久才定位到是梯度反传路径的问题。3.3 左右一致性损失两个视角互相咬合的最后一道锁前两个损失加起来其实已经能让网络输出一个看起来不错的视差图重建得够像、区域够平滑。但只靠这两项左右两套视差之间仍然可能是各自为政的。于是论文引入了第三个也是本篇真正的主角——Left-Right Consistency Loss。左右一致性的直觉是如果左视差图在某个像素认为物体视差为d那么把左图这个像素按d移动到右图对应位置后右视差图在那个位置的值应该和d相差无几。换句话说从左右两个方向看同一个三维点看到的视差应该是同一个数。损失就是这两个视差之间差异的绝对值lr_loss |D_left - D_right_flipped|其中D_right_flipped是把右视差图按左右方向做几何对齐后的结果。这个损失的威力在于它是纯粹的几何一致性约束不需要任何图外观信息。它强制网络在左右两个视角之间做出同一个空间结论而不是各自“看起来合理”。正是这个损失让整张深度图变成一个互相牵制的整体只要左视差和右视差有一处对不上梯度就会同时修正两侧。这也是为什么该方法在许多无纹理区域和重复纹理区域比单纯的光度法表现更稳——即便颜色上完全没有信息左右几何关系仍然在监督。我做一个表格把这三种损失的作用和弱点整理出来读代码时对照着看会清晰很多损失监督信号主要作用主要弱点光度一致性左右原图与重建图的相似度让视差符合像素视角对应遮挡、反射、动态物下失效视差平滑视差梯度 图像梯度权重清理平坦区域噪声保持边缘细长结构容易被压平左右一致性左右视差互相映射的差异保证两个视角几何自洽遮挡区域被硬性要求一致4. 那些论文里没有明说但会影响成败的训练细节4.1 最大视差范围决定网络表达能力的上限论文在输出视差时不是让网络直接回归任意大数值而是通过 sigmoid 激活把视差限制到一个最大范围。常见的设置是最大视差约为图像宽度的 0.1 倍输入宽度为 512 时最大视差大约 51 个像素。这个细节非常关键。最大视差设得太小近处大视差的物体比如紧贴镜头的栏杆、前车车尾会被硬性截断深度图看起来发糊设得太大网络把大量表达能力浪费在极近处远处小视差的区分度变差。如果按图像宽度比例来设在不同分辨率之间迁移时网络的经验可以直接平移。我在实际训练里还有一个体会最大视差应该结合数据集的“最近有效深度”来调。训练集中最近物体的距离决定了最大视差的实际值如果你的任务里相机离物体最近可以到 30 厘米而默认按 0.1 倍宽度设置很可能把贴脸物体直接抹掉。这个数值值得作为超参数单独扫一遍。4.2 超参数从哪里起步比较稳网络结构之外训练超参也很影响结果。论文以及后续大量复现使用的组合基本比较一致Adam 优化器初始学习率大约 3e-4批次大小 8 到 12输入分辨率 512x256训练轮数在 40 到 50 个 epoch 之间。学习率在后半段做衰减。损失权重方面一个比较稳的起步配置是total_loss appearance_loss 0.1 * smooth_loss 1.0 * lr_consistency_loss也就是说光度损失和左右一致性损失为主平滑损失的权重控制在 0.1 左右。我调过的任务里平滑权重低于 0.05 时深度图会出现细密噪声高于 0.3 时物体边缘会被越抹越平尤其是细栏杆、树叶这些结构。左右一致性权重也不是越大越好因为遮挡区域本来就是矛盾的权重过高会逼着网络在遮挡边界做出扭曲的视差来强行满足约束。4.3 边缘填充、遮挡区域和数据分布里藏着的坑训练时重投影采样会遇到图像边缘越界。常见的三种处理方式零填充、最近邻填充、镜像填充。零填充是最省事但最坑的——它会在图像边缘产生一排不存在的黑边网络很快会学会用错误的视差来抑制这些黑边产生的误差边缘深度会出现严重伪影。前后对比下来最稳的是镜像填充它不引入真实世界中不存在的颜色给边缘一个相对自然的延续。遮挡区域则是左右一致性的天然痛点。前景物体左侧或右侧的像素在另一个视角里根本没有对应点左右一致性规定那里必须一致这本身体现就是一个过度约束。早期实现通常不做遮挡掩码所以边缘处会出现某种“妥协”——深度值被推到一个两边都不太满意、但误差可接受的中间值。后来的自监督方法比如引入最小重投影损失、自动遮挡掩码的那一批很大程度上就是为了修补这里。数据分布同样要小心。用双目图像对训练的模型会被训练数据里的相机配置“驯化”。如果你只用一种固定基线的双目数据模型对近处和远处的尺度感受就会偏难实测其他相机时输出深度缺少度量意义。至少要保证训练集中的场景包含丰富的近距离物体和远距离远景否则网络只在某个深度区间里“舒服”区间之外全部胡猜。5. 测试阶段还能再薅一把左右一致性的羊毛5.1 左右一致性作为质量图哪里能信哪里不能信这个方法有一个非常划算的隐藏福利训练时算过的左右一致性在推理时也能继续用来判断每个像素的可靠性。测试阶段如果手里仍然有左右图可以分别拿到左视差图和右视差图然后做一轮反向映射计算每个像素的左右一致性误差。误差小的位置说明两个视角对该点的深度结论一致可信度高误差大的位置通常落在遮挡边界、反射区域或动态物体附近可信度低。这张“可信度图”不需要任何额外网络直接从网络的几何输出中算出来。这个特性在很多落地场景里很实用。比如在边缘检测、点云滤波、立体匹配后处理里可以用它把不可靠的深度点过滤掉避免下游任务拿到一堆边缘毛刺。哪怕只做可视化我也建议把左右一致性误差画出来它比深度图本身更容易暴露模型在哪些局部犯傻。5.2 测试期视差融合不增加额外网络但提升明显论文在推理时还做了一步后处理利用左右一致性把左视差图和右视差图的互补信息融合起来。因为遮挡区域里左视角看不到的点在右视角可能能看到两套视差各自的错误区域往往互补。于是可以做一个加权融合——左右一致性误差小的像素给高权重误差大的给低权重再把两套视差按权重合成一份最终视差。这样做的收益很直接边缘更连贯遮挡边界的毛刺更少整体平滑度提升。关键是这一步和训练完全无关不需要重训网络只需要在推理时多算一次重投影和一致性误差。我在测试中对比过融合前后的深度图融合后的边缘抖动明显减少尤其是在远处天际线和车辆侧面这些区域。注意一个前提要享受这个融合收益推理时仍然需要同时输入左右两幅图。如果你的产品形态是纯单目相机、推理时只有一张图那这部分后处理就用不上但训练阶段学到的几何先验仍然保留在模型里所以单图推理时深度图依然可看。6. 这方法撑得起什么场景又在哪些场景露怯6.1 失效场景分析不只是争议而是几何先验的边界没有一种方法是万能的左右一致性非常依赖几个隐式假设一旦场景突破这些假设模型会迅速失去可靠性。第一个软肋是动态物体。光度一致性损失要求“同一个三维点在左右视角中颜色一致”但一辆正在行驶的车在左右两个图像中的外观和位置本身就因为运动而不一致重建误差完全不可信。左右一致性损失也管不住它因为两个视角看到的根本不是一个静态世界。所以行人、车辆穿行的城市道路场景早期这类方法的效果会明显下降。第二个软肋是反射、透明和细长结构。车窗会倒映背景重建出的图像可能因为反射完全对不上细长的电线、栏杆在低分辨率下几乎没有足够的纹理锚点平滑损失会把它们压成整片平滑的区域。第三个软肋是训练分布本身。换一个相机基线、换一个分辨率深度尺度和表达能力都可能需要重新适配。理解这些边界比背诵损失公式更重要——至少接手一个项目时你能第一时间判断它适不适合用左右一致性的方案。6.2 后来者往哪里改从左右约束到多帧约束的演进线索读这篇论文时最好把它的位置放在演进脉络里看。它的核心贡献是把“左右几何自洽”变成了训练信号后继工作基本沿着三条线扩展。第一条线是把“左右两帧”扩展成“连续多帧”。既然左右两帧可以作为监督那视频里前后多帧也可以——于是出现了用位姿网络估计相机运动、把相邻帧重投影到当前帧的系列方法。第二条线是处理动态物和遮挡。后来的最小重投影损失和自动遮挡掩码本质上就是给光度一致性加了一个“只信误差最小的那个视角”的开关。第三条线是引入传统立体匹配的先验作为辅助信号也就是深度提示的思路把经典算法的计算结果和网络学习结合起来。回看这些演进最让我感慨的是后来的工作改得很大但核心框架基本没变一种几何上合理的监督信号 可微重投影 一组处理边界的正则项。只要理解这篇论文的损失设计思路读后续那些五花八门的无监督深度估计工作时会快很多。6.3 我最后留在这篇论文空白处的几行批注如果让我给这篇论文一个标签我会写“无监督深度估计的分水岭”。它不一定是最早提出用重投影做自监督的但却是把左右一致性做成完整训练框架、并带领一批后续工作转向几何自监督的代表性工作。我个人复现和改造下来最深的体会是与其死记它用了哪些损失项不如理解它为什么把这三项损失绑在一起。光度损失提供像素级外观证据平滑损失提供结构先验左右一致性提供几何互锁——三者在训练中互相补偿。很多后来失败的魔改几乎都是把其中某一项权重拔得过高、或者为了工程简化扔掉了左右一致性。我的建议也很简单如果你打算把这个模型用到自己的项目里不要一上来就追求 SOTA 指标。先在小数据集上把三个损失逐一打开观察每个损失对最终重建图的影响。左右一致性方法的一大优点是它的训练曲线非常稳定——三个约束互相牵制比单 loss 更容易收敛。这大概也是它能成为经典的重要原因。等你把三个损失如何协作的体感建立起来后面的模型改进才有扎实的地基。
返回列表