├── .gitignore
├── LICENSE
├── README.md
├── classification.py
├── dataset.py
├── gaussian.npy
├── image
├── dgcnn_cls_gaussian
│ ├── shapenetcorev2_250_modelnet40_train0_laptop.jpg
│ ├── shapenetcorev2_250_modelnet40_train10_bookshelf.jpg
│ ├── shapenetcorev2_250_modelnet40_train11_airplane.jpg
│ ├── shapenetcorev2_250_modelnet40_train12_chair.jpg
│ ├── shapenetcorev2_250_modelnet40_train14_plant.jpg
│ ├── shapenetcorev2_250_modelnet40_train16_table.jpg
│ ├── shapenetcorev2_250_modelnet40_train19_bench.jpg
│ ├── shapenetcorev2_250_modelnet40_train7_vase.jpg
│ ├── shapenetcorev2_250_shapenetcorev2_test37_earphone.jpg
│ ├── shapenetcorev2_250_shapenetcorev2_test57_chair.jpg
│ ├── shapenetcorev2_250_shapenetcorev2_test59_lamp.jpg
│ ├── shapenetcorev2_250_shapenetcorev2_train10_bag.jpg
│ ├── shapenetcorev2_250_shapenetcorev2_train12_bench.jpg
│ ├── shapenetcorev2_250_shapenetcorev2_train13_table.jpg
│ ├── shapenetcorev2_250_shapenetcorev2_train16_airplane.jpg
│ └── shapenetcorev2_250_shapenetcorev2_train4_tower.jpg
├── dgcnn_cls_plane
│ ├── shapenetcorev2_250_modelnet40_train0_laptop.jpg
│ ├── shapenetcorev2_250_modelnet40_train10_bookshelf.jpg
│ ├── shapenetcorev2_250_modelnet40_train11_airplane.jpg
│ ├── shapenetcorev2_250_modelnet40_train12_chair.jpg
│ ├── shapenetcorev2_250_modelnet40_train14_plant.jpg
│ ├── shapenetcorev2_250_modelnet40_train16_table.jpg
│ ├── shapenetcorev2_250_modelnet40_train19_bench.jpg
│ ├── shapenetcorev2_250_modelnet40_train7_vase.jpg
│ ├── shapenetcorev2_250_shapenetcorev2_test37_earphone.jpg
│ ├── shapenetcorev2_250_shapenetcorev2_test57_chair.jpg
│ ├── shapenetcorev2_250_shapenetcorev2_test59_lamp.jpg
│ ├── shapenetcorev2_250_shapenetcorev2_train10_bag.jpg
│ ├── shapenetcorev2_250_shapenetcorev2_train12_bench.jpg
│ ├── shapenetcorev2_250_shapenetcorev2_train13_table.jpg
│ ├── shapenetcorev2_250_shapenetcorev2_train16_airplane.jpg
│ └── shapenetcorev2_250_shapenetcorev2_train4_tower.jpg
├── dgcnn_cls_sphere
│ ├── shapenetcorev2_250_modelnet40_train0_laptop.jpg
│ ├── shapenetcorev2_250_modelnet40_train10_bookshelf.jpg
│ ├── shapenetcorev2_250_modelnet40_train11_airplane.jpg
│ ├── shapenetcorev2_250_modelnet40_train12_chair.jpg
│ ├── shapenetcorev2_250_modelnet40_train14_plant.jpg
│ ├── shapenetcorev2_250_modelnet40_train16_table.jpg
│ ├── shapenetcorev2_250_modelnet40_train19_bench.jpg
│ ├── shapenetcorev2_250_modelnet40_train7_vase.jpg
│ ├── shapenetcorev2_250_shapenetcorev2_test37_earphone.jpg
│ ├── shapenetcorev2_250_shapenetcorev2_test57_chair.jpg
│ ├── shapenetcorev2_250_shapenetcorev2_test59_lamp.jpg
│ ├── shapenetcorev2_250_shapenetcorev2_train10_bag.jpg
│ ├── shapenetcorev2_250_shapenetcorev2_train12_bench.jpg
│ ├── shapenetcorev2_250_shapenetcorev2_train13_table.jpg
│ ├── shapenetcorev2_250_shapenetcorev2_train16_airplane.jpg
│ └── shapenetcorev2_250_shapenetcorev2_train4_tower.jpg
├── dgcnn_seg_gaussian
│ ├── shapenetcorev2_290_modelnet40_train0_laptop.jpg
│ ├── shapenetcorev2_290_modelnet40_train10_bookshelf.jpg
│ ├── shapenetcorev2_290_modelnet40_train11_airplane.jpg
│ ├── shapenetcorev2_290_modelnet40_train12_chair.jpg
│ ├── shapenetcorev2_290_modelnet40_train14_plant.jpg
│ ├── shapenetcorev2_290_modelnet40_train16_table.jpg
│ ├── shapenetcorev2_290_modelnet40_train19_bench.jpg
│ ├── shapenetcorev2_290_modelnet40_train7_vase.jpg
│ ├── shapenetcorev2_290_shapenetcorev2_test37_earphone.jpg
│ ├── shapenetcorev2_290_shapenetcorev2_test57_chair.jpg
│ ├── shapenetcorev2_290_shapenetcorev2_test59_lamp.jpg
│ ├── shapenetcorev2_290_shapenetcorev2_train10_bag.jpg
│ ├── shapenetcorev2_290_shapenetcorev2_train12_bench.jpg
│ ├── shapenetcorev2_290_shapenetcorev2_train13_table.jpg
│ ├── shapenetcorev2_290_shapenetcorev2_train16_airplane.jpg
│ └── shapenetcorev2_290_shapenetcorev2_train4_tower.jpg
├── dgcnn_seg_plane
│ ├── shapenetcorev2_290_modelnet40_train0_laptop.jpg
│ ├── shapenetcorev2_290_modelnet40_train10_bookshelf.jpg
│ ├── shapenetcorev2_290_modelnet40_train11_airplane.jpg
│ ├── shapenetcorev2_290_modelnet40_train12_chair.jpg
│ ├── shapenetcorev2_290_modelnet40_train14_plant.jpg
│ ├── shapenetcorev2_290_modelnet40_train16_table.jpg
│ ├── shapenetcorev2_290_modelnet40_train19_bench.jpg
│ ├── shapenetcorev2_290_modelnet40_train7_vase.jpg
│ ├── shapenetcorev2_290_shapenetcorev2_test37_earphone.jpg
│ ├── shapenetcorev2_290_shapenetcorev2_test57_chair.jpg
│ ├── shapenetcorev2_290_shapenetcorev2_test59_lamp.jpg
│ ├── shapenetcorev2_290_shapenetcorev2_train10_bag.jpg
│ ├── shapenetcorev2_290_shapenetcorev2_train12_bench.jpg
│ ├── shapenetcorev2_290_shapenetcorev2_train13_table.jpg
│ ├── shapenetcorev2_290_shapenetcorev2_train16_airplane.jpg
│ └── shapenetcorev2_290_shapenetcorev2_train4_tower.jpg
├── dgcnn_seg_sphere
│ ├── shapenetcorev2_290_modelnet40_train0_laptop.jpg
│ ├── shapenetcorev2_290_modelnet40_train10_bookshelf.jpg
│ ├── shapenetcorev2_290_modelnet40_train11_airplane.jpg
│ ├── shapenetcorev2_290_modelnet40_train12_chair.jpg
│ ├── shapenetcorev2_290_modelnet40_train14_plant.jpg
│ ├── shapenetcorev2_290_modelnet40_train16_table.jpg
│ ├── shapenetcorev2_290_modelnet40_train19_bench.jpg
│ ├── shapenetcorev2_290_modelnet40_train7_vase.jpg
│ ├── shapenetcorev2_290_shapenetcorev2_test37_earphone.jpg
│ ├── shapenetcorev2_290_shapenetcorev2_test57_chair.jpg
│ ├── shapenetcorev2_290_shapenetcorev2_test59_lamp.jpg
│ ├── shapenetcorev2_290_shapenetcorev2_train10_bag.jpg
│ ├── shapenetcorev2_290_shapenetcorev2_train12_bench.jpg
│ ├── shapenetcorev2_290_shapenetcorev2_train13_table.jpg
│ ├── shapenetcorev2_290_shapenetcorev2_train16_airplane.jpg
│ └── shapenetcorev2_290_shapenetcorev2_train4_tower.jpg
├── distance.png
├── gaussian.png
├── input
│ ├── modelnet40_train0_laptop_orign.jpg
│ ├── modelnet40_train10_bookshelf_orign.jpg
│ ├── modelnet40_train11_airplane_orign.jpg
│ ├── modelnet40_train12_chair_orign.jpg
│ ├── modelnet40_train14_plant_orign.jpg
│ ├── modelnet40_train16_table_orign.jpg
│ ├── modelnet40_train19_bench_orign.jpg
│ ├── modelnet40_train7_vase_orign.jpg
│ ├── shapenetcorev2_test37_earphone_orign.jpg
│ ├── shapenetcorev2_test57_chair_orign.jpg
│ ├── shapenetcorev2_test59_lamp_orign.jpg
│ ├── shapenetcorev2_train10_bag_orign.jpg
│ ├── shapenetcorev2_train12_bench_orign.jpg
│ ├── shapenetcorev2_train13_table_orign.jpg
│ ├── shapenetcorev2_train16_airplane_orign.jpg
│ └── shapenetcorev2_train4_tower_orign.jpg
├── original_gaussian
│ ├── shapenetcorev2_278_modelnet40_train0_laptop.jpg
│ ├── shapenetcorev2_278_modelnet40_train10_bookshelf.jpg
│ ├── shapenetcorev2_278_modelnet40_train11_airplane.jpg
│ ├── shapenetcorev2_278_modelnet40_train12_chair.jpg
│ ├── shapenetcorev2_278_modelnet40_train14_plant.jpg
│ ├── shapenetcorev2_278_modelnet40_train16_table.jpg
│ ├── shapenetcorev2_278_modelnet40_train19_bench.jpg
│ ├── shapenetcorev2_278_modelnet40_train7_vase.jpg
│ ├── shapenetcorev2_278_shapenetcorev2_test37_earphone.jpg
│ ├── shapenetcorev2_278_shapenetcorev2_test57_chair.jpg
│ ├── shapenetcorev2_278_shapenetcorev2_test59_lamp.jpg
│ ├── shapenetcorev2_278_shapenetcorev2_train10_bag.jpg
│ ├── shapenetcorev2_278_shapenetcorev2_train12_bench.jpg
│ ├── shapenetcorev2_278_shapenetcorev2_train13_table.jpg
│ ├── shapenetcorev2_278_shapenetcorev2_train16_airplane.jpg
│ └── shapenetcorev2_278_shapenetcorev2_train4_tower.jpg
├── original_plane
│ ├── shapenetcorev2_278_modelnet40_train0_laptop.jpg
│ ├── shapenetcorev2_278_modelnet40_train10_bookshelf.jpg
│ ├── shapenetcorev2_278_modelnet40_train11_airplane.jpg
│ ├── shapenetcorev2_278_modelnet40_train12_chair.jpg
│ ├── shapenetcorev2_278_modelnet40_train14_plant.jpg
│ ├── shapenetcorev2_278_modelnet40_train16_table.jpg
│ ├── shapenetcorev2_278_modelnet40_train19_bench.jpg
│ ├── shapenetcorev2_278_modelnet40_train7_vase.jpg
│ ├── shapenetcorev2_278_shapenetcorev2_test37_earphone.jpg
│ ├── shapenetcorev2_278_shapenetcorev2_test57_chair.jpg
│ ├── shapenetcorev2_278_shapenetcorev2_test59_lamp.jpg
│ ├── shapenetcorev2_278_shapenetcorev2_train10_bag.jpg
│ ├── shapenetcorev2_278_shapenetcorev2_train12_bench.jpg
│ ├── shapenetcorev2_278_shapenetcorev2_train13_table.jpg
│ ├── shapenetcorev2_278_shapenetcorev2_train16_airplane.jpg
│ └── shapenetcorev2_278_shapenetcorev2_train4_tower.jpg
├── original_sphere
│ ├── shapenetcorev2_278_modelnet40_train0_laptop.jpg
│ ├── shapenetcorev2_278_modelnet40_train10_bookshelf.jpg
│ ├── shapenetcorev2_278_modelnet40_train11_airplane.jpg
│ ├── shapenetcorev2_278_modelnet40_train12_chair.jpg
│ ├── shapenetcorev2_278_modelnet40_train14_plant.jpg
│ ├── shapenetcorev2_278_modelnet40_train16_table.jpg
│ ├── shapenetcorev2_278_modelnet40_train19_bench.jpg
│ ├── shapenetcorev2_278_modelnet40_train7_vase.jpg
│ ├── shapenetcorev2_278_shapenetcorev2_test37_earphone.jpg
│ ├── shapenetcorev2_278_shapenetcorev2_test57_chair.jpg
│ ├── shapenetcorev2_278_shapenetcorev2_test59_lamp.jpg
│ ├── shapenetcorev2_278_shapenetcorev2_train10_bag.jpg
│ ├── shapenetcorev2_278_shapenetcorev2_train12_bench.jpg
│ ├── shapenetcorev2_278_shapenetcorev2_train13_table.jpg
│ ├── shapenetcorev2_278_shapenetcorev2_train16_airplane.jpg
│ └── shapenetcorev2_278_shapenetcorev2_train4_tower.jpg
├── plane.png
└── sphere.png
├── inference.py
├── loss.py
├── main.py
├── model.py
├── reconstruction.py
├── sphere.npy
├── svm.py
├── tensorboard
├── Classify_dgcnn_cls_k20
│ └── events.out.tfevents.1578666096.human1
├── Classify_dgcnn_cls_k40_1024_b32
│ └── events.out.tfevents.1579746166.server231
├── Reconstruct_dgcnn_cls_k20_gaussian
│ └── events.out.tfevents.1578226376.human1
├── Reconstruct_dgcnn_cls_k20_plane
│ └── events.out.tfevents.1577427494.human1
├── Reconstruct_dgcnn_cls_k20_sphere
│ └── events.out.tfevents.1577698740.human1
├── Reconstruct_dgcnn_cls_k40_gaussian
│ └── events.out.tfevents.1579955081.server231
├── Reconstruct_dgcnn_cls_k40_plane
│ └── events.out.tfevents.1577866606.human1
├── Reconstruct_dgcnn_cls_k40_sphere
│ └── events.out.tfevents.1577935530.human1
├── Reconstruct_dgcnn_cls_k40_sphere_1024_b32
│ └── events.out.tfevents.1579919706.server231
├── Reconstruct_dgcnn_seg_k20_gaussian
│ ├── events.out.tfevents.1578371932.human1
│ └── events.out.tfevents.1578661771.human1
├── Reconstruct_dgcnn_seg_k20_plane
│ ├── events.out.tfevents.1578186628.human1
│ └── events.out.tfevents.1578443368.human1
├── Reconstruct_dgcnn_seg_k20_sphere
│ ├── events.out.tfevents.1578202920.human1
│ └── events.out.tfevents.1578447006.human1
├── Reconstruct_dgcnn_seg_k40_gaussian
│ └── events.out.tfevents.1580628995.server231
├── Reconstruct_dgcnn_seg_k40_plane
│ └── events.out.tfevents.1580304772.server231
├── Reconstruct_dgcnn_seg_k40_sphere
│ └── events.out.tfevents.1580304803.server231
├── Reconstruct_original_gaussian
│ └── events.out.tfevents.1578226412.human1
├── Reconstruct_original_plane
│ └── events.out.tfevents.1577003758.human1
└── Reconstruct_original_sphere
│ └── events.out.tfevents.1577366104.human1
├── utils.py
└── visualization.py
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | */.DS_Store
3 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 An Tao
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Unsupervised Point Cloud Reconstruction for Classific Feature Learning
2 | ## Introduction
3 | Can unsupervised point cloud reconstruction extract features suitable for classification?
4 |
5 | This work aims to show whether learning a unsupervised point cloud reconstruction task, for example FoldingNet, is able to extract features performing well in classification. We do all experiments under the framework of FoldingNet.
6 |
7 | Details for FoldingNet see **FoldingNet: Point Cloud Auto-encoder via Deep Grid Deformation** (https://arxiv.org/abs/1712.07262).
8 |
9 | We also tried to use [DGCNN](https://arxiv.org/abs/1831.07829) as encoder. DGCNN provides two type of networks, one for classification and one for segmentation. We use "DGCNN_Cls" to denote network for classification and "DGCNN_Seg" for segmentation. For both network, we adopt the feature extraction part as encoder in FoldingNet.
10 |
11 | Experimental results show that better reconstruction performance do not correspond with better classfication accuracy of linear SVM classifier. Feature which good at classfication contains more nonobjective information, losing the ability to reconstruct detailedly. However, it is only this nonobjective information that is capable to capture the high level characteristic of its belonging category and thus make a great contribution in classfication task.
12 |
13 | **The key contributions of this work are as follows:**
14 |
15 | - We provide a pytorch reimplementation for FoldingNet.
16 | - We also use source points for decoder from sphere surface and gaussian distribution. Results show that source points from sphere surface can reconstruct better.
17 | - We do experiments using DGCNN as encoder and provide the classification performance for linear SVM classifier. The transfer dataset performance is better than the state-of-the-art unsupervised methods. We also train our best unsupervised model supervisedly, our unsupervised results still win out.
18 | - We illustrate that better reconstruction results do not correspond with better feature for classfication.
19 |
20 | If you find this work useful, please cite:
21 | ```
22 | @article{tao2020,
23 | Author = {An Tao},
24 | Title = {Unsupervised Point Cloud Reconstruction for Classific Feature Learning},
25 | Journal = {https://github.com/antao97/UnsupervisedPointCloudReconstruction},
26 | Year = {2020}
27 | }
28 | ```
29 |
30 |
31 | ## Requirements
32 | - Python 3.7
33 | - PyTorch 1.2
34 | - CUDA 10.0
35 | - Package: glob, h5py, tensorflow, tensorboard, tensorboardX and sklearn
36 |
37 |
38 | ## Download datasets
39 | Download the HDF5 format datasets (where each shape is sampled 2,048 points uniformly):
40 |
41 | - ShapeNetCore.v2 (0.98G) [[TsinghuaCloud]](https://cloud.tsinghua.edu.cn/f/06a3c383dc474179b97d/) [[BaiduDisk]](https://pan.baidu.com/s/154As2kzHZczMipuoZIc0kg)
42 | - ModelNet40 (194M) [[TsinghuaCloud]](https://cloud.tsinghua.edu.cn/f/b3d9fe3e2a514def8097/) [[BaiduDisk]](https://pan.baidu.com/s/1NQZgN8tvHVqQntxefcdVAg)
43 |
44 | You can find more details about the above datasets in this [repo](https://github.com/antao97/PointCloudDatasets).
45 |
46 |
47 | ## Experiment settings
48 | To evaluate the quality of extracted features, we use ShapeNetCore.v2 dataset to both train the FoldingNet auto-encoder and a linear SVM classifier. Specifically, we train the linear SVM classifier on ShapeNetCore.v2 dataset using the features (latent representations) obtained from the auto-encoder, while training the autoencoder from the ShapeNetCore.v2 dataset with 278 epoches.
49 |
50 | For transfer performance, we train the linear SVM classifier on ModelNet 40 dataset using the features (latent representations) obtained from the same auto-encoder trained from the ShapeNetCore.v2 dataset.
51 |
52 | FoldingNet has demonstrated that a 2D plane grid can be gradually folded into a meaningful point cloud. However, can uniformly sampled points from surface of sphere gradually turn into a meaningful point cloud? This is reasonable because 3D point clouds are actually sampled from surface of an object. We generate source points from surface of sphere using farthest point sampling algorithm.
53 |
54 | A cloud of points corresponding to a shape can also be thought of as samples from a distribution that corresponds to the surface of this shape. Thus the goal for reconstruction task is to train a model which is able to transform source distribution, for example gaussian distribution, into the distribution corresponds to the surface of this shape. In this work we also try to use source points for decoder sampled from gaussian distribution N(0, I). However, it's worth noting that there is no relationship among x, y and z axises for points sampled from gaussian distribution, while for points from both plane grid and sphere surfance the relationship exists. Also because points sampled from gaussian distribution are i.i.d., there is no relationship among all points.
55 |
56 | In all experiments, we follow the training scheme of FoldingNet.
57 |
58 | **Note that:**
59 |
60 | - Other than using the modified Chamfer distance in FoldingNet paper, we adopt the original Chamfer distance proposed by [A Point Set Generation Network for 3D Object Reconstruction from a Single Image](https://arxiv.xilesou.top/pdf/1612.00603.pdf):
61 |
62 |
63 |
64 |
65 |
66 | - To use the local covariance proposed in FoldingNet paper, pleanse comment line 49 and uncomment line 50 in `model.py`. See this [issue](issues/1) for detailed information.
67 |
68 | **To train the network, run**
69 | ```
70 | python main.py --exp_name --dataset_root --encoder --k <16 | 20 | 40> --shape --dataset shapenetcorev2 --gpu
71 | ```
72 |
73 | You can download our already trained models from [[TsinghuaCloud]](https://cloud.tsinghua.edu.cn/d/835fb3e4b7dd43e88c1e/) or [[BaiduDisk]](https://pan.baidu.com/s/1FDNgZnrkCGqbQzH-CM6uBw) and place them under `snapshot/`.
74 |
75 | **To evaluate the performance of a given trained model, run**
76 | ```
77 | python main.py --eval --model_path --dataset_root --encoder --k <16 | 20 | 40> --shape --dataset --batch_size 4 --gpu
78 | ```
79 |
80 | Use `--no_cuda` if you want to run in CPU.
81 |
82 | **To visulize the reconstruction performance, run**
83 | ```
84 | python visualization.py --dataset_root --dataset --item= --split --encoder --k <16 | 20 | 40> --shape --model_path=snapshot//models --draw_original --draw_source_points
85 | ```
86 |
87 | Our script generates XML files and you are required to use [Mitsuba](https://www.mitsuba-renderer.org/index.html) to render them.
88 |
89 | **To use Tensorboard, run**
90 | ```
91 | tensorboard --logdir tensorboard --bind_all
92 | ```
93 | You can find the Tensorboard records under `tensorboard/`.
94 |
95 |
96 | ## Classification accuracy of linear SVM classifier
97 | ### Results with different settings
98 | | | Encoder | K | Epochs | Shape | ShapeNetCore.v2 | ModelNet40 |
99 | | :---: | :---: | :---: | :---: | :---: | :---: | :---: |
100 | | FoldingNet paper | Original | 16 | 278 | Plane | Unknown | 88.4% |
101 | | This work | Original | 16 | 278 | Plane | 81.5% | 88.4% |
102 | | This work | Original | 16 | 278 | Sphere | 81.9% | 88.8% |
103 | | This work | Original | 16 | 278 | Gaussian | 81.2% | 87.6% |
104 | | This work | DGCNN_cls | 20 | 250 | Plane | 83.7% | 90.6% |
105 | | This work | DGCNN_cls | 20 | 250 | Sphere | 83.7% | **91.0%** |
106 | | This work | DGCNN_cls | 20 | 250 | Gaussian | **84.0%** | 90.6% |
107 | | This work | DGCNN_cls | 40 | 250 | Plane | 83.5% | 90.0% |
108 | | This work | DGCNN_cls | 40 | 250 | Sphere | 83.6% | 90.0% |
109 | | This work | DGCNN_cls | 40 | 250 | Gaussian | 83.2% | 90.0% |
110 | | This work | DGCNN_seg | 20 | 290 | Plane | 83.2% | 90.0% |
111 | | This work | DGCNN_seg | 20 | 290 | Sphere | 83.5% | 90.4% |
112 | | This work | DGCNN_seg | 20 | 290 | Gaussian | 83.3% | 89.9% |
113 | | This work | DGCNN_seg | 40 | 290 | Plane | 83.7% | 89.6% |
114 | | This work | DGCNN_seg | 40 | 290 | Sphere | 83.6% | 90.7% |
115 | | This work | DGCNN_seg | 40 | 290 | Gaussian | 83.2% | 89.8% |
116 |
117 | ### Comparison to supervised method
118 | We also train DGCNN_Cls with classification task on ShapeNetCore.v2 dataset, using the training scheme from DGCNN paper. We train two networks for classification. One uses the setting the same as reconstruction and the other uses the best setting for classification.
119 |
120 | | Task | Encoder | K | Feature Dim | Epochs | Batch Size | ShapeNetCore.v2 | ModelNet40 |
121 | | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: |
122 | | Reconstruction | DGCNN_cls | 20 | 512 | 250 | 16 | 83.7% | 91.0% |
123 | | Classification | DGCNN_cls | 20 | 512 | 250 | 16 | 94.5% | 90.4% |
124 | | Reconstruction | DGCNN_cls | 40 | 1024 | 250 | 32 | 82.8% | 89.0% |
125 | | Classification | DGCNN_cls | 40 | 1024 | 250 | 32 | **96.8%** | **92.0%** |
126 |
127 | If you want to run this experiment, just run
128 | ```
129 | python main.py --task --exp_name --dataset_root --encoder dgcnn_cls --feat_dims <512 | 1024> --k <20 | 40> --dataset shapenetcorev2 --batch_size <16 | 32> --gpu
130 | ```
131 |
132 | You can also find our trained model in above mentioned links. To evaluate the performance, run
133 | ```
134 | python main.py --eval --task --model_path --dataset_root --encoder dgcnn_cls --feat_dims <512 | 1024> --k <20 | 40> --shape sphere --dataset --batch_size 4 --gpu
135 | ```
136 |
137 | ### Baseline Results
138 |
139 | We test classification accuracy of linear SVM classifier with untrained encoder. This table shows the baseline performance.
140 |
141 | | Encoder | K | ShapeNetCore.v2 | ModelNet40 |
142 | | :---: | :---: | :---: | :---: |
143 | | Original | 16 | 25.4% | 5.2% |
144 | | DGCNN_cls | 20 | 74.7% | 69.5% |
145 | | DGCNN_cls | 40 | **75.0%** | **73.0%** |
146 | | DGCNN_seg | 20 | 72.0% | 62.0% |
147 | | DGCNN_seg | 40 | 73.1% | 64.0% |
148 |
149 | If you want to run this experiment, just run
150 | ```
151 | python main.py --eval --dataset_root --encoder dgcnn_cls --k <16 | 20 | 40> --dataset --gpu
152 | ```
153 |
154 | ### Compare to other unsupervised feature learning models
155 |
156 | Models are all trained in ShapeNetCore dataset and transfered into ModelNet40 dataset.
157 |
158 | | Model | Reference | ModelNet40 |
159 | | :---: | :---: | :---: |
160 | | [SPH](https://pdfs.semanticscholar.org/da27/5dcffd835ddfd41fd73ea147c767c605d3f0.pdf) | SGP 2003| 68.2% |
161 | | [LFD](http://citeseerx.ist.psu.edu/viewdoc/download;jsessionid=46D0F4C488A2AF0FCF3A63837F391EED?doi=10.1.1.10.8872&rep=rep1&type=pdf) | CGF 2003| 75.5% |
162 | | [T-L Network](https://arxiv.xilesou.top/pdf/1603.08637) | ECCV 2016 | 74.4% |
163 | | [VConv-DAE](https://arxiv.xilesou.top/pdf/1604.03755) | ECCV 2016 | 75.5% |
164 | | [3D-GAN](http://papers.nips.cc/paper/6096-learning-a-probabilistic-latent-space-of-object-shapes-via-3d-generative-adversarial-modeling.pdf) | NIPS 2016 | 83.3% |
165 | | [Latent-GAN](https://arxiv.xilesou.top/pdf/1707.02392) | ICML 2018 | 83.7% |
166 | | [PointGrow](https://arxiv.xilesou.top/pdf/1810.05591) | ArXiv 2018 | 83.8% |
167 | | [MRTNet-VAE](http://openaccess.thecvf.com/content_ECCV_2018/papers/Matheus_Gadelha_Multiresolution_Tree_Networks_ECCV_2018_paper.pdf) | ECCV 2018 | 86.4% |
168 | | [PointFlow](https://arxiv.org/pdf/1906.12320) | ICCV 2019 | 86.8% |
169 | | [PCGAN](https://arxiv.xilesou.top/pdf/1810.05795) | ArXiv 2018 | 87.8% |
170 | | [FoldingNet](https://arxiv.org/abs/1712.07262) | CVPR 2018 | 88.4% |
171 | | [PointCapsNet](http://openaccess.thecvf.com/content_CVPR_2019/papers/Zhao_3D_Point_Capsule_Networks_CVPR_2019_paper.pdf) | CVPR 2019 | 88.9% |
172 | | [Multi-Task](https://arxiv.org/pdf/1910.08207) | ICCV 2019 | 89.1% |
173 | | [MAP-VAE](https://arxiv.xilesou.top/pdf/1907.12704.pdf) | ICCV 2019 | 90.2% |
174 | | FoldingNet (DGCNN_Cls_K20 + Sphere) | - | **91.0%** |
175 |
176 |
177 | ## Reconstruction performance
178 | ### Sourse
179 | 2D Plane Spherical surface Gaussian distribution
180 |
181 |
182 |
183 |
184 |
185 |
186 | ### ShapeNetCore.v2 dataset
187 | Original DGCNN_Cls (K20) DGCNN_Seg (K20)
188 |
189 | Input Plane Sphere Gaussian Plane Sphere Gaussian Plane Sphere Gaussian
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 | ### ModelNet40 dataset
274 | Original DGCNN_Cls (K20) DGCNN_Seg (K20)
275 |
276 | Input Plane Sphere Gaussian Plane Sphere Gaussian Plane Sphere Gaussian
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 | ## CD (Chamfer Distance) scores for trained model
362 | We provide the avg CD scores in each dataset after training, which serves as the measurement of folding performance. CD scores are multiplied by 10^4.
363 |
364 | ### Results with different settings
365 |
366 | | Encoder | K | Shape | ShapeNetCore.v2 | ModelNet40 |
367 | | :---: | :---: | :---: | :---: | :---: |
368 | | Original | 16 | Plane | 11.11 | 9.88 |
369 | | Original | 16 | Sphere | 10.58 | **9.69** |
370 | | Original | 16 | Gaussian | **9.63** | 11.09 |
371 | | DGCNN_cls | 20 | Plane | 11.08 | 12.68 |
372 | | DGCNN_cls | 20 | Sphere | 11.07 | 12.68 |
373 | | DGCNN_cls | 20 | Gaussian | 11.18 | 12.77 |
374 | | DGCNN_cls | 40 | Plane | 11.74 | 13.36 |
375 | | DGCNN_cls | 40 | Sphere | 11.17 | 12.58 |
376 | | DGCNN_cls | 40 | Gaussian | 14.77 | 17.03 |
377 | | DGCNN_seg | 20 | Plane | 11.28 | 12.55 |
378 | | DGCNN_seg | 20 | Sphere | 10.88 | 12.49 |
379 | | DGCNN_seg | 20 | Gaussian | 13.36 | 15.19 |
380 | | DGCNN_seg | 40 | Plane | 11.19 | 12.69 |
381 | | DGCNN_seg | 40 | Sphere | 10.68 | 12.69 |
382 | | DGCNN_seg | 40 | Gaussian | 11.95 | 13.74 |
383 |
384 | ### Compare to other reconstruction methods
385 | Models are all trained and evaluated in ShapeNetCore dataset.
386 |
387 | | Model | Reference | ShapeNetCore.v2 |
388 | | :---: | :---: | :---: |
389 | | [Latent-GAN](https://arxiv.xilesou.top/pdf/1707.02392) | ICML 2018 | **7.12** |
390 | | [AtlasNet](https://arxiv.xilesou.top/pdf/1802.05383.pdf) | CVPR 2018 | 5.13 |
391 | | [PointFlow](https://arxiv.org/pdf/1906.12320.pdf) | ICCV 2019 | 7.54 |
392 | | FoldingNet (Gaussian) | - | 9.63 |
393 |
394 |
395 | ## Performance analysis
396 | ### Effectiveness of our reimplementation
397 | The performance on ModelNet40 dataset is enough to validate the effectiveness of our reimplementation.
398 |
399 | ### Points from sphere surface
400 | The results of sphere show that the so-called "FoldingNet" does not restrict with folding operation. The essensce of FoldingNet decoder, i.e. MLP, is to map points from original space into new space, no matter the structure of points in original space is 2D plane grid or something else. Also, this mapping does not change neighbouring relations of points, which means adjacent points in original space are also adjacent in new space. Because point clouds are sampled from surface of an object, i.e. closed surface, the closed surface can be seen as mapped from surface of sphere just like pinching a blowing glass or Chinese sugar-figure. Thus it is reasonable to map uniformly sampled points from sphere surface to target point clouds through MLP, and as a matter of course we would consider reconstruction results for source points from sphere surface is better than 2D plane grid.
401 |
402 | ### Points from gaussian distribution
403 | Because each point is sampled independently from same gaussian distribution N(0, I), i.e. i.i.d., there is no relationship among points and the values of three axises. The reconstruction model has to learn the relationship with no prior knowledge, just like drawing on a white paper. If designed properly source points from gaussian distribution can do perfect job for reconstruction, but they can not help to extract good features for classification. This is because in order to learn the relationship the model need to focus to every details, and that is the reason why the learned model lose the ablity to extract feature in a more abstract sight, which is crucial for classification. The experimental results validate that in order to extract features suitable for classification, it is better to have some proper prior knowledge for souce points in order.
404 |
405 | ### Classification v.s. reconstruction
406 | This experiment shows that training without labels can also obtain comparable results and thus validates the effectiveness of reconstruction.
407 |
408 | ### Reconstruction performance
409 | All networks run well in low curvature smooth surface, but fail in not differentiable area (crossing of planes) and high curvature surface. Because a large number of training samples have four legs, e.g. chair and table, reconstruction network also runs well in these four legs shapes. The visualized results also show characteristics of reconstructed point cloud with different corresponding source points types and encoder types.
410 |
411 | From both visualized results and avg CD sorces, the overall reconstruction performance of ShapeNetCore.v2 dataset (training dataset) is better than ModelNet40 dataset (transfer dataset).
412 |
413 |
414 | #### Reference repos:
415 |
416 | - [FoldingNet](http://www.merl.com/research/license#FoldingNet)
417 | - [XuyangBai/FoldingNet](https://github.com/XuyangBai/FoldingNet)
418 | - [WangYueFt/dgcnn](https://github.com/WangYueFt/dgcnn)
419 | - [antao97/PointCloudDatasets](https://github.com/antao97/PointCloudDatasets)
420 | - [zekunhao1995/PointFlowRenderer](https://github.com/zekunhao1995/PointFlowRenderer)
421 |
--------------------------------------------------------------------------------
/classification.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | """
4 | @Author: An Tao
5 | @Contact: ta19@mails.tsinghua.edu.cn
6 | @File: reconstruction.py
7 | @Time: 2020/1/2 10:26 AM
8 | """
9 |
10 | import os
11 | import sys
12 | import time
13 | import shutil
14 | import numpy as np
15 | import torch
16 | import torch.optim as optim
17 | from torch.optim.lr_scheduler import CosineAnnealingLR
18 | import sklearn.metrics as metrics
19 |
20 | from tensorboardX import SummaryWriter
21 |
22 | from model import ClassificationNet
23 | from dataset import Dataset
24 | from utils import Logger
25 |
26 |
27 | class Classification(object):
28 | def __init__(self, args):
29 | self.dataset_name = args.dataset
30 | if args.epochs != None:
31 | self.epochs = args.epochs
32 | else:
33 | self.epochs = 250
34 | self.batch_size = args.batch_size
35 | self.snapshot_interval = args.snapshot_interval
36 | self.no_cuda = args.no_cuda
37 | self.model_path = args.model_path
38 |
39 | # create exp directory
40 | file = [f for f in args.model_path.split('/')]
41 | if args.exp_name != None:
42 | self.experiment_id = "Classify_" + args.exp_name
43 | elif file[-2] == 'models':
44 | self.experiment_id = file[-3]
45 | else:
46 | self.experiment_id = "Classify" + time.strftime('%m%d%H%M%S')
47 | snapshot_root = 'snapshot/%s' % self.experiment_id
48 | tensorboard_root = 'tensorboard/%s' % self.experiment_id
49 | self.save_dir = os.path.join(snapshot_root, 'models/')
50 | self.tboard_dir = tensorboard_root
51 |
52 | # check arguments
53 | if self.model_path == '':
54 | if not os.path.exists(self.save_dir):
55 | os.makedirs(self.save_dir)
56 | else:
57 | choose = input("Remove " + self.save_dir + " ? (y/n)")
58 | if choose == "y":
59 | shutil.rmtree(self.save_dir)
60 | os.makedirs(self.save_dir)
61 | else:
62 | sys.exit(0)
63 | if not os.path.exists(self.tboard_dir):
64 | os.makedirs(self.tboard_dir)
65 | else:
66 | shutil.rmtree(self.tboard_dir)
67 | os.makedirs(self.tboard_dir)
68 | sys.stdout = Logger(os.path.join(snapshot_root, 'log.txt'))
69 | self.writer = SummaryWriter(log_dir=self.tboard_dir)
70 |
71 | # print args
72 | print(str(args))
73 |
74 | # get gpu id
75 | gids = ''.join(args.gpu.split())
76 | self.gpu_ids = [int(gid) for gid in gids.split(',')]
77 | self.first_gpu = self.gpu_ids[0]
78 |
79 | # generate dataset
80 | self.train_dataset = Dataset(
81 | root=args.dataset_root,
82 | dataset_name=args.dataset,
83 | split='all',
84 | num_points=args.num_points,
85 | random_translate=True,
86 | random_rotate=args.use_rotate,
87 | random_jitter=args.use_jitter
88 | )
89 | self.train_loader = torch.utils.data.DataLoader(
90 | self.train_dataset,
91 | batch_size=args.batch_size,
92 | shuffle=True,
93 | num_workers=args.workers
94 | )
95 | print("Training set size:", self.train_loader.dataset.__len__())
96 |
97 | # initialize model
98 | self.model = ClassificationNet(args)
99 | if self.model_path != '':
100 | self._load_pretrain(args.model_path)
101 |
102 | # load model to gpu
103 | if not self.no_cuda:
104 | if len(self.gpu_ids) != 1: # multiple gpus
105 | self.model = torch.nn.DataParallel(self.model.cuda(self.first_gpu), self.gpu_ids)
106 | else:
107 | self.model = self.model.cuda(self.gpu_ids[0])
108 |
109 | # initialize optimizer
110 | self.parameter = self.model.parameters()
111 | self.optimizer = optim.SGD(self.parameter, lr=0.1, weight_decay=1e-4)
112 | self.scheduler = CosineAnnealingLR(self.optimizer, self.epochs, eta_min=1e-3)
113 |
114 |
115 | def run(self):
116 | self.train_hist = {
117 | 'loss': [],
118 | 'per_epoch_time': [],
119 | 'total_time': []
120 | }
121 | best_loss = 1000000000
122 | print('Training start!!')
123 | start_time = time.time()
124 | self.model.train()
125 | if self.model_path != '':
126 | start_epoch = self.model_path[-7:-4]
127 | if start_epoch[0] == '_':
128 | start_epoch = start_epoch[1:]
129 | start_epoch = int(start_epoch)
130 | else:
131 | start_epoch = 0
132 | for epoch in range(start_epoch, self.epochs):
133 | loss = self.train_epoch(epoch)
134 |
135 | # save snapeshot
136 | if (epoch + 1) % self.snapshot_interval == 0:
137 | self._snapshot(epoch + 1)
138 | if loss < best_loss:
139 | best_loss = loss
140 | self._snapshot('best')
141 |
142 | # save tensorboard
143 | if self.writer:
144 | self.writer.add_scalar('Train Loss', self.train_hist['loss'][-1], epoch)
145 | self.writer.add_scalar('Learning Rate', self._get_lr(), epoch)
146 |
147 | # finish all epoch
148 | self._snapshot(epoch + 1)
149 | if loss < best_loss:
150 | best_loss = loss
151 | self._snapshot('best')
152 | self.train_hist['total_time'].append(time.time() - start_time)
153 | print("Avg one epoch time: %.2f, total %d epochs time: %.2f" % (np.mean(self.train_hist['per_epoch_time']),
154 | self.epochs, self.train_hist['total_time'][0]))
155 | print("Training finish!... save training results")
156 |
157 |
158 | def train_epoch(self, epoch):
159 | epoch_start_time = time.time()
160 | loss_buf = []
161 | train_pred = []
162 | train_true = []
163 | num_batch = int(len(self.train_loader.dataset) / self.batch_size)
164 | for iter, (pts, label) in enumerate(self.train_loader):
165 | if not self.no_cuda:
166 | pts = pts.cuda(self.first_gpu)
167 | label = label.cuda(self.first_gpu)
168 |
169 | # forward
170 | self.optimizer.zero_grad()
171 | output, _ = self.model(pts)
172 |
173 | # loss
174 | if len(self.gpu_ids) != 1: # multiple gpus
175 | loss = self.model.module.get_loss(output, label)
176 | else:
177 | loss = self.model.get_loss(output, label)
178 |
179 | # backward
180 | loss.backward()
181 | self.optimizer.step()
182 | loss_buf.append(loss.detach().cpu().numpy())
183 |
184 | preds = output.max(dim=1)[1]
185 | train_true.append(label.view(-1).cpu().numpy())
186 | train_pred.append(preds.detach().cpu().numpy())
187 |
188 | # finish one epoch
189 | self.scheduler.step()
190 | epoch_time = time.time() - epoch_start_time
191 | self.train_hist['per_epoch_time'].append(epoch_time)
192 | self.train_hist['loss'].append(np.mean(loss_buf))
193 | train_true = np.concatenate(train_true)
194 | train_pred = np.concatenate(train_pred)
195 | print("Epoch %d: Loss %.6f, train acc: %.6f, train avg acc: %.6f, time %.4fs" % (epoch+1,
196 | np.mean(loss_buf),
197 | metrics.accuracy_score(
198 | train_true, train_pred),
199 | metrics.balanced_accuracy_score(
200 | train_true, train_pred),
201 | epoch_time))
202 | return np.mean(loss_buf)
203 |
204 |
205 | def _snapshot(self, epoch):
206 | state_dict = self.model.state_dict()
207 | from collections import OrderedDict
208 | new_state_dict = OrderedDict()
209 | for key, val in state_dict.items():
210 | if key[:6] == 'module':
211 | name = key[7:] # remove 'module.'
212 | else:
213 | name = key
214 | new_state_dict[name] = val
215 | save_dir = os.path.join(self.save_dir, self.dataset_name)
216 | torch.save(new_state_dict, save_dir + "_" + str(epoch) + '.pkl')
217 | print(f"Save model to {save_dir}_{str(epoch)}.pkl")
218 |
219 |
220 | def _load_pretrain(self, pretrain):
221 | state_dict = torch.load(pretrain, map_location='cpu')
222 | from collections import OrderedDict
223 | new_state_dict = OrderedDict()
224 | for key, val in state_dict.items():
225 | if key[:6] == 'module':
226 | name = key[7:] # remove 'module.'
227 | else:
228 | name = key
229 | new_state_dict[name] = val
230 | self.model.load_state_dict(new_state_dict)
231 | print(f"Load model from {pretrain}")
232 |
233 |
234 | def _get_lr(self, group=0):
235 | return self.optimizer.param_groups[group]['lr']
236 |
--------------------------------------------------------------------------------
/dataset.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | """
4 | @Author: An Tao
5 | @Contact: ta19@mails.tsinghua.edu.cn
6 | @File: dataset.py
7 | @Time: 2020/1/2 10:26 AM
8 | """
9 |
10 | import os
11 | import torch
12 | import json
13 | import h5py
14 | from glob import glob
15 | import numpy as np
16 | import torch.utils.data as data
17 |
18 |
19 | def translate_pointcloud(pointcloud):
20 | xyz1 = np.random.uniform(low=2./3., high=3./2., size=[3])
21 | xyz2 = np.random.uniform(low=-0.2, high=0.2, size=[3])
22 |
23 | translated_pointcloud = np.add(np.multiply(pointcloud, xyz1), xyz2).astype('float32')
24 | return translated_pointcloud
25 |
26 |
27 | def jitter_pointcloud(pointcloud, sigma=0.01, clip=0.02):
28 | N, C = pointcloud.shape
29 | pointcloud += np.clip(sigma * np.random.randn(N, C), -1*clip, clip)
30 | return pointcloud
31 |
32 |
33 | def rotate_pointcloud(pointcloud):
34 | theta = np.pi*2 * np.random.choice(24) / 24
35 | rotation_matrix = np.array([[np.cos(theta), -np.sin(theta)],[np.sin(theta), np.cos(theta)]])
36 | pointcloud[:,[0,2]] = pointcloud[:,[0,2]].dot(rotation_matrix) # random rotation (x,z)
37 | return pointcloud
38 |
39 |
40 | class Dataset(data.Dataset):
41 | def __init__(self, root, dataset_name='modelnet40',
42 | num_points=2048, split='train', load_name=False,
43 | random_rotate=False, random_jitter=False, random_translate=False):
44 |
45 | assert dataset_name.lower() in ['shapenetcorev2',
46 | 'shapenetpart', 'modelnet10', 'modelnet40']
47 | assert num_points <= 2048
48 |
49 | if dataset_name in ['shapenetpart', 'shapenetcorev2']:
50 | assert split.lower() in ['train', 'test', 'val', 'trainval', 'all']
51 | else:
52 | assert split.lower() in ['train', 'test', 'all']
53 |
54 | self.root = os.path.join(root, dataset_name + '*hdf5_2048')
55 | self.dataset_name = dataset_name
56 | self.num_points = num_points
57 | self.split = split
58 | self.load_name = load_name
59 | self.random_rotate = random_rotate
60 | self.random_jitter = random_jitter
61 | self.random_translate = random_translate
62 |
63 | self.path_h5py_all = []
64 | self.path_json_all = []
65 | if self.split in ['train','trainval','all']:
66 | self.get_path('train')
67 | if self.dataset_name in ['shapenetpart', 'shapenetcorev2']:
68 | if self.split in ['val','trainval','all']:
69 | self.get_path('val')
70 | if self.split in ['test', 'all']:
71 | self.get_path('test')
72 |
73 | self.path_h5py_all.sort()
74 | data, label = self.load_h5py(self.path_h5py_all)
75 | if self.load_name:
76 | self.path_json_all.sort()
77 | self.name = self.load_json(self.path_json_all) # load label name
78 |
79 | self.data = np.concatenate(data, axis=0)
80 | self.label = np.concatenate(label, axis=0)
81 |
82 | def get_path(self, type):
83 | path_h5py = os.path.join(self.root, '*%s*.h5'%type)
84 | self.path_h5py_all += glob(path_h5py)
85 | if self.load_name:
86 | path_json = os.path.join(self.root, '%s*_id2name.json'%type)
87 | self.path_json_all += glob(path_json)
88 | return
89 |
90 | def load_h5py(self, path):
91 | all_data = []
92 | all_label = []
93 | for h5_name in path:
94 | f = h5py.File(h5_name, 'r+')
95 | data = f['data'][:].astype('float32')
96 | label = f['label'][:].astype('int64')
97 | f.close()
98 | all_data.append(data)
99 | all_label.append(label)
100 | return all_data, all_label
101 |
102 | def load_json(self, path):
103 | all_data = []
104 | for json_name in path:
105 | j = open(json_name, 'r+')
106 | data = json.load(j)
107 | all_data += data
108 | return all_data
109 |
110 | def __getitem__(self, item):
111 | point_set = self.data[item][:self.num_points]
112 | label = self.label[item]
113 | if self.load_name:
114 | name = self.name[item] # get label name
115 |
116 | if self.random_rotate:
117 | point_set = rotate_pointcloud(point_set)
118 | if self.random_jitter:
119 | point_set = jitter_pointcloud(point_set)
120 | if self.random_translate:
121 | point_set = translate_pointcloud(point_set)
122 |
123 | # convert numpy array to pytorch Tensor
124 | point_set = torch.from_numpy(point_set)
125 | label = torch.from_numpy(np.array([label]).astype(np.int64))
126 | label = label.squeeze(0)
127 |
128 | if self.load_name:
129 | return point_set, label, name
130 | else:
131 | return point_set, label
132 |
133 | def __len__(self):
134 | return self.data.shape[0]
--------------------------------------------------------------------------------
/gaussian.npy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/gaussian.npy
--------------------------------------------------------------------------------
/image/dgcnn_cls_gaussian/shapenetcorev2_250_modelnet40_train0_laptop.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_gaussian/shapenetcorev2_250_modelnet40_train0_laptop.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_gaussian/shapenetcorev2_250_modelnet40_train10_bookshelf.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_gaussian/shapenetcorev2_250_modelnet40_train10_bookshelf.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_gaussian/shapenetcorev2_250_modelnet40_train11_airplane.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_gaussian/shapenetcorev2_250_modelnet40_train11_airplane.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_gaussian/shapenetcorev2_250_modelnet40_train12_chair.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_gaussian/shapenetcorev2_250_modelnet40_train12_chair.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_gaussian/shapenetcorev2_250_modelnet40_train14_plant.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_gaussian/shapenetcorev2_250_modelnet40_train14_plant.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_gaussian/shapenetcorev2_250_modelnet40_train16_table.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_gaussian/shapenetcorev2_250_modelnet40_train16_table.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_gaussian/shapenetcorev2_250_modelnet40_train19_bench.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_gaussian/shapenetcorev2_250_modelnet40_train19_bench.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_gaussian/shapenetcorev2_250_modelnet40_train7_vase.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_gaussian/shapenetcorev2_250_modelnet40_train7_vase.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_gaussian/shapenetcorev2_250_shapenetcorev2_test37_earphone.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_gaussian/shapenetcorev2_250_shapenetcorev2_test37_earphone.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_gaussian/shapenetcorev2_250_shapenetcorev2_test57_chair.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_gaussian/shapenetcorev2_250_shapenetcorev2_test57_chair.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_gaussian/shapenetcorev2_250_shapenetcorev2_test59_lamp.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_gaussian/shapenetcorev2_250_shapenetcorev2_test59_lamp.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_gaussian/shapenetcorev2_250_shapenetcorev2_train10_bag.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_gaussian/shapenetcorev2_250_shapenetcorev2_train10_bag.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_gaussian/shapenetcorev2_250_shapenetcorev2_train12_bench.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_gaussian/shapenetcorev2_250_shapenetcorev2_train12_bench.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_gaussian/shapenetcorev2_250_shapenetcorev2_train13_table.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_gaussian/shapenetcorev2_250_shapenetcorev2_train13_table.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_gaussian/shapenetcorev2_250_shapenetcorev2_train16_airplane.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_gaussian/shapenetcorev2_250_shapenetcorev2_train16_airplane.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_gaussian/shapenetcorev2_250_shapenetcorev2_train4_tower.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_gaussian/shapenetcorev2_250_shapenetcorev2_train4_tower.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_plane/shapenetcorev2_250_modelnet40_train0_laptop.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_plane/shapenetcorev2_250_modelnet40_train0_laptop.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_plane/shapenetcorev2_250_modelnet40_train10_bookshelf.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_plane/shapenetcorev2_250_modelnet40_train10_bookshelf.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_plane/shapenetcorev2_250_modelnet40_train11_airplane.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_plane/shapenetcorev2_250_modelnet40_train11_airplane.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_plane/shapenetcorev2_250_modelnet40_train12_chair.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_plane/shapenetcorev2_250_modelnet40_train12_chair.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_plane/shapenetcorev2_250_modelnet40_train14_plant.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_plane/shapenetcorev2_250_modelnet40_train14_plant.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_plane/shapenetcorev2_250_modelnet40_train16_table.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_plane/shapenetcorev2_250_modelnet40_train16_table.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_plane/shapenetcorev2_250_modelnet40_train19_bench.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_plane/shapenetcorev2_250_modelnet40_train19_bench.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_plane/shapenetcorev2_250_modelnet40_train7_vase.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_plane/shapenetcorev2_250_modelnet40_train7_vase.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_plane/shapenetcorev2_250_shapenetcorev2_test37_earphone.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_plane/shapenetcorev2_250_shapenetcorev2_test37_earphone.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_plane/shapenetcorev2_250_shapenetcorev2_test57_chair.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_plane/shapenetcorev2_250_shapenetcorev2_test57_chair.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_plane/shapenetcorev2_250_shapenetcorev2_test59_lamp.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_plane/shapenetcorev2_250_shapenetcorev2_test59_lamp.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_plane/shapenetcorev2_250_shapenetcorev2_train10_bag.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_plane/shapenetcorev2_250_shapenetcorev2_train10_bag.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_plane/shapenetcorev2_250_shapenetcorev2_train12_bench.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_plane/shapenetcorev2_250_shapenetcorev2_train12_bench.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_plane/shapenetcorev2_250_shapenetcorev2_train13_table.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_plane/shapenetcorev2_250_shapenetcorev2_train13_table.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_plane/shapenetcorev2_250_shapenetcorev2_train16_airplane.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_plane/shapenetcorev2_250_shapenetcorev2_train16_airplane.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_plane/shapenetcorev2_250_shapenetcorev2_train4_tower.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_plane/shapenetcorev2_250_shapenetcorev2_train4_tower.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_sphere/shapenetcorev2_250_modelnet40_train0_laptop.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_sphere/shapenetcorev2_250_modelnet40_train0_laptop.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_sphere/shapenetcorev2_250_modelnet40_train10_bookshelf.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_sphere/shapenetcorev2_250_modelnet40_train10_bookshelf.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_sphere/shapenetcorev2_250_modelnet40_train11_airplane.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_sphere/shapenetcorev2_250_modelnet40_train11_airplane.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_sphere/shapenetcorev2_250_modelnet40_train12_chair.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_sphere/shapenetcorev2_250_modelnet40_train12_chair.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_sphere/shapenetcorev2_250_modelnet40_train14_plant.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_sphere/shapenetcorev2_250_modelnet40_train14_plant.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_sphere/shapenetcorev2_250_modelnet40_train16_table.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_sphere/shapenetcorev2_250_modelnet40_train16_table.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_sphere/shapenetcorev2_250_modelnet40_train19_bench.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_sphere/shapenetcorev2_250_modelnet40_train19_bench.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_sphere/shapenetcorev2_250_modelnet40_train7_vase.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_sphere/shapenetcorev2_250_modelnet40_train7_vase.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_sphere/shapenetcorev2_250_shapenetcorev2_test37_earphone.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_sphere/shapenetcorev2_250_shapenetcorev2_test37_earphone.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_sphere/shapenetcorev2_250_shapenetcorev2_test57_chair.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_sphere/shapenetcorev2_250_shapenetcorev2_test57_chair.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_sphere/shapenetcorev2_250_shapenetcorev2_test59_lamp.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_sphere/shapenetcorev2_250_shapenetcorev2_test59_lamp.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_sphere/shapenetcorev2_250_shapenetcorev2_train10_bag.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_sphere/shapenetcorev2_250_shapenetcorev2_train10_bag.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_sphere/shapenetcorev2_250_shapenetcorev2_train12_bench.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_sphere/shapenetcorev2_250_shapenetcorev2_train12_bench.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_sphere/shapenetcorev2_250_shapenetcorev2_train13_table.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_sphere/shapenetcorev2_250_shapenetcorev2_train13_table.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_sphere/shapenetcorev2_250_shapenetcorev2_train16_airplane.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_sphere/shapenetcorev2_250_shapenetcorev2_train16_airplane.jpg
--------------------------------------------------------------------------------
/image/dgcnn_cls_sphere/shapenetcorev2_250_shapenetcorev2_train4_tower.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_sphere/shapenetcorev2_250_shapenetcorev2_train4_tower.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_gaussian/shapenetcorev2_290_modelnet40_train0_laptop.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_gaussian/shapenetcorev2_290_modelnet40_train0_laptop.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_gaussian/shapenetcorev2_290_modelnet40_train10_bookshelf.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_gaussian/shapenetcorev2_290_modelnet40_train10_bookshelf.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_gaussian/shapenetcorev2_290_modelnet40_train11_airplane.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_gaussian/shapenetcorev2_290_modelnet40_train11_airplane.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_gaussian/shapenetcorev2_290_modelnet40_train12_chair.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_gaussian/shapenetcorev2_290_modelnet40_train12_chair.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_gaussian/shapenetcorev2_290_modelnet40_train14_plant.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_gaussian/shapenetcorev2_290_modelnet40_train14_plant.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_gaussian/shapenetcorev2_290_modelnet40_train16_table.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_gaussian/shapenetcorev2_290_modelnet40_train16_table.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_gaussian/shapenetcorev2_290_modelnet40_train19_bench.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_gaussian/shapenetcorev2_290_modelnet40_train19_bench.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_gaussian/shapenetcorev2_290_modelnet40_train7_vase.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_gaussian/shapenetcorev2_290_modelnet40_train7_vase.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_gaussian/shapenetcorev2_290_shapenetcorev2_test37_earphone.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_gaussian/shapenetcorev2_290_shapenetcorev2_test37_earphone.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_gaussian/shapenetcorev2_290_shapenetcorev2_test57_chair.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_gaussian/shapenetcorev2_290_shapenetcorev2_test57_chair.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_gaussian/shapenetcorev2_290_shapenetcorev2_test59_lamp.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_gaussian/shapenetcorev2_290_shapenetcorev2_test59_lamp.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_gaussian/shapenetcorev2_290_shapenetcorev2_train10_bag.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_gaussian/shapenetcorev2_290_shapenetcorev2_train10_bag.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_gaussian/shapenetcorev2_290_shapenetcorev2_train12_bench.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_gaussian/shapenetcorev2_290_shapenetcorev2_train12_bench.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_gaussian/shapenetcorev2_290_shapenetcorev2_train13_table.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_gaussian/shapenetcorev2_290_shapenetcorev2_train13_table.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_gaussian/shapenetcorev2_290_shapenetcorev2_train16_airplane.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_gaussian/shapenetcorev2_290_shapenetcorev2_train16_airplane.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_gaussian/shapenetcorev2_290_shapenetcorev2_train4_tower.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_gaussian/shapenetcorev2_290_shapenetcorev2_train4_tower.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_plane/shapenetcorev2_290_modelnet40_train0_laptop.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_plane/shapenetcorev2_290_modelnet40_train0_laptop.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_plane/shapenetcorev2_290_modelnet40_train10_bookshelf.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_plane/shapenetcorev2_290_modelnet40_train10_bookshelf.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_plane/shapenetcorev2_290_modelnet40_train11_airplane.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_plane/shapenetcorev2_290_modelnet40_train11_airplane.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_plane/shapenetcorev2_290_modelnet40_train12_chair.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_plane/shapenetcorev2_290_modelnet40_train12_chair.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_plane/shapenetcorev2_290_modelnet40_train14_plant.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_plane/shapenetcorev2_290_modelnet40_train14_plant.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_plane/shapenetcorev2_290_modelnet40_train16_table.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_plane/shapenetcorev2_290_modelnet40_train16_table.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_plane/shapenetcorev2_290_modelnet40_train19_bench.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_plane/shapenetcorev2_290_modelnet40_train19_bench.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_plane/shapenetcorev2_290_modelnet40_train7_vase.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_plane/shapenetcorev2_290_modelnet40_train7_vase.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_plane/shapenetcorev2_290_shapenetcorev2_test37_earphone.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_plane/shapenetcorev2_290_shapenetcorev2_test37_earphone.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_plane/shapenetcorev2_290_shapenetcorev2_test57_chair.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_plane/shapenetcorev2_290_shapenetcorev2_test57_chair.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_plane/shapenetcorev2_290_shapenetcorev2_test59_lamp.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_plane/shapenetcorev2_290_shapenetcorev2_test59_lamp.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_plane/shapenetcorev2_290_shapenetcorev2_train10_bag.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_plane/shapenetcorev2_290_shapenetcorev2_train10_bag.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_plane/shapenetcorev2_290_shapenetcorev2_train12_bench.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_plane/shapenetcorev2_290_shapenetcorev2_train12_bench.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_plane/shapenetcorev2_290_shapenetcorev2_train13_table.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_plane/shapenetcorev2_290_shapenetcorev2_train13_table.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_plane/shapenetcorev2_290_shapenetcorev2_train16_airplane.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_plane/shapenetcorev2_290_shapenetcorev2_train16_airplane.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_plane/shapenetcorev2_290_shapenetcorev2_train4_tower.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_plane/shapenetcorev2_290_shapenetcorev2_train4_tower.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_sphere/shapenetcorev2_290_modelnet40_train0_laptop.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_sphere/shapenetcorev2_290_modelnet40_train0_laptop.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_sphere/shapenetcorev2_290_modelnet40_train10_bookshelf.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_sphere/shapenetcorev2_290_modelnet40_train10_bookshelf.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_sphere/shapenetcorev2_290_modelnet40_train11_airplane.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_sphere/shapenetcorev2_290_modelnet40_train11_airplane.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_sphere/shapenetcorev2_290_modelnet40_train12_chair.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_sphere/shapenetcorev2_290_modelnet40_train12_chair.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_sphere/shapenetcorev2_290_modelnet40_train14_plant.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_sphere/shapenetcorev2_290_modelnet40_train14_plant.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_sphere/shapenetcorev2_290_modelnet40_train16_table.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_sphere/shapenetcorev2_290_modelnet40_train16_table.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_sphere/shapenetcorev2_290_modelnet40_train19_bench.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_sphere/shapenetcorev2_290_modelnet40_train19_bench.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_sphere/shapenetcorev2_290_modelnet40_train7_vase.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_sphere/shapenetcorev2_290_modelnet40_train7_vase.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_sphere/shapenetcorev2_290_shapenetcorev2_test37_earphone.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_sphere/shapenetcorev2_290_shapenetcorev2_test37_earphone.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_sphere/shapenetcorev2_290_shapenetcorev2_test57_chair.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_sphere/shapenetcorev2_290_shapenetcorev2_test57_chair.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_sphere/shapenetcorev2_290_shapenetcorev2_test59_lamp.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_sphere/shapenetcorev2_290_shapenetcorev2_test59_lamp.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_sphere/shapenetcorev2_290_shapenetcorev2_train10_bag.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_sphere/shapenetcorev2_290_shapenetcorev2_train10_bag.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_sphere/shapenetcorev2_290_shapenetcorev2_train12_bench.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_sphere/shapenetcorev2_290_shapenetcorev2_train12_bench.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_sphere/shapenetcorev2_290_shapenetcorev2_train13_table.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_sphere/shapenetcorev2_290_shapenetcorev2_train13_table.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_sphere/shapenetcorev2_290_shapenetcorev2_train16_airplane.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_sphere/shapenetcorev2_290_shapenetcorev2_train16_airplane.jpg
--------------------------------------------------------------------------------
/image/dgcnn_seg_sphere/shapenetcorev2_290_shapenetcorev2_train4_tower.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_sphere/shapenetcorev2_290_shapenetcorev2_train4_tower.jpg
--------------------------------------------------------------------------------
/image/distance.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/distance.png
--------------------------------------------------------------------------------
/image/gaussian.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/gaussian.png
--------------------------------------------------------------------------------
/image/input/modelnet40_train0_laptop_orign.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/input/modelnet40_train0_laptop_orign.jpg
--------------------------------------------------------------------------------
/image/input/modelnet40_train10_bookshelf_orign.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/input/modelnet40_train10_bookshelf_orign.jpg
--------------------------------------------------------------------------------
/image/input/modelnet40_train11_airplane_orign.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/input/modelnet40_train11_airplane_orign.jpg
--------------------------------------------------------------------------------
/image/input/modelnet40_train12_chair_orign.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/input/modelnet40_train12_chair_orign.jpg
--------------------------------------------------------------------------------
/image/input/modelnet40_train14_plant_orign.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/input/modelnet40_train14_plant_orign.jpg
--------------------------------------------------------------------------------
/image/input/modelnet40_train16_table_orign.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/input/modelnet40_train16_table_orign.jpg
--------------------------------------------------------------------------------
/image/input/modelnet40_train19_bench_orign.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/input/modelnet40_train19_bench_orign.jpg
--------------------------------------------------------------------------------
/image/input/modelnet40_train7_vase_orign.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/input/modelnet40_train7_vase_orign.jpg
--------------------------------------------------------------------------------
/image/input/shapenetcorev2_test37_earphone_orign.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/input/shapenetcorev2_test37_earphone_orign.jpg
--------------------------------------------------------------------------------
/image/input/shapenetcorev2_test57_chair_orign.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/input/shapenetcorev2_test57_chair_orign.jpg
--------------------------------------------------------------------------------
/image/input/shapenetcorev2_test59_lamp_orign.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/input/shapenetcorev2_test59_lamp_orign.jpg
--------------------------------------------------------------------------------
/image/input/shapenetcorev2_train10_bag_orign.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/input/shapenetcorev2_train10_bag_orign.jpg
--------------------------------------------------------------------------------
/image/input/shapenetcorev2_train12_bench_orign.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/input/shapenetcorev2_train12_bench_orign.jpg
--------------------------------------------------------------------------------
/image/input/shapenetcorev2_train13_table_orign.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/input/shapenetcorev2_train13_table_orign.jpg
--------------------------------------------------------------------------------
/image/input/shapenetcorev2_train16_airplane_orign.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/input/shapenetcorev2_train16_airplane_orign.jpg
--------------------------------------------------------------------------------
/image/input/shapenetcorev2_train4_tower_orign.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/input/shapenetcorev2_train4_tower_orign.jpg
--------------------------------------------------------------------------------
/image/original_gaussian/shapenetcorev2_278_modelnet40_train0_laptop.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_gaussian/shapenetcorev2_278_modelnet40_train0_laptop.jpg
--------------------------------------------------------------------------------
/image/original_gaussian/shapenetcorev2_278_modelnet40_train10_bookshelf.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_gaussian/shapenetcorev2_278_modelnet40_train10_bookshelf.jpg
--------------------------------------------------------------------------------
/image/original_gaussian/shapenetcorev2_278_modelnet40_train11_airplane.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_gaussian/shapenetcorev2_278_modelnet40_train11_airplane.jpg
--------------------------------------------------------------------------------
/image/original_gaussian/shapenetcorev2_278_modelnet40_train12_chair.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_gaussian/shapenetcorev2_278_modelnet40_train12_chair.jpg
--------------------------------------------------------------------------------
/image/original_gaussian/shapenetcorev2_278_modelnet40_train14_plant.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_gaussian/shapenetcorev2_278_modelnet40_train14_plant.jpg
--------------------------------------------------------------------------------
/image/original_gaussian/shapenetcorev2_278_modelnet40_train16_table.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_gaussian/shapenetcorev2_278_modelnet40_train16_table.jpg
--------------------------------------------------------------------------------
/image/original_gaussian/shapenetcorev2_278_modelnet40_train19_bench.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_gaussian/shapenetcorev2_278_modelnet40_train19_bench.jpg
--------------------------------------------------------------------------------
/image/original_gaussian/shapenetcorev2_278_modelnet40_train7_vase.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_gaussian/shapenetcorev2_278_modelnet40_train7_vase.jpg
--------------------------------------------------------------------------------
/image/original_gaussian/shapenetcorev2_278_shapenetcorev2_test37_earphone.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_gaussian/shapenetcorev2_278_shapenetcorev2_test37_earphone.jpg
--------------------------------------------------------------------------------
/image/original_gaussian/shapenetcorev2_278_shapenetcorev2_test57_chair.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_gaussian/shapenetcorev2_278_shapenetcorev2_test57_chair.jpg
--------------------------------------------------------------------------------
/image/original_gaussian/shapenetcorev2_278_shapenetcorev2_test59_lamp.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_gaussian/shapenetcorev2_278_shapenetcorev2_test59_lamp.jpg
--------------------------------------------------------------------------------
/image/original_gaussian/shapenetcorev2_278_shapenetcorev2_train10_bag.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_gaussian/shapenetcorev2_278_shapenetcorev2_train10_bag.jpg
--------------------------------------------------------------------------------
/image/original_gaussian/shapenetcorev2_278_shapenetcorev2_train12_bench.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_gaussian/shapenetcorev2_278_shapenetcorev2_train12_bench.jpg
--------------------------------------------------------------------------------
/image/original_gaussian/shapenetcorev2_278_shapenetcorev2_train13_table.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_gaussian/shapenetcorev2_278_shapenetcorev2_train13_table.jpg
--------------------------------------------------------------------------------
/image/original_gaussian/shapenetcorev2_278_shapenetcorev2_train16_airplane.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_gaussian/shapenetcorev2_278_shapenetcorev2_train16_airplane.jpg
--------------------------------------------------------------------------------
/image/original_gaussian/shapenetcorev2_278_shapenetcorev2_train4_tower.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_gaussian/shapenetcorev2_278_shapenetcorev2_train4_tower.jpg
--------------------------------------------------------------------------------
/image/original_plane/shapenetcorev2_278_modelnet40_train0_laptop.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_plane/shapenetcorev2_278_modelnet40_train0_laptop.jpg
--------------------------------------------------------------------------------
/image/original_plane/shapenetcorev2_278_modelnet40_train10_bookshelf.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_plane/shapenetcorev2_278_modelnet40_train10_bookshelf.jpg
--------------------------------------------------------------------------------
/image/original_plane/shapenetcorev2_278_modelnet40_train11_airplane.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_plane/shapenetcorev2_278_modelnet40_train11_airplane.jpg
--------------------------------------------------------------------------------
/image/original_plane/shapenetcorev2_278_modelnet40_train12_chair.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_plane/shapenetcorev2_278_modelnet40_train12_chair.jpg
--------------------------------------------------------------------------------
/image/original_plane/shapenetcorev2_278_modelnet40_train14_plant.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_plane/shapenetcorev2_278_modelnet40_train14_plant.jpg
--------------------------------------------------------------------------------
/image/original_plane/shapenetcorev2_278_modelnet40_train16_table.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_plane/shapenetcorev2_278_modelnet40_train16_table.jpg
--------------------------------------------------------------------------------
/image/original_plane/shapenetcorev2_278_modelnet40_train19_bench.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_plane/shapenetcorev2_278_modelnet40_train19_bench.jpg
--------------------------------------------------------------------------------
/image/original_plane/shapenetcorev2_278_modelnet40_train7_vase.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_plane/shapenetcorev2_278_modelnet40_train7_vase.jpg
--------------------------------------------------------------------------------
/image/original_plane/shapenetcorev2_278_shapenetcorev2_test37_earphone.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_plane/shapenetcorev2_278_shapenetcorev2_test37_earphone.jpg
--------------------------------------------------------------------------------
/image/original_plane/shapenetcorev2_278_shapenetcorev2_test57_chair.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_plane/shapenetcorev2_278_shapenetcorev2_test57_chair.jpg
--------------------------------------------------------------------------------
/image/original_plane/shapenetcorev2_278_shapenetcorev2_test59_lamp.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_plane/shapenetcorev2_278_shapenetcorev2_test59_lamp.jpg
--------------------------------------------------------------------------------
/image/original_plane/shapenetcorev2_278_shapenetcorev2_train10_bag.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_plane/shapenetcorev2_278_shapenetcorev2_train10_bag.jpg
--------------------------------------------------------------------------------
/image/original_plane/shapenetcorev2_278_shapenetcorev2_train12_bench.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_plane/shapenetcorev2_278_shapenetcorev2_train12_bench.jpg
--------------------------------------------------------------------------------
/image/original_plane/shapenetcorev2_278_shapenetcorev2_train13_table.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_plane/shapenetcorev2_278_shapenetcorev2_train13_table.jpg
--------------------------------------------------------------------------------
/image/original_plane/shapenetcorev2_278_shapenetcorev2_train16_airplane.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_plane/shapenetcorev2_278_shapenetcorev2_train16_airplane.jpg
--------------------------------------------------------------------------------
/image/original_plane/shapenetcorev2_278_shapenetcorev2_train4_tower.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_plane/shapenetcorev2_278_shapenetcorev2_train4_tower.jpg
--------------------------------------------------------------------------------
/image/original_sphere/shapenetcorev2_278_modelnet40_train0_laptop.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_sphere/shapenetcorev2_278_modelnet40_train0_laptop.jpg
--------------------------------------------------------------------------------
/image/original_sphere/shapenetcorev2_278_modelnet40_train10_bookshelf.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_sphere/shapenetcorev2_278_modelnet40_train10_bookshelf.jpg
--------------------------------------------------------------------------------
/image/original_sphere/shapenetcorev2_278_modelnet40_train11_airplane.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_sphere/shapenetcorev2_278_modelnet40_train11_airplane.jpg
--------------------------------------------------------------------------------
/image/original_sphere/shapenetcorev2_278_modelnet40_train12_chair.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_sphere/shapenetcorev2_278_modelnet40_train12_chair.jpg
--------------------------------------------------------------------------------
/image/original_sphere/shapenetcorev2_278_modelnet40_train14_plant.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_sphere/shapenetcorev2_278_modelnet40_train14_plant.jpg
--------------------------------------------------------------------------------
/image/original_sphere/shapenetcorev2_278_modelnet40_train16_table.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_sphere/shapenetcorev2_278_modelnet40_train16_table.jpg
--------------------------------------------------------------------------------
/image/original_sphere/shapenetcorev2_278_modelnet40_train19_bench.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_sphere/shapenetcorev2_278_modelnet40_train19_bench.jpg
--------------------------------------------------------------------------------
/image/original_sphere/shapenetcorev2_278_modelnet40_train7_vase.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_sphere/shapenetcorev2_278_modelnet40_train7_vase.jpg
--------------------------------------------------------------------------------
/image/original_sphere/shapenetcorev2_278_shapenetcorev2_test37_earphone.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_sphere/shapenetcorev2_278_shapenetcorev2_test37_earphone.jpg
--------------------------------------------------------------------------------
/image/original_sphere/shapenetcorev2_278_shapenetcorev2_test57_chair.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_sphere/shapenetcorev2_278_shapenetcorev2_test57_chair.jpg
--------------------------------------------------------------------------------
/image/original_sphere/shapenetcorev2_278_shapenetcorev2_test59_lamp.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_sphere/shapenetcorev2_278_shapenetcorev2_test59_lamp.jpg
--------------------------------------------------------------------------------
/image/original_sphere/shapenetcorev2_278_shapenetcorev2_train10_bag.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_sphere/shapenetcorev2_278_shapenetcorev2_train10_bag.jpg
--------------------------------------------------------------------------------
/image/original_sphere/shapenetcorev2_278_shapenetcorev2_train12_bench.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_sphere/shapenetcorev2_278_shapenetcorev2_train12_bench.jpg
--------------------------------------------------------------------------------
/image/original_sphere/shapenetcorev2_278_shapenetcorev2_train13_table.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_sphere/shapenetcorev2_278_shapenetcorev2_train13_table.jpg
--------------------------------------------------------------------------------
/image/original_sphere/shapenetcorev2_278_shapenetcorev2_train16_airplane.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_sphere/shapenetcorev2_278_shapenetcorev2_train16_airplane.jpg
--------------------------------------------------------------------------------
/image/original_sphere/shapenetcorev2_278_shapenetcorev2_train4_tower.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_sphere/shapenetcorev2_278_shapenetcorev2_train4_tower.jpg
--------------------------------------------------------------------------------
/image/plane.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/plane.png
--------------------------------------------------------------------------------
/image/sphere.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/sphere.png
--------------------------------------------------------------------------------
/inference.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | """
4 | @Author: An Tao
5 | @Contact: ta19@mails.tsinghua.edu.cn
6 | @File: inference.py
7 | @Time: 2020/1/2 10:26 AM
8 | """
9 |
10 | import os
11 | import sys
12 | import time
13 | import shutil
14 | import torch
15 | import numpy as np
16 | import h5py
17 |
18 | from tensorboardX import SummaryWriter
19 |
20 | from model import ReconstructionNet, ClassificationNet
21 | from dataset import Dataset
22 | from utils import Logger
23 |
24 |
25 | class Inference(object):
26 | def __init__(self, args):
27 | self.batch_size = args.batch_size
28 | self.no_cuda = args.no_cuda
29 | self.task = args.task
30 |
31 | # create exp directory
32 | file = [f for f in args.model_path.split('/')]
33 | if args.exp_name != None:
34 | self.experiment_id = args.exp_name
35 | else:
36 | self.experiment_id = time.strftime('%m%d%H%M%S')
37 | cache_root = 'cache/%s' % self.experiment_id
38 | os.makedirs(cache_root, exist_ok=True)
39 | self.feature_dir = os.path.join(cache_root, 'features/')
40 | sys.stdout = Logger(os.path.join(cache_root, 'log.txt'))
41 |
42 | # check directory
43 | if not os.path.exists(self.feature_dir):
44 | os.makedirs(self.feature_dir)
45 | else:
46 | shutil.rmtree(self.feature_dir)
47 | os.makedirs(self.feature_dir)
48 |
49 | # print args
50 | print(str(args))
51 |
52 | # get gpu id
53 | gids = ''.join(args.gpu.split())
54 | self.gpu_ids = [int(gid) for gid in gids.split(',')]
55 | self.first_gpu = self.gpu_ids[0]
56 |
57 | # generate dataset
58 | self.infer_dataset_train = Dataset(
59 | root=args.dataset_root,
60 | dataset_name=args.dataset,
61 | split='train',
62 | num_points=args.num_points,
63 | )
64 | self.infer_dataset_test = Dataset(
65 | root=args.dataset_root,
66 | dataset_name=args.dataset,
67 | split='test',
68 | num_points=args.num_points,
69 | )
70 | self.infer_loader_train = torch.utils.data.DataLoader(
71 | self.infer_dataset_train,
72 | batch_size=args.batch_size,
73 | shuffle=False,
74 | num_workers=args.workers
75 | )
76 | self.infer_loader_test = torch.utils.data.DataLoader(
77 | self.infer_dataset_test,
78 | batch_size=args.batch_size,
79 | shuffle=False,
80 | num_workers=args.workers
81 | )
82 | print("Inference set size (train):", self.infer_loader_train.dataset.__len__())
83 | print("Inference set size (test):", self.infer_loader_test.dataset.__len__())
84 |
85 | # initialize model
86 | if args.task == "reconstruct":
87 | self.model = ReconstructionNet(args)
88 | elif args.task == "classify":
89 | self.model = ClassificationNet(args)
90 | if args.model_path != '':
91 | self._load_pretrain(args.model_path)
92 |
93 | # load model to gpu
94 | if not args.no_cuda:
95 | if len(self.gpu_ids) != 1: # multiple gpus
96 | self.model = torch.nn.DataParallel(self.model.cuda(self.first_gpu), self.gpu_ids)
97 | else:
98 | self.model = self.model.cuda(self.gpu_ids[0])
99 |
100 | def run(self):
101 | self.model.eval()
102 |
103 | # generate train set for SVM
104 | loss_buf = []
105 | feature_train = []
106 | lbs_train = []
107 | n = 0
108 | for iter, (pts, lbs) in enumerate(self.infer_loader_train):
109 | if not self.no_cuda:
110 | pts = pts.cuda(self.first_gpu)
111 | lbs = lbs.cuda(self.first_gpu)
112 | if self.task == "reconstruct":
113 | output, feature = self.model(pts)
114 | elif self.task == "classify":
115 | feature = self.model(pts)
116 | feature_train.append(feature.detach().cpu().numpy().squeeze(1))
117 | lbs_train.append(lbs.cpu().numpy().squeeze(1))
118 | if ((iter+1) * self.batch_size % 2048) == 0 \
119 | or (iter+1) == len(self.infer_loader_train):
120 | feature_train = np.concatenate(feature_train, axis=0)
121 | lbs_train = np.concatenate(lbs_train, axis=0)
122 | f = h5py.File(os.path.join(self.feature_dir, 'train' + str(n) + '.h5'),'w')
123 | f['data'] = feature_train
124 | f['label'] = lbs_train
125 | f.close()
126 | print("Train set {} for SVM saved.".format(n))
127 | feature_train = []
128 | lbs_train = []
129 | n += 1
130 | if self.task == "reconstruct":
131 | if len(self.gpu_ids) != 1: # multiple gpus
132 | loss = self.model.module.get_loss(pts, output)
133 | else:
134 | loss = self.model.get_loss(pts, output)
135 | loss_buf.append(loss.detach().cpu().numpy())
136 | if self.task == "reconstruct":
137 | print(f'Avg loss {np.mean(loss_buf)}')
138 | print("Finish generating train set for SVM.")
139 |
140 | # generate test set for SVM
141 | loss_buf = []
142 | feature_test = []
143 | lbs_test = []
144 | n = 0
145 | for iter, (pts, lbs) in enumerate(self.infer_loader_test):
146 | if not self.no_cuda:
147 | pts = pts.cuda(self.first_gpu)
148 | lbs = lbs.cuda(self.first_gpu)
149 | if self.task == "reconstruct":
150 | output, feature = self.model(pts)
151 | elif self.task == "classify":
152 | feature = self.model(pts)
153 | feature_test.append(feature.detach().cpu().numpy().squeeze(1))
154 | lbs_test.append(lbs.cpu().numpy().squeeze(1))
155 | if ((iter+1) * self.batch_size % 2048) == 0 \
156 | or (iter+1) == len(self.infer_loader_test):
157 | feature_test = np.concatenate(feature_test, axis=0)
158 | lbs_test = np.concatenate(lbs_test, axis=0)
159 | f = h5py.File(os.path.join(self.feature_dir, 'test' + str(n) + '.h5'),'w')
160 | f['data'] = feature_test
161 | f['label'] = lbs_test
162 | f.close()
163 | print("Test set {} for SVM saved.".format(n))
164 | feature_test = []
165 | lbs_test = []
166 | n += 1
167 | if self.task == "reconstruct":
168 | if len(self.gpu_ids) != 1: # multiple gpus
169 | loss = self.model.module.get_loss(pts, output)
170 | else:
171 | loss = self.model.get_loss(pts, output)
172 | loss_buf.append(loss.detach().cpu().numpy())
173 | if self.task == "reconstruct":
174 | print(f'Avg loss {np.mean(loss_buf)}')
175 | print("Finish generating test set for SVM.")
176 |
177 | return self.feature_dir
178 |
179 |
180 | def _load_pretrain(self, pretrain):
181 | state_dict = torch.load(pretrain, map_location='cpu')
182 | from collections import OrderedDict
183 | new_state_dict = OrderedDict()
184 | for key, val in state_dict.items():
185 | if key[:6] == 'module':
186 | name = key[7:] # remove 'module.'
187 | else:
188 | name = key
189 | if key[:10] == 'classifier':
190 | continue
191 | new_state_dict[name] = val
192 | self.model.load_state_dict(new_state_dict)
193 | print(f"Load model from {pretrain}")
194 |
--------------------------------------------------------------------------------
/loss.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | """
4 | @Author: An Tao
5 | @Contact: ta19@mails.tsinghua.edu.cn
6 | @File: loss.py
7 | @Time: 2020/1/2 10:26 AM
8 | """
9 |
10 | import torch
11 | import torch.nn as nn
12 | import torch.nn.functional as F
13 |
14 |
15 | class ChamferLoss(nn.Module):
16 | def __init__(self):
17 | super(ChamferLoss, self).__init__()
18 | self.use_cuda = torch.cuda.is_available()
19 |
20 | def batch_pairwise_dist(self, x, y):
21 | bs, num_points_x, points_dim = x.size()
22 | _, num_points_y, _ = y.size()
23 | xx = x.pow(2).sum(dim=-1)
24 | yy = y.pow(2).sum(dim=-1)
25 | zz = torch.bmm(x, y.transpose(2, 1))
26 | rx = xx.unsqueeze(1).expand_as(zz.transpose(2, 1))
27 | ry = yy.unsqueeze(1).expand_as(zz)
28 | P = (rx.transpose(2, 1) + ry - 2 * zz)
29 | return P
30 |
31 | def forward(self, preds, gts):
32 | P = self.batch_pairwise_dist(gts, preds)
33 | mins, _ = torch.min(P, 1)
34 | loss_1 = torch.sum(mins)
35 | mins, _ = torch.min(P, 2)
36 | loss_2 = torch.sum(mins)
37 | return loss_1 + loss_2
38 |
39 |
40 | class CrossEntropyLoss(nn.Module):
41 | def __init__(self, smoothing=True):
42 | super(CrossEntropyLoss, self).__init__()
43 | self.smoothing = smoothing
44 |
45 | def forward(self, preds, gts):
46 | gts = gts.contiguous().view(-1)
47 |
48 | if self.smoothing:
49 | eps = 0.2
50 | n_class = preds.size(1)
51 |
52 | one_hot = torch.zeros_like(preds).scatter(1, gts.view(-1, 1), 1)
53 | one_hot = one_hot * (1 - eps) + (1 - one_hot) * eps / (n_class - 1)
54 | log_prb = F.log_softmax(preds, dim=1)
55 |
56 | loss = -(one_hot * log_prb).sum(dim=1).mean()
57 | else:
58 | loss = F.cross_entropy(preds, gts, reduction='mean')
59 |
60 | return loss
61 |
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | """
4 | @Author: An Tao
5 | @Contact: ta19@mails.tsinghua.edu.cn
6 | @File: main.py
7 | @Time: 2020/1/2 10:26 AM
8 | """
9 |
10 | import argparse
11 |
12 | from reconstruction import Reconstruction
13 | from classification import Classification
14 | from inference import Inference
15 | from svm import SVM
16 |
17 |
18 | def get_parser():
19 | parser = argparse.ArgumentParser(description='Unsupervised Point Cloud Feature Learning')
20 | parser.add_argument('--exp_name', type=str, default=None, metavar='N',
21 | help='Name of the experiment')
22 | parser.add_argument('--task', type=str, default='reconstruct', metavar='N',
23 | choices=['reconstruct', 'classify'],
24 | help='Experiment task, [reconstruct, classify]')
25 | parser.add_argument('--encoder', type=str, default='foldingnet', metavar='N',
26 | choices=['foldnet', 'dgcnn_cls', 'dgcnn_seg'],
27 | help='Encoder to use, [foldingnet, dgcnn_cls, dgcnn_seg]')
28 | parser.add_argument('--dropout', type=float, default=0.5,
29 | help='dropout rate')
30 | parser.add_argument('--feat_dims', type=int, default=512, metavar='N',
31 | help='Number of dims for feature ')
32 | parser.add_argument('--k', type=int, default=None, metavar='N',
33 | help='Num of nearest neighbors to use for KNN')
34 | parser.add_argument('--shape', type=str, default='plane', metavar='N',
35 | choices=['plane', 'sphere', 'gaussian'],
36 | help='Shape of points to input decoder, [plane, sphere, gaussian]')
37 | parser.add_argument('--dataset', type=str, default='shapenetcorev2', metavar='N',
38 | choices=['shapenetcorev2','modelnet40', 'modelnet10'],
39 | help='Encoder to use, [shapenetcorev2,modelnet40, modelnet10]')
40 | parser.add_argument('--use_rotate', action='store_true',
41 | help='Rotate the pointcloud before training')
42 | parser.add_argument('--use_translate', action='store_true',
43 | help='Translate the pointcloud before training')
44 | parser.add_argument('--use_jitter', action='store_true',
45 | help='Jitter the pointcloud before training')
46 | parser.add_argument('--dataset_root', type=str, default='../dataset', help="Dataset root path")
47 | parser.add_argument('--gpu', type=str, help='Id of gpu device to be used', default='0')
48 | parser.add_argument('--batch_size', type=int, default=16, metavar='batch_size',
49 | help='Size of batch)')
50 | parser.add_argument('--workers', type=int, help='Number of data loading workers', default=16)
51 | parser.add_argument('--epochs', type=int, default=None, metavar='N',
52 | help='Number of episode to train ')
53 | parser.add_argument('--snapshot_interval', type=int, default=10, metavar='N',
54 | help='Save snapshot interval ')
55 | parser.add_argument('--no_cuda', action='store_true',
56 | help='Enables CUDA training')
57 | parser.add_argument('--eval', action='store_true',
58 | help='Evaluate the model')
59 | parser.add_argument('--num_points', type=int, default=2048,
60 | help='Num of points to use')
61 | parser.add_argument('--model_path', type=str, default='', metavar='N',
62 | help='Path to load model')
63 | args = parser.parse_args()
64 | return args
65 |
66 |
67 | if __name__ == '__main__':
68 | args = get_parser()
69 | if args.eval == False:
70 | if args.task == 'reconstruct':
71 | reconstruction = Reconstruction(args)
72 | reconstruction.run()
73 | elif args.task == 'classify':
74 | classification = Classification(args)
75 | classification.run()
76 | else:
77 | inference = Inference(args)
78 | feature_dir = inference.run()
79 | svm = SVM(feature_dir)
80 | svm.run()
81 |
--------------------------------------------------------------------------------
/model.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | """
4 | @Author: An Tao
5 | @Contact: ta19@mails.tsinghua.edu.cn
6 | @File: model.py
7 | @Time: 2020/3/23 5:39 PM
8 | """
9 |
10 | import torch
11 | import torch.nn as nn
12 | import torch.nn.init as init
13 | import torch.nn.functional as F
14 | import numpy as np
15 | import itertools
16 | from loss import ChamferLoss, CrossEntropyLoss
17 |
18 | def knn(x, k):
19 | batch_size = x.size(0)
20 | num_points = x.size(2)
21 |
22 | inner = -2*torch.matmul(x.transpose(2, 1), x)
23 | xx = torch.sum(x**2, dim=1, keepdim=True)
24 | pairwise_distance = -xx - inner - xx.transpose(2, 1)
25 |
26 | idx = pairwise_distance.topk(k=k, dim=-1)[1] # (batch_size, num_points, k)
27 |
28 | if idx.get_device() == -1:
29 | idx_base = torch.arange(0, batch_size).view(-1, 1, 1)*num_points
30 | else:
31 | idx_base = torch.arange(0, batch_size, device=idx.get_device()).view(-1, 1, 1)*num_points
32 | idx = idx + idx_base
33 | idx = idx.view(-1)
34 |
35 | return idx
36 |
37 |
38 | def local_cov(pts, idx):
39 | batch_size = pts.size(0)
40 | num_points = pts.size(2)
41 | pts = pts.view(batch_size, -1, num_points) # (batch_size, 3, num_points)
42 |
43 | _, num_dims, _ = pts.size()
44 |
45 | x = pts.transpose(2, 1).contiguous() # (batch_size, num_points, 3)
46 | x = x.view(batch_size*num_points, -1)[idx, :] # (batch_size*num_points*2, 3)
47 | x = x.view(batch_size, num_points, -1, num_dims) # (batch_size, num_points, k, 3)
48 |
49 | x = torch.matmul(x[:,:,0].unsqueeze(3), x[:,:,1].unsqueeze(2)) # (batch_size, num_points, 3, 1) * (batch_size, num_points, 1, 3) -> (batch_size, num_points, 3, 3)
50 | # x = torch.matmul(x[:,:,1:].transpose(3, 2), x[:,:,1:])
51 | x = x.view(batch_size, num_points, 9).transpose(2, 1) # (batch_size, 9, num_points)
52 |
53 | x = torch.cat((pts, x), dim=1) # (batch_size, 12, num_points)
54 |
55 | return x
56 |
57 |
58 | def local_maxpool(x, idx):
59 | batch_size = x.size(0)
60 | num_points = x.size(2)
61 | x = x.view(batch_size, -1, num_points)
62 |
63 | _, num_dims, _ = x.size()
64 |
65 | x = x.transpose(2, 1).contiguous() # (batch_size, num_points, num_dims)
66 | x = x.view(batch_size*num_points, -1)[idx, :] # (batch_size*n, num_dims) -> (batch_size*n*k, num_dims)
67 | x = x.view(batch_size, num_points, -1, num_dims) # (batch_size, num_points, k, num_dims)
68 | x, _ = torch.max(x, dim=2) # (batch_size, num_points, num_dims)
69 |
70 | return x
71 |
72 |
73 | def get_graph_feature(x, k=20, idx=None):
74 | batch_size = x.size(0)
75 | num_points = x.size(2)
76 | x = x.view(batch_size, -1, num_points) # (batch_size, num_dims, num_points)
77 | if idx is None:
78 | idx = knn(x, k=k) # (batch_size, num_points, k)
79 |
80 | _, num_dims, _ = x.size()
81 |
82 | x = x.transpose(2, 1).contiguous() # (batch_size, num_points, num_dims)
83 | feature = x.view(batch_size*num_points, -1)[idx, :] # (batch_size*n, num_dims) -> (batch_size*n*k, num_dims)
84 | feature = feature.view(batch_size, num_points, k, num_dims) # (batch_size, num_points, k, num_dims)
85 | x = x.view(batch_size, num_points, 1, num_dims).repeat(1, 1, k, 1) # (batch_size, num_points, k, num_dims)
86 |
87 | feature = torch.cat((feature-x, x), dim=3).permute(0, 3, 1, 2) # (batch_size, num_points, k, 2*num_dims) -> (batch_size, 2*num_dims, num_points, k)
88 |
89 | return feature # (batch_size, 2*num_dims, num_points, k)
90 |
91 |
92 | class DGCNN_Cls_Encoder(nn.Module):
93 | def __init__(self, args):
94 | super(DGCNN_Cls_Encoder, self).__init__()
95 | if args.k == None:
96 | self.k = 20
97 | else:
98 | self.k = args.k
99 | self.task = args.task
100 |
101 | self.bn1 = nn.BatchNorm2d(64)
102 | self.bn2 = nn.BatchNorm2d(64)
103 | self.bn3 = nn.BatchNorm2d(128)
104 | self.bn4 = nn.BatchNorm2d(256)
105 | self.bn5 = nn.BatchNorm1d(args.feat_dims)
106 |
107 | self.conv1 = nn.Sequential(nn.Conv2d(3*2, 64, kernel_size=1, bias=False),
108 | self.bn1,
109 | nn.LeakyReLU(negative_slope=0.2))
110 | self.conv2 = nn.Sequential(nn.Conv2d(64*2, 64, kernel_size=1, bias=False),
111 | self.bn2,
112 | nn.LeakyReLU(negative_slope=0.2))
113 | self.conv3 = nn.Sequential(nn.Conv2d(64*2, 128, kernel_size=1, bias=False),
114 | self.bn3,
115 | nn.LeakyReLU(negative_slope=0.2))
116 | self.conv4 = nn.Sequential(nn.Conv2d(128*2, 256, kernel_size=1, bias=False),
117 | self.bn4,
118 | nn.LeakyReLU(negative_slope=0.2))
119 | self.conv5 = nn.Sequential(nn.Conv1d(512, args.feat_dims, kernel_size=1, bias=False),
120 | self.bn5,
121 | nn.LeakyReLU(negative_slope=0.2))
122 |
123 | def forward(self, x):
124 | x = x.transpose(2, 1)
125 |
126 | batch_size = x.size(0)
127 | x = get_graph_feature(x, k=self.k) # (batch_size, 3, num_points) -> (batch_size, 3*2, num_points, k)
128 | x = self.conv1(x) # (batch_size, 3*2, num_points, k) -> (batch_size, 64, num_points, k)
129 | x1 = x.max(dim=-1, keepdim=False)[0] # (batch_size, 64, num_points, k) -> (batch_size, 64, num_points)
130 |
131 | x = get_graph_feature(x1, k=self.k) # (batch_size, 64, num_points) -> (batch_size, 64*2, num_points, k)
132 | x = self.conv2(x) # (batch_size, 64*2, num_points, k) -> (batch_size, 64, num_points, k)
133 | x2 = x.max(dim=-1, keepdim=False)[0] # (batch_size, 64, num_points, k) -> (batch_size, 64, num_points)
134 |
135 | x = get_graph_feature(x2, k=self.k) # (batch_size, 64, num_points) -> (batch_size, 64*2, num_points, k)
136 | x = self.conv3(x) # (batch_size, 64*2, num_points, k) -> (batch_size, 128, num_points, k)
137 | x3 = x.max(dim=-1, keepdim=False)[0] # (batch_size, 128, num_points, k) -> (batch_size, 128, num_points)
138 |
139 | x = get_graph_feature(x3, k=self.k) # (batch_size, 128, num_points) -> (batch_size, 128*2, num_points, k)
140 | x = self.conv4(x) # (batch_size, 128*2, num_points, k) -> (batch_size, 256, num_points, k)
141 | x4 = x.max(dim=-1, keepdim=False)[0] # (batch_size, 256, num_points, k) -> (batch_size, 256, num_points)
142 |
143 | x = torch.cat((x1, x2, x3, x4), dim=1) # (batch_size, 512, num_points)
144 |
145 | x0 = self.conv5(x) # (batch_size, 512, num_points) -> (batch_size, feat_dims, num_points)
146 | x = x0.max(dim=-1, keepdim=False)[0] # (batch_size, feat_dims, num_points) -> (batch_size, feat_dims)
147 | feat = x.unsqueeze(1) # (batch_size, feat_dims) -> (batch_size, 1, feat_dims)
148 |
149 | if self.task == 'classify':
150 | return feat, x0
151 | elif self.task == 'reconstruct':
152 | return feat # (batch_size, 1, feat_dims)
153 |
154 |
155 | class Point_Transform_Net(nn.Module):
156 | def __init__(self):
157 | super(Point_Transform_Net, self).__init__()
158 | self.k = 3
159 |
160 | self.bn1 = nn.BatchNorm2d(64)
161 | self.bn2 = nn.BatchNorm2d(128)
162 | self.bn3 = nn.BatchNorm1d(1024)
163 |
164 | self.conv1 = nn.Sequential(nn.Conv2d(6, 64, kernel_size=1, bias=False),
165 | self.bn1,
166 | nn.LeakyReLU(negative_slope=0.2))
167 | self.conv2 = nn.Sequential(nn.Conv2d(64, 128, kernel_size=1, bias=False),
168 | self.bn2,
169 | nn.LeakyReLU(negative_slope=0.2))
170 | self.conv3 = nn.Sequential(nn.Conv1d(128, 1024, kernel_size=1, bias=False),
171 | self.bn3,
172 | nn.LeakyReLU(negative_slope=0.2))
173 |
174 | self.linear1 = nn.Linear(1024, 512, bias=False)
175 | self.bn3 = nn.BatchNorm1d(512)
176 | self.linear2 = nn.Linear(512, 256, bias=False)
177 | self.bn4 = nn.BatchNorm1d(256)
178 |
179 | self.transform = nn.Linear(256, 3*3)
180 | init.constant_(self.transform.weight, 0)
181 | init.eye_(self.transform.bias.view(3, 3))
182 |
183 | def forward(self, x):
184 | batch_size = x.size(0)
185 |
186 | x = self.conv1(x) # (batch_size, 3*2, num_points, k) -> (batch_size, 64, num_points, k)
187 | x = self.conv2(x) # (batch_size, 64, num_points, k) -> (batch_size, 128, num_points, k)
188 | x = x.max(dim=-1, keepdim=False)[0] # (batch_size, 128, num_points, k) -> (batch_size, 128, num_points)
189 |
190 | x = self.conv3(x) # (batch_size, 128, num_points) -> (batch_size, 1024, num_points)
191 | x = x.max(dim=-1, keepdim=False)[0] # (batch_size, 1024, num_points) -> (batch_size, 1024)
192 |
193 | x = F.leaky_relu(self.bn3(self.linear1(x)), negative_slope=0.2) # (batch_size, 1024) -> (batch_size, 512)
194 | x = F.leaky_relu(self.bn4(self.linear2(x)), negative_slope=0.2) # (batch_size, 512) -> (batch_size, 256)
195 |
196 | x = self.transform(x) # (batch_size, 256) -> (batch_size, 3*3)
197 | x = x.view(batch_size, 3, 3) # (batch_size, 3*3) -> (batch_size, 3, 3)
198 |
199 | return x # (batch_size, 3, 3)
200 |
201 |
202 | class DGCNN_Seg_Encoder(nn.Module):
203 | def __init__(self, args):
204 | super(DGCNN_Seg_Encoder, self).__init__()
205 | if args.k == None:
206 | self.k = 20
207 | else:
208 | self.k = args.k
209 | self.transform_net = Point_Transform_Net()
210 |
211 | self.bn1 = nn.BatchNorm2d(64)
212 | self.bn2 = nn.BatchNorm2d(64)
213 | self.bn3 = nn.BatchNorm2d(64)
214 | self.bn4 = nn.BatchNorm2d(64)
215 | self.bn5 = nn.BatchNorm2d(64)
216 | self.bn6 = nn.BatchNorm1d(args.feat_dims)
217 |
218 | self.conv1 = nn.Sequential(nn.Conv2d(6, 64, kernel_size=1, bias=False),
219 | self.bn1,
220 | nn.LeakyReLU(negative_slope=0.2))
221 | self.conv2 = nn.Sequential(nn.Conv2d(64, 64, kernel_size=1, bias=False),
222 | self.bn2,
223 | nn.LeakyReLU(negative_slope=0.2))
224 | self.conv3 = nn.Sequential(nn.Conv2d(64*2, 64, kernel_size=1, bias=False),
225 | self.bn3,
226 | nn.LeakyReLU(negative_slope=0.2))
227 | self.conv4 = nn.Sequential(nn.Conv2d(64, 64, kernel_size=1, bias=False),
228 | self.bn4,
229 | nn.LeakyReLU(negative_slope=0.2))
230 | self.conv5 = nn.Sequential(nn.Conv2d(64*2, 64, kernel_size=1, bias=False),
231 | self.bn5,
232 | nn.LeakyReLU(negative_slope=0.2))
233 | self.conv6 = nn.Sequential(nn.Conv1d(192, args.feat_dims, kernel_size=1, bias=False),
234 | self.bn6,
235 | nn.LeakyReLU(negative_slope=0.2))
236 |
237 |
238 | def forward(self, x):
239 | x = x.transpose(2, 1)
240 |
241 | batch_size = x.size(0)
242 | num_points = x.size(2)
243 |
244 | x0 = get_graph_feature(x, k=self.k) # (batch_size, 3, num_points) -> (batch_size, 3*2, num_points, k)
245 | t = self.transform_net(x0) # (batch_size, 3, 3)
246 | x = x.transpose(2, 1) # (batch_size, 3, num_points) -> (batch_size, num_points, 3)
247 | x = torch.bmm(x, t) # (batch_size, num_points, 3) * (batch_size, 3, 3) -> (batch_size, num_points, 3)
248 | x = x.transpose(2, 1) # (batch_size, num_points, 3) -> (batch_size, 3, num_points)
249 |
250 | x = get_graph_feature(x, k=self.k) # (batch_size, 3, num_points) -> (batch_size, 3*2, num_points, k)
251 | x = self.conv1(x) # (batch_size, 3*2, num_points, k) -> (batch_size, 64, num_points, k)
252 | x = self.conv2(x) # (batch_size, 64, num_points, k) -> (batch_size, 64, num_points, k)
253 | x1 = x.max(dim=-1, keepdim=False)[0] # (batch_size, 64, num_points, k) -> (batch_size, 64, num_points)
254 |
255 | x = get_graph_feature(x1, k=self.k) # (batch_size, 64, num_points) -> (batch_size, 64*2, num_points, k)
256 | x = self.conv3(x) # (batch_size, 64*2, num_points, k) -> (batch_size, 64, num_points, k)
257 | x = self.conv4(x) # (batch_size, 64, num_points, k) -> (batch_size, 64, num_points, k)
258 | x2 = x.max(dim=-1, keepdim=False)[0] # (batch_size, 64, num_points, k) -> (batch_size, 64, num_points)
259 |
260 | x = get_graph_feature(x2, k=self.k) # (batch_size, 64, num_points) -> (batch_size, 64*2, num_points, k)
261 | x = self.conv5(x) # (batch_size, 64*2, num_points, k) -> (batch_size, 64, num_points, k)
262 | x3 = x.max(dim=-1, keepdim=False)[0] # (batch_size, 64, num_points, k) -> (batch_size, 64, num_points)
263 |
264 | x = torch.cat((x1, x2, x3), dim=1) # (batch_size, 64*3, num_points)
265 |
266 | x = self.conv6(x) # (batch_size, 64*3, num_points) -> (batch_size, emb_dims, num_points)
267 | x = x.max(dim=-1, keepdim=False)[0] # (batch_size, emb_dims, num_points) -> (batch_size, emb_dims)
268 |
269 | feat = x.unsqueeze(1) # (batch_size, num_points) -> (batch_size, 1, emb_dims)
270 |
271 | return feat # (batch_size, 1, emb_dims)
272 |
273 |
274 | class FoldNet_Encoder(nn.Module):
275 | def __init__(self, args):
276 | super(FoldNet_Encoder, self).__init__()
277 | if args.k == None:
278 | self.k = 16
279 | else:
280 | self.k = args.k
281 | self.n = 2048 # input point cloud size
282 | self.mlp1 = nn.Sequential(
283 | nn.Conv1d(12, 64, 1),
284 | nn.ReLU(),
285 | nn.Conv1d(64, 64, 1),
286 | nn.ReLU(),
287 | nn.Conv1d(64, 64, 1),
288 | nn.ReLU(),
289 | )
290 | self.linear1 = nn.Linear(64, 64)
291 | self.conv1 = nn.Conv1d(64, 128, 1)
292 | self.linear2 = nn.Linear(128, 128)
293 | self.conv2 = nn.Conv1d(128, 1024, 1)
294 | self.mlp2 = nn.Sequential(
295 | nn.Conv1d(1024, args.feat_dims, 1),
296 | nn.ReLU(),
297 | nn.Conv1d(args.feat_dims, args.feat_dims, 1),
298 | )
299 |
300 | def graph_layer(self, x, idx):
301 | x = local_maxpool(x, idx)
302 | x = self.linear1(x)
303 | x = x.transpose(2, 1)
304 | x = F.relu(self.conv1(x))
305 | x = local_maxpool(x, idx)
306 | x = self.linear2(x)
307 | x = x.transpose(2, 1)
308 | x = self.conv2(x)
309 | return x
310 |
311 | def forward(self, pts):
312 | pts = pts.transpose(2, 1) # (batch_size, 3, num_points)
313 | idx = knn(pts, k=self.k)
314 | x = local_cov(pts, idx) # (batch_size, 3, num_points) -> (batch_size, 12, num_points])
315 | x = self.mlp1(x) # (batch_size, 12, num_points) -> (batch_size, 64, num_points])
316 | x = self.graph_layer(x, idx) # (batch_size, 64, num_points) -> (batch_size, 1024, num_points)
317 | x = torch.max(x, 2, keepdim=True)[0] # (batch_size, 1024, num_points) -> (batch_size, 1024, 1)
318 | x = self.mlp2(x) # (batch_size, 1024, 1) -> (batch_size, feat_dims, 1)
319 | feat = x.transpose(2,1) # (batch_size, feat_dims, 1) -> (batch_size, 1, feat_dims)
320 | return feat # (batch_size, 1, feat_dims)
321 |
322 |
323 | class FoldNet_Decoder(nn.Module):
324 | def __init__(self, args):
325 | super(FoldNet_Decoder, self).__init__()
326 | self.m = 2025 # 45 * 45.
327 | self.shape = args.shape
328 | self.meshgrid = [[-0.3, 0.3, 45], [-0.3, 0.3, 45]]
329 | self.sphere = np.load("sphere.npy")
330 | self.gaussian = np.load("gaussian.npy")
331 | if self.shape == 'plane':
332 | self.folding1 = nn.Sequential(
333 | nn.Conv1d(args.feat_dims+2, args.feat_dims, 1),
334 | nn.ReLU(),
335 | nn.Conv1d(args.feat_dims, args.feat_dims, 1),
336 | nn.ReLU(),
337 | nn.Conv1d(args.feat_dims, 3, 1),
338 | )
339 | else:
340 | self.folding1 = nn.Sequential(
341 | nn.Conv1d(args.feat_dims+3, args.feat_dims, 1),
342 | nn.ReLU(),
343 | nn.Conv1d(args.feat_dims, args.feat_dims, 1),
344 | nn.ReLU(),
345 | nn.Conv1d(args.feat_dims, 3, 1),
346 | )
347 | self.folding2 = nn.Sequential(
348 | nn.Conv1d(args.feat_dims+3, args.feat_dims, 1),
349 | nn.ReLU(),
350 | nn.Conv1d(args.feat_dims, args.feat_dims, 1),
351 | nn.ReLU(),
352 | nn.Conv1d(args.feat_dims, 3, 1),
353 | )
354 |
355 | def build_grid(self, batch_size):
356 | if self.shape == 'plane':
357 | x = np.linspace(*self.meshgrid[0])
358 | y = np.linspace(*self.meshgrid[1])
359 | points = np.array(list(itertools.product(x, y)))
360 | elif self.shape == 'sphere':
361 | points = self.sphere
362 | elif self.shape == 'gaussian':
363 | points = self.gaussian
364 | points = np.repeat(points[np.newaxis, ...], repeats=batch_size, axis=0)
365 | points = torch.tensor(points)
366 | return points.float()
367 |
368 | def forward(self, x):
369 | x = x.transpose(1, 2).repeat(1, 1, self.m) # (batch_size, feat_dims, num_points)
370 | points = self.build_grid(x.shape[0]).transpose(1, 2) # (batch_size, 2, num_points) or (batch_size, 3, num_points)
371 | if x.get_device() != -1:
372 | points = points.cuda(x.get_device())
373 | cat1 = torch.cat((x, points), dim=1) # (batch_size, feat_dims+2, num_points) or (batch_size, feat_dims+3, num_points)
374 | folding_result1 = self.folding1(cat1) # (batch_size, 3, num_points)
375 | cat2 = torch.cat((x, folding_result1), dim=1) # (batch_size, 515, num_points)
376 | folding_result2 = self.folding2(cat2) # (batch_size, 3, num_points)
377 | return folding_result2.transpose(1, 2) # (batch_size, num_points ,3)
378 |
379 |
380 | class DGCNN_Cls_Classifier(nn.Module):
381 | def __init__(self, args):
382 | super(DGCNN_Cls_Classifier, self).__init__()
383 | if args.dataset == 'modelnet40':
384 | output_channels = 40
385 | elif args.dataset == 'modelnet10':
386 | output_channels = 10
387 | elif args.dataset == 'shapenetcorev2':
388 | output_channels = 55
389 | elif args.dataset == 'shapenetpart':
390 | output_channels = 16
391 |
392 | self.linear1 = nn.Linear(args.feat_dims*2, 512, bias=False)
393 | self.bn6 = nn.BatchNorm1d(512)
394 | self.dp1 = nn.Dropout(p=args.dropout)
395 | self.linear2 = nn.Linear(512, 256)
396 | self.bn7 = nn.BatchNorm1d(256)
397 | self.dp2 = nn.Dropout(p=args.dropout)
398 | self.linear3 = nn.Linear(256, output_channels)
399 |
400 | def forward(self, x):
401 | batch_size = x.size(0)
402 |
403 | x1 = F.adaptive_max_pool1d(x, 1).view(batch_size, -1)
404 | x2 = F.adaptive_avg_pool1d(x, 1).view(batch_size, -1)
405 | x = torch.cat((x1, x2), 1)
406 |
407 | x = F.leaky_relu(self.bn6(self.linear1(x)), negative_slope=0.2)
408 | x = self.dp1(x)
409 | x = F.leaky_relu(self.bn7(self.linear2(x)), negative_slope=0.2)
410 | x = self.dp2(x)
411 | x = self.linear3(x)
412 | return x
413 |
414 |
415 | class ReconstructionNet(nn.Module):
416 | def __init__(self, args):
417 | super(ReconstructionNet, self).__init__()
418 | if args.encoder == 'foldnet':
419 | self.encoder = FoldNet_Encoder(args)
420 | elif args.encoder == 'dgcnn_cls':
421 | self.encoder = DGCNN_Cls_Encoder(args)
422 | elif args.encoder == 'dgcnn_seg':
423 | self.encoder = DGCNN_Seg_Encoder(args)
424 | self.decoder = FoldNet_Decoder(args)
425 | self.loss = ChamferLoss()
426 |
427 | def forward(self, input):
428 | feature = self.encoder(input)
429 | output = self.decoder(feature)
430 | return output, feature
431 |
432 | def get_parameter(self):
433 | return list(self.encoder.parameters()) + list(self.decoder.parameters())
434 |
435 | def get_loss(self, input, output):
436 | # input shape (batch_size, 2048, 3)
437 | # output shape (batch_size, 2025, 3)
438 | return self.loss(input, output)
439 |
440 |
441 | class ClassificationNet(nn.Module):
442 | def __init__(self, args):
443 | super(ClassificationNet, self).__init__()
444 | self.is_eval = args.eval
445 | if args.encoder == 'foldnet':
446 | self.encoder = FoldNet_Encoder(args)
447 | elif args.encoder == 'dgcnn_cls':
448 | self.encoder = DGCNN_Cls_Encoder(args)
449 | elif args.encoder == 'dgcnn_seg':
450 | self.encoder = DGCNN_Seg_Encoder(args)
451 | if not self.is_eval:
452 | self.classifier = DGCNN_Cls_Classifier(args)
453 | self.loss = CrossEntropyLoss()
454 |
455 | def forward(self, input):
456 | feature, latent = self.encoder(input)
457 | if not self.is_eval:
458 | output = self.classifier(latent)
459 | return output, feature
460 | else:
461 | return feature
462 |
463 | def get_parameter(self):
464 | return list(self.encoder.parameters()) + list(self.classifier.parameters())
465 |
466 | def get_loss(self, input, output):
467 | # input shape (batch_size, 2048)
468 | # output shape (batch_size, 2025)
469 | return self.loss(input, output)
470 |
--------------------------------------------------------------------------------
/reconstruction.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | """
4 | @Author: An Tao
5 | @Contact: ta19@mails.tsinghua.edu.cn
6 | @File: reconstruction.py
7 | @Time: 2020/1/2 10:26 AM
8 | """
9 |
10 | import os
11 | import sys
12 | import time
13 | import shutil
14 | import torch
15 | import torch.optim as optim
16 | import numpy as np
17 |
18 | from tensorboardX import SummaryWriter
19 |
20 | from model import ReconstructionNet
21 | from dataset import Dataset
22 | from utils import Logger
23 |
24 |
25 | class Reconstruction(object):
26 | def __init__(self, args):
27 | self.dataset_name = args.dataset
28 | if args.epochs != None:
29 | self.epochs = args.epochs
30 | elif args.encoder == 'foldnet':
31 | self.epochs = 278
32 | elif args.encoder == 'dgcnn_cls':
33 | self.epochs = 250
34 | elif args.encoder == 'dgcnn_seg':
35 | self.epochs = 290
36 | self.batch_size = args.batch_size
37 | self.snapshot_interval = args.snapshot_interval
38 | self.no_cuda = args.no_cuda
39 | self.model_path = args.model_path
40 |
41 | # create exp directory
42 | file = [f for f in args.model_path.split('/')]
43 | if args.exp_name != None:
44 | self.experiment_id = "Reconstruct_" + args.exp_name
45 | elif file[-2] == 'models':
46 | self.experiment_id = file[-3]
47 | else:
48 | self.experiment_id = "Reconstruct" + time.strftime('%m%d%H%M%S')
49 | snapshot_root = 'snapshot/%s' % self.experiment_id
50 | tensorboard_root = 'tensorboard/%s' % self.experiment_id
51 | self.save_dir = os.path.join(snapshot_root, 'models/')
52 | self.tboard_dir = tensorboard_root
53 |
54 | # check arguments
55 | if self.model_path == '':
56 | if not os.path.exists(self.save_dir):
57 | os.makedirs(self.save_dir)
58 | else:
59 | choose = input("Remove " + self.save_dir + " ? (y/n)")
60 | if choose == "y":
61 | shutil.rmtree(self.save_dir)
62 | os.makedirs(self.save_dir)
63 | else:
64 | sys.exit(0)
65 | if not os.path.exists(self.tboard_dir):
66 | os.makedirs(self.tboard_dir)
67 | else:
68 | shutil.rmtree(self.tboard_dir)
69 | os.makedirs(self.tboard_dir)
70 | sys.stdout = Logger(os.path.join(snapshot_root, 'log.txt'))
71 | self.writer = SummaryWriter(log_dir=self.tboard_dir)
72 |
73 | # print args
74 | print(str(args))
75 |
76 | # get gpu id
77 | gids = ''.join(args.gpu.split())
78 | self.gpu_ids = [int(gid) for gid in gids.split(',')]
79 | self.first_gpu = self.gpu_ids[0]
80 |
81 | # generate dataset
82 | self.train_dataset = Dataset(
83 | root=args.dataset_root,
84 | dataset_name=args.dataset,
85 | split='all',
86 | num_points=args.num_points,
87 | random_translate=args.use_translate,
88 | random_rotate=True,
89 | random_jitter=args.use_jitter
90 | )
91 | self.train_loader = torch.utils.data.DataLoader(
92 | self.train_dataset,
93 | batch_size=args.batch_size,
94 | shuffle=True,
95 | num_workers=args.workers
96 | )
97 | print("Training set size:", self.train_loader.dataset.__len__())
98 |
99 | # initialize model
100 | self.model = ReconstructionNet(args)
101 | if self.model_path != '':
102 | self._load_pretrain(args.model_path)
103 |
104 | # load model to gpu
105 | if not self.no_cuda:
106 | if len(self.gpu_ids) != 1: # multiple gpus
107 | self.model = torch.nn.DataParallel(self.model.cuda(self.first_gpu), self.gpu_ids)
108 | else:
109 | self.model = self.model.cuda(self.gpu_ids[0])
110 |
111 | # initialize optimizer
112 | self.parameter = self.model.parameters()
113 | self.optimizer = optim.Adam(self.parameter, lr=0.0001*16/args.batch_size, betas=(0.9, 0.999), weight_decay=1e-6)
114 |
115 |
116 | def run(self):
117 | self.train_hist = {
118 | 'loss': [],
119 | 'per_epoch_time': [],
120 | 'total_time': []
121 | }
122 | best_loss = 1000000000
123 | print('Training start!!')
124 | start_time = time.time()
125 | self.model.train()
126 | if self.model_path != '':
127 | start_epoch = self.model_path[-7:-4]
128 | if start_epoch[0] == '_':
129 | start_epoch = start_epoch[1:]
130 | start_epoch = int(start_epoch)
131 | else:
132 | start_epoch = 0
133 | for epoch in range(start_epoch, self.epochs):
134 | loss = self.train_epoch(epoch)
135 |
136 | # save snapeshot
137 | if (epoch + 1) % self.snapshot_interval == 0:
138 | self._snapshot(epoch + 1)
139 | if loss < best_loss:
140 | best_loss = loss
141 | self._snapshot('best')
142 |
143 | # save tensorboard
144 | if self.writer:
145 | self.writer.add_scalar('Train Loss', self.train_hist['loss'][-1], epoch)
146 | self.writer.add_scalar('Learning Rate', self._get_lr(), epoch)
147 |
148 | # finish all epoch
149 | self._snapshot(epoch + 1)
150 | if loss < best_loss:
151 | best_loss = loss
152 | self._snapshot('best')
153 | self.train_hist['total_time'].append(time.time() - start_time)
154 | print("Avg one epoch time: %.2f, total %d epochs time: %.2f" % (np.mean(self.train_hist['per_epoch_time']),
155 | self.epochs, self.train_hist['total_time'][0]))
156 | print("Training finish!... save training results")
157 |
158 |
159 | def train_epoch(self, epoch):
160 | epoch_start_time = time.time()
161 | loss_buf = []
162 | num_batch = int(len(self.train_loader.dataset) / self.batch_size)
163 | for iter, (pts, _) in enumerate(self.train_loader):
164 | if not self.no_cuda:
165 | pts = pts.cuda(self.first_gpu)
166 |
167 | # forward
168 | self.optimizer.zero_grad()
169 | output, _ = self.model(pts)
170 |
171 | # loss
172 | if len(self.gpu_ids) != 1: # multiple gpus
173 | loss = self.model.module.get_loss(pts, output)
174 | else:
175 | loss = self.model.get_loss(pts, output)
176 |
177 | # backward
178 | loss.backward()
179 | self.optimizer.step()
180 | loss_buf.append(loss.detach().cpu().numpy())
181 |
182 | # finish one epoch
183 | epoch_time = time.time() - epoch_start_time
184 | self.train_hist['per_epoch_time'].append(epoch_time)
185 | self.train_hist['loss'].append(np.mean(loss_buf))
186 | print(f'Epoch {epoch+1}: Loss {np.mean(loss_buf)}, time {epoch_time:.4f}s')
187 | return np.mean(loss_buf)
188 |
189 |
190 | def _snapshot(self, epoch):
191 | state_dict = self.model.state_dict()
192 | from collections import OrderedDict
193 | new_state_dict = OrderedDict()
194 | for key, val in state_dict.items():
195 | if key[:6] == 'module':
196 | name = key[7:] # remove 'module.'
197 | else:
198 | name = key
199 | new_state_dict[name] = val
200 | save_dir = os.path.join(self.save_dir, self.dataset_name)
201 | torch.save(new_state_dict, save_dir + "_" + str(epoch) + '.pkl')
202 | print(f"Save model to {save_dir}_{str(epoch)}.pkl")
203 |
204 |
205 | def _load_pretrain(self, pretrain):
206 | state_dict = torch.load(pretrain, map_location='cpu')
207 | from collections import OrderedDict
208 | new_state_dict = OrderedDict()
209 | for key, val in state_dict.items():
210 | if key[:6] == 'module':
211 | name = key[7:] # remove 'module.'
212 | else:
213 | name = key
214 | new_state_dict[name] = val
215 | self.model.load_state_dict(new_state_dict)
216 | print(f"Load model from {pretrain}")
217 |
218 |
219 | def _get_lr(self, group=0):
220 | return self.optimizer.param_groups[group]['lr']
221 |
--------------------------------------------------------------------------------
/sphere.npy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/sphere.npy
--------------------------------------------------------------------------------
/svm.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | """
4 | @Author: An Tao
5 | @Contact: ta19@mails.tsinghua.edu.cn
6 | @File: svm.py
7 | @Time: 2020/1/2 10:26 AM
8 | """
9 |
10 | import os
11 | import h5py
12 | import numpy as np
13 | from glob import glob
14 | from sklearn.svm import LinearSVC
15 |
16 |
17 | class SVM(object):
18 | def __init__(self, feature_dir):
19 | self.feature_dir = feature_dir
20 |
21 | self.train_path = glob(os.path.join(self.feature_dir, 'train*.h5'))
22 | self.test_path = glob(os.path.join(self.feature_dir, 'test*.h5'))
23 |
24 | print("Loading feature dataset...")
25 | train_data = []
26 | train_label = []
27 | for path in self.train_path:
28 | f = h5py.File(path, 'r+')
29 | data = f['data'][:].astype('float32')
30 | label = f['label'][:].astype('int64')
31 | f.close()
32 | train_data.append(data)
33 | train_label.append(label)
34 | self.train_data = np.concatenate(train_data, axis=0)
35 | self.train_label = np.concatenate(train_label, axis=0)
36 | print("Training set size:", np.size(self.train_data, 0))
37 |
38 | test_data = []
39 | test_label = []
40 | for path in self.test_path:
41 | f = h5py.File(path, 'r+')
42 | data = f['data'][:].astype('float32')
43 | label = f['label'][:].astype('int64')
44 | f.close()
45 | test_data.append(data)
46 | test_label.append(label)
47 | self.test_data = np.concatenate(test_data, axis=0)
48 | self.test_label = np.concatenate(test_label, axis=0)
49 | print("Testing set size:", np.size(self.test_data, 0))
50 |
51 | def run(self):
52 | clf = LinearSVC(random_state=0)
53 | clf.fit(self.train_data, self.train_label)
54 | result = clf.predict(self.test_data)
55 | accuracy = np.sum(result==self.test_label).astype(float) / np.size(self.test_label)
56 | print("Transfer linear SVM accuracy: {:.2f}%".format(accuracy*100))
57 |
58 |
59 |
--------------------------------------------------------------------------------
/tensorboard/Classify_dgcnn_cls_k20/events.out.tfevents.1578666096.human1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/tensorboard/Classify_dgcnn_cls_k20/events.out.tfevents.1578666096.human1
--------------------------------------------------------------------------------
/tensorboard/Classify_dgcnn_cls_k40_1024_b32/events.out.tfevents.1579746166.server231:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/tensorboard/Classify_dgcnn_cls_k40_1024_b32/events.out.tfevents.1579746166.server231
--------------------------------------------------------------------------------
/tensorboard/Reconstruct_dgcnn_cls_k20_gaussian/events.out.tfevents.1578226376.human1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/tensorboard/Reconstruct_dgcnn_cls_k20_gaussian/events.out.tfevents.1578226376.human1
--------------------------------------------------------------------------------
/tensorboard/Reconstruct_dgcnn_cls_k20_plane/events.out.tfevents.1577427494.human1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/tensorboard/Reconstruct_dgcnn_cls_k20_plane/events.out.tfevents.1577427494.human1
--------------------------------------------------------------------------------
/tensorboard/Reconstruct_dgcnn_cls_k20_sphere/events.out.tfevents.1577698740.human1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/tensorboard/Reconstruct_dgcnn_cls_k20_sphere/events.out.tfevents.1577698740.human1
--------------------------------------------------------------------------------
/tensorboard/Reconstruct_dgcnn_cls_k40_gaussian/events.out.tfevents.1579955081.server231:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/tensorboard/Reconstruct_dgcnn_cls_k40_gaussian/events.out.tfevents.1579955081.server231
--------------------------------------------------------------------------------
/tensorboard/Reconstruct_dgcnn_cls_k40_plane/events.out.tfevents.1577866606.human1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/tensorboard/Reconstruct_dgcnn_cls_k40_plane/events.out.tfevents.1577866606.human1
--------------------------------------------------------------------------------
/tensorboard/Reconstruct_dgcnn_cls_k40_sphere/events.out.tfevents.1577935530.human1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/tensorboard/Reconstruct_dgcnn_cls_k40_sphere/events.out.tfevents.1577935530.human1
--------------------------------------------------------------------------------
/tensorboard/Reconstruct_dgcnn_cls_k40_sphere_1024_b32/events.out.tfevents.1579919706.server231:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/tensorboard/Reconstruct_dgcnn_cls_k40_sphere_1024_b32/events.out.tfevents.1579919706.server231
--------------------------------------------------------------------------------
/tensorboard/Reconstruct_dgcnn_seg_k20_gaussian/events.out.tfevents.1578371932.human1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/tensorboard/Reconstruct_dgcnn_seg_k20_gaussian/events.out.tfevents.1578371932.human1
--------------------------------------------------------------------------------
/tensorboard/Reconstruct_dgcnn_seg_k20_gaussian/events.out.tfevents.1578661771.human1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/tensorboard/Reconstruct_dgcnn_seg_k20_gaussian/events.out.tfevents.1578661771.human1
--------------------------------------------------------------------------------
/tensorboard/Reconstruct_dgcnn_seg_k20_plane/events.out.tfevents.1578186628.human1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/tensorboard/Reconstruct_dgcnn_seg_k20_plane/events.out.tfevents.1578186628.human1
--------------------------------------------------------------------------------
/tensorboard/Reconstruct_dgcnn_seg_k20_plane/events.out.tfevents.1578443368.human1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/tensorboard/Reconstruct_dgcnn_seg_k20_plane/events.out.tfevents.1578443368.human1
--------------------------------------------------------------------------------
/tensorboard/Reconstruct_dgcnn_seg_k20_sphere/events.out.tfevents.1578202920.human1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/tensorboard/Reconstruct_dgcnn_seg_k20_sphere/events.out.tfevents.1578202920.human1
--------------------------------------------------------------------------------
/tensorboard/Reconstruct_dgcnn_seg_k20_sphere/events.out.tfevents.1578447006.human1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/tensorboard/Reconstruct_dgcnn_seg_k20_sphere/events.out.tfevents.1578447006.human1
--------------------------------------------------------------------------------
/tensorboard/Reconstruct_dgcnn_seg_k40_gaussian/events.out.tfevents.1580628995.server231:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/tensorboard/Reconstruct_dgcnn_seg_k40_gaussian/events.out.tfevents.1580628995.server231
--------------------------------------------------------------------------------
/tensorboard/Reconstruct_dgcnn_seg_k40_plane/events.out.tfevents.1580304772.server231:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/tensorboard/Reconstruct_dgcnn_seg_k40_plane/events.out.tfevents.1580304772.server231
--------------------------------------------------------------------------------
/tensorboard/Reconstruct_dgcnn_seg_k40_sphere/events.out.tfevents.1580304803.server231:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/tensorboard/Reconstruct_dgcnn_seg_k40_sphere/events.out.tfevents.1580304803.server231
--------------------------------------------------------------------------------
/tensorboard/Reconstruct_original_gaussian/events.out.tfevents.1578226412.human1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/tensorboard/Reconstruct_original_gaussian/events.out.tfevents.1578226412.human1
--------------------------------------------------------------------------------
/tensorboard/Reconstruct_original_plane/events.out.tfevents.1577003758.human1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/tensorboard/Reconstruct_original_plane/events.out.tfevents.1577003758.human1
--------------------------------------------------------------------------------
/tensorboard/Reconstruct_original_sphere/events.out.tfevents.1577366104.human1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/tensorboard/Reconstruct_original_sphere/events.out.tfevents.1577366104.human1
--------------------------------------------------------------------------------
/utils.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | """
4 | @Author: An Tao
5 | @Contact: ta19@mails.tsinghua.edu.cn
6 | @File: utils.py
7 | @Time: 2020/1/2 10:26 AM
8 | """
9 |
10 | import os
11 | import sys
12 |
13 |
14 | class AverageMeter(object):
15 | """Computes and stores the average and current value"""
16 | def __init__(self):
17 | self.reset()
18 |
19 | def reset(self):
20 | self.val = 0
21 | self.avg = 0
22 | self.sum = 0
23 | self.count = 0
24 |
25 | def update(self, val, n=1):
26 | self.val = val
27 | self.sum += val * n
28 | self.count += n
29 | self.avg = self.sum / self.count
30 |
31 |
32 | def learning_rate_decay(optimizer, t, lr_0):
33 | for param_group in optimizer.param_groups:
34 | lr = lr_0 / np.sqrt(1 + lr_0 * param_group['weight_decay'] * t)
35 | param_group['lr'] = lr
36 |
37 |
38 | class Logger(object):
39 | def __init__(self, fpath=None):
40 | self.console = sys.stdout
41 | self.file = None
42 | if fpath is not None:
43 | self.file = open(fpath, 'w')
44 |
45 | def __del__(self):
46 | self.close()
47 |
48 | def __enter__(self):
49 | pass
50 |
51 | def __exit__(self, *args):
52 | self.close()
53 |
54 | def write(self, msg):
55 | self.console.write(msg)
56 | if self.file is not None:
57 | self.file.write(msg)
58 |
59 | def flush(self):
60 | self.console.flush()
61 | if self.file is not None:
62 | self.file.flush()
63 | os.fsync(self.file.fileno())
64 |
65 | def close(self):
66 | self.console.close()
67 | if self.file is not None:
68 | self.file.close()
--------------------------------------------------------------------------------
/visualization.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | """
4 | @Author: An Tao
5 | @Contact: ta19@mails.tsinghua.edu.cn
6 | @File: visualization.py
7 | @Time: 2020/1/2 10:26 AM
8 | """
9 |
10 | import os
11 | import time
12 | import numpy as np
13 | import torch
14 | import itertools
15 | import argparse
16 | from glob import glob
17 |
18 | from model import ReconstructionNet
19 |
20 | def standardize_bbox(pcl, points_per_object):
21 | pt_indices = np.random.choice(pcl.shape[0], points_per_object, replace=False)
22 | np.random.shuffle(pt_indices)
23 | pcl = pcl[pt_indices] # n by 3
24 | mins = np.amin(pcl, axis=0)
25 | maxs = np.amax(pcl, axis=0)
26 | center = ( mins + maxs ) / 2.
27 | scale = np.amax(maxs-mins)
28 | print("Center: {}, Scale: {}".format(center, scale))
29 | result = ((pcl - center)/scale).astype(np.float32) # [-0.5, 0.5]
30 | return result
31 |
32 | xml_head = \
33 | """
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 | """
65 |
66 | xml_ball_segment = \
67 | """
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 | """
79 |
80 | xml_tail = \
81 | """
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 | """
101 |
102 | def colormap(x,y,z):
103 | vec = np.array([x,y,z])
104 | vec = np.clip(vec, 0.001,1.0)
105 | norm = np.sqrt(np.sum(vec**2))
106 | vec /= norm
107 | return [vec[0], vec[1], vec[2]]
108 |
109 | def mitsuba(pcl, path, clr=None):
110 | xml_segments = [xml_head]
111 |
112 | # pcl = standardize_bbox(pcl, 2048)
113 | # pcl = pcl - np.expand_dims(np.mean(pcl, axis=0), 0) # center
114 | # dist = np.max(np.sqrt(np.sum(pcl ** 2, axis=1)), 0)
115 | # pcl = pcl / dist # scale
116 |
117 | pcl = pcl[:,[2,0,1]]
118 | pcl[:,0] *= -1
119 | h = np.min(pcl[:,2])
120 |
121 | if clr == "plane":
122 | clrgrid = [[0, 1, 45], [1, 0, 45]]
123 | b = np.linspace(*clrgrid[0])
124 | c = np.linspace(*clrgrid[1])
125 | color_all = np.array(list(itertools.product(b, c)))
126 | color_all = np.concatenate((np.linspace(1, 0, 2025)[..., np.newaxis], color_all), axis=1)
127 | elif clr == "sphere":
128 | color_all = np.load("sphere.npy")
129 | color_all = (color_all + 0.3) / 0.6
130 | elif clr == "gaussian":
131 | color_all = np.load("gaussian.npy")
132 | color_all = (color_all + 0.3) / 0.6
133 |
134 | for i in range(pcl.shape[0]):
135 | if clr == None:
136 | color = colormap(pcl[i,0]+0.5,pcl[i,1]+0.5,pcl[i,2]+0.5)
137 | elif clr in ["plane", "sphere", "gaussian"]:
138 | color = color_all[i]
139 | else:
140 | color = clr
141 | if h < -0.25:
142 | xml_segments.append(xml_ball_segment.format(pcl[i,0],pcl[i,1],pcl[i,2]-h-0.6875, *color))
143 | else:
144 | xml_segments.append(xml_ball_segment.format(pcl[i,0],pcl[i,1],pcl[i,2], *color))
145 | xml_segments.append(xml_tail)
146 |
147 | xml_content = str.join('', xml_segments)
148 |
149 | with open(path, 'w') as f:
150 | f.write(xml_content)
151 |
152 | def load_pretrain(model, pretrain):
153 | state_dict = torch.load(pretrain, map_location='cpu')
154 | from collections import OrderedDict
155 | new_state_dict = OrderedDict()
156 | for key, val in state_dict.items():
157 | if key[:6] == 'module':
158 | name = key[7:] # remove 'module.'
159 | else:
160 | name = key
161 | new_state_dict[name] = val
162 | model.load_state_dict(new_state_dict)
163 | print(f"Load model from {pretrain}")
164 | return model
165 |
166 |
167 | def visualize(args):
168 | # create exp directory
169 | file = [f for f in args.model_path.split('/')]
170 | if args.exp_name != None:
171 | experiment_id = args.exp_name
172 | elif file[-1] == '':
173 | experiment_id = time.strftime('%m%d%H%M%S')
174 | one_model = True
175 | elif file[-1][-4:] == '.pkl':
176 | experiment_id = file[-3]
177 | one_model = True
178 | elif file[-1] == 'models':
179 | experiment_id = file[-2]
180 | one_model = False
181 | else:
182 | experiment_id = time.strftime('%m%d%H%M%S')
183 | save_root = os.path.join('mitsuba', experiment_id, args.dataset, args.split + str(args.item))
184 | os.makedirs(save_root, exist_ok=True)
185 |
186 | # initialize dataset
187 | from dataset import Dataset
188 | dataset = Dataset(root=args.dataset_root, dataset_name=args.dataset,
189 | num_points=args.num_points, split=args.split, load_name=True)
190 |
191 | # load data from dataset
192 | pts, lb, n = dataset[args.item]
193 | print(f"Dataset: {args.dataset}, split: {args.split}, item: {args.item}, category: {n}")
194 |
195 | # generate XML file for original point cloud
196 | if args.draw_original:
197 | save_path = os.path.join(save_root, args.dataset + '_' + args.split + str(args.item) + '_' + str(n) + '_origin.xml')
198 | color = [0.4, 0.4, 0.6]
199 | mitsuba(pts.numpy(), save_path, color)
200 |
201 | # generate XML file for decoder souce point
202 | if args.draw_source_points:
203 | if args.shape == 'plane':
204 | meshgrid = [[-0.3, 0.3, 45], [-0.3, 0.3, 45]]
205 | x = np.linspace(*meshgrid[0])
206 | y = np.linspace(*meshgrid[1])
207 | points = np.array(list(itertools.product(x, y)))
208 | points = np.concatenate((points,np.zeros(2025)[..., np.newaxis]), axis=1)
209 | elif args.shape == 'sphere':
210 | points = np.load("sphere.npy")
211 | elif args.shape == 'gaussian':
212 | points = np.load("gaussian.npy")
213 | save_path = os.path.join(save_root, args.dataset + '_' + args.split + str(args.item) + '_' + str(n) + '_epoch0.xml')
214 | mitsuba(points, save_path, clr=args.shape)
215 |
216 | # initialize model
217 | model = ReconstructionNet(args)
218 |
219 | if one_model:
220 | if file[0] != '':
221 | model = load_pretrain(model, args.model_path)
222 | model.eval()
223 | reconstructed_pl, _ = model(pts.view(1, 2048, 3))
224 | save_path = os.path.join(save_root, file[-1][:-4] + args.split + str(args.item) + '_' + str(n) + '.xml')
225 | mitsuba(reconstructed_pl[0].detach().numpy(), save_path, clr=args.shape)
226 | else:
227 | load_path = glob(os.path.join(args.model_path, '*.pkl'))
228 | load_path.sort()
229 | for path in load_path:
230 | model_name = [p for p in path.split('/')][-1]
231 | model = load_pretrain(model, path)
232 | model.eval()
233 | reconstructed_pl, _ = model(pts.view(1, 2048, 3))
234 | save_path = os.path.join(save_root, model_name[:-4] + '_' + args.dataset + '_' + args.split + str(args.item) + '_' + str(n) + '.xml')
235 | mitsuba(reconstructed_pl[0].detach().numpy(), save_path, clr=args.shape)
236 |
237 |
238 | if __name__ == '__main__':
239 | parser = argparse.ArgumentParser(description='Unsupervised Point Cloud Feature Learning')
240 | parser.add_argument('--exp_name', type=str, default=None, metavar='N',
241 | help='Name of the experiment')
242 | parser.add_argument('--item', type=int, default=0, metavar='N',
243 | help='Item of point cloud to load')
244 | parser.add_argument('--split', type=str, default='train', metavar='N',
245 | choices=['train','test', 'val', 'trainval', 'all'],
246 | help='Split to use, [foldingnet, dgcnn_cls, dgcnn_seg]')
247 | parser.add_argument('--encoder', type=str, default='foldingnet', metavar='N',
248 | choices=['foldnet', 'dgcnn_cls', 'dgcnn_seg'],
249 | help='Encoder to use, [foldingnet, dgcnn_cls, dgcnn_seg]')
250 | parser.add_argument('--feat_dims', type=int, default=512, metavar='N',
251 | help='Number of dims for feature ')
252 | parser.add_argument('--k', type=int, default=None, metavar='N',
253 | help='Num of nearest neighbors to use for KNN')
254 | parser.add_argument('--shape', type=str, default='plane', metavar='N',
255 | choices=['plane', 'sphere', 'gaussian'],
256 | help='Shape of points to input decoder, [plane, sphere, gaussian]')
257 | parser.add_argument('--dataset', type=str, default='shapenetcorev2', metavar='N',
258 | choices=['shapenetcorev2','modelnet40', 'modelnet10'],
259 | help='Encoder to use, [shapenetcorev2,modelnet40, modelnet10]')
260 | parser.add_argument('--dataset_root', type=str, default='../dataset', help="Dataset root path")
261 | parser.add_argument('--num_points', type=int, default=2048,
262 | help='Num of points to use')
263 | parser.add_argument('--model_path', type=str, default='', metavar='N',
264 | help='Path to load model')
265 | parser.add_argument('--draw_original', action='store_true',
266 | help='Draw original point cloud')
267 | parser.add_argument('--draw_source_points', action='store_true',
268 | help='Draw source points for decoder')
269 | args = parser.parse_args()
270 |
271 | print(str(args))
272 |
273 | visualize(args)
--------------------------------------------------------------------------------