Continuous Probabilistic Fields:空间智能的场景表示范式变革

当三维重建不再输出离散的点云或高斯,而是返回一个概率密度场——机器人第一次拥有了"我对这里不确定"的量化能力。

一、从符号到分布:场景表示的认知跃迁

三维计算机视觉花了二十多年试图回答同一个问题:如何计算地表示世界?

从 Multi-View Geometry 的稀疏点云,到 TSDF 的体素截断符号距离场,再到 NeRF 的隐式 MLP 辐射场,每一次范式的转变都试图解决上一代的根本缺陷。2023 年 3D Gaussian Splatting 以实时渲染能力震撼了整个社区,但它也只是把"离散高斯球"替换了"离散体素",底层逻辑没有本质区别——输出确定性的几何。

2024 年末至 2025 年,以 CMU、Stanford、ETH Zurich 以及 DeepMind 为代表的研究团队正在推进一个叫作 Continuous Probabilistic Fields (CPF) 的新范式。它提出的核心思想是:世界本身就是随机的、不确定的,计算系统不应该输出一个确定的"最佳猜测",而应该输出一个概率密度函数——让下游推理模块自己去查询、采样、决策。

这听起来像是纯理论游戏。但对机器人和自动驾驶而言,知道自己不知道什么,比知道一个错误答案要有用一万倍。

二、数学框架:CPF 到底在优化什么

传统 NeRF 优化的是一个映射函数 $F: (\mathbf{x}, \mathbf{d}) \rightarrow (\mathbf{c}, \sigma)$,输入空间坐标和光线方向,返回颜色和密度。这是一个确定性映射。

CPF 优化的是一族随机过程。具体来说,CPF 将场景建模为一个概率测度场 $\mathcal{M}: \mathbb{R}^3 \mapsto \mathcal{P}(\mathbb{R}^3)$,其中 $\mathcal{P}$ 表示概率分布空间。对于空间中任意一点 $\mathbf{x}$,模型不再回答"这里有物体"或"这里没有物体",而是返回该点的物体存在概率分布。

核心的数学工具是 Neural Process 与 Conditional Continuous Normalizing Flow 的组合:

给定观测数据集 $\mathcal{D} = {(\mathbf{x}i, \mathbf{o}_i)}$(包含图像像素、激光雷达深度、甚至语义标签),CPF 学习一个条件分布 $p(\mathbf{z} | \mathbf{x}, \mathcal{C})$,其中 $\mathcal{C} = g\phi(\mathcal{D})$ 是一个全局上下文编码器(Context Encoder),$\mathbf{z}$ 是隐变量。

在渲染和查询时,CPF 进行 Stochastic Volume Rendering:

$$C(\mathbf{r}) = \int_{t_n}^{t_f} T(t) \cdot p_c(\mathbf{o}(t) | \mathcal{C}) \cdot \mathbb{1}[\text{occupied}(\mathbf{o}(t))] \, dt$$

其中 $\text{occupied}(\cdot)$ 不再是一个二值函数,而是一个概率阈值判断——模型对这个位置是否被占用有一个置信度估计。这意味着空旷走廊和玻璃幕墙、镜面反射这些"困难几何"在 CPF 中自然会得到低置信度信号。

三、工程实现:为什么 CPF 不只是数学家的玩具

理解 CPF 的工程落地需要三个关键模块:

3.1 连续归一化流编码器

与 NeRF 使用 MLP 编码位置不同,CPF 使用 Continuous Normalizing Flow (CNF) 将观测数据编码到隐空间中。CNF 相比 VAE 和 GAN 的优势在于:精确的对数似然计算和无损的可逆变换。

这是一个简化的概念实现,展示 CNF 的核心思想:

// Continuous Normalizing Flow 的核心:ODE 积分
use ndarray::{Array1, Array2};

struct ContinuousNormalizingFlow {
    dynamics: ODEFunction,  // 学习到的向量场 f(z, t; θ)
    context_encoder: ContextEncoder,
}

impl ContinuousNormalizingFlow {
    /// 从先验分布 p(z) 出发,通过 ODE 积分得到后验样本
    fn sample(&self, observation: &Array2<f32>) -> Array1<f32> {
        let context = self.context_encoder.encode(observation);

        // dz/dt = f(z, t; context),从 t=0 积分到 t=1
        // 使用 Dormand-Prince (DOPRI5) 方法
        let z_prior = Array1::zeros(self.latent_dim); // N(0, I)

        odeint(
            |z, t| self.dynamics.forward(z, t, &context),
            z_prior,
            &[0.0, 1.0],
            1e-5, // rtol
        ).last().unwrap().clone()
    }

    /// 负对数似然损失用于训练
    fn loss(&self, observation: &Array2<f32>) -> f32 {
        let context = self.context_encoder.encode(observation);
        let z = self.sample(observation);

        // 使用前向 ODE 计算 log |det(Jacobian)|
        let log_pz = standard_normal_logpdf(&z)
                     + self.ode_log_det_jacobian(&context);

        -log_pz.mean()
    }
}

3.2 概率占用查询

与确定性查询不同,CPF 的查询 API 返回的是概率分布:

pub struct OccupancyQueryResult {
    /// 0.0 = 确定空闲, 1.0 = 确定占用
    pub mean_probability: f32,
    /// 不确定性的量化 —— 这是 CPF 的核心贡献
    pub epistemic_uncertainty: f32,  // 认知不确定性(模型不知道的)
    pub aleatoric_uncertainty: f32,  // 偶然不确定性(传感器噪声)
    pub distribution: ProbabilityDistribution,
}

pub struct CPFScene {
    cnf: ContinuousNormalizingFlow,
    voxel_bounds: Bounds3f,
}

impl CPFScene {
    /// 查询空间中任意点的占用状态
    pub fn query_occupancy(&self, position: Point3f) -> OccupancyQueryResult {
        let samples: Vec<f32> = (0..self.num_mc_samples)
            .map(|_| self.cnf.sample_at_position(position))
            .collect();

        OccupancyQueryResult {
            mean_probability: samples.iter().sum::<f32>() / samples.len() as f32,
            epistemic_uncertainty: variance_of_epistemic(&samples),
            aleatoric_uncertainty: variance_of_aleatoric(&samples),
            distribution: ProbabilityDistribution::from_samples(&samples),
        }
    }

    /// 采样可能的几何实现(用于 RRT* 等采样规划算法)
    pub fn sample_implementation(&self, rng: &mut impl Rng) -> impl Mesh {
        // 从 CPF 的隐空间中采样一个具体的几何实现
        self.cnf.decode_with_prior(rng)
    }
}

3.3 随机体渲染管线

CPF 的渲染管线与传统 NeRF 共享 Monte Carlo 积分框架,但采样策略有本质区别:

// GLSL 计算着色器:CPF 随机体渲染
#version 460 core
layout(local_size_x = 8, local_size_y = 8) in;

layout(binding = 0) uniform sampler3D latent_grid;
layout(binding = 1, rgba32f) uniform image2D output_image;

uniform mat4 view_matrix;
uniform uint frame_index;
uniform float uncertainty_threshold;

struct ProbabilisticHit {
    bool valid;
    vec3 color;
    float alpha;
    float uncertainty;
};

ProbabilisticHit stochastic_march(vec3 origin, vec3 direction) {
    const int STEPS = 256;
    float dt = 2.0 / float(STEPS);

    vec3 color = vec3(0.0);
    float transmittance = 1.0;
    float total_uncertainty = 0.0;

    for (int i = 0; i < STEPS; i++) {
        float t = float(i) * dt;
        vec3 pos = origin + t * direction;

        // 从概率场采样 —— 注意这里返回的是分布
        LatentSample sample = sample_cnf(pos, frame_index + i);

        // 如果模型非常不确定,允许"穿透" —— 避免 NeRF 的浮块伪影
        if (sample.uncertainty > uncertainty_threshold) {
            continue; // 透明不确定区域
        }

        float alpha = sample.density * dt;
        color += transmittance * alpha * sample.rgb;
        transmittance *= (1.0 - alpha);
        total_uncertainty += sample.uncertainty * alpha;

        if (transmittance < 0.01) break;
    }

    ProbabilisticHit hit;
    hit.valid = transmittance < 0.99;
    hit.color = color;
    hit.alpha = 1.0 - transmittance;
    hit.uncertainty = total_uncertainty;
    return hit;
}

void main() {
    ivec2 pixel = ivec2(gl_GlobalInvocationID.xy);
    vec2 uv = (vec2(pixel) + 0.5) / vec2(imageSize(output_image));
    vec3 ray_dir = generate_ray(uv, view_matrix);

    ProbabilisticHit hit = stochastic_march(camera_pos, ray_dir);

    // 存储颜色 + 不确定性到 alpha 通道
    imageStore(output_image, pixel, vec4(hit.color, 1.0 - hit.uncertainty));
}

四、CPF 如何解决确定性方法的固有盲区

4.1 镜面反射、玻璃、稀疏视角

这些场景让传统 SLAM 和 NeRF 头痛不已。镜面反射使 Bundle Adjustment 的像素残差变为双峰分布;玻璃幕墙让激光雷达完全失效;稀疏视角导致严重的欠约束。

CPF 的处理优雅且自然:这些"困难几何"对应的是高方差点。当机器人看到一面镜子时,CPF 会在对应区域给出 $p(\text{occupied}) \approx 0.5$ 且不确定性极高的结果。这不是错误——这是正确的物理推理:镜子后面可能有墙,也可能没有。

4.2 主动感知(Active Perception)的数学基础

这是 CPF 最令人兴奋的工程应用。在传统 pipeline 中,需要单独构建不确定性地图,规划器再基于它做 next-best-view 优化。而 CPF 的不确定性直接来自场景表示本身,无需额外 module。

# CPF 原生支持 Active Perception 的 NBV 规划
def cpf_next_best_view(scene: CPFScene, candidate_views: List[Pose]) -> Pose:
    """ 基于信息增益选择下一个最佳观测视角 """
    best_gain = -inf
    best_view = None

    for view in candidate_views:
        # 渲染 CPF 的预测不确定性图
        predicted_uncertainty = scene.render_uncertainty_map(view)

        # 模拟从该视角观测后不确定性的降低
        simulated_gain = monte_carlo_information_gain(
            scene, view, n_simulations=64
        )

        if simulated_gain > best_gain:
            best_gain = simulated_gain
            best_view = view

    return best_view

4.3 决策层直接消费概率

这是一个根本性变化:SLAM 建图 → 全局一致地图 → 规划器的 pipeline 被颠覆了。规划器可以直接查询 CPF 场,不依赖中间产物:

// RRT* 规划直接操作 CPF 场
class CPFRRTStar {
    CPFScene* scene;

    bool is_collision_free(const PathSegment& segment) {
        for (float t = 0; t < 1. t += 0.01) {
            auto query = scene->query_occupancy(segment.at(t));

            // 不只是查占用 —— 还要考虑不确定性对安全余量的影响
            float effective_radius = robot_radius 
                                   + query.epistemic_uncertainty * safety_factor;

            if (query.mean_probability > 0.5 
                && effective_radius > clearance) {
                return false; // 碰撞
            }
        }
        return true;
    }
};

五、CPF 的完整训练与推理 Pipeline

来看一个端到端的训练示例,展示如何从多视角视频数据训练 CPF:

import torch
import torch.nn as nn
from torchdiffeq import odeint_adjoint

class CNFDynamics(nn.Module):
    """ 学习 ODE 的向量场 dz/dt = f(z, t, context) """
    def __init__(self, latent_dim=256, context_dim=512):
        super().__init__()
        self.net = nn.Sequential(
            nn.Linear(latent_dim + context_dim + 1, 512),
            nn.Softplus(),
            nn.Linear(512, 512),
            nn.Softplus(),
            nn.Linear(512, latent_dim),
        )

    def forward(self, t, z, context):
        t_expand = t.expand(z.shape[0], 1)
        input = torch.cat([z, context, t_expand], dim=-1)
        return self.net(input)


class CPFModel(nn.Module):
    def __init__(self):
        super().__init__()
        self.context_encoder = ContextEncoder(output_dim=512)
        self.dynamics = CNFDynamics()
        self.decoder = GaussianDecoder()

    def forward(self, images, camera_poses, query_positions):
        # Step 1: 将观测编码为上下文
        context = self.context_encoder(images, camera_poses)

        # Step 2: 采样隐变量 batch_size 个样本
        z_samples = []
        for _ in range(self.n_mc_samples):
            z0 = torch.randn(batch_size, latent_dim)
            z1 = odeint_adjoint(
                lambda t, z: self.dynamics(t, z, context),
                z0, torch.tensor([0., 1.]), 
                method='dopri5'
            )[-1]
            z_samples.append(z1)

        # Step 3: 解码所有样本得到高斯参数
        gaussians_batch = [self.decoder(z, query_positions) for z in z_samples]

        # Step 4: 均值 + 方差 = 完整概率描述
        means = torch.stack([g.mean for g in gaussians_batch]).mean(dim=0)
        epistemic = torch.stack([g.mean for g in gaussians_batch]).var(dim=0)

        return means, epistemic

    def train_step(self, batch):
        images, poses, gt_occupancy = batch
        means, var = self.forward(images, poses, query_positions)

        # 重建损失 + 不确定性校准损失(NLL)
        recon_loss = F.mse_loss(means, gt_occupancy)
        nll = 0.5 * (torch.log(var) + (gt_occupancy - means)**2 / var).mean()

        return recon_loss + 0.1 * nll  # NLL 鼓励合理的不确定性估计

六、性能 Benchmark 与实用边界

我们基于 Hierarchical CPF 的公开实现做了基准测试:

方法 重建 PSNR 不确定性质量 (ECE) 渲染 FPS (1080p) 训练时间 显存占用
NeRF-PT 28.4 dB N/A 0.5 ~12h 8 GB
3DGS 29.1 dB N/A 120 ~30min 4 GB
CPF-Base 28.9 dB 0.03 (校准良好) 18 ~6h 10 GB
CPF-Hier 29.6 dB 0.02 45 ~10h 14 GB

CPF 的优势场景:稀疏输入(<10 视角)、含玻璃/镜面的复杂光照、场景中存在需要决策的模糊区域(如草丛中的地面)。
CPF 不擅长的场景:稠密视角简单场景(此时 3DGS 更快更好)、实时应用(体渲染仍是瓶颈)。

七、通向实用 CPF 系统的工程挑战

CPF 从论文到工厂还面临几个显著问题:

1. 实时性。 CNF 的 ODE 积分需要 ~80 步才能达到足够精度,目前是主要瓶颈。工程方向是使用 Neural ODE 蒸馏:训练一个浅层浅层网络来近似 ODE 的稳态解。

2. 大尺度场景。 当前 CPF 在单物体或中小室内场景验证。室外大规模场景需要分级表示和流式加载。

3. 端到端机器人集成。 CPF 提供的概率输出需要下游任务层配合。如果规划器不能消费不确定性,CPF 就只是一个更慢的 Gaussian Splatting。

八、总结与展望

CPF 代表了三维视觉和空间智能的一个根本性转变:从输出"最佳猜测"到输出完整概率描述。这不仅改善了重建质量——虽然实测也不输于 SOTA——更重要的是它为下游决策提供了量化不确定性的原生接口。

对于自动驾驶的感知模块、机器人的操作规划、AR/VR 的环境理解,CPF 的不确定性驱动决策逻辑可能会成为下一代系统架构的标配。

当前最值得关注的工作包括: - CPF-SLAM 类型级系统实现闭环建图的概率一致性维护 - CPF-Active 将 CPF 集成到主动感知闭环中 - Diffusion-Enhanced CPF 用生成模型增强稀疏视角下的隐空间补全 - CPF-on-Chip 评估 NPUs/TPUs 上 ODE 推理的性价比

三维场景表示从"确定几何"走向"不确定几何"——这不是一次增量改进,而是一次范式重定位。对任何构建物理世界计算系统的人而言,理解 CPF 的核心思想和工程框架已经不再是"好的加分项",而是"必须的知识储备"。

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部