在自动驾驶和机器人感知领域,3D场景理解一直是核心技术挑战。传统基于激光雷达的占用网格(Occupancy Grid)方法虽然精度高,但成本昂贵且难以规模化。近年来,基于视觉的自监督占用预测(Self-Supervised Occupancy)逐渐成为研究热点,它仅需摄像头输入即可构建3D场景表示,但面临两个关键瓶颈:
TT-Occ提出的解决方案颇具创新性——将新兴的时空高斯泼溅(Spatio-Temporal Gaussian Splatting)技术与自监督学习结合,通过动态调整测试时计算量(Test-Time Compute)实现精度与效率的自适应平衡。我在实际部署自动驾驶感知系统时深有体会:静态场景用轻量级模型足够,但遇到复杂交通流时往往需要"临时增强"模型能力,这正是TT-Occ要解决的核心问题。
高斯泼溅本质是一种可微分的渲染技术,用3D高斯椭球作为基本几何单元。与传统点云不同,每个高斯单元包含:
时空扩展的关键在于引入时间维度参数化。假设第k个高斯单元在时间t的状态为:
math复制μ_k(t) = μ_k^0 + v_k·t + 0.5a_k·t²
Σ_k(t) = R_k(t)Λ_kR_k(t)^T
其中v_k和a_k分别是学习到的瞬时速度和加速度,R_k(t)表示随时间变化的旋转矩阵。这种参数化方式使得模型能够用少量高斯单元高效表征动态场景。
实际实现时会采用分层高斯泼溅树(HGST)加速渲染,将场景划分为不同LOD层级的体素网格,每个体素内维护一组高斯单元。测试时会根据相机运动速度动态调整渲染层级。
模型训练完全不需要3D标注,仅依靠多视角视频序列构建监督信号:
python复制L_photo = ∑|I_t(p) - I_t'(p')| + λSSIM(I_t(p), I_t'(p'))
其中p'是通过高斯泼溅得到的对应点投影坐标。
python复制L_depth = smooth_L1(d_rendered, d_pseudo)
python复制L_reg = λ1||a||² + λ2|v·a| + λ3|∇×v|
最后两项分别惩罚非惯性运动和旋转变换。
核心创新在于测试时根据场景复杂度动态调整计算资源:
python复制entropy = -∑(p*logp) # 渲染深度图的熵
flow_mag = ||optical_flow||₂
score = α·entropy + β·flow_mag
实测在nuScenes数据集上,相比固定计算量方法,TT-Occ在保持相同mIoU时减少37%平均计算开销。下表对比关键指标:
| 方法 | mIoU | 参数量(M) | 推理时间(ms) |
|---|---|---|---|
| OccNet(基线) | 58.2 | 42.1 | 120 |
| OG-Splat | 61.7 | 38.5 | 95 |
| TT-Occ(ours) | 63.4 | 40.2 | 76 |
高斯泼溅的并行化需要特殊处理,我们实现了以下优化:
cpp复制__global__ void render_kernel(
Gaussian* gaussians,
float* depth_buffer,
uchar4* color_buffer,
int tile_size) {
int tile_idx = blockIdx.x;
int pixel_in_tile = threadIdx.x;
// ... 每个线程处理tile内特定像素
}
python复制class GaussianRender(Function):
@staticmethod
def forward(ctx, gaussians, camera):
# 保存渲染所需中间变量
ctx.save_for_backward(...)
return rendered_image
@staticmethod
def backward(ctx, grad_output):
# 基于物理的近似梯度计算
return grad_gaussians, None
极端光照条件:
夜间或强反射场景下,光度一致性假设会失效。我们尝试引入事件相机数据作为补充信号,但需要修改高斯泼溅的光度模型。
长时序漂移:
超过200帧的连续预测会出现地图扭曲。解决方案之一是引入视觉定位模块提供全局约束。
硬件兼容性:
当前CUDA实现难以移植到车规级SoC(如Orin)。正在开发基于TensorRT的量化版本,目标是将延迟控制在50ms以内。
在KITTI和自定义数据集上的实验表明,这套方法有几个出乎意料的特性:
运动模糊的正面作用:
适度的运动模糊反而有助于模型学习更鲁棒的运动表示,因为模糊区域提供了连续运动的梯度信号。但需要控制模糊范围在3-5像素内。
计算分配策略的敏感度:
动态调整的阈值设置非常关键。我们发现用ReLU6缩放后的场景分数效果最好:
python复制threshold = base_th * (1 + 0.5*sigmoid(score/6 - 3))