点云处理: 基于飞桨复现PointNet++

本文介绍PointNet++在PaddlePaddle的复现项目。PointNet++通过分层结构提取点云局部特征,解决点集分布不均问题。复现基于ModelNet40数据集,top-1 Acc达92.0,超原论文。说明环境依赖、快速开始步骤,分析代码结构及复现中PaddlePaddle多维索引支持不足的问题与解决方法。
pointnet_plus_plus_paddlepaddle
Paper: PointNet++: Deep Hierarchical Feature Learning on Point Sets in a Metric Space
一、项目简介
PointNet++与PointNet相比网络可以更好的提取局部特征。网络使用空间距离(metric space distances),使用PointNet对点集局部区域进行特征迭代提取,使其能够学到局部尺度越来越大的特征。基于自适应密度的特征提取方法,解决了点集分布不均匀的问题。
论文地址:
PointNet++
论文背景:
论文主要解决的是点云分割与点云分类的问题。该方法对PointNet进行了改进。针对PointNet存在的无法获得局部特征,难以对复杂场景进行分析的缺点。PointNet++,通过两个主要的方法进行了改进:
利用空间距离(metric space distances),使用PointNet对点集局部区域进行特征迭代提取,使其能够学到局部尺度越来越大的特征。由于点集分布很多时候是不均匀的,如果默认是均匀的,会使得网络性能变差,所以作者提出了一种自适应密度的特征提取方法。通过以上两种方法,能够更高效的学习特征,也更有鲁棒性。论文方案介绍
在PointNet++中,作者利用所在空间的距离度量将点集划分(partition)为有重叠的局部区域(可以理解为patch)。在此基础上,在小范围中从几何结构中提取局部特征(浅层特征),然后扩大范围,在这些局部特征的基础上提取更高层次的特征,从而提取到整个点集的全局特征。
PointNet++解决了两个关键的问题:第一,将点集划分为不同的区域;第二,利用特征提取器获取不同区域的局部特征。
在本文中,作者使用了PointNet作为特征提取器,使用邻域球来定义分区,每个区域可以通过中心坐标和半径来确定。中心坐标的选取,作者使用了快速采样算法来完成(farthest point sampling (FPS) algorithm)。区域半径的选择使用了Multi-scale grouping (MSG) and Multi-resolution grouping (MRG)来实现。
论文模型介绍
PointNet++是PointNet的延伸,在PointNet的基础上加入了多层次结构(hierarchical structure),使得网络能够在越来越大的区域上提供更高级别的特征。
网络的每一组set abstraction layers主要包括3个部分:Sampling layer, Grouping layer and PointNet layer。
· Sample layer:主要是对输入点进行采样,在这些点中选出若干个中心点; · Grouping layer:是利用上一步得到的中心点将点集划分成若干个区域; · PointNet layer:是对上述得到的每个区域进行编码,变成特征向量。 每一组提取层的输入是N * (d + C),其中N是输入点的数量,d是坐标维度,C是特征维度。输出是N'* (d + C'),其中N'是输出点的数量,d是坐标维度不变,C'是新的特征维度。
二、复现精度
三、数据集
使用的数据集为:ModelNet40。
ModelNet包含了来自662类的127915个三维形状,其子集Model10包含了来自10类的4899个三维形状,ModelNet40包含了来自40类的12311个三维形状。ModelNet40是常用的三维点云分割数据集,现在是一个用来评判三维点云分割性能的常规benchmark。
四、环境依赖
硬件:GPU、CPU
框架:
PaddlePaddle >= 2.0.0tqdm五、快速开始
Data Preparation
Download alignment ModelNet and put it in ./dataset/modelnet40_normal_resampled/
Train
python train_modelnet.py --process_data登录后复制
Test
python test_modelnet.py --log_dir path_to_model登录后复制
六、代码结构与详细说明
6.1 代码结构
|—— README.md|—— provider.py # 点云数据增强|—— ModelNetDataset.py # 数据集定义及加载|── train_modelnet.py # 训练网络|── test_modelnet.py # 测试网络|—— models # 模型文件定义登录后复制
6.2 参数说明
可以在 train_modelnet.py 中设置训练与评估相关参数,具体如下:
Reference Implementation:
TensorFlow (Official)PyTorch七、复现总结与心得
问题
复现主要参考的是PyTorch的pytorch实现,pytorch的大部分api可以在paddlepaddle中找到对应,最困难的地方在于,paddlepaddle没法办法进行二维的索引,对应原实现中的多个部分
def index_points(points, idx): """ Input: points: input points data, [B, N, C] idx: sample index data, [B, S] Return: new_points:, indexed points data, [B, S, C] """ device = points.device B = points.shape[0] view_shape = list(idx.shape) view_shape[1:] = [1] * (len(view_shape) - 1) repeat_shape = list(idx.shape) repeat_shape[0] = 1 batch_indices = torch.arange(B, dtype=torch.long).to(device).view(view_shape).repeat(repeat_shape) new_points = points[batch_indices, idx, :] return new_points登录后复制
def farthest_point_sample(xyz, npoint): """ Input: xyz: pointcloud data, [B, N, 3] npoint: number of samples Return: centroids: sampled pointcloud index, [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): """ Input: radius: local region radius nsample: max sample number in local region xyz: all points, [B, N, 3] new_xyz: query points, [B, S, 3] Return: group_idx: grouped points index, [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) group_idx[sqrdists > radius ** 2] = N group_idx = group_idx.sort(dim=-1)[0][:, :, :nsample] group_first = group_idx[:, :, 0].view(B, S, 1).repeat([1, 1, nsample]) mask = group_idx == N group_idx[mask] = group_first[mask] return group_idx登录后复制
def sample_and_group(npoint, radius, nsample, xyz, points, returnfps=False): """ Input: npoint: radius: nsample: xyz: input points position data, [B, N, 3] points: input points data, [B, N, D] Return: new_xyz: sampled points position data, [B, npoint, nsample, 3] new_points: sampled points data, [B, npoint, nsample, 3+D] """ B, N, C = xyz.shape S = npoint fps_idx = farthest_point_sample(xyz, npoint) # [B, npoint, C] new_xyz = index_points(xyz, fps_idx) idx = query_ball_point(radius, nsample, xyz, new_xyz) grouped_xyz = index_points(xyz, idx) # [B, npoint, nsample, C] grouped_xyz_norm = grouped_xyz - new_xyz.view(B, S, 1, C) if points is not None: grouped_points = index_points(points, idx) new_points = torch.cat([grouped_xyz_norm, grouped_points], dim=-1) # [B, npoint, nsample, C+D] else: new_points = grouped_xyz_norm if returnfps: return new_xyz, new_points, grouped_xyz, fps_idx else: return new_xyz, new_points登录后复制
这里所有的二维索引都没有办法使用,包括经常使用的mask方法
这里进行了一些妥协,将需要二维索引的地方进行拉直,从而可以将二维索引变为n个一维索引,但是这里肯定对速度有所损失,暂时没有想到好的办法
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)登录后复制
farthest = paddle.randint(0, N, (B, ), dtype="int64")for i in range(npoint): centroids[:, i] = farthest # centroid = xyz[batch_indices, farthest, :].reshape((B, 1, 3)) centroid = paddle.zeros((B, 1, 3), dtype="float32") for j in range(3): centroid[:,:,j] = xyz[:,:,j].index_sample(farthest.reshape((-1, 1))).reshape((B, 1))登录后复制
对于mask的地方,可以直接使用数值运算的方法达到mask的目的
mask = dist < distancedistance[mask] = dist[mask]farthest = torch.max(distance, -1)[1]登录后复制
mask = dist < distancemask = mask.astype("int64")mask_index = paddle.nonzero(mask)if mask_index.size > 0: distance = distance * (1 - mask.astype("float32")) + dist * mask.astype("float32")登录后复制
总结
目前的paddlepaddle可以支持大多数pytorch的API,但是其对于多维索引的支持不足,非常影响使用体验,而多维索引又是一个在日常的研究以及工程中,非常常规的功能,这里需要改进。
安装依赖
In [ ]!python3 -m pip install tqdm登录后复制
解压缩数据集
In [ ]%cd /home/aistudio/data/data50045/!unzip modelnet40_normal_resampled.zip登录后复制
解压缩代码并链接数据集
In [ ]%cd /home/aistudio/!unzip pointnet_plus_plus_paddlepaddle-main.zip%cd pointnet_plus_plus_paddlepaddle-main/登录后复制 In [ ]
%mkdir /home/aistudio/pointnet_plus_plus_paddlepaddle-main/dataset%cp -r /home/aistudio/data/data50045/modelnet40_normal_resampled /home/aistudio/pointnet_plus_plus_paddlepaddle-main/dataset登录后复制
训练模型
In [2]%cd /home/aistudio/pointnet_plus_plus_paddlepaddle-main/!python3 train_modelnet.py --process_data登录后复制
测试
In [ ]%cd /home/aistudio/pointnet_plus_plus_paddlepaddle-main/!python3 test_modelnet.py --log_dir path_to_log登录后复制
免责声明
游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。
同类文章
爱彼迎CEO切斯基:ChatGPT不成熟,阿里通义千问高效又实惠
爱彼迎首席执行官布莱恩·切斯基近日在接受媒体采访时透露,公司目前尚未将应用程序与OpenAI的ChatGPT进行技术整合。他指出,尽管ChatGPT在生成式人工智能领域表现突出,但其现有连接工具的成
荣耀AI投入超百亿:升级HONOR AI Connect平台 共建智慧生态
在荣耀AI终端生态大会上,荣耀董事长吴晖提出“得AI者得天下,得终端者得未来”的论断,强调人工智能技术正以颠覆性力量重构终端产业生态。他指出,智能体将取代传统交互方式,成为连接人与数字世界的核心入口
字节跳动Seed团队发布Seed3D+1.0:单图生成高质量3D模型
字节跳动Seed团队近日宣布,正式推出其最新研发的3D生成大模型——Seed3D 1 0。这款模型具备从单张图像直接生成高质量仿真级3D模型的端到端能力,为3D内容创作领域带来了突破性进展。在性能对
Meta优化AI部门架构,裁员600人紧追行业竞争
meta公司近期对其人工智能部门展开大规模调整,宣布裁减约600名员工。此次裁员由首席人工智能官亚历山大·王通过内部备忘录披露,旨在精简组织架构、提升运营效率。被裁岗位主要涉及AI基础设施团队、基础
阿里夸克上线对话助手,Qwen模型融合搜索能力提升AI体验
阿里巴巴旗下智能应用夸克近日正式推出对话助手功能,该产品基于阿里自研的Qwen最新闭源大模型构建,成为国内首个将搜索服务与智能对话深度整合的AI工具。这一创新被视为夸克 "C计划 "战略的重要突破,此前
相关攻略
热门教程
更多- 游戏攻略
- 安卓教程
- 苹果教程
- 电脑教程



















