论文学习随记:Unsupervised 3D Shape Completion through GAN Inversion

论文研读

1.两个component:

①用于提升均匀性的PatchVariance loss:

loss采样小的patch,更接近于平面运算;
方差between patch中心和它的最近neighbor;
我们的是一个软正则化器,在训练GANs时,可以在动态的对象级别上增强均匀性。

②用于估计点对应关系的masking机制K-Mask:

input中的每个点都去predicted shape中寻找k最近邻;
可见的region的mask就由k-nearest的指数定义;
基于以上,去计算reconstruction loss。

2.KNN

核心思想:

“找到离它最近的k个实例,哪个类别最多即可”

如何选取k值:

k的意义:
通过极限情况(k=1、k=N)判断:
k小:可能会遇见噪声
k大:模型会变得简单
如何选取:
我们一般选取一个较小的数值,通常采取 交叉验证法来选取最优的k值。(也就是说,选取k值很重要的关键是实验调参,类似于神经网络选取多少层这种,通过调整超参数来得到一个较好的结果)

“最邻近”如何度量:

用于度量距离的标准:
几种距离标准

注:让每个特征都同等重要——特征归一化

学习参考链接

3.GAN inversion的目的

GAN inversion的目的是重建Xin,所以ShapeInversion才不需要paired training data。

4.预训练借鉴的tree-GAN是什么

是一个GAN网络,但是generator是一个新的树形结构:tree-GCN,特点是可以利用祖先节点的信息。论文中的FPD也是来自于这篇论文。
网络结构如下:
tree-GAN网络结构
结合原文描述理解网络结构:

  • input:从输入点云中视作高斯分布的一部分点中取一个单点进入生成器网络。
  • Branching:简单理解为这层的每个点,都能通过transform生成dl个新点,生成器以此扩充点的数量。
  • GraphConv:通过branching之后多了很多新点,GraphConv开始修改这些点的坐标,修改过程可以归纳成总式(4)。GraphConv的修改方式
  • All points generated by previous layers are stored and appended to the tree of the current layer:通过GraphConv后生成了一个set的新点,将与原本的z一起结合起来,作为下一层branching+GraphConv的输入。

5.整个网络流程究竟是怎样的

网络流程
首先是预训练的tree-gan中的generator使得能从原点云生成一个完整点云,然后通过k-mask降级到缺失点云,再通过两个loss使其接近xin,这个过程中会修正参数,最后获得一个最佳的潜在向量z、生成器去生成一个最佳的xc。所以它的output还是应该是中间的xc!!!

代码研读

1.解决问题:ImportError: cannot import name 'PILLOW_VERSION' from 'PIL' (/home/renke/anaconda3/envs/shapeinversion/lib/python3.7/site-packages/PIL/__init__.py)

pillow7.0.0已经没有PILLOW_VERSION这个东西了
pillow6.1还保留着,所以只需要conda install pillow=6.1即可

2.h5py 文件介绍

一个h5py文件是 “dataset” 和 “group” 二合一的容器。

  1. dataset : 类似数组组织的数据的集合,像 numpy 数组一样工作
  2. group : 包含了其它 dataset 和 其它 group ,像字典一样工作
    h5py文件结构示意图
    所以h5py文件的读取可以参考文件夹读取文件的方式。

3.pytorch加载数据

pytorch中加载数据的顺序是:
①创建一个dataset对象
②创建一个dataloader对象
③循环dataloader对象,将data,label拿到模型中去训练

4.epoch、batch_size、iteration等的理解

epoch:训练时,所有训练数据集都训练过一次。

举个例子:
mnist 数据集有 60000 张图片作为训练数据,10000 张图片作为测试数据。假设现在选择 Batch Size = 100 对模型进行训练。迭代30000次。

每个 Epoch 要训练的图片数量:60000(训练集上的所有图像)
训练集具有的 Batch 个数: 60000/100=600
每个 Epoch 需要完成的 Batch 个数: 600
每个 Epoch 具有的 Iteration 个数: 600(完成一个Batch训练,相当于参数迭代一次)
每个 Epoch 中发生模型权重更新的次数:600
训练 10 个Epoch后,模型权重更新的次数: 600*10=6000
不同Epoch的训练,其实用的是同一个训练集的数据。 第1个Epoch和第10个Epoch虽然用的都是训练集的60000图片,但是对模型的权重更新值却是完全不同的。因为不同Epoch的模型处于代价函数空间上的不同位置,模型的训练代越靠后,越接近谷底,其代价越小。总共完成30000次迭代,相当于完成了 30000/600=50 个Epoch。
参考链接

5.有关模型保存

  • 一般只保存模型参数,整个模型的保存、加载很费时间。
  • 过程其实是保存很多个epoch的模型参数,然后能从其中选择到一个表现最好的。例如作者应该就是保存了很多个epoch的模型参数,然后选了最好的重新命名为xxx.pt,然后放到云盘当中供其他人下载pretrain_models。

这篇源代码的模型参数保存(在pretrain_treegan.py中)是利用自定义结构(torch.save有两个参数,第一个是{},包含了所有想要保存下来的参数;第二个是本次保存的名称):

torch.save({
                        'epoch': epoch,
                        'D_state_dict': self.D.module.state_dict(),
                        'G_state_dict': self.G.module.state_dict(),
                        'D_loss': loss_log['D_loss'],
                        'G_loss': loss_log['G_loss'],
                        'FPD': metric['FPD']
                }, save_ckpt+str(epoch)+'_'+class_name+'.pt')

然后在shape_inversion.py中有对预训练模型的加载:

# load weights
checkpoint = torch.load(args.ckpt_load, map_location=self.args.device)
self.G.load_state_dict(checkpoint['G_state_dict'])
self.D.load_state_dict(checkpoint['D_state_dict'])

6.自己跑代码的顺序

通过以下流程小试了一下程序能不能跑通(只为了复现一遍实验流程,所以没有在意效果,所以其实是用测试集训练的)

pretrain_treegan.py

python pretrain_treegan.py --dataset_path ~/Data/CRN --split test --ckpt_path ./rk_pretrain_checkpoints/chair --epoch 5

【代码更改:LOAD_CHECKPOINT = None】
遇到的问题:
from scipy.misc import imread
ImportError: cannot import name ‘imread’
解决:
conda install imageio
然后再将代码中的from scipy.misc import imread改成from imageio import imread

trainer.py

python trainer.py --dataset CRN --class_choice chair --inversion_mode completion --mask_type k_mask --save_inversion_path ./rk_saved_results/CRN_chair --ckpt_load rk_pretrain_models/chairtree_ckpt_0_multi.pt --dataset_path ~/Data/CRN

这篇源代码的补全网络并没有保存模型进行评估,而是保存了补全结果进行评估.

eval_completion.py

python eval_completion.py --eval_with_GT true --saved_results_path rk_saved_results/CRN_chair

遇到的问题:阈值设置
min_dists[min_dists < thre]的意思是取min_dists中点的值小于阈值的点。我跑的时候发现报错了一个除数为零的问题,排查出来就出现在这个阈值上,表达的意思是之前训练输出保存下来的点离实际位置太远了。(通过下图看出的:)
差距太远
不过本身只是为了看这个代码我是否跑通了,所以把阈值设置为了3就能成功跑通了,最后的结果非常bad,不过也是在意料之中。

至此,with_gt的训练及评估情况就已经跑通了,所以现在要去继续做的任务是:1.了解tree-gan 2.看懂tree-gan的代码、看懂with_gt训练网络的代码、看懂without_gt的代码 3.尝试导入kitti(without_gt的代码)进行训练 4.阅读其他论文、尝试修改网络模块

其他尝试

在看tree-gan论文的同时,把plane类的pretrain_treegan.py跑了:

python pretrain_treegan.py --dataset_path ~/Data/CRN --split train --ckpt_path ./rk_pretrain_checkpoints/chair --class_choice plane --epoch 150

一个重要的血泪教训的知识!!
如果你的模型要跑一两天的话,你应该挂在后台:
直接在终端里跑,会话消失的时候进程就结束了。换句话说,你的终端要一直开着且保持稳定,如果意外断网了,你的训练模型就停止了。比较稳妥的方式是使用screen。

screen -S train 建立一个名为train的窗口,这样即使终端会话中断了,窗口依然存在。
conda activate xxx 激活你的环境
CUDA_VISIBLE_DEVICES=1,2 python train.py 设置显卡1和2为可用显卡,使用python运行文件
【screen相关用法】

要把最好的一个epoch作为rk_plane.pt,于是eval_treegan.py:

python eval_treegan.py --dataset_path ~/Data/CRN --save_sample_path ./rk_treegan_saved_results --model_pathname ./rk_pretrain_checkpoints/plane/tree_ckpt_0_multi.pt --gpu 1

为了一次性获得所有评估,对代码进行了改动:

G_net = Generator(features=args.G_FEAT, degrees=args.DEGREE, support=args.support,args=args).to(args.device)
    pathnames = glob.glob(args.model_pathname + "/*")
    for i in pathnames:
        checkpoint = torch.load(i, map_location=args.device)

评估结果如下:
评估结果
可以看到最低值出现在第80个epoch,于是把这个设置为rk_plane.pt

接着进行了对于plane类的训练:

python trainer.py --dataset CRN --class_choice plane --inversion_mode completion --mask_type k_mask --save_inversion_path ./rk_saved_results/CRN_plane --ckpt_load rk_pretrain_checkpoints/rk_plane.pt --dataset_path ~/Data/CRN --split train

然后进行评估:

python eval_completion.py --eval_with_GT true --saved_results_path rk_saved_results/CRN_plane
  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值