赞
踩
本文为10月5日~10月11日的学习小结。
本周学习的主要内容为PointNet分类以及语义分割部分的代码调试。分类以及语义分割的测试部分都涉及到了点云可视化。零件分割以及语义分割使用到的分割模型也是在分类模型上进行修改得到的,后面将会对其进行分析,同时也对调试过程中遇到的一些问题进行了总结。论文部分看了一下文章末尾的补充材料,文中设计了不同实验来表现模型的性能,这些实验也解释了为何PointNet相比其他已有的方法更加有效。
执行以下语句可以测试模型并输出一些分类错误点云的可视化图像。
python evaluate.py –-visu
分类预测结果保存在dump/pred_label.txt文件中,其中左侧为预测标签,右侧为真实标签。
同时对于分类出错的点云,会输出对应的三视图图像并保存到dump文件夹内。
例如:网络在测试时错误的将书架预测为了门。因此输出了一张图像如下:27_label_bookshelf_pred_door.jpg
图中包含输入点云三个不同视角下的二维图像。
又如下图为梳妆台,而PointNet给出的预测标签为洗碗槽:32_label_dresser_pred_sink.jpg
其中绘图部分的实现如下:
当满足特定条件时(可视化参数设为True且预测结果与真实标签不同)会输出当前点云的三视图图像。
#如果满足两个条件则执行可视化:1、预测标签不等于真实标签。2、visu = true。
if pred_val[i-start_idx] != l and FLAGS.visu: # ERROR CASE, DUMP!
#图像文件名为:[编号]_label_[预测标签]_pred_[真实标签].jpg
img_filename = '%d_label_%s_pred_%s.jpg' % (error_cnt, SHAPE_NAMES[l],SHAPE_NAMES[pred_val[i-start_idx]])
img_filename = os.path.join(DUMP_DIR, img_filename)
#绘制预测错误点云的三视图
output_img = pc_util.point_cloud_three_views(np.squeeze(current_data[i, :, :]))
#保存图像
scipy.misc.imsave(img_filename, output_img)
#预测错误计数+1
error_cnt += 1
由pc_util.point_cloud_three_views方法实现三视图的绘制。原理是使用draw_point_cloud方法绘制二维点云图像,通过修改旋转系数xrot,yrot,zrot来改变主视图方向,最终输出三种不同视角的图像。
零件分割部分在 part_seg/ 目录下,其中分割网络模型在 pointnet_part_seg.py 中定义。
分割使用到的数据集为shapenet零件分割数据集。
数据集名称:
shapenet_part_seg_hdf5_data.zip
下载地址:
https://shapenet.cs.stanford.edu/media/shapenet_part_seg_hdf5_data.zip
以下是我对分割网络整体结构的整理,前半部分由分类网络构成,每层输出的局部特征与最终的全局特征经过连接整合后输入分割网络。
'''
分割网络结构:
*input* -------T-Net------->
Clas- --MLP(64,128,128)-->
sifi- -------T-Net------->
cati- ---MLP(512,2048)--->
on -----MaxPooling----> Local Features
______ ---FullConnection--> Global Feature
Segm- FeatureConcatenate-> New Feature
enta- MLP(256,256,128,P)-> *output*
tion
'''
特征的连接使用了 tf.concant() 方法实现,将分类网络中得到的局部特征以及最后的全局特征组合起来得到新的特征用于分割网络的输入。
# segmentation network
one_hot_label_expand = tf.reshape(input_label, [batch_size, 1, 1, cat_num])
out_max = tf.concat(axis=3, values=[out_max, one_hot_label_expand])
expand = tf.tile(out_max, [1, num_point, 1, 1])
'''
Out_Max And Input_label(reshape) -->Expand_Feature
Expand_Feature And Out_1,2,3,4,5 -->Concatenate_Feature
'''
#Condcat Feature
concat = tf.concat(axis=3, values=[expand, out1, out2, out3, out4, out5])
可以看到新特征结合了全局特征以及经过多个浅层网络得到的特征。
语义分割部分在 sem_seg/ 目录下。
由MD说明文件可以知道训练用的数据集为一个hdf5文件,该文件是由斯坦福大学的室内点云数据集(S3DIS)处理后得到的,hdf5格式的文件用于模型的训练。
代码中提供了用于训练的hdf5格式数据集的下载地址:
数据集名称:
indoor3d_sem_seg_hdf5_data.zip
下载地址:
https://shapenet.cs.stanford.edu/media/indoor3d_sem_seg_hdf5_data.zip
同时也可以下载原始数据集,根据需要制作自己的数据集。文件夹中提供了两个python脚本用于制作自己的数据集:collect_indoor3d_data.py 以及 gen_indoor3d_h5.py。前者用于数据的重组,转换为.npy格式(Numpy)的文件,后者用于将npy文件批量转换为HDF5文件。
上面的HDF5文件对应原始数据集中area6部分点云。也可以自行下载原始数据集,制作其他区域的数据集。
模型训练:
python train.py --log_dir log6 --test_area 6
由于训练耗时较长,要想得到较好的结果建议在服务器端训练,训练好后将model.ckpt文件下载到本地即可。我训练了30轮,精确度约为0.875。
evaluate部分需要下载原始数据集(Stanford3dDataset_v1.2_Aligned_Version),并转换为.npy格式用于程序读取。最终将会输出测试结果以及.obj格式的点云,可以借助MeshLab软件进行可视化。
数据集的下载地址为谷歌云盘:
数据集名称:
Stanford3dDataset_v1.2_Aligned_Version.zip
下载地址:
https://docs.google.com/forms/d/e/1FAIpQLScDimvNMCGhy_rmBA2gHfDu3naktRm6A8BPwAWWDv-Uhm6Shw/viewform?c=0&w=1
注意:直接下载成功率较低。谷歌云盘的文件下载由于有密匙认证的机制,不支持断点续传。当你下载到一半如果由于网络状况中断了连接,那么只能从头下载,非常麻烦。
解决方法:使用IDM下载器(需设置代理),当下载中断时IDM会提示你输入当前下载文件的新地址,此时重新点一次谷歌云盘中的下载链接,就能继续下载剩余部分了。
在下载好了原始数据集后,需要将点云数据转换为.npy格式:
collect_indoor3d_data.py
接下来在使用 batch_inference.py 文件进行测试。
以Area6为例:
python batch_inference.py --model_path log6/model.ckpt --dump_dir log6/dump --output_filelist log6/output_filelist.txt --room_data_filelist meta/area6_data_label.txt --visu
注意indoor3d_util.py中有一处需要修改:
#sample_data()方法中的这一句在python3下运行会报错
return np.concatenate([data, dup_data], 0), range(N)+list(sample)
需要将range(N)转换为list类型:↓
return np.concatenate([data, dup_data], 0), list(range(N)) + list(sample)
最终在sem_seg/log6/dump 文件夹下会保存测试的结果(数据集中Area6部分)。
log_evaluate.txt文件中保存了每个点云的loss以及accuracy结果。
同时程序将Area6分为了一个个独立的房间,每个房间对应四个文件:pred.obj,pred.txt,gt.obj,gt.txt。
分别为预测,真实值对应的.obj格式的点云文件及txt格式的语义标记结果。
以Area6中的office37为例:
Area_6_office_2_pred.obj为模型预测的语义标记结果。使用MeshLab可视化显示:
Area_6_office_2_gt.obj为真实语义标记结果。如下图:
最终整个Area6的所有房间语义分割结果的准确度约为0.858。我观察了一些预测标记结果,大体上分类较为准确,但是也会出现一些“低级错误”,一面墙上零散的几个点被标记为了其他的物品,因此模型的性能仍有很大的提升空间。
调试某个程序时遇到了这个问题,提示缺少包:pretrainedmodels
这个包保存了一些经过了预训练的经典模型,免去了搭模型的步骤。
直接安装就可以解决问题,但是有一点需要特别注意:在调用对应的网络模型前会先下载对应的模型,下载速度较慢,建议自行手动下载。
在分类结果可视化中使用到了imsave函数用于保存图像,但是重装了多次scipy都没有消除这个bug,这是因为只有较老版本(1.2.1)才有这个函数。
因此解决方案就是安装1.2.1之前版本的scipy。
conda install scipy=1.2.1
在补充材料B中,文章中设计了一项模型健壮性测试:测试模型在丢失部分输入点情况下的表现。
实验对比了PointNet与VoxNet的准确度下降情况:
可以看到当输入点丢失50%时PointNet预测结果的准确度下降非常小,这也体现了PointNet的高性能
在补充材料F的第一项测试中,文章通过控制输入点数量以及单层网络的宽度来测试二者对结果的影响,如图:
由前一项实验已经得出输入点数量对结果的影响,当输入点数量足够时,PointNet都能取得较好的结果。
但网络的宽度同样很重要,当神经元数量较少时,网络的性能将会大幅下降,数量达到512,1024时已经达到了模型的性能瓶颈。因此在模型的定义中MLP最后一层通常为1024,而不是更大的数值。
在设计自己的网络时也可以参考这项实验,网络不够宽将会影响到结果表现,而太宽又会导致训练的时间成本大幅增加。因此需要根据实验结果来确定最佳的宽度。
在网络的训练中见过几种不同的测试集划分方法,比如使用scikit-learn的train_test_split函数,或者K折交叉验证等。
以下总结了几种常用的数据集划分方法,以后在编写程序训练时可以根据使用情况来选择不同的划分策略。
留出法(hold-out):留出法将数据集分为两个互斥的子集,如70%的训练集与30%的测试集,注意采用分层采样法(即保留类别比例,使得测试集中每一类的占比与训练集中相近)
使用这种方法常常将2/3~4/5的数据用于训练,其余的用于测试。
交叉验证又称K折交叉验证(k-fold cross validation):这种方法将数据集划分为K个互斥子集,每次使用k-1个子集进行训练,剩下的一个子集用于测试。总共进行K次训练测试,取平均值。
以10折交叉验证为例,首先将数据集分为编号1,2,3……10。那么第一次训练则使用2 ~ 10 作为数据集,1作为测试集。第二次训练使用1,3 ~ 10作为数据集,2作为测试集,以此类推,总共进行10次训练与测试,最终的结果为这10次测试结果的平均值。
采用这种方式,结果的稳定性与保真性取决于K的取值,一般K常取5,10,20等。
特殊情况:留一法(leave-one-out)可以看为一种特殊的K折交叉验证。令K的取值等于样本数量m,那么每次都是用m-1个样本进行训练,一个样本用于测试,总共重复m次。
由于测试集足够大,能够很好的代表样本。同时每个样本能够用于验证模型的准确性,因此这种方法的评估结果更加准确真实。
但是这种方法的弊端也比较明显,即对数据量有限制,当样本数量较多时,将会耗费大量时间。因此只适用于小数据集。
自助法(bootstrapping):首先对数据集进行m次有放回的采样:每次取一个样本,重复m次。最终得到的训练集中包含了m个样本,由于是有放回采样,因此可能包含一些重复的样本,同时原始数据集中也有大约36.8%的样本从来都没被采到,这些样本作为测试集。
这种方法在数据集较小、难以有效划分数据集、训练集的情况下很有效。但是采样的随机性会导致最终得到的训练集中样本的分布可能会改变,因此在数据量足够大的情况下,使用交叉验证法与留出法是更好的选择。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。