PointNet与PointNet++实战对比:从零搭建三维点云分割模型(附PyTorch代码)

Pytorch1.7复现PointNet++点云分割(含Open3D可视化)(文末有一个自己做的书缝识别项目代码) 毕设需要,复现一下PointNet++的对象分类、零件分割和场景分割,找点灵感和思路,做个踩坑记录。 阅读详情

PointNet与PointNet++实战对比:从零搭建三维点云分割模型(附PyTorch代码)

如果你正在为三维点云数据头疼,想找一个能直接上手、效果又好的分割模型,那么PointNet和PointNet++这两个名字你一定绕不开。几年前我第一次接触自动驾驶点云分割项目时,面对一堆无序的XYZ坐标,传统的图像处理方法完全失效,正是这两个模型打开了新世界的大门。它们不像体素方法那样笨重,也不像多视图投影那样丢失信息,而是直接“硬刚”原始点云,这种思路在当时堪称革命。但理论归理论,真正要把它们用起来,尤其是用PyTorch从零搭建,你会发现两者在代码结构、训练技巧和实际表现上差异巨大。这篇文章,我就结合自己踩过的坑和调参的经验,带你深入代码层面,看看PointNet和PointNet++到底该怎么选、怎么用。

1. 环境搭建与数据准备:万事开头难

在动手写模型之前,一个干净、可复现的环境是高效开发的基础。我强烈建议使用Anaconda来管理Python环境,它能很好地解决依赖冲突问题。

# 创建并激活一个名为pointnet的虚拟环境
conda create -n pointnet python=3.8
conda activate pointnet

# 安装核心依赖
pip install torch==1.12.1+cu113 torchvision==0.13.1+cu113 --extra-index-url https://download.pytorch.org/whl/cu113
pip install numpy scipy matplotlib tqdm
pip install open3d  # 用于点云可视化,非常有用

这里我固定了PyTorch的版本,因为不同版本间一些API可能有细微变动,为了代码的稳定性,锁定版本是个好习惯。CUDA版本请根据你自己的显卡驱动进行选择。

接下来是数据。对于点云分割,斯坦福大学的S3DIS(Stanford 3D Indoor Spaces)数据集是一个经典的室内场景分割基准。它包含了6个大型室内区域的3D扫描,每个点都被标注为13个类别(如天花板、地板、桌子等)。

注意:直接处理原始的S3DIS数据(.txt格式)比较低效。一个常见的预处理步骤是将每个房间的点云切割成重叠的1m x 1m的块(block),这样既能控制输入规模,又能通过数据增强增加样本多样性。

下面是一个简化的数据加载器示例,展示了如何读取预处理后的.npy数据块:

import numpy as np
import torch
from torch.utils.data import Dataset, DataLoader

class S3DISDataset(Dataset):
    def __init__(self, data_root, split='train', block_size=1.0, num_point=4096):
        self.data_root = data_root
        self.split = split
        self.block_size = block_size
        self.num_point = num_point
        # 假设数据已预处理为.npy文件,存储在data_root/split目录下
        self.file_list = self._load_file_list()

    def __len__(self):
        return len(self.file_list)

    def __getitem__(self, idx):
        # 加载一个数据块:包含点坐标和标签
        data = np.load(self.file_list[idx])  # shape: (N, 4) -> x, y, z, label
        points, labels = data[:, :3], data[:, 3].astype(np.int64)

        # 数据增强(仅在训练时)
        if self.split == 'train':
            points = self._augment_point_cloud(points)

        # 采样固定数量的点(如果N > num_point,则随机下采样;如果N < num_point,则重复采样)
        choice = np.random.choice(len(points), self.num_point, replace=len(points) < self.num_point)
        points = points[choice, :]
        labels = labels[choice]

        # 归一化:将块中心移到原点
        points -= np.mean(points, axis=0, keepdims=True)

        # 转换为Tensor
        points = torch.from_numpy(points).float()
        labels = torch.from_numpy(labels).long()
        return points, labels

    def _augment_point_cloud(self, points):
        """简单的数据增强:随机旋转和抖动"""
        # 绕Z轴随机旋转
        theta = np.random.uniform(0, 2*np.pi)
        rotation_matrix = np.array([
            [np.cos(theta), -np.sin(theta), 0],
            [np.sin(theta), np.cos(theta), 0],
            [0, 0, 1]
        ])
        points = np.dot(points, rotation_matrix)
        # 添加微小抖动
        jitter = np.random.normal(0, 0.02, size=points.shape)
        points += jitter
        return points

这个Dataset类封装了数据读取、采样、归一化和增强的核心逻辑。使用DataLoader进行批量加载时,由于每个样本的点数已经通过采样固定为num_point,所以可以直接进行堆叠(stack),无需使用pad_sequence。

2. PointNet核心实现:对称函数的艺术

PointNet的核心思想非常优雅:它通过一个共享权重的多层感知机(MLP)独立处理每个点,然后使用一个对称函数(如最大池化)来聚合所有点的信息,从而解决点云的无序性问题。此外,它引入了T-Net来学习一个变换矩阵,对齐输入点云或特征,提升模型的旋转不变性。

我们先来看最关键的模块——T-Net。它的目标是学习一个变换矩阵(对于输入是3x3,对于特征可以是64x64),使网络对空间变换更鲁棒。

import torch.nn as nn
import torch.nn.functional as F

class TNet(nn.Module):
    """学习空间或特征变换的模块"""
    def __init__(self, k=3):
        super().__init__()
        self.k = k  # 变换矩阵的维度,输入变换为3,特征变换为64
        self.conv1 = nn.Conv1d(k, 64, 1)
        self.conv2 = nn.Conv1d(64, 128, 1)
        self.conv3 = nn.Conv1d(128, 1024, 1)
        self.fc1 = nn.Linear(1024, 512)
        self.fc2 = nn.Linear(512, 256)
        self.fc3 = nn.Linear(256, k*k)

        self.bn1 = nn.BatchNorm1d(64)
        self.bn2 = nn.BatchNorm1d(128)
        self.bn3 = nn.BatchNorm1d(1024)
        self.bn4 = nn.BatchNorm1d(512)
        self.bn5 = nn.BatchNorm1d(256)

    def forward(self, x):
        # x shape: (batch_size, k, num_points)
        batch_size = x.size(0)
        x = F.relu(self.bn1(self.conv1(x)))
        x = F.relu(self.bn2(self.conv2(x)))
        x = F.relu(self.bn3(self.conv3(x)))
        x = torch.max(x, 2, keepdim=True)[0]  # 全局最大池化
        x = x.view(-1, 1024)
        x = F.relu(self.bn4(self.fc1(x)))
        x = F.relu(self.bn5(self.fc2(x)))
        x = self.fc3(x)

        # 将输出reshape为batch_size个k*k的矩阵,并添加单位矩阵作为初始偏置
        iden = torch.eye(self.k, requires_grad=True).repeat(batch_size, 1, 1)
        if x.is_cuda:
            iden = iden.cuda()
        x = x.view(-1, self.k, self.k) + iden
        return x

有了T-Net,我们就可以构建完整的PointNet分割网络了。分割网络需要输出每个点的类别,因此它在提取全局特征后,会将全局特征与每个点的局部特征进行拼接,再通过MLP进行逐点分类。

class PointNetSeg(nn.Module):
    """PointNet语义分割网络"""
    def __init__(self, num_classes=13, num_point=4096):
        super().__init__()
        self.num_point = num_point
        self.input_transform = TNet(k=3)
        self.feature_transform = TNet(k=64)

        # 共享权重的MLP (卷积实现)
        self.conv1 = nn.Conv1d(3, 64, 1)
        self.conv2 = nn.Conv1d(64, 64, 1)
        self.conv3 = nn.Conv1d(64, 64, 1)
        self.conv4 = nn.Conv1d(64, 128, 1)
        self.conv5 = nn.Conv1d(128, 1024, 1)

        self.bn1 = nn.BatchNorm1d(64)
        self.bn2 = nn.BatchNorm1d(64)
        self.bn3 = nn.BatchNorm1d(64)
        self.bn4 = nn.BatchNorm1d(128)
        self.bn5 = nn.BatchNorm1d(1024)

        # 分割头:将全局特征与局部特征融合
        self.conv6 = nn.Conv1d(1088, 512, 1)  # 1024+64=1088
        self.conv7 = nn.Conv1d(512, 256, 1)
        self.conv8 = nn.Conv1d(256, 128, 1)
        self.conv9 = nn.Conv1d(128, num_classes, 1)

        self.bn6 = nn.BatchNorm1d(512)
        self.bn7 = nn.BatchNorm1d(256)
        self.bn8 = nn.BatchNorm1d(128)

    def forward(self, x):
        # x shape: (batch_size, 3, num_points)
        batch_size, _, num_points = x.size()

        # 输入变换
        trans_input = self.input_transform(x)
        x = torch.bmm(x.transpose(2, 1), trans_input).transpose(2, 1)

        # 第一层特征提取
        x = F.relu(self.bn1(self.conv1(x)))
        x = F.relu(self.bn2(self.conv2(x)))
        point_feat = x  # 保存此时的局部特征 (batch_size, 64, num_points)

        # 特征变换
        trans_feat = self.feature_transform(x)
        x = torch.bmm(x.transpose(2, 1), trans_feat).transpose(2, 1)

        # 继续提取更高层特征
        x = F.relu(self.bn3(self.conv3(x)))
        x = F.relu(self.bn4(self.conv4(x)))
        x = F.relu(self.bn5(self.conv5(x)))  # (batch_size, 1024, num_points)

        # 全局特征:最大池化
        global_feat = torch.max(x, 2, keepdim=True)[0]  # (batch_size, 1024, 1)
        global_feat_repeated = global_feat.repeat(1, 1, num_points)  # 复制到每个点

        # 拼接局部特征与全局特征
        x = torch.cat([point_feat, global_feat_repeated], dim=1)  # (batch_size, 1088, num_points)

        # 分割头
        x = F.relu(self.bn6(self.conv6(x)))
        x = F.relu(self.bn7(self.conv7(x)))
        x = F.relu(self.bn8(self.conv8(x)))
        x = self.conv9(x)  # (batch_size, num_classes, num_points)

        x = x.transpose(2, 1).contiguous()  # (batch_size, num_points, num_classes)
        return x, trans_input, trans_feat

在训练时,论文中除了常规的交叉熵损失,还为正则化特征变换矩阵增加了一个辅助损失,希望它接近正交矩阵,以保持特征空间的稳定性。

def feature_transform_regularizer(trans):
    """特征变换矩阵的正则化损失,使其接近正交矩阵"""
    batch_size, k, _ = trans.size()
    I = torch.eye(k, device=trans.device)[None, :, :]
    loss = torch.norm(torch.bmm(trans, trans.transpose(2, 1)) - I, dim=(1, 2))
    return loss.mean()

PointNet的优势与局限:

  • 优势:结构简单,参数少,训练快,对点云的无序性和旋转有理论保证的鲁棒性。
  • 局限:最大池化聚合全局特征的方式过于粗暴,完全丢失了点的局部邻域结构信息。这在处理复杂场景(如室内场景分割)时,会导致对细节和边界的分割效果不佳,因为模型“看”不到点与点之间的相对位置关系。

3. PointNet++架构解析:分层与局部感知

PointNet++的核心改进在于引入了分层特征学习和局部区域抽象。它模仿了CNN中卷积层和池化层堆叠的思想,通过多次“采样-分组-特征提取”的操作(称为Set Abstraction),逐步扩大感受野,同时保留局部几何信息。

首先,我们需要实现最远点采样(FPS)和球查询(Ball Query),这是构建局部区域的基础。

def farthest_point_sample(xyz, npoint):
    """
    最远点采样 (FPS)
    Args:
        xyz: (B, N, 3) 点云坐标
        npoint: 需要采样的中心点数量
    Returns:
        centroids: (B, npoint) 采样得到的中心点索引
    """
    device = xyz.device
    B, N, C = xyz.shape
    centroids = torch.zeros(B, npoint, dtype=torch.long).to(device)
    distance = torch.ones(B, N).to(device) * 1e10
    farthest = torch.randint(0, N, (B,), dtype=torch.long).to(device)
    batch_indices = torch.arange(B, dtype=torch.long).to(device)

    for i in range(npoint):
        centroids[:, i] = farthest
        centroid = xyz[batch_indices, farthest, :].view(B, 1, 3)
        dist = torch.sum((xyz - centroid) ** 2, -1)
        mask = dist < distance
        distance[mask] = dist[mask]
        farthest = torch.max(distance, -1)[1]
    return centroids

def query_ball_point(radius, nsample, xyz, new_xyz):
    """
    球查询 (Ball Query)
    Args:
        radius: 搜索半径
        nsample: 每个区域最多采样的点数
        xyz: (B, N, 3) 所有点的坐标
        new_xyz: (B, S, 3) 中心点坐标
    Returns:
        group_idx: (B, S, nsample) 每个中心点邻域内的点索引
    """
    device = xyz.device
    B, N, C = xyz.shape
    _, S, _ = new_xyz.shape
    group_idx = torch.arange(N, dtype=torch.long).to(device).view(1, 1, N).repeat([B, S, 1])
    sqrdists = square_distance(new_xyz, xyz)  # (B, S, N)
    group_idx[sqrdists > radius ** 2] = N  # 将距离大于半径的索引标记为N(无效索引)
    group_idx = group_idx.sort(dim=-1)[0][:, :, :nsample]  # 取前nsample个最近的
    # 如果某个区域内有效点不足nsample,会有N这个无效索引,后续需要处理
    return group_idx

有了这些基础操作,我们就可以构建PointNet++的核心模块——Set Abstraction (SA) Layer。

class PointNetSetAbstraction(nn.Module):
    """PointNet++的Set Abstraction层"""
    def __init__(self, npoint, radius, nsample, in_channel, mlp, group_all=False):
        super().__init__()
        self.npoint = npoint
        self.radius = radius
        self.nsample = nsample
        self.group_all = group_all  # 如果为True,则将所有点作为一个组(用于最后一层)

        # 用于提取局部特征的微型PointNet (MLP)
        self.mlp_convs = nn.ModuleList()
        self.mlp_bns = nn.ModuleList()
        last_channel = in_channel
        for out_channel in mlp:
            self.mlp_convs.append(nn.Conv2d(last_channel, out_channel, 1))
            self.mlp_bns.append(nn.BatchNorm2d(out_channel))
            last_channel = out_channel

    def forward(self, xyz, points):
        """
        Args:
            xyz: (B, N, 3) 输入点坐标
            points: (B, C, N) 输入点特征,可以为None
        Returns:
            new_xyz: (B, npoint, 3) 采样后的中心点坐标
            new_points: (B, mlp[-1], npoint) 采样后中心点的新特征
        """
        if self.group_all:
            new_xyz, new_points = sample_and_group_all(xyz, points)
        else:
            new_xyz, new_points = sample_and_group(self.npoint, self.radius, self.nsample, xyz, points)
        # new_points shape: (B, 3+C, npoint, nsample)

        # 使用微型PointNet处理每个局部区域
        new_points = new_points.permute(0, 3, 2, 1)  # (B, nsample, npoint, 3+C) -> (B, 3+C, npoint, nsample)
        for i, conv in enumerate(self.mlp_convs):
            bn = self.mlp_bns[i]
            new_points = F.relu(bn(conv(new_points)))
        # new_points shape: (B, mlp[-1], npoint, nsample)

        # 在nsample维度上进行最大池化,得到每个局部区域的聚合特征
        new_points = torch.max(new_points, 3)[0]  # (B, mlp[-1], npoint)
        return new_xyz, new_points

PointNet++的分割网络是一个编码器-解码器结构,类似于U-Net。编码器通过多个SA层下采样并提取多尺度特征,解码器则通过特征传播(Feature Propagation)层进行上采样,并将编码器对应层的特征进行跳跃连接(Skip Connection),以恢复细节信息。

class PointNet2Seg(nn.Module):
    """PointNet++语义分割网络"""
    def __init__(self, num_classes=13, num_point=4096):
        super().__init__()
        self.sa1 = PointNetSetAbstraction(npoint=1024, radius=0.1, nsample=32, in_channel=3, mlp=[32, 32, 64])
        self.sa2 = PointNetSetAbstraction(npoint=256, radius=0.2, nsample=32, in_channel=64+3, mlp=[64, 64, 128])
        self.sa3 = PointNetSetAbstraction(npoint=64, radius=0.4, nsample=32, in_channel=128+3, mlp=[128, 128, 256])
        self.sa4 = PointNetSetAbstraction(npoint=16, radius=0.8, nsample=32, in_channel=256+3, mlp=[256, 256, 512])

        # 特征传播(上采样)层
        self.fp4 = PointNetFeaturePropagation(in_channel=512+256, mlp=[256, 256])
        self.fp3 = PointNetFeaturePropagation(in_channel=256+128, mlp=[256, 256])
        self.fp2 = PointNetFeaturePropagation(in_channel=256+64, mlp=[256, 128])
        self.fp1 = PointNetFeaturePropagation(in_channel=128+3, mlp=[128, 128, 128])

        # 分割头
        self.conv1 = nn.Conv1d(128, 128, 1)
        self.bn1 = nn.BatchNorm1d(128)
        self.drop1 = nn.Dropout(0.5)
        self.conv2 = nn.Conv1d(128, num_classes, 1)

    def forward(self, xyz):
        # xyz: (B, N, 3)
        B, N, _ = xyz.shape
        l0_points = xyz.transpose(2, 1)  # (B, 3, N)
        l0_xyz = xyz

        # 编码器
        l1_xyz, l1_points = self.sa1(l0_xyz, l0_points)  # (B, 1024, 3), (B, 64, 1024)
        l2_xyz, l2_points = self.sa2(l1_xyz, l1_points)  # (B, 256, 3), (B, 128, 256)
        l3_xyz, l3_points = self.sa3(l2_xyz, l2_points)  # (B, 64, 3), (B, 256, 64)
        l4_xyz, l4_points = self.sa4(l3_xyz, l3_points)  # (B, 16, 3), (B, 512, 16)

        # 解码器(特征传播)
        l3_points = self.fp4(l3_xyz, l4_xyz, l3_points, l4_points)  # (B, 256, 64)
        l2_points = self.fp3(l2_xyz, l3_xyz, l2_points, l3_points)  # (B, 256, 256)
        l1_points = self.fp2(l1_xyz, l2_xyz, l1_points, l2_points)  # (B, 128, 1024)
        l0_points = self.fp1(l0_xyz, l1_xyz, None, l1_points)       # (B, 128, N)

        # 分割头
        x = F.relu(self.bn1(self.conv1(l0_points)))
        x = self.drop1(x)
        x = self.conv2(x)  # (B, num_classes, N)
        x = x.transpose(2, 1).contiguous()  # (B, N, num_classes)
        return x

PointNet++的优势与挑战:

  • 优势:通过分层结构捕获了丰富的局部几何信息,在复杂场景的分割任务上精度显著优于PointNet,尤其是对物体边界和细节部分。
  • 挑战:计算复杂度高,尤其是FPS和Ball Query操作在点数多时非常耗时。对点云密度的变化敏感,在稀疏区域可能无法有效分组。网络结构更复杂,调参(如半径radius、采样数nsample)需要更多经验。

4. 训练策略与调参实战:从理论到结果

模型搭建好了,但要让它们真正work起来,训练策略和参数调优才是关键。这里我分享一些在S3DIS数据集上训练这两个模型时积累的经验。

优化器与学习率调度:对于这类3D任务,Adam优化器通常是稳妥的起点。学习率初始值可以设为0.001。我习惯使用余弦退火(CosineAnnealingLR)或者带热重启的余弦退火(CosineAnnealingWarmRestarts),它们能让模型在训练后期更精细地收敛。

import torch.optim as optim
from torch.optim.lr_scheduler import CosineAnnealingLR

model = PointNet2Seg(num_classes=13).cuda()
optimizer = optim.Adam(model.parameters(), lr=0.001, betas=(0.9, 0.999), weight_decay=1e-4)
scheduler = CosineAnnealingLR(optimizer, T_max=200, eta_min=1e-5)  # 假设总epoch为200

损失函数:对于分割任务,标准的交叉熵损失(CrossEntropyLoss)是基础。但在点云数据中,类别不平衡问题非常严重(例如,墙和地板点的数量远多于家具)。一个有效的技巧是使用加权交叉熵损失,根据每个类别在训练集中的频率来设置权重。

# 假设我们统计了训练集中13个类别的点数,得到类别权重列表 class_weights
class_weights = torch.tensor([...], dtype=torch.float32).cuda()
criterion = nn.CrossEntropyLoss(weight=class_weights, ignore_index=-1)  # ignore_index用于忽略无效点

数据增强:这是提升模型泛化能力、防止过拟合的利器。除了代码示例中提到的随机旋转和坐标抖动,还可以尝试:

  • 随机缩放:以轻微不同的比例缩放点云。
  • 随机平移:在三个轴上随机移动点云。
  • 随机丢弃点:以一定概率随机丢弃一些点,模拟传感器噪声或遮挡,这对提升鲁棒性很有帮助。

训练过程中的常见问题与解决:

  1. 梯度爆炸/消失:如果训练初期loss就变成NaN,很可能是梯度爆炸。可以尝试:降低学习率;使用梯度裁剪(torch.nn.utils.clip_grad_norm_);检查网络初始化,确保没有过大的权重。
  2. 过拟合:如果训练集精度很高但验证集精度停滞不前,就是过拟合。对策包括:增加数据增强的强度;在MLP层后添加Dropout层(如PointNet++分割头所示);增大权重衰减(weight_decay);使用早停法(Early Stopping)。
  3. PointNet++训练速度慢:FPS和Ball Query是瓶颈。可以尝试:在训练初期使用较小的num_point(如2048),后期再增大;使用CUDA加速的最近邻搜索库(如torch_cluster);如果显存充足,可以适当增大batch_size以更充分利用GPU。

模型评估与对比:在S3DIS数据集上,我们通常使用**平均交并比(mIoU)**作为主要评估指标。下表展示了一个简单的性能对比框架(数值为示意,实际结果需训练得到):

模型整体精度 (OA)平均交并比 (mIoU)参数量推理速度 (pts/s)适用场景分析
PointNet~85%~45%~3M快对简单物体、部件分割效果好,适合计算资源受限、对实时性要求高的场景。
PointNet++~88%~55%~5M中等对复杂室内外场景分割更优,能捕捉细节,但计算开销大,需仔细调参。

实际训练中,PointNet可能更快达到一个不错的基线,而PointNet++则需要更长的训练时间和更精细的超参数调整(特别是radius和nsample),但一旦调好,其上限通常更高。

最后,别忘了可视化你的结果。用Open3D这样的库将预测结果和真实标签渲染出来,直观对比,能帮你发现模型在哪里犯了错,是边界模糊、小物体漏检,还是类别混淆,这比只看数字更有助于理解模型的优缺点。

【3D计算机视觉】从PointNet到PointNet++理论及pytorch代码 从PointNet到PointNet++理论及代码详解1. 点云是什么1.1 三维数据的表现形式1.2 为什么使用点云1.3 点云上以往的相关工作2. PointNet2.1 基于点云的置换不变性2.1.1 由对称函数到PointNet(vanilla)2.1.2 理论证明2.2 基于点云的旋转不变性2.3 网络总体结构2.4 实验结果和网络的鲁棒性2.5 代码解析3. PointNet++3.1... 阅读详情

相关推荐

(四) 三维点云课程---PointNet-Pytorch运行

三维点云课程—PointNet-Pytorch运行 三维点云课程---PointNet-Pytorch运行三维点云课程---PointNet-Pytorch运行1.分类1.1训练1.2 分类训练可能出现的问题1.3测试分类后的模型文件1.4测试分类时源码可能遇到的问题2.分割2.1训练2.2分割训练可能出现的问题2.3测试分类后的模型文件2.4测试分类时源码可能遇到的问题 PointNet 源码下载地址:https://github.com/fxia22/pointnet.pytorch 源代码存在一些问题

qq_45369294的博客 7204

PointNet++点云处理精讲(PyTorch)

三维点云是物理世界的三维数据表达形式,其应用日益广泛,如自动驾驶、AR/VR、FaceID等。PointNet网络模型是直接对三维点云数据进行深度学习的开山之作,PointNet++是对PointNet的改进技术。作为点云处理深度学习方法的里程碑工作,启发了很多后续研究。本课程对PyTorch版的PointNet++进行原理讲解、论文复现和代码详解。包括:  (1)提供三维点云物体分类数据集ModelNet40、物体部件分割数据集ShapeNet和场景分割数据集S3DIS的下载、可视化软件和方法;(2)在Ubuntu系统上演示使用PointNet++进行三维点云的物体分类、部件分割和场景语义分割的训练和测试;(3)详解PointNet++的原理、程序代码和实现细节,并使用PyCharm进行Debug调试代码和单步跟踪。需要学习TensorFlow版PointNet++的学员可前往本人推出了课程《PointNet++点云处理TensorFlow版》

Windows系统下复现PointNet++算法

本文详细介绍了如何在Windows系统下复现PointNet++算法,内容包括程序下载、环境配置、数据集准备以及三个主要任务(语义分割、分类、部件分割)的实现步骤和常见报错解决方法。通过遵循本文的指导,用户可以顺利完成PointNet++算法的复现。

LingYi_5的博客 4326

3D点云目标检测算法Pointnet++项目实战 Pytorch实现

本人研二在读,3D点云目标检测方向,自动驾驶场景,刚刚复现完成PointNet++分类和分割网络,效果还不错,分享给大家。 Pointnet++算法的原理在此不再赘述,本文专注讲一下重要代码,从输入数据到输出结果展现复现过程。注:复现的是MSG特征拼接方法,MRG的代码作者没有公布出来,代码里还有SSG的,也就是没有做半径特征拼接的原始方法,自己也可以跑一下。 附代码。代码里对重要的语句都进行了详细的注释喔~ 链接:https://pan.baidu.c...

qq_42446745的博客 2万+

PointNet与PointNet++实战:从零搭建三维点云语义分割模型(附PyTorch代码)

本文详细介绍了如何使用PyTorch从零搭建PointNet与PointNet++三维点云语义分割模型,涵盖环境配置、数据准备、核心模块实现及工业级优化策略。通过实战代码示例,帮助开发者掌握点云处理关键技术,解决自动驾驶、机器人导航等领域的实际应用问题。

weixin_29090917的博客 283

从零搭建运行Pytorch版pointNet++模型全流程及个性化数据集训练测试可视化

从零搭建运行Pytorch版pointNet++模型全流程及个性化数据集训练测试可视化

funfan的博客 9438

【PonintNet++:从Pytorch代码角度理解原理】

PointNet++:从pytorch角度理解原理和代码实现前言提出问题网络结构参考 前言 前几天了解了3D深度学习的入门之作:PointNet(具体原理解释可以点击链接看另一篇博客),今天为Ponint++的理解做篇笔记。最好结合原理和代码来看可以理解的更加深刻。 论文:PointNet++ 代码:Pytorch-PointNet++ 提出问题 前篇PointNet是对每一个点做从低维到高维的映射的学习,缺点就是没有局部的概念,要么对一个点的操作要么是对所有点的操作,很难对更加精细复杂的场景进行分析。所以

qingliange的博客 3129

从零到一:华为iMaster NCE-Campus部署中的Euler OS与FusionInsight深度解析

本文深入解析华为iMaster NCE-Campus部署中Euler OS与FusionInsight的关键技术要点,包括RAID配置、网络绑定技术、安装避坑指南及性能调优方案。通过实战经验和详细配置示例,帮助工程师提升部署效率与系统稳定性,确保华为企业级解决方案的高效运行。

f6g7h8i9j的博客 550

PyTorch复现PointNet++——模型训练+模型测试

PyTorch复现PointNet++——模型训练+模型测试

beyond谚语的博客 1万+

模型可解释性分析:基于SHAP的深度探索

SHAP模型可解释性分析摘要 本文系统性地介绍了SHAP(SHapley Additive exPlanations)方法在机器学习模型可解释性分析中的应用。SHAP基于博弈论的Shapley值理论,为特征重要性评估提供了统一框架。文章详细阐述了四种核心算法:Kernel SHAP(模型无关方法)、Tree SHAP(针对树模型的高效算法)、Deep SHAP(适用于深度学习)和Linear SHAP(线性模型专用)。通过Python实现展示了从数据准备到SHAP分析的全流程,包括摘要图、依赖图等可视化技术

huanghm88的专栏 614

万字详解YOLOv8网络结构Backbone/neck/head以及Conv、Bottleneck、C2f、SPPF、Detect等模块

YOLOv8是由Ultralytics开发的最先进的目标检测模型,推升了速度、准确性和用户友好性的界限。YOLO这一缩写代表“你只看一次”(You Only Look Once),通过在一次网络传递中同时预测所有边界框,提升了算法的效率和实时处理能力。相比之下,其他一些目标检测技术需要经过多个阶段或过程来完成检测。YOLOv8在流行的YOLOv5架构上进行了扩展,在多个方面提供了改进。

专注于图像领域,主要研究内容包括计算机视觉和深度学习,特别是在图像分类、目标检测和图像生成等方面有深入的研究和实践经验。 14万+

【3D计算机视觉】PointNet++的pytorch实现代码阅读

最全的PointNet++的pytorch代码阅读1. 功能函数文件1.1 square_distance函数1.2 farthest_point_sample函数1.3 index_points函数1.4 query_ball_point函数1.5 Sampling + Grouping1.6 SetAbstraction层1.7 FeaturePropagation层2. 模型主文件2.1 C...

小执着的博客 3万+

计算机应用数学--第一次作业

中科大 计算机应用数学 第一次作业

一杯水果茶!足矣~ 1329

基于PyTorch实现PointNet++

关于点云的深度学习表示 PointNet / PointNet++是基于深度学习方法的点云表征的里程碑式的工作, 都出自于斯坦福大学的Charles R. Qi, 这两个工作分别收录于CVPR 2017和NIPS 2017. 最近,我在读一些关于点云配准和点云表示学习的深度学习论文,了解到目前点云的深度表示/学习有几个火热的研究方向: 基于point wise + MLP提取特征,典型代表是PointNet++; 基于Pseudo Grid和常规卷积提取特征,典型代表是ICCV 2019的工作KPConv

zhulf0804的博客 7810

【100%通过率】华为OD机试真题 Python 实现【字符串重新排列】【2022.11 Q4新题】

给定一个字符串s,s包括以空格分隔的若干个单词,请对s进行如下处理后输出: 1、单词内部调整:对每个单词字母重新按字典序排序 2、单词间顺序调整: 1)统计每个单词出现的次数,并按次数降序排列 2)次数相同,按单词长度升序排列 3)次数和单词长度均相同,按字典升序排列 请输出处理后的字符串,每个单词以一个空格分隔。

MISAYAONE的博客 7982

大模型实战—通义千问大模型微调

这个参数仅针对 llama 类型的模型结构,默认勾选的是 q_proj 和 v_proj,具体的名词不容易理解,我就不多说了,可以简单的认为是对模型的理解能力进行优化,一般这两个就够了。当这个值较高时,适应新任务的能力会增强,但是对基础模型的影响会比较大,有过拟合的风险,尤其是在数据量有限的情况下。为了方便测试,我在云环境也创建了一个镜像,相关的环境都配置好了,可以直接使用几个国内开源的大语言模型,比如清华智谱的ChatGLM3-6B、零一万物的Yi-34B,还有最近阿里云开源的Qwen1.5-32B。

7万+

【PointNet++】PointNet++复现(PyTorch版本)

【PointNet++】PointNet++复现(PyTorch版本)

Addery的学习日常 6601

Dify智能体开发:Dify文件上传

相较于聊天文本,文档文件能够承载大量的信息,例如学术报告、法律合同。受限于 LLM 自身仅能够支持文件或图片,难以获取文件内更加丰富的上下文信息,应用的使用者不得不手动复制粘贴大量信息与 LLM 对话,增加了许多不必要的使用成本。

王国平的博客 2592

Windows11和Ubuntu用PointNet++训练自己的数据集(部件分割模型partseg)

自建了一个轮胎表面的点云,需要用pointnet++网络分出luntai的 槽顶 和 槽底。所以就是1个物体(即luntai)2个部件(即槽底 和 槽顶)。

qq_15243129的博客 7466

Mac电脑安装burp suite2024版本记录

下载最新版本burpsuitloader-XXX-all.jar,改名为burpsuitloader.jar。目录下,修改vmoptions.txt文件,新增以下内容,如果keygen不是这个名称的话,需要修改。,点击license左侧的copy复制它,然后手动从启动台启动burpsuite。,复制如下命令到终端即可(要加双引号,不然目录中空格会导致命令截断)再复制激活响应信息到burpsuite中即可激活。后续运行burp直接从启动台运行即可。将如下框的信息复制到激活器中。输入后下一步,点击手动激活。

墨痕诉清风的博客 910

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

PointNet与PointNet++在PyTorch中的实现教程

本项目旨在提供PointNet及PointNet++两种深度学习模型的纯PyTorch实现。PointNet是最早直接处理不规则点云数据的深度学习架构之一,而PointNet++则在其基础上进行了改进,提升了局部特征的提取能力。此仓库适用于希望在ModelNet、ShapeNet和S3DIS等数据集上进行点云分类与分割实验的研究人员和开发者。 - **技术栈**: PyTorch - **许可*...

gitblog_00348的博客 953

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

三维点云语义分割新突破:基于深度学习的PointNet++实战全解析

解决三维点云语义分割难题,本文深入解析基于深度学习的PointNet++模型及其在点云的处理中的创新应用。涵盖架构原理、实战步骤与性能优势,适用于自动驾驶、三维重建等场景,方法前沿且可复现,值得收藏。

ByteShoal的博客 845

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

PointNet++三维点云处理精讲(TensorFlow版):论文复现+代码详解

课程链接:https://edu.youkuaiyun.com/course/detail/30462 三维点云是物理世界的三维数据表达形式,其应用日益广泛,如自动驾驶、AR/VR、FaceID等。PointNet网络模型是直接对三维点云数据进行深度学习的开山之作,PointNet++是对PointNet的改进技术。 本课程对TensorFlow版的PointNet++进行原理讲解、论文复现和代码详解。包括: 提供三维点云数据集ModelNet40、ShapeNet和Scannet的下载、可视化软件和方法; .

bai666ai的博客 3596

【亲测免费】 点云深度学习模型PointNet和PointNet++的PyTorch实现教程

该项目的目录结构简洁明了,主要分为以下几个部分: - **data_utils**: 包含数据处理相关的代码。 - `data_utils.py`: 数据加载器与数据预处理的脚本。 - **model**: 存放PointNet和PointNet++模型定义。 - `pointnet.py`: PointNet模型的实现。 - `pointnet2.py`: Point...

gitblog_00452的博客 1317
上一篇: 从Tegra到Ryzen:Tesla智能座舱域控制器(MCU)的芯片演进与技术突破
下一篇: SpringAI集成ZhiPu AI实战指南:从配置到流式响应
devops8pract
博客等级 码龄4年 533粉丝 849原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值