3. 隐式函数与占用场建模

任务目标

构建一个最小可运行的隐式占用场模型:以二维平面坐标 (x, y) 和条件特征 z 作为输入,通过多层感知机(MLP)回归连续占用值 o ∈ [0,1],其中 o=1 表示空间被占据,o=0 表示空闲。本案例聚焦于隐式函数的核心思想——用神经网络替代显式网格存储,实现任意分辨率下的连续场查询。

实现方案

采用 PyTorch 实现一个 4 层 MLP。输入层接收 3 维向量(x, y, z),隐藏层使用 ReLU 激活,输出层经 Sigmoid 将结果压缩至 (0,1) 区间。训练数据由解析函数实时生成:以圆心 (0.5, 0.5)、半径 0.25 的圆作为真实占用边界,条件特征 z 表示圆心 x 坐标偏移量,从而验证网络对条件输入的响应能力。

完整代码

import torch
import torch.nn as nn
import torch.optim as optim

# 1. 定义隐式占用场网络
class OccupancyMLP(nn.Module):
    def __init__(self, input_dim=3, hidden_dim=64):
        super().__init__()
        self.net = nn.Sequential(
            nn.Linear(input_dim, hidden_dim),
            nn.ReLU(),
            nn.Linear(hidden_dim, hidden_dim),
            nn.ReLU(),
            nn.Linear(hidden_dim, hidden_dim),
            nn.ReLU(),
            nn.Linear(hidden_dim, 1),
            nn.Sigmoid()
        )

    def forward(self, x, z):
        # x: (N,2), z: (N,1) -> 拼接后输入
        inp = torch.cat([x, z], dim=1)
        return self.net(inp).squeeze(-1)

# 2. 生成训练数据(解析占用场)
def sample_data(num_points=2048, batch_size=256):
    while True:
        # 随机采样坐标 [0,1]^2
        coords = torch.rand(batch_size, 2)
        # 随机条件特征 z ∈ [0.2, 0.8](圆心 x 偏移)
        z = torch.rand(batch_size, 1) * 0.6 + 0.2
        # 真实占用:圆心 (z, 0.5),半径 0.25
        dist = torch.norm(coords - torch.cat([z, torch.full_like(z, 0.5)], dim=1), dim=1)
        occupancy = (dist < 0.25).float()
        yield coords, z, occupancy

# 3. 训练循环
model = OccupancyMLP()
optimizer = optim.Adam(model.parameters(), lr=1e-3)
loss_fn = nn.BCELoss()

data_iter = sample_data()
model.train()
for step in range(3000):
    coords, z, occ = next(data_iter)
    pred = model(coords, z)
    loss = loss_fn(pred, occ)

    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

    if step % 500 == 0:
        print(f"Step {step}, Loss: {loss.item():.4f}")

# 4. 验证:固定 z=0.5,查询网格点占用值
model.eval()
with torch.no_grad():
    test_z = torch.full((10000, 1), 0.5)
    grid_y, grid_x = torch.meshgrid(torch.linspace(0, 1, 100), torch.linspace(0, 1, 100), indexing='ij')
    test_coords = torch.stack([grid_x.flatten(), grid_y.flatten()], dim=1)
    pred_occ = model(test_coords, test_z).reshape(100, 100)

# 5. 判定标准:中心点应接近1,四角应接近0
center_val = pred_occ[50, 50].item()
corner_val = pred_occ[0, 0].item()
print(f"Center occupancy: {center_val:.3f} (expected ~1.0)")
print(f"Corner occupancy: {corner_val:.3f} (expected ~0.0)")
assert center_val > 0.9, "中心点应被预测为占据"
assert corner_val < 0.1, "角落应被预测为空闲"
print("验证通过:隐式占用场建模正确")

运行与验证

环境依赖:Python 3.8+,PyTorch 1.9+(CPU 版本即可)。

运行方式:将代码保存为 occupancy_mlp.py,执行 python occupancy_mlp.py。训练约需 10~20 秒(CPU)。

通过条件:程序正常结束且输出断言通过信息。训练过程中 Loss 应持续下降至 0.1 以下;最终验证输出中,中心点 (0.5, 0.5) 的占用值应大于 0.9,角落 (0,0) 的占用值应小于 0.1,证明网络已学会用连续函数表达该圆形占用场。

关键说明

  • 条件特征 z 直接控制圆心位置,验证了网络能根据条件输入调制输出场——这是隐式函数泛化到不同形状的基础机制。
  • 训练数据为实时采样生成,无需预存数据集;每次迭代使用新采样点,等效于无限训练样本。
  • 验证阶段在 100×100 网格上密集查询,展示了隐式表示的核心优势:可以任意分辨率查询,无需存储离散体素网格。