目录

一、论文动机

现有的问题:

作者的思路及面临的问题:

二、论文方法

如何解决点云无序性问题?作者提出了三种想法。

针对点云的刚体运动不变性

三、网络结构

四、代码阅读

五、Reference(两篇都是对原论文的翻译)


论文地址:https://arxiv.org/pdf/1612.00593.pdf

代码地址:https://github.com/yanx27/Pointnet_Pointnet2_pytorch

一、论文动机

现有的问题:

因为卷积神经网络一般都要求高度规则的输入数据格式,如图像和3D体素,所以现有的方法一般是把点云转换成体素格式或者投影到二维图中。但是由于算力的限制,体素的分辨率最多只能达到32*32*32,而且体素是立方体,对于点云表面的特征都没有表达出来。

作者的思路及面临的问题:

我们能否设计一个神经网络直接对点云的特征进行学习,而不进行转换?

面临两个问题:1.如何解决点云的无序性问题

                          2.如何保证点云的刚体运动不变性

二、论文方法

如何解决点云无序性问题?作者提出了三种想法。

1.对点云排序之后送入——高维空间不存在稳定的排序,因为有点的扰动。

2.将点云作为一个序列来用RNN处理——RNN对于长度较小的序列具有很好的鲁棒性,但点云序列太长了

3.使用对称函数来解决无序性问题,如均值池化,最大池化。实验证明最大池化效果最好。

针对点云的刚体运动不变性

引入两个对齐输入点和点特征的联合对齐网络,在点云进行特征提取之前将所有的输入对齐到规范空间。通过T-Net网络预测一个仿射变换矩阵,与点云进行相乘。

为什么联合对齐网络可以引入刚体运动不变性?

三、网络结构

原理就是对输入的点云先进行对齐,引入刚体运动不变性,然后通过MLP对特征升维,再对特征进行对齐,然后再MLP升维特征,这时进行最大池化,解决无序性问题,得到1024维的全局特征,如果是分类,则直接对全局特征进行MLP操作,输出k维结果就是分类结果。如果是分割的话,则把全局特征与每个点的特征进行拼接,然后两次MLP得到每个点的分割结果。

四、代码阅读

import torch
import torch.nn as nn
import torch.nn.parallel
import torch.utils.data
from torch.autograd import Variable
import numpy as np
import torch.nn.functional as F#nn.relu模块调用一般用在init里,而F.relu是函数调用一般用在forward里
#Conv1d和Linear的区别,当你必须保留语义分割中的空间信息时,使用卷积 Conv1d() 。当你不需要做任何与空间信息相关的事情时,比如在基本分类(mnist、猫狗分类器)中,使用线性层 Linear()
class STN3d(nn.Module):  #第一个T-Netdef __init__(self, channel):super(STN3d, self).__init__()self.conv1 = torch.nn.Conv1d(channel, 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-(B,C,N)N表示n个点,C表示特征数x = F.relu(self.bn1(self.conv1(x)))x = F.relu(self.bn2(self.conv2(x)))x = F.relu(self.bn3(self.conv3(x))) #(B,1024,N)x = torch.max(x, 2, keepdim=True)[0] #只返回最大值的每个数(B,1024,1)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)  #(B,9)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)  #tensor不能反向传播,variable可以反向传播。同时在单位矩阵的基础上进行调整if x.is_cuda:iden = iden.cuda()x = x + idenx = x.view(-1, 3, 3)return xclass STNkd(nn.Module):   #特征T-Netdef __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 = kdef 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 + idenx = x.view(-1, self.k, self.k)return xclass PointNetEncoder(nn.Module):def __init__(self, global_feat=True, feature_transform=False, channel=3):super(PointNetEncoder, self).__init__()self.stn = STN3d(channel)self.conv1 = torch.nn.Conv1d(channel, 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_featself.feature_transform = feature_transformif self.feature_transform:self.fstn = STNkd(k=64)def forward(self, x):B, D, N = x.size()trans = self.stn(x)x = x.transpose(2, 1) #交换矩阵的两个维度,也可以torch.transposeif D > 3:feature = x[:, :, 3:]x = x[:, :, :3]x = torch.bmm(x, trans) #计算两个tensor的矩阵乘法,torch.bmm(a,b),tensor a 的size为(b,h,w),tensor b的size为(b,w,m) 也就是说两个tensor的第一维是相等的,然后第一个数组的第三维和第二个数组的第二维度要求一样,对于剩下的则不做要求,输出维度 (b,h,m)if D > 3:x = torch.cat([x, feature], dim=2)x = x.transpose(2, 1)x = F.relu(self.bn1(self.conv1(x)))  #(B,64,N)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 = Nonepointfeat = x  #这里记录一下点的特征,后面分割用x = F.relu(self.bn2(self.conv2(x))) #(B,128,N)x = self.bn3(self.conv3(x))   #(B,1024,N)x = torch.max(x, 2, keepdim=True)[0]x = x.view(-1, 1024)   #(B,1024)if self.global_feat:return x, trans, trans_featelse:x = x.view(-1, 1024, 1).repeat(1, 1, N)   #(B,1024,N)return torch.cat([x, pointfeat], 1), trans, trans_feat  #如果有分割,则返回合并后的特征##对齐特征的时候,由于特征空间维度更高,优化难度大,所以加了一项正则项,让求解出来的仿射变换矩阵接近于正交,这里返回的在后面损失函数会用到
#扩充维度可以先view扩充一维,再repeat
def feature_transform_reguliarzer(trans):d = trans.size()[1]I = torch.eye(d)[None, :, :]if trans.is_cuda:I = I.cuda()loss = torch.mean(torch.norm(torch.bmm(trans, trans.transpose(2, 1)) - I, dim=(1, 2))) #torch.norm默认求所有元素的平方和,dim指定维度,是在一二维求,得到(B,loss)再求平均 return loss#损失函数nn.CrossEntropyLoss()=F.log_softmax() + F.nll_loss()

五、Reference(两篇都是对原论文的翻译)

(3条消息) 【论文翻译】从零开始PointNet论文分析与代码复现_花花大魔王的博客-CSDN博客

PointNet 文献阅读及拓展阅读_万俟淋曦的博客-CSDN博客

PointNet论文解读和代码解析相关推荐

  1. PointNet++论文解读和代码解析

    目录 一.论文动机 二.论文方法 三.网络结构 Set Abstraction 非均匀采样密度下的鲁棒性学习 上采样 四.代码阅读 论文地址:https://arxiv.org/pdf/1706.02 ...

  2. 单目标跟踪算法:Siamese RPN论文解读和代码解析

    点击上方"3D视觉工坊",选择"星标" 干货第一时间送达 作者:周威 | 来源:知乎 https://zhuanlan.zhihu.com/p/16198364 ...

  3. Longformer论文解读和代码解析

    前言 这篇博文记录了longformer论文的主要思想.代码实现和结果复现方面的一些工作,相关链接如下: 原longformer论文地址 github上原作者公开的代码 huggingface上原作者 ...

  4. Inception V3论文解读和代码解析

    目录 论文解读 代码解析 小结 论文解读 在介绍inception V2时提到过,inception V3的论文依据是Rethinking the Inception Architecture for ...

  5. YOLOv7来临:论文解读附代码解析

    前言: 是一份关于YOLOv7的论文解读,首发于[GiantPandaCV]公众号,写的不是很好,望大佬们包涵! 2022年7月,YOLOv7来临, 论文链接:https://arxiv.org/ab ...

  6. Wav2Lip模型------《A Lip Sync Expert Is All You Need for Speech to Lip Generation In The Wild》论文解读及代码解析

    ABSTRACT: 在这篇文档中,我们将研究任意人物的人脸视频与目标音频的口型匹配问题.当前领域能做到对特定训练过的人物进行精准的口型匹配,但在其他未训练的人物上效果不好.我们找到了导致这种问题的主要 ...

  7. 【Cylinder3D论文解读及代码略解】

    Cylinder3D论文解读及代码略解 论文解读 Abstract Introduction Related work 室内点云分割 室外点云分割 3D体素划分 Methodology(本文方法) C ...

  8. CVPR 2020 Oral 文章汇总,包括论文解读与代码实现

    点击上方,选择星标或置顶,不定期资源大放送! 阅读大概需要10分钟 Follow小博主,每天更新前沿干货 [导读]本文为大家整理了10篇CVPR2020上被评为Oral的论文解读和代码汇总. 1.Ra ...

  9. FPN论文解读 和 代码详解

    FPN论文解读 和 代码详解 论文地址:[Feature Pyramid Networks for Object Detection](1612.03144v2.pdf (arxiv.org)) 代码 ...

最新文章

  1. ubuntu 命令整合1
  2. s3c2440地址分配
  3. 创建工程并测试RedisTemplate
  4. Dapr + .NET Core实战(二) 服务调用
  5. WPF中删除打开过的图片
  6. scala 数组合并_Scala程序合并两个数组或数组缓冲区
  7. python时间序列预测不连续怎么办_手把手教你用Python处理非平稳时间序列(附代码)...
  8. C#图像细化:Hilditch细化算法
  9. 计算机病毒实践汇总六:IDA Pro基础
  10. hget如何获取多个value_《深入微服务》之 如何给老婆解释什么是微服务的基础框架SpringBoot?...
  11. 这月到手的工资多了没?
  12. 求助matable基本
  13. 分享win10常用图标ico_png_html素材
  14. VB编程的RS485通讯操作界面源码 本程序适应各类带RS485通讯的设备,参数可以自由修改,主要是针对各类变频器RS485通讯(RTU)格式!
  15. 修改服务器域名解析,总结修改Godaddy解析服务器(DNS)三步骤
  16. python中的ln函数_python中的对数log函数表示及用法
  17. matlab 不等式组求解例子,matlab求解不等式组
  18. 安装office2021时报错,无法卸载以前office版本残留项
  19. 曲面细分着色器---细分二维四边形
  20. Java中Map接口及实现

热门文章

  1. Tomcat配置数据源及部署项目
  2. 生产前端控制台报504的解决思路
  3. win10电脑蓝牙怎么开
  4. pyansys库配合Ansys软件成功启动
  5. 2021年全球与中国连续搅拌釜反应器(CSTR)行业市场规模及发展前景分析
  6. ajax传图片以及后台接收,前端ajax上传文件,图片,后端nodejs接收文件;
  7. TensorRT 概述、原理、Linux下安装
  8. NetSuite 中国财务常用报表功能包
  9. Python+Vue计算机毕业设计警务巡逻系统0871r(源码+程序+LW+部署)
  10. Django合并清理migrations文件