PointNet.pytorch点云三维深度学习论文与代码复现

news2024/12/26 13:53:07

PointNet.pytorch

  • 1. 概要
    • 1.1 文章
    • 1.2 点云和三维深度学习,PointNet 网络结构
    • 1.3 复现说明
  • 2. 代码
    • 2.1 代码逻辑
    • 2.2 思路详解
  • 3. 解析
  • 组会2023.1.18远程
    • arcivdaily
    • onedb

1. 概要

1.1 文章

链接: 论文

1.2 点云和三维深度学习,PointNet 网络结构

链接: 三维深度学习之pointnet系列详解

1.3 复现说明

链接: readme

2. 代码

2.1 代码逻辑

链接:PointNet模型的Pytorch代码详解

2.2 思路详解

链接:PointNet代码详细解释(Pytorch版本)

3. 解析

总图

  • MLP:多层感知器(Multilayer Perceptron,缩写MLP)是一种前向结构的人工神经网络,映射一组输入向量到一组输出向量。MLP可以被看作是一个有向图,由多个的节点层所组成,每一层都全连接到下一层。除了输入节点,每个节点都是一个带有非线性激活函数的神经元(或称处理单元)。一种被称为反向传播算法的监督学习方法常被用来训练MLP。[1][2] 多层感知器遵循人类神经系统原理,学习并进行数据预测。它首先学习,然后使用权重存储数据,并使用算法来调整权重并减少训练过程中的偏差,即实际值和预测值之间的误差。主要优势在于其快速解决复杂问题的能力。多层感知的基本结构由三层组成:第一输入层,中间隐藏层和最后输出层,输入元素和权重的乘积被馈给具有神经元偏差的求和结点,主要优势在于其快速解决复杂问题的能力。 [3] MLP是感知器的推广,克服了感知器不能对线性不可分数据进行识别的弱点。
  • Feature Transform: 尺度不变特征转换(Scale-invariant feature transform 或 SIFT)是一种机器视觉的算法用来侦测与描述影像中的局部性特征,它在空间尺度中寻找极值点,并提取出其位置、尺度、旋转不变数
  1. 在分类网络中,输入n个点,对输入做特征变换,再进行最大池化输出k个种类;分割网络是分类网络的一个拓展,它考虑了全局和局部的特征以及每个点的输出分数。mlp代表多层感知机,括号中是感知机的层数,批标准化(Batchnorm)本用于所有带有ReLU函数的层,Dropout层被用于分类网络中最后一个多层感知机中。
  2. 代码详解
    首先讲解分类网络,图中深色部分,首先输入点经过一个transform,再经过多层感知机,再经过一个feature transform,再经过多层感知机和max pooling,最后经过多层感知机获得分类结果,网络结构是比较清晰的,下边一块一块看:

input transform
首先这一层的目的是对输入的每一个点云,在这里是2500个三坐标点,目的是要获得一个3×3的变换矩阵,获得这个矩阵的原因是:要对点云的姿态进行校正,而该变换矩阵就是根据点云特性,做出一个刚体变换,使点云处于一个比较容易检测的姿态。先对输入经过三级卷积核为1×1的卷积处理得到1024通道的数据,再经过全连接处映射到九个数据,最后调整为3×3

class STN3d(nn.Module):
def init(self):
super(STN3d, self).init()
self.conv1 = torch.nn.Conv1d(3, 64, 1)
self.conv2 = torch.nn.Conv1d(64, 128, 1)
self.conv3 = torch.nn.Conv1d(128, 1024, 1)
self.fc1 = nn.Linear(1024, 512)
self.fc2 = nn.Linear(512, 256)
self.fc3 = nn.Linear(256, 9)
self.relu = nn.ReLU()

    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):
    batchsize = 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)

    iden = Variable(torch.from_numpy(np.array([1,0,0,0,1,0,0,0,1]).astype(np.float32))).view(1,9).repeat(batchsize,1)
    if x.is_cuda:
        iden = iden.cuda()
    x = x + iden
    x = x.view(-1, 3, 3)
    return x

feature transform
下边我们先考虑后边这个feature transform层,这个其实和上边那个是一样的,只是从电源数据中获取一个64×64的变换矩阵,这个也是对特征的一种校正,一种广义的位姿变换,代码几乎没有差别

class STNkd(nn.Module):
def init(self, k=64):
super(STNkd, self).init()
self.conv1 = torch.nn.Conv1d(k, 64, 1)
self.conv2 = torch.nn.Conv1d(64, 128, 1)
self.conv3 = torch.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.relu = nn.ReLU()

    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)

    self.k = k

def forward(self, x):
    batchsize = 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)

    iden = Variable(torch.from_numpy(np.eye(self.k).flatten().astype(np.float32))).view(1,self.k*self.k).repeat(batchsize,1)
    if x.is_cuda:
        iden = iden.cuda()
    x = x + iden
    x = x.view(-1, self.k, self.k)
    return x

主体部分
这部分讲max pooling之前的剩余部分,首先经过STN3d获得3×3矩阵,乘以点云做完位姿变换,再经过多层感知机(实际上多层感知机与卷积核边长为1的卷积操作本质是一样的),再乘以经过STNkd获得的64×64的矩阵,完成位姿变换,再经过多层感知机(这里同样用边长为1的卷积核的卷积操作),得到n×1024的矩阵,n为每批次读入的数据文件个数。下边这个类中调用了前边两个类。

class PointNetfeat(nn.Module):
def init(self, global_feat = True, feature_transform = False):
super(PointNetfeat, self).init()
self.stn = STN3d()
self.conv1 = torch.nn.Conv1d(3, 64, 1)
self.conv2 = torch.nn.Conv1d(64, 128, 1)
self.conv3 = torch.nn.Conv1d(128, 1024, 1)
self.bn1 = nn.BatchNorm1d(64)
self.bn2 = nn.BatchNorm1d(128)
self.bn3 = nn.BatchNorm1d(1024)
self.global_feat = global_feat
self.feature_transform = feature_transform
if self.feature_transform:
self.fstn = STNkd(k=64)

def forward(self, x):
    n_pts = x.size()[2]
    trans = self.stn(x)
    x = x.transpose(2, 1)
    x = torch.bmm(x, trans)
    x = x.transpose(2, 1)
    x = F.relu(self.bn1(self.conv1(x)))

    if self.feature_transform:
        trans_feat = self.fstn(x)
        x = x.transpose(2,1)
        x = torch.bmm(x, trans_feat)
        x = x.transpose(2,1)
    else:
        trans_feat = None

    pointfeat = x
    x = F.relu(self.bn2(self.conv2(x)))
    x = self.bn3(self.conv3(x))
    x = torch.max(x, 2, keepdim=True)[0]
    x = x.view(-1, 1024)
    if self.global_feat:
        return x, trans, trans_feat
    else:
        x = x.view(-1, 1024, 1).repeat(1, 1, n_pts)
        return torch.cat([x, pointfeat], 1), trans, trans_feat

后处理部分
下边就要进行最大池化和多层感知机进行分类了,经过全连接分成k类,根据概率来判别究竟属于哪一类

class PointNetCls(nn.Module):
def init(self, k=2, feature_transform=False):
super(PointNetCls, self).init()
self.feature_transform = feature_transform
self.feat = PointNetfeat(global_feat=True, feature_transform=feature_transform)
self.fc1 = nn.Linear(1024, 512)
self.fc2 = nn.Linear(512, 256)
self.fc3 = nn.Linear(256, k)
# 防止过拟合
self.dropout = nn.Dropout(p=0.3)
# 归一化防止梯度爆炸与梯度消失
self.bn1 = nn.BatchNorm1d(512)
self.bn2 = nn.BatchNorm1d(256)
self.relu = nn.ReLU()

def forward(self, x):
    # 完成网络主体部分
    x, trans, trans_feat = self.feat(x)
    # 经过三个全连接层(多层感知机)映射成k类
    x = F.relu(self.bn1(self.fc1(x)))
    x = F.relu(self.bn2(self.dropout(self.fc2(x))))
    x = self.fc3(x)
    # 返回的是该点云是第ki类的概率
    return F.log_softmax(x, dim=1), trans, trans_feat

分割网络
分割网络是借用了分类网络的两部分,分别是64通道和1024通道,堆积在一起形成1088通道的输入,经过多层感知机输出了结果m通道的结果,m代表类的个数,也就是每个点属于哪一类,实际上分割是在像素级或者点级的分类,本质上是一样的

class PointNetDenseCls(nn.Module):
def init(self, k = 2, feature_transform=False):
super(PointNetDenseCls, self).init()
self.k = k
self.feature_transform=feature_transform
self.feat = PointNetfeat(global_feat=False, feature_transform=feature_transform)
self.conv1 = torch.nn.Conv1d(1088, 512, 1)
self.conv2 = torch.nn.Conv1d(512, 256, 1)
self.conv3 = torch.nn.Conv1d(256, 128, 1)
self.conv4 = torch.nn.Conv1d(128, self.k, 1)
self.bn1 = nn.BatchNorm1d(512)
self.bn2 = nn.BatchNorm1d(256)
self.bn3 = nn.BatchNorm1d(128)

def forward(self, x):
    batchsize = x.size()[0]
    n_pts = x.size()[2]
    x, trans, trans_feat = self.feat(x)
    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 = self.conv4(x)
    x = x.transpose(2,1).contiguous()
    x = F.log_softmax(x.view(-1,self.k), dim=-1)
    x = x.view(batchsize, n_pts, self.k)
    return x, trans, trans_feat

训练结果
训练过程可以参考源码

    网络分类性能还是很强的,只是迭代了一次,精度就达到了91%以上

                    

    在点较少的情况下,分割效果也还是可以的,5次迭代可以达到 80.0mIoU

组会2023.1.18远程

arcivdaily

onedb

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/170837.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

程序员必备素质:代码整洁之道

本次分享的内容是《代码整洁之道》,书中是以现实案例,以讲故事形式来总结归纳问题,并给出解决方案,很容易与我们产生共鸣。文中会有大量书中内容摘抄,都是个人认为很值得分享的内容。当然,也会有个人感悟&a…

【C++】从0到1入门C++编程学习笔记 - 基础入门篇:C++初识

文章目录一、第一个C程序1.1 创建项目1.2 创建文件1.3 编写代码1.4 运行程序二、注释三、变量四、常量五、关键字六、标识符命名规则一、第一个C程序 编写一个C程序总共分为4个步骤 创建项目创建文件编写代码运行程序 1.1 创建项目 Visual Studio是我们用来编写C程序的主要…

【C语言课程设计】通讯录(2.0版本)

前言 在前面的博客中,我们已经了解了通讯录的基本写法。当然那个通讯录是不够完善的。我们本小节对前面的通讯录做一次小升级,添加动态增容模块与利用枚举来优化选择语句 【C语言课程设计】通讯录(1.0版本)_青色_忘川的博客-CSDN博…

JVM-内存模型详解

JVM 把内存分为若干个不同的区域,这些区域有些是线程私有的,有些则是线程共享的,Java 内存区域也叫做运行时数据区,它的具体划分如下: 虚拟机栈 Java 虚拟机栈是线程私有的数据区,Java 虚拟机栈的生命周期…

word查看技巧:如何快速找到文档的修改痕迹

不知道大家在工作中有没有遇到过这类的工作场景:当初步拟好一份合作协议或是项目策划书后,发给老板或其他同事审阅和修订,通常会不断地来回修改文档。此时,如果你想要查看文档哪里被修改过?你会怎么操作?很…

SpringBoot集成Elasticsearch7.4 实战(二)

1、前言本篇文章主要讲的是:在Springboot环境下,利用JAVA环境操作索引,集成SpringBoot等相关知识2. SpringBoot集成开发工具,这里选择的是IDEA 2019.2,构建Maven工程等一堆通用操作,不清楚的自行百度。2.1. POM配置我这边选择 ela…

协程应用——aiohttp异步爬虫实战

aiohttp异步爬虫实战1. 案例介绍2. 准备工作3. 页面分析4. 实现思路5. 基本配置6. 爬取列表页7. 爬取详情页8. 总结1. 案例介绍 本例要爬取的网站是https://spa5.scrape.center/,数据量相对大,所以用到了异步爬虫,主要学习这种方法是如何提高效率的。网…

Maven学习(三):纯手撸一个Maven项目

纯手撸一个Maven项目一、创建Maven工程目录二、Maven项目构建命令三、插件创建工程1、创建java工程2、创建web工程3、对比java工程和web工程区别一、创建Maven工程目录 按照下图所示的结构创建项目所需文件夹: 在Demo.java文件内输入以下代码: package…

数据库被勒索删除,解决方法

突然数据库被黑了,有一条勒索信息: To recover your lost Database send 0.018 Bitcoin (BTC) to our Bitcoin address: bc1qe4yefrptv2k8shawu3h84j0n8kyvxfk4wwate5 After this, contact us by email with your Server IP or Domain Name and a Proof of Payment …

JavaScript中的严格模式

一.什么是严格模式 在ECMAScript5标准中,JavaScript提出了严格模式的概念: 严格模式是一种具有限制性的JavaScript模式,从而使代码隐式脱离了“懒散(sloppy)模式”;支持严格模式的浏览器在检测到代码中有严格模式时,…

卡方检验的基本原理详解

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录一、卡方检验基本原理1. 1 χ2统计量计算公式1.2 理论频数如何计算?1.3 χ2值的结果如何理解?1.4 χ2检验的自由度如何理解?1.5 χ…

Arduino开发串口控制ESP8266 RGB LED

根据板卡原理RGB三色LED对应引脚:int LEDR12、int LEDG14、int LEDB13;设置串口波特率为115200Serial.begin(115200);源代码如下所示:/*名称:串口控制RGB亮灭实验功能:通过串口输入R、G、B三个字母来点亮对应的LED灯,关…

Java集合进阶——Map

一、Java Map集合详解 Map集合概述和特点 概述: 将键映射到值的对象 一个映射不能包含重复的键 每个键最多只能映射到一个值 Map接口和Collection接口的不同 Map是双列的,Collection是单列的 Map的键唯一,Collection的子体系Set是唯一的 Map集合的数据结构针对键有…

放假第三天

假期 # 生活 # 水文 咱们继续假期第三天的日常更文,没看上篇的铁子们我把地址贴在下面。 点我 虽然是假期,但我规划已久的睡懒觉流程却是一直执行不下去。这不今天早上八点我就起床了,当然起的早不是为了“卷”,而是吃早餐。说出…

Python操作 JWT(python-jose包)、哈希(passlib包)、用户验证完整流程

一、JWT简介 JWT是什么? JWT 即JSON 网络令牌(JSON Web Tokens)。 JWT(JSON Web Token) 是一种用于在身份提供者和服务提供者之间传递身份验证和授权数据的开放标准。JWT是一个JSON对象,其中包含了被签名的声明。这些声明可以是…

电脑开机出现绿屏错误无法启动怎么办?

电脑开机出现绿屏错误无法启动怎么办?有用户电脑开机的时候,突然出现了屏幕变成绿色的情况,而且上面有很多的错误代码。然后卡在页面上一直无法进入到桌面,重启电脑后依然无效。那么如何去解决这个问题呢?来看看具体的…

Java---Spring---SpringCache

SpringCache入门学习SpringCache介绍SpringCatch常用注解SpringCatch使用1.导入maven坐标2.配置application.yml3.在启动类上加入EnableCaching注解,开启缓存注解功能4.在controller的方法上加入Cacheable,CacheEvict等注解,进行缓存操作缓存穿透定义解决…

【Nginx】入门看这一篇就够啦,nginx 简介、安装、工作原理、工作方式、详解配置文件

目录 1、nginx 简介 2、nginx的工作原理 3、nginx 工作方式 4、nginx 安装 命令行安装 卸载命令 从源码构建 查看版本 测试启动 5、详解nginx配置文件 第一部分:全局块 第二部分:events块 第三部分:http 6、hosts 文件简介 1、…

解析Activity启动-窗口篇

解析Activity启动-窗口篇 在 解析Activity启动 前两篇文章中,我们分别专注于 堆栈 和 生命周期角度大致的过了一遍启动流程,而本篇会着重窗口的创建和显示流程,继续梳理Activity的启动流程 顺着前两篇文章的分析流程,我们知道和 …

DBCO高分子PEG_DBCO-PEG-Lipoic COOH_二苯并环辛炔-聚乙二醇-硫辛酸

DBCO-PEG-Lipoic acid“点击化学"一般由叠氮化物(azide)和炔烃(alkyne)作用形共价键,具有高效稳定,高特异性等优点。反应不受PH影响,能在常温条件下的水中进行,甚至能在活细胞中进行。DBCO…