3、深度学习基础回顾:卷积神经网络、全连接网络、激活函数、损失函数、优化器,以及如何迁移到点云处理
在正式进入 PointNet 的模型结构与训练流程之前,有必要系统回顾深度学习的核心组件。PointNet 并非凭空出现的全新架构,它本质上是将全连接网络(MLP)、卷积思想(共享权重)、激活函数、损失函数与优化器在无序点集上的重新组合与适配。理解这些基础模块在图像领域的运作方式,再对比它们在点云处理中的变形与约束,是掌握 PointNet 的关键路径。本章将从五个核心组件出发,逐一剖析其原理、在点云场景中的迁移方式,以及常见的工程陷阱。
3.1 卷积神经网络:从滑窗到共享权重
核心原理:卷积神经网络(CNN)的核心设计理念包含两个关键点:局部感受野与权重共享。在图像处理中,卷积核在二维空间上滑动,每个位置的输出仅依赖于输入的一个局部区域,同时同一个卷积核在所有空间位置复用。这种设计大幅减少了参数量,同时天然具备平移等变性——物体在图像中移动时,其特征响应也随之移动。对于 224×224 的 RGB 图像,第一层卷积若使用 64 个 3×3 卷积核,参数量仅为 64×3×3×3 = 1728 个,而全连接层处理同样输入则需要 224×224×3×64 ≈ 960 万个参数。
迁移到点云:点云数据不具备规则的网格结构,点与点之间没有固定的邻域关系,因此无法直接使用滑窗卷积。PointNet 采取的策略是“逐点共享 MLP”:将每个点视为独立样本,使用共享权重的多层感知机对每个点进行特征提取。从实现角度看,这等价于对形状为 [B, N, C] 的点云张量执行 1×1 卷积(或 Conv1D),其中 B 为 batch size,N 为点数,C 为特征通道数。1×1 卷积在通道维度上做线性组合,不跨点操作,因此天然满足置换不变性——无论点云中点的顺序如何打乱,每个点的特征提取结果不变。
工程实现对照:在 PyTorch 中,PointNet 的共享 MLP 通常使用 nn.Conv1d(in_channels, out_channels, 1) 实现。输入张量形状为 [B, C_in, N],输出为 [B, C_out, N]。这与图像卷积的区别在于 kernel_size=1,即不聚合邻域信息,仅做逐点通道变换。
常见误区:初学者容易将点云中的“卷积”理解为对点云体素化后的 3D 卷积。体素化确实可以复用标准 3D CNN,但会引入量化误差、内存爆炸(稀疏体素除外)以及分辨率与计算量的矛盾。PointNet 的共享 MLP 方案避免了体素化,直接处理原始点坐标,但代价是丢失了局部邻域结构信息——这是 PointNet 后续版本(如 PointNet++)引入局部区域划分的动机。
3.2 全连接网络与特征聚合
核心原理:全连接网络(MLP)的每一层将输入的所有维度与输出的所有维度进行全连接,通过矩阵乘法与偏置项实现特征变换。MLP 擅长将高维稀疏特征映射到低维密集语义空间,或反之。在分类任务中,最后一层 MLP 通常将特征向量映射到类别数维度,配合 Softmax 输出概率分布。
在 PointNet 中的角色:PointNet 的架构中,MLP 出现在两个关键位置:一是逐点特征提取阶段(与 1×1 卷积等价),二是全局特征分类/分割头。逐点 MLP 将每个点的坐标 (x, y, z) 逐步映射到高维特征空间(如 64 → 128 → 1024 维)。随后,PointNet 使用最大池化(Max Pooling)对所有点的特征在点维度上取最大值,得到全局特征向量。这个全局向量再经过若干全连接层,输出分类得分或分割标签。
| 组件 | 输入形状 | 输出形状 | 作用 |
|---|---|---|---|
| 输入点云 | [B, N, 3] | [B, N, 3] | 原始坐标 (x, y, z) |
| 共享 MLP (Conv1D) | [B, 3, N] | [B, 64, N] | 逐点特征提取 |
| 共享 MLP (Conv1D) | [B, 64, N] | [B, 1024, N] | 高维特征映射 |
| Max Pooling | [B, 1024, N] | [B, 1024] | 全局特征聚合 |
| 全连接层 | [B, 1024] | [B, 512] → [B, 256] | 特征压缩与语义映射 |
| 输出层 | [B, 256] | [B, num_classes] | 分类得分 |
案例拆解:以 ModelNet40 分类任务为例,输入 1024 个点,每个点 3 维坐标。PointNet 首先通过 T-Net 预测一个 3×3 的变换矩阵对输入坐标进行对齐,然后经过三层共享 MLP(3→64→128→1024),得到每个点的 1024 维特征。Max Pooling 后得到全局特征,再经过三个全连接层(1024→512→256→40),最终输出 40 个类别的 logits。整个网络参数量约 3.5M,远小于同等能力的图像 CNN 模型。
风险提示:Max Pooling 虽然解决了点序问题,但会丢失点的分布密度信息。当点云点数变化较大(如 1024 点 vs 4096 点)时,Max Pooling 对稀疏点云的响应可能不稳定。实践中建议固定输入点数(采样或插值),或使用加权池化策略。
3.3 激活函数:非线性变换的选择
核心原理:激活函数为神经网络引入非线性,使其能够逼近任意复杂函数。ReLU(Rectified Linear Unit)是当前默认选择:f(x) = max(0, x)。其优势在于计算简单、梯度不饱和(正区间梯度恒为 1)、能缓解梯度消失。但 ReLU 存在“神经元死亡”问题——当输入为负时梯度为 0,若某个神经元长期接收负输入,其权重将无法更新。LeakyReLU 通过给负区间一个小的斜率(如 0.01)缓解此问题。Tanh 将输出压缩到 (-1, 1),适合需要中心化输出的场景。
在 PointNet 中的实践:PointNet 默认使用 ReLU,并在每个卷积/全连接层后紧跟 BatchNorm 和 ReLU。BatchNorm 的作用是稳定训练过程,加速收敛,同时允许使用较大的学习率。在点云任务中,由于输入坐标的尺度可能变化(如激光雷达点云范围可达数十米),BatchNorm 对逐点特征的归一化尤为重要。
经验建议:在 PointNet 的 T-Net 中,最后一层输出变换矩阵时不要使用 ReLU,因为变换矩阵的元素需要允许负值。通常 T-Net 的回归头使用线性激活(无激活函数)或 Tanh。若使用 ReLU,变换矩阵将只能产生非负变换,严重限制空间对齐能力。
常见误区:部分实现会在 Max Pooling 之前使用 Sigmoid 激活,这会导致梯度饱和。Max Pooling 本身对输入尺度敏感,若特征值被压缩到 (0,1) 区间,池化后的区分度会下降。推荐在池化前保持特征的原始尺度(通过 BatchNorm 控制方差),池化后再接 ReLU 或直接进入分类头。
3.4 损失函数与优化器
核心原理:损失函数衡量模型预测与真实标签之间的差异,是训练优化的目标函数。分类任务常用交叉熵损失(CrossEntropy Loss),其定义为 L = -Σ y_i * log(p_i),其中 y_i 为 one-hot 标签,p_i 为 Softmax 概率。交叉熵对错误预测的惩罚呈对数增长,梯度形式简洁,与 Softmax 组合时反向传播计算高效。分割任务则使用逐点交叉熵的平均值。优化器负责根据损失梯度更新网络参数。SGD 简单稳定但收敛慢;Adam 结合动量与自适应学习率,在点云任务中通常表现更好,默认学习率 1e-3。
在 PointNet 中的适配:PointNet 的分类头输出 [B, num_classes] 的 logits,直接使用 nn.CrossEntropyLoss()。分割任务中,每个点输出一个类别概率,损失为所有点的交叉熵均值。对于 T-Net 的变换矩阵,PointNet 额外添加了正交性正则化损失:L_reg = || I - A·A^T ||²,其中 A 为预测的变换矩阵。该正则项约束变换矩阵接近正交,防止特征空间被过度扭曲,权重系数通常设为 0.001。
# PointNet 训练核心代码示意
criterion_cls = nn.CrossEntropyLoss()
criterion_reg = nn.MSELoss() # 正交性正则
optimizer = torch.optim.Adam(model.parameters(), lr=0.001, betas=(0.9, 0.999))
scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=20, gamma=0.5)
for epoch in range(epochs):
for points, labels in train_loader:
# points: [B, N, 3], labels: [B]
logits, trans_feat = model(points) # 前向传播
loss_cls = criterion_cls(logits, labels)
loss_reg = criterion_reg(torch.eye(3), torch.bmm(trans_feat, trans_feat.transpose(1, 2)))
loss = loss_cls + 0.001 * loss_reg
optimizer.zero_grad()
loss.backward()
optimizer.step()
案例拆解:在 ModelNet40 上训练 PointNet 时,若使用 SGD(momentum=0.9, lr=0.01),通常需要 200+ epoch 才能达到 85% 左右的准确率;而使用 Adam(lr=0.001)配合 StepLR 衰减,约 100 epoch 即可达到 89% 的准确率。关键差异在于 Adam 的自适应学习率对点云这种高维稀疏梯度更友好。此外,BatchNorm 的 momentum 参数(默认 0.1)在点云任务中建议调低至 0.01,因为点云 batch 通常较小(如 16 或 32),过大的 momentum 会导致 batch 统计量波动剧烈。
风险提示:PointNet 在小数据集(如 ScanObjectNN)上容易过拟合。建议使用 Dropout(分类头中 p=0.3~0.5)、权重衰减(weight_decay=1e-4)以及数据增强(随机旋转、缩放、抖动)。若验证集准确率停滞在 70% 左右,优先检查 T-Net 是否收敛——可打印变换矩阵的行列式,若偏离 1 过大,说明正则化权重过高或学习率过大。
3.5 从图像到点云的迁移总结
核心原理:深度学习的核心组件在点云处理中的迁移并非简单替换,而是需要针对无序性、置换不变性和坐标变换鲁棒性进行重新设计。下表总结了各组件在图像与点云领域的对应关系与关键差异。
| 组件 | 图像领域 | 点云领域 (PointNet) | 关键差异 |
|---|---|---|---|
| 特征提取 | 2D 卷积 (3×3, 5×5) | 1×1 卷积 / 共享 MLP | 无局部邻域,逐点独立 |
| 聚合方式 | 全局平均池化 / 全连接 | Max Pooling(对称函数) | 需满足置换不变性 |
| 空间变换 | 数据增强(平移/旋转) | T-Net 预测变换矩阵 | 显式学习对齐,增强鲁棒性 |
| 激活函数 | ReLU + BN | ReLU + BN(T-Net 输出层除外) | 变换矩阵需允许负值 |
| 损失函数 | CrossEntropy / MSE | CrossEntropy + 正交正则 | 额外约束变换矩阵 |
| 优化器 | SGD / Adam | Adam 优先 | 点云梯度更稀疏,自适应学习率更稳 |
判断方法:当设计一个新的点云网络时,可以按以下流程决策:① 是否需要局部邻域信息?若需要,考虑 PointNet++ 或基于图的方法;若不需要(如全局分类),PointNet 的共享 MLP + Max Pooling 足够。② 输入点云是否经过严格配准?若未配准,必须加入 T-Net 或使用数据增强模拟变换。③ 点云密度是否均匀?若密度变化大,Max Pooling 可能偏向密集区域,需考虑加权池化或 FPS 采样。
常见误区与复盘:一个典型错误是在 PointNet 的逐点 MLP 中使用标准 2D 卷积(如 nn.Conv2d),这要求输入为规则的 [B, C, H, W] 张量,无法直接处理 [B, N, C] 的点云。正确做法是使用 nn.Conv1d 并将点云转置为 [B, C, N]。另一个误区是忽略 T-Net 的初始化——T-Net 的最后一层应初始化为单位矩阵(或接近单位矩阵),否则训练初期变换矩阵可能产生剧烈扭曲,导致损失震荡。实践中,可在 T-Net 的线性层权重上加上单位矩阵的偏置,或使用 nn.init.eye_() 初始化。
复盘总结:PointNet 的成功证明了“简单架构 + 正确归纳偏置”的有效性。共享 MLP 保证了逐点特征提取的一致性,Max Pooling 解决了无序性问题,T-Net 提供了空间变换鲁棒性。这三个设计分别对应了深度学习中权重共享、对称函数和显式变换学习的思想。掌握这些基础组件的迁移逻辑,后续理解 PointNet++ 的局部区域划分、注意力机制等进阶设计将更加顺畅。