torch-pointcloud 0.0.2__tar.gz → 0.0.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/.gitignore +1 -0
  2. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/PKG-INFO +2 -2
  3. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/README.md +1 -1
  4. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/pyproject.toml +1 -1
  5. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/inferers/sliding_window.py +99 -50
  6. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/layers/serialized_attention.py +57 -18
  7. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/models/_base.py +10 -4
  8. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/models/concerto.py +8 -4
  9. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/models/dgcnn.py +1 -8
  10. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/models/kpconv.py +13 -14
  11. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/models/octformer.py +13 -12
  12. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/models/point_bert.py +10 -4
  13. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/models/point_m2ae.py +2 -9
  14. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/models/point_mae.py +2 -7
  15. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/models/point_transformer.py +9 -9
  16. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/models/point_transformer_v2.py +11 -12
  17. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/models/point_transformer_v3.py +42 -19
  18. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/models/pointcnn.py +12 -22
  19. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/models/pointconv.py +9 -17
  20. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/models/pointmlp.py +12 -22
  21. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/models/pointnet2.py +7 -7
  22. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/models/pointnext.py +23 -34
  23. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/models/pvcnn.py +16 -12
  24. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/models/pvcnn2.py +17 -11
  25. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/models/randlanet.py +14 -20
  26. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/models/sonata.py +8 -4
  27. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/models/spformer_unet.py +41 -14
  28. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/models/spunet.py +40 -16
  29. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/models/spvcnn.py +29 -8
  30. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/models/utonia.py +4 -4
  31. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/utils/types.py +26 -0
  32. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/LICENSE +0 -0
  33. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/THIRD_PARTY_NOTICES.md +0 -0
  34. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/__init__.py +0 -0
  35. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/config.py +0 -0
  36. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/datasets/__init__.py +0 -0
  37. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/datasets/concat.py +0 -0
  38. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/datasets/kitti.py +0 -0
  39. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/datasets/mix.py +0 -0
  40. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/datasets/modelnet.py +0 -0
  41. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/datasets/nuscenes.py +0 -0
  42. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/datasets/parislille3d.py +0 -0
  43. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/datasets/pointcloud.py +0 -0
  44. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/datasets/repeat.py +0 -0
  45. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/datasets/s3dis.py +0 -0
  46. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/datasets/scannet.py +0 -0
  47. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/datasets/scanobjectnn.py +0 -0
  48. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/datasets/semantic3d.py +0 -0
  49. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/datasets/semantickitti.py +0 -0
  50. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/datasets/shapenetpart.py +0 -0
  51. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/datasets/sunrgbd.py +0 -0
  52. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/datasets/toronto3d.py +0 -0
  53. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/datasets/utils.py +0 -0
  54. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/inferers/__init__.py +0 -0
  55. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/inferers/_utils.py +0 -0
  56. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/inferers/inferer.py +0 -0
  57. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/inferers/knn_window.py +0 -0
  58. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/inferers/part_refinement.py +0 -0
  59. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/inferers/potential_sphere.py +0 -0
  60. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/inferers/simple.py +0 -0
  61. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/inferers/tta.py +0 -0
  62. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/inferers/voxel_partition.py +0 -0
  63. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/layers/__init__.py +0 -0
  64. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/layers/_modules.py +0 -0
  65. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/layers/act.py +0 -0
  66. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/layers/affine.py +0 -0
  67. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/layers/anchors.py +0 -0
  68. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/layers/bev_backbone.py +0 -0
  69. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/layers/conv2d_blocks.py +0 -0
  70. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/layers/conv3d_blocks.py +0 -0
  71. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/layers/dropouts.py +0 -0
  72. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/layers/fps.py +0 -0
  73. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/layers/geometric_affine.py +0 -0
  74. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/layers/grid_pool.py +0 -0
  75. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/layers/linear_blocks.py +0 -0
  76. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/layers/norms.py +0 -0
  77. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/layers/octree_attention.py +0 -0
  78. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/layers/octree_blocks.py +0 -0
  79. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/layers/pdnorm.py +0 -0
  80. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/layers/point_patch_embed.py +0 -0
  81. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/layers/pointconv.py +0 -0
  82. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/layers/pointconv_sa.py +0 -0
  83. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/layers/pointnet2_blocks.py +0 -0
  84. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/layers/pointnext_blocks.py +0 -0
  85. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/layers/pools.py +0 -0
  86. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/layers/pvcnn_blocks.py +0 -0
  87. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/layers/rope.py +0 -0
  88. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/layers/serialized_pool.py +0 -0
  89. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/layers/spconv_blocks.py +0 -0
  90. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/layers/tnet.py +0 -0
  91. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/layers/transformer.py +0 -0
  92. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/layers/vfe.py +0 -0
  93. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/layers/view.py +0 -0
  94. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/layers/xconv.py +0 -0
  95. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/lightning/__init__.py +0 -0
  96. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/lightning/callbacks.py +0 -0
  97. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/lightning/datamodule.py +0 -0
  98. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/lightning/metrics.py +0 -0
  99. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/lightning/module.py +0 -0
  100. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/losses/__init__.py +0 -0
  101. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/losses/_utils.py +0 -0
  102. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/losses/anchor.py +0 -0
  103. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/losses/center.py +0 -0
  104. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/losses/chamfer.py +0 -0
  105. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/losses/detr3d.py +0 -0
  106. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/losses/lovasz.py +0 -0
  107. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/losses/pointrcnn.py +0 -0
  108. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/losses/sum.py +0 -0
  109. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/losses/transfusion.py +0 -0
  110. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/losses/votenet.py +0 -0
  111. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/models/__init__.py +0 -0
  112. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/models/_registry.py +0 -0
  113. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/models/detr3d.py +0 -0
  114. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/models/lion.py +0 -0
  115. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/models/point_mamba.py +0 -0
  116. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/models/pointgpt.py +0 -0
  117. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/models/pointnet.py +0 -0
  118. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/models/pointpillars.py +0 -0
  119. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/models/pointrcnn.py +0 -0
  120. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/models/second.py +0 -0
  121. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/models/sphereformer.py +0 -0
  122. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/models/votenet.py +0 -0
  123. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/models/voxel_mamba.py +0 -0
  124. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/models/voxelnext.py +0 -0
  125. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/py.typed +0 -0
  126. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/transforms/__init__.py +0 -0
  127. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/transforms/functional.py +0 -0
  128. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/transforms/transforms.py +0 -0
  129. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/utils/__init__.py +0 -0
  130. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/utils/box3d.py +0 -0
  131. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/utils/cluster.py +0 -0
  132. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/utils/conversion.py +0 -0
  133. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/utils/data.py +0 -0
  134. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/utils/diffusion.py +0 -0
  135. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/utils/ensemble.py +0 -0
  136. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/utils/geometry.py +0 -0
  137. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/utils/heatmap.py +0 -0
  138. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/utils/hilbert.py +0 -0
  139. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/utils/imports.py +0 -0
  140. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/utils/io.py +0 -0
  141. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/utils/metrics.py +0 -0
  142. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/utils/misc.py +0 -0
  143. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/utils/neighbors.py +0 -0
  144. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/utils/octree.py +0 -0
  145. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/utils/ops.py +0 -0
  146. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/utils/optim.py +0 -0
  147. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/utils/random.py +0 -0
  148. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/utils/serialization.py +0 -0
  149. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/utils/state_dict.py +0 -0
  150. {torch_pointcloud-0.0.2 → torch_pointcloud-0.0.3}/src/torch_pointcloud/utils/voxelization.py +0 -0
@@ -164,6 +164,7 @@ cython_debug/
164
164
  weights/**
165
165
  data/**
166
166
  docs/api/**
167
+ docs/assets/data/
167
168
  docs/examples/**
168
169
  docs/scripts/**
169
170
  !docs/examples/*.ipynb
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: torch-pointcloud
3
- Version: 0.0.2
3
+ Version: 0.0.3
4
4
  Summary: PyTorch Point Cloud models, scripts, pretrained weights and more
5
5
  Project-URL: Homepage, https://github.com/arthurdjn/pytorch-pointcloud
6
6
  Project-URL: Repository, https://github.com/arthurdjn/pytorch-pointcloud
@@ -158,7 +158,7 @@ Every checkpoint ships the transform that turns a raw point cloud into what the
158
158
  # Requires torch-scatter, torch-cluster, spconv
159
159
  model, info = tp.create_model("ptv3-base.scannet20.pointcept", task="segmentation", pretrained=True, return_info=True)
160
160
  info["transform"] # the preprocessing pipeline of that checkpoint
161
- info["weights"]["metrics"] # {"mIoU": 76.29}
161
+ info["weights"]["metrics"] # {"mIoU": 77.40}
162
162
 
163
163
  tp.list_models("pointnext*") # every registered PointNeXt config
164
164
  tp.list_models(task="detection", pretrained=True) # all detection checkpoints
@@ -115,7 +115,7 @@ Every checkpoint ships the transform that turns a raw point cloud into what the
115
115
  # Requires torch-scatter, torch-cluster, spconv
116
116
  model, info = tp.create_model("ptv3-base.scannet20.pointcept", task="segmentation", pretrained=True, return_info=True)
117
117
  info["transform"] # the preprocessing pipeline of that checkpoint
118
- info["weights"]["metrics"] # {"mIoU": 76.29}
118
+ info["weights"]["metrics"] # {"mIoU": 77.40}
119
119
 
120
120
  tp.list_models("pointnext*") # every registered PointNeXt config
121
121
  tp.list_models(task="detection", pretrained=True) # all detection checkpoints
@@ -16,7 +16,7 @@ include = [
16
16
 
17
17
  [project]
18
18
  name = "torch-pointcloud"
19
- version = "0.0.2"
19
+ version = "0.0.3"
20
20
  description = "PyTorch Point Cloud models, scripts, pretrained weights and more"
21
21
  readme = "README.md"
22
22
  license = "Apache-2.0"
@@ -27,7 +27,7 @@ import torch
27
27
  from torch import Tensor
28
28
  from tqdm import tqdm
29
29
 
30
- from torch_pointcloud.utils.data import DataKeys
30
+ from torch_pointcloud.utils.data import DataKeys, collate
31
31
 
32
32
  from ._utils import check_batch_alignment, gaussian_weights, index_select_dict, split_chunks
33
33
  from .inferer import Inferer
@@ -194,6 +194,7 @@ def sliding_window_inference(
194
194
  mode: WindowMode = "constant",
195
195
  sigma_scale: float = 0.125,
196
196
  roi_num_points: Optional[int] = None,
197
+ sw_batch_size: int = 1,
197
198
  softmax: bool = True,
198
199
  aggregate: AggregateMode = "mean",
199
200
  transform: Optional[Callable[[Dict[str, Any]], Dict[str, Any]]] = None,
@@ -239,13 +240,18 @@ def sliding_window_inference(
239
240
  $D_\text{tiled}$ the number of tiled axes.
240
241
  sigma_scale: Gaussian sigma scale factor. Only used when
241
242
  `mode="gaussian"`.
242
- roi_num_points: Optional cap on points per `predictor` call. Blocks
243
+ roi_num_points: Optional cap on points per batch element. Blocks
243
244
  exceeding this are split into random sub-batches and every point is
244
245
  predicted exactly once per block pass. `None` passes the whole block
245
- in one call. To enforce a fixed-N predictor input, pair the inferer
246
+ in one element. At the default `sw_batch_size=1` an element is a call,
247
+ so this also caps the points per `predictor` call. To enforce a fixed-N predictor input, pair the inferer
246
248
  with a `DivisiblePad`-style `transform` that pads each block to a
247
249
  multiple of `roi_num_points` and writes its source-to-padded index
248
250
  map under `inverse_key`.
251
+ sw_batch_size: Number of batch elements packed into a single `predictor` call. Blocks are
252
+ independent, so they are collated along the batch index and their predictions are
253
+ accumulated in block order: only the number of calls changes. Small blocks are
254
+ dominated by per-call overhead, where a larger value is several times faster.
249
255
  softmax: If `True`, softmax each block's logits before accumulating.
250
256
  Use `True` when averaging predictions across multiple blocks or
251
257
  TTA passes. Set `False` to accumulate raw logits. `"max"` and
@@ -307,6 +313,8 @@ def sliding_window_inference(
307
313
  raise ValueError(f"`aggregate` must be 'mean', 'max' or 'vote', got {aggregate!r}.")
308
314
  if roi_num_points is not None and roi_num_points < 1:
309
315
  raise ValueError(f"`roi_num_points` must be >= 1 or None, got {roi_num_points}.")
316
+ if sw_batch_size < 1:
317
+ raise ValueError(f"`sw_batch_size` must be >= 1, got {sw_batch_size}.")
310
318
  if padding < 0.0:
311
319
  raise ValueError(f"`padding` must be >= 0, got {padding}.")
312
320
 
@@ -343,59 +351,97 @@ def sliding_window_inference(
343
351
  weights_b = torch.zeros(n_b, device=device, dtype=torch.float32)
344
352
  confidence_b = torch.full((n_b,), -1.0, device=device, dtype=torch.float32)
345
353
 
346
- for point_ids, w, bbox in tqdm(
347
- zip(point_groups, weight_groups, bbox_groups),
348
- total=len(point_groups),
354
+ blocks = list(zip(point_groups, weight_groups, bbox_groups))
355
+ for start in tqdm(
356
+ range(0, len(blocks), sw_batch_size),
357
+ total=math.ceil(len(blocks) / sw_batch_size),
349
358
  desc=f"batch {int(b)}",
350
359
  leave=False,
351
360
  disable=not progress,
352
361
  ):
353
- n_block = int(point_ids.numel())
354
- window = index_select_dict(data_b, point_ids, n_b)
355
- window[batch_key] = torch.zeros(n_block, device=device, dtype=torch.long)
356
- window[block_bbox_key] = bbox
357
- if inverse_key is not None:
358
- window.pop(inverse_key, None)
359
- if transform is not None:
360
- window = transform(window)
361
-
362
- n_window = int(window[pos_key].size(0))
363
- inverse_map = window.pop(inverse_key, None) if inverse_key is not None else None
364
-
365
- chunks = split_chunks(n_window, roi_num_points, rng)
366
-
367
- window_preds: Optional[Tensor] = None
368
- for chunk_local in chunks:
369
- sub_window = index_select_dict(window, chunk_local, n_window)
370
- sub_window[batch_key] = torch.zeros(chunk_local.numel(), device=device, dtype=torch.long)
371
- logits = predictor(sub_window)
372
- if window_preds is None:
373
- window_preds = torch.zeros(n_window, int(logits.size(-1)), device=device, dtype=torch.float32)
374
- preds = torch.softmax(logits, dim=-1) if softmax or aggregate != "mean" else logits
375
- window_preds[chunk_local] = preds.to(window_preds)
376
-
377
- if window_preds is None:
362
+ windows: List[Dict[str, Any]] = []
363
+ inverse_maps: List[Optional[Tensor]] = []
364
+ samples: List[Dict[str, Any]] = []
365
+ owners: List[Tuple[int, Tensor]] = []
366
+
367
+ for point_ids, _, bbox in blocks[start : start + sw_batch_size]:
368
+ n_block = int(point_ids.numel())
369
+ window = index_select_dict(data_b, point_ids, n_b)
370
+ window[batch_key] = torch.zeros(n_block, device=device, dtype=torch.long)
371
+ window[block_bbox_key] = bbox
372
+ if inverse_key is not None:
373
+ window.pop(inverse_key, None)
374
+ if transform is not None:
375
+ window = transform(window)
376
+
377
+ n_window = int(window[pos_key].size(0))
378
+ inverse_maps.append(window.pop(inverse_key, None) if inverse_key is not None else None)
379
+ windows.append(window)
380
+
381
+ for chunk_local in split_chunks(n_window, roi_num_points, rng):
382
+ sub_window = index_select_dict(window, chunk_local, n_window)
383
+ samples.append(sub_window)
384
+ owners.append((len(windows) - 1, chunk_local))
385
+
386
+ if not samples:
378
387
  continue
379
388
 
380
- preds_at_block = window_preds if inverse_map is None else window_preds[inverse_map]
381
- if scores_b is None:
382
- scores_b = torch.zeros(n_b, int(window_preds.size(-1)), device=device, dtype=torch.float32)
383
-
384
- if aggregate == "max":
385
- confidence, _ = preds_at_block.max(dim=-1)
386
- better = confidence > confidence_b[point_ids]
387
- scores_b[point_ids[better]] = preds_at_block[better]
388
- confidence_b[point_ids[better]] = confidence[better]
389
- weights_b[point_ids] = 1.0
390
- continue
391
-
392
- if aggregate == "vote":
393
- preds_at_block = torch.nn.functional.one_hot(
394
- preds_at_block.argmax(dim=-1), num_classes=int(preds_at_block.size(-1))
395
- ).to(scores_b.dtype)
396
-
397
- scores_b.index_add_(0, point_ids, preds_at_block * w.unsqueeze(-1))
398
- weights_b.index_add_(0, point_ids, w)
389
+ parts: List[Tensor] = []
390
+ for pack_start in range(0, len(samples), sw_batch_size):
391
+ packed = collate(
392
+ samples[pack_start : pack_start + sw_batch_size],
393
+ batch_from=pos_key,
394
+ batch_key=batch_key,
395
+ )
396
+ logits = predictor(packed)
397
+ parts.append(torch.softmax(logits, dim=-1) if softmax or aggregate != "mean" else logits)
398
+ preds = torch.cat(parts)
399
+
400
+ window_preds: List[Optional[Tensor]] = [None] * len(windows)
401
+ offset = 0
402
+ for (index, chunk_local), sample in zip(owners, samples):
403
+ count = int(sample[pos_key].size(0))
404
+ chunk_preds = preds[offset : offset + count]
405
+ offset += count
406
+ preds_at_window = window_preds[index]
407
+ if preds_at_window is None:
408
+ n_window = int(windows[index][pos_key].size(0))
409
+ preds_at_window = torch.zeros(
410
+ n_window,
411
+ int(chunk_preds.size(-1)),
412
+ device=device,
413
+ dtype=torch.float32,
414
+ )
415
+ window_preds[index] = preds_at_window
416
+ preds_at_window[chunk_local] = chunk_preds.to(preds_at_window)
417
+
418
+ for (point_ids, w, _), block_preds, inverse_map in zip(
419
+ blocks[start : start + sw_batch_size],
420
+ window_preds,
421
+ inverse_maps,
422
+ ):
423
+ if block_preds is None:
424
+ continue
425
+
426
+ preds_at_block = block_preds if inverse_map is None else block_preds[inverse_map]
427
+ if scores_b is None:
428
+ scores_b = torch.zeros(n_b, int(block_preds.size(-1)), device=device, dtype=torch.float32)
429
+
430
+ if aggregate == "max":
431
+ confidence, _ = preds_at_block.max(dim=-1)
432
+ better = confidence > confidence_b[point_ids]
433
+ scores_b[point_ids[better]] = preds_at_block[better]
434
+ confidence_b[point_ids[better]] = confidence[better]
435
+ weights_b[point_ids] = 1.0
436
+ continue
437
+
438
+ if aggregate == "vote":
439
+ preds_at_block = torch.nn.functional.one_hot(
440
+ preds_at_block.argmax(dim=-1), num_classes=int(preds_at_block.size(-1))
441
+ ).to(scores_b.dtype)
442
+
443
+ scores_b.index_add_(0, point_ids, preds_at_block * w.unsqueeze(-1))
444
+ weights_b.index_add_(0, point_ids, w)
399
445
 
400
446
  if scores_b is None:
401
447
  continue
@@ -442,6 +488,7 @@ class SlidingWindowInferer(Inferer):
442
488
  mode: WindowMode = "constant",
443
489
  sigma_scale: float = 0.125,
444
490
  roi_num_points: Optional[int] = None,
491
+ sw_batch_size: int = 1,
445
492
  softmax: bool = True,
446
493
  aggregate: AggregateMode = "mean",
447
494
  transform: Optional[Callable[[Dict[str, Any]], Dict[str, Any]]] = None,
@@ -459,6 +506,7 @@ class SlidingWindowInferer(Inferer):
459
506
  self.mode = mode
460
507
  self.sigma_scale = sigma_scale
461
508
  self.roi_num_points = roi_num_points
509
+ self.sw_batch_size = sw_batch_size
462
510
  self.softmax = softmax
463
511
  self.aggregate = aggregate
464
512
  self.transform = transform
@@ -484,6 +532,7 @@ class SlidingWindowInferer(Inferer):
484
532
  mode=self.mode,
485
533
  sigma_scale=self.sigma_scale,
486
534
  roi_num_points=self.roi_num_points,
535
+ sw_batch_size=self.sw_batch_size,
487
536
  softmax=self.softmax,
488
537
  aggregate=self.aggregate,
489
538
  transform=self.transform,
@@ -25,11 +25,25 @@ class RelativePositionalEncoding(nn.Module):
25
25
  r"""Table-based relative position bias added to the attention logits of a serialized patch.
26
26
 
27
27
  Each axis of the clamped relative grid coordinates indexes its own slice of a shared table, and the three
28
- per-head biases are summed.
28
+ per-head biases are summed. Clamping leaves $\text{rpe\_num}^3$ distinct offsets, so the three rows are
29
+ summed once per *combination* into a lookup table and the bias is a single gather. Summing them per point
30
+ pair instead would hold $(\text{pairs}, 3)$ offsets and $(\text{pairs}, 3, H)$ gathered rows, which on a
31
+ large cloud is the peak allocation of the whole model.
29
32
 
30
33
  Args:
31
34
  patch_size: Number of points attending to each other, setting the clamping boundary.
32
35
  num_heads: Number of attention heads.
36
+
37
+ Shape:
38
+ - Input: $(P, K, 3)$ integer grid coordinates, $K$ points per patch.
39
+ - Output: $(P, H, K, K)$ bias, aligned with the attention logits.
40
+
41
+ Example:
42
+ ```python
43
+ rpe = RelativePositionalEncoding(patch_size=8, num_heads=4)
44
+ bias = rpe(torch.randint(0, 16, (2, 8, 3)))
45
+ bias.shape # (2, 4, 8, 8)
46
+ ```
33
47
  """
34
48
 
35
49
  def __init__(self, patch_size: int, num_heads: int) -> None:
@@ -41,18 +55,24 @@ class RelativePositionalEncoding(nn.Module):
41
55
  self.rpe_table = nn.Parameter(torch.zeros(3 * self.rpe_num, num_heads))
42
56
  nn.init.trunc_normal_(self.rpe_table, std=0.02)
43
57
 
44
- def forward(self, relative_pos: Tensor) -> Tensor:
45
- clamped_pos = relative_pos.clamp(-self.coords_boundary, self.coords_boundary)
46
- positive_indices = clamped_pos + self.coords_boundary
47
- dim_strides = torch.arange(3, device=relative_pos.device) * self.rpe_num
58
+ def _relative_index(self, coord: Tensor) -> Tensor:
59
+ r"""Clamped relative offset of every point pair along one axis. $(P, K) \to (P, K, K)$."""
60
+ relative = coord.unsqueeze(2) - coord.unsqueeze(1)
61
+ return relative.clamp(-self.coords_boundary, self.coords_boundary) + self.coords_boundary
48
62
 
49
- idx = positive_indices + dim_strides
63
+ def forward(self, pos_grid: Tensor) -> Tensor:
64
+ table = self.rpe_table.view(3, self.rpe_num, self.num_heads)
65
+ combined = table[0].view(-1, 1, 1, self.num_heads) + table[1].view(1, -1, 1, self.num_heads)
66
+ combined = combined + table[2].view(1, 1, -1, self.num_heads)
50
67
 
51
- encodings = self.rpe_table.index_select(0, idx.reshape(-1))
52
- encodings = encodings.view(idx.shape + (-1,)).sum(3)
53
- encodings = encodings.permute(0, 3, 1, 2)
68
+ x, y, z = pos_grid.unbind(dim=-1)
69
+ idx = self._relative_index(x) * self.rpe_num + self._relative_index(y)
70
+ idx = idx * self.rpe_num + self._relative_index(z)
54
71
 
55
- return encodings
72
+ encodings = combined.view(-1, self.num_heads).index_select(0, idx.reshape(-1))
73
+ encodings = encodings.view(idx.shape + (self.num_heads,))
74
+
75
+ return encodings.permute(0, 3, 1, 2)
56
76
 
57
77
  def extra_repr(self) -> str:
58
78
  return f"patch_size={self.patch_size}, num_heads={self.num_heads}"
@@ -124,6 +144,7 @@ class SerializedAttention(nn.Module):
124
144
  raise ValueError("Upcasting attention is not supported with Flash Attention.")
125
145
  if upcast_softmax:
126
146
  raise ValueError("Upcasting softmax is not supported with Flash Attention.")
147
+
127
148
  self.channels = channels
128
149
  self.num_heads = num_heads
129
150
  self.patch_size = patch_size
@@ -155,8 +176,13 @@ class SerializedAttention(nn.Module):
155
176
  pad_mode: PadMode = "above" if self.use_flash_attn else "all"
156
177
 
157
178
  padded_indices, unpadded_indices, padded_batch = divisible_pad(
158
- batch, patch_size, mode=pad_mode, pad_fill="replicate", return_inverse=True
179
+ batch,
180
+ patch_size,
181
+ mode=pad_mode,
182
+ pad_fill="replicate",
183
+ return_inverse=True,
159
184
  )
185
+
160
186
  order = serialized_order[padded_indices] if serialized_order is not None else padded_indices
161
187
  inverse = unpadded_indices[serialized_inverse] if serialized_inverse is not None else unpadded_indices
162
188
  qkv = self.qkv(x)[order]
@@ -171,9 +197,11 @@ class SerializedAttention(nn.Module):
171
197
  if self.upcast_attn:
172
198
  q = q.float()
173
199
  k = k.float()
200
+
174
201
  attn = (q * self.scale) @ k.transpose(-2, -1)
175
202
  if self.upcast_softmax:
176
203
  attn = attn.float()
204
+
177
205
  attn = attn.softmax(dim=-1)
178
206
  attn = F.dropout(attn, p=self.attn_drop, training=self.training).to(qkv.dtype)
179
207
  feat = (attn @ v).transpose(1, 2).reshape(-1, C)
@@ -243,8 +271,13 @@ class SerializedAttentionRPE(nn.Module):
243
271
  patch_size = self.patch_size
244
272
 
245
273
  padded_indices, unpadded_indices, _ = divisible_pad(
246
- batch, patch_size, mode="all", pad_fill="replicate", return_inverse=True
274
+ batch,
275
+ patch_size,
276
+ mode="all",
277
+ pad_fill="replicate",
278
+ return_inverse=True,
247
279
  )
280
+
248
281
  order = serialized_order[padded_indices] if serialized_order is not None else padded_indices
249
282
  inverse = unpadded_indices[serialized_inverse] if serialized_inverse is not None else unpadded_indices
250
283
  qkv = self.qkv(x)[order]
@@ -255,14 +288,12 @@ class SerializedAttentionRPE(nn.Module):
255
288
  if self.upcast_attn:
256
289
  q = q.float()
257
290
  k = k.float()
258
- attn = (q * self.scale) @ k.transpose(-2, -1)
259
-
260
- pos_grid_ordered = pos_grid_ordered.reshape(-1, K, 3)
261
- relative_pos = pos_grid_ordered.unsqueeze(2) - pos_grid_ordered.unsqueeze(1)
262
- attn = attn + self.rpe(relative_pos)
263
291
 
292
+ attn = (q * self.scale) @ k.transpose(-2, -1)
293
+ attn = attn + self.rpe(pos_grid_ordered.reshape(-1, K, 3))
264
294
  if self.upcast_softmax:
265
295
  attn = attn.float()
296
+
266
297
  attn = attn.softmax(dim=-1)
267
298
  attn = F.dropout(attn, p=self.attn_drop, training=self.training).to(qkv.dtype)
268
299
  feat = (attn @ v).transpose(1, 2).reshape(-1, C)
@@ -313,6 +344,7 @@ class SerializedAttentionRoPE(nn.Module):
313
344
  raise ValueError("Upcasting attention is not supported with Flash Attention.")
314
345
  if upcast_softmax:
315
346
  raise ValueError("Upcasting softmax is not supported with Flash Attention.")
347
+
316
348
  self.channels = channels
317
349
  self.num_heads = num_heads
318
350
  self.patch_size = patch_size
@@ -344,8 +376,13 @@ class SerializedAttentionRoPE(nn.Module):
344
376
  pad_mode: PadMode = "above" if self.use_flash_attn else "all"
345
377
 
346
378
  padded_indices, unpadded_indices, padded_batch = divisible_pad(
347
- batch, patch_size, mode=pad_mode, pad_fill="replicate", return_inverse=True
379
+ batch,
380
+ patch_size,
381
+ mode=pad_mode,
382
+ pad_fill="replicate",
383
+ return_inverse=True,
348
384
  )
385
+
349
386
  order = serialized_order[padded_indices] if serialized_order is not None else padded_indices
350
387
  inverse = unpadded_indices[serialized_inverse] if serialized_inverse is not None else unpadded_indices
351
388
  qkv = self.qkv(x)[order]
@@ -366,9 +403,11 @@ class SerializedAttentionRoPE(nn.Module):
366
403
  if self.upcast_attn:
367
404
  q = q.float()
368
405
  k = k.float()
406
+
369
407
  attn = (q * self.scale) @ k.transpose(-2, -1)
370
408
  if self.upcast_softmax:
371
409
  attn = attn.float()
410
+
372
411
  attn = attn.softmax(dim=-1)
373
412
  attn = F.dropout(attn, p=self.attn_drop, training=self.training).to(qkv.dtype)
374
413
  feat = (attn @ v).transpose(1, 2).reshape(-1, C)
@@ -87,8 +87,11 @@ class ClassificationModel(nn.Module, metaclass=ABCMeta):
87
87
  def forward_features(self, *args: Any, **kwargs: Any) -> Any:
88
88
  r"""Encode a packed point cloud into features for `forward_head`.
89
89
 
90
- Canonical signature: `forward_features(x, pos, batch)`, returning the encoded features (often with
91
- the downsampled `pos` / `batch`).
90
+ Canonical signature: `forward_features(x, pos, batch, return_intermediates=False)`, returning the encoded
91
+ features (often with the downsampled `pos` / `batch`). With `return_intermediates=True`, the finer encoder
92
+ stages are appended as the last element of the return: a `List[FeaturesDict]` in fine-to-coarse order, each
93
+ entry holding `x`, `batch` and the stage's `pos` or `pos_grid`. Models add the keys their decoder needs or use
94
+ their own container when a stage is not a packed point set (dense tokens, voxel-point pairs).
92
95
  """
93
96
 
94
97
  @abstractmethod
@@ -157,8 +160,11 @@ class SegmentationModel(nn.Module, metaclass=ABCMeta):
157
160
  def forward_features(self, *args: Any, **kwargs: Any) -> Any:
158
161
  r"""Encode a packed point cloud, keeping what `forward_decoder` needs for the skip connections.
159
162
 
160
- Canonical signature: `forward_features(x, pos, batch)`, returning the encoder output together with
161
- the per-stage intermediates.
163
+ Canonical signature: `forward_features(x, pos, batch, return_intermediates=False)`, returning the encoder
164
+ output. With `return_intermediates=True`, the finer encoder stages are appended as the last element of the
165
+ return: a `List[FeaturesDict]` in fine-to-coarse order, each entry holding `x`, `batch` and the stage's `pos`
166
+ or `pos_grid`. Models add the keys their decoder needs (e.g. `pooling_inverse`) or use their own container
167
+ when a stage is not a packed point set (dense tokens, voxel-point pairs).
162
168
  """
163
169
 
164
170
  def forward_decoder(self, *args: Any, **kwargs: Any) -> Any:
@@ -14,7 +14,11 @@ import torch_pointcloud.transforms as T
14
14
  from torch_pointcloud.datasets.scannet import SCANNET20_CLASSES
15
15
  from torch_pointcloud.models._base import SegmentationModel
16
16
  from torch_pointcloud.models._registry import WeightsDict, register_model
17
- from torch_pointcloud.models.point_transformer_v3 import AttentionKind, PointTransformerV3Encoder
17
+ from torch_pointcloud.models.point_transformer_v3 import (
18
+ AttentionKind,
19
+ PointTransformerV3Encoder,
20
+ SerializedFeaturesDict,
21
+ )
18
22
  from torch_pointcloud.utils.data import DataKeys
19
23
  from torch_pointcloud.utils.serialization import SerializationOrder
20
24
  from torch_pointcloud.utils.types import OptTensor
@@ -154,7 +158,7 @@ class ConcertoSegmentation(SegmentationModel):
154
158
  pos_grid: Tensor,
155
159
  batch: Tensor,
156
160
  return_intermediates: Literal[True],
157
- ) -> Tuple[Tensor, Tensor, Tensor, List[Dict[str, Tensor]]]: ...
161
+ ) -> Tuple[Tensor, Tensor, Tensor, List[SerializedFeaturesDict]]: ...
158
162
 
159
163
  @overload
160
164
  def forward_features(
@@ -176,10 +180,10 @@ class ConcertoSegmentation(SegmentationModel):
176
180
  return self.encoder.forward(x, pos_grid, batch, return_intermediates=True)
177
181
  return self.encoder.forward(x, pos_grid, batch, return_intermediates=False)
178
182
 
179
- def forward_decoder(self, x: Tensor, intermediates: List[Dict[str, Tensor]]) -> Tuple[Tensor, Tensor, Tensor]:
183
+ def forward_decoder(self, x: Tensor, intermediates: List[SerializedFeaturesDict]) -> Tuple[Tensor, Tensor, Tensor]:
180
184
  pos_grid = batch = None
181
185
  for intermediate in reversed(intermediates):
182
- inverse = intermediate["inverse"]
186
+ inverse = intermediate["pooling_inverse"]
183
187
  x = torch.cat([intermediate["x"], x[inverse]], dim=-1)
184
188
  pos_grid = intermediate["pos_grid"]
185
189
  batch = intermediate["batch"]
@@ -3,7 +3,7 @@
3
3
  {{ paper("1801.07829") }}
4
4
  """
5
5
 
6
- from typing import Any, Callable, Dict, NamedTuple, Optional, Sequence, Tuple, Union
6
+ from typing import Any, Callable, Dict, Optional, Sequence, Tuple, Union
7
7
 
8
8
  import torch
9
9
  import torch.nn as nn
@@ -26,13 +26,6 @@ from ._base import ClassificationModel, SegmentationModel
26
26
  from ._registry import WeightsDict, register_model
27
27
 
28
28
 
29
- class DGCNNIntermediate(NamedTuple):
30
- """Per-block encoder features and their batch index."""
31
-
32
- x: Tensor
33
- batch: Tensor
34
-
35
-
36
29
  class DGCNNEncoderBlock(nn.Module):
37
30
  """EdgeConv block: rebuilds a $k$-nearest-neighbor graph in feature space and runs an MLP over the edges.
38
31
 
@@ -27,7 +27,7 @@ from torch_pointcloud.utils.conversion import ensure_tuple, ensure_tuple_size
27
27
  from torch_pointcloud.utils.data import DataKeys
28
28
  from torch_pointcloud.utils.geometry import rodrigues_rotation_matrix, spherical_points_gradient, spherical_points_lloyd
29
29
  from torch_pointcloud.utils.imports import _TORCH_CLUSTER_GITHUB_URL, _TORCH_SCATTER_GITHUB_URL, optional_import
30
- from torch_pointcloud.utils.types import OptTensor
30
+ from torch_pointcloud.utils.types import OptTensor, PooledFeaturesDict
31
31
 
32
32
  from ._base import ClassificationModel, SegmentationModel
33
33
  from ._registry import WeightsDict, register_model
@@ -770,7 +770,7 @@ class KPFCNNEncoder(nn.Module):
770
770
  pos: Tensor,
771
771
  batch: Tensor,
772
772
  return_intermediates: Literal[True],
773
- ) -> Tuple[Tensor, Tensor, Tensor, List[Dict[str, Tensor]]]: ...
773
+ ) -> Tuple[Tensor, Tensor, Tensor, List[PooledFeaturesDict]]: ...
774
774
 
775
775
  @overload
776
776
  def forward(
@@ -788,12 +788,12 @@ class KPFCNNEncoder(nn.Module):
788
788
  batch: Tensor,
789
789
  return_intermediates: bool = False,
790
790
  ) -> Any:
791
- intermediates = []
791
+ intermediates: List[PooledFeaturesDict] = []
792
792
  for i, block in enumerate(self.blocks):
793
- intermediate = {"x": x, "pos": pos, "batch": batch}
793
+ intermediate: PooledFeaturesDict = {"x": x, "pos": pos, "batch": batch}
794
794
  x, pos, batch, inv = block(x, pos, batch, return_inverse=True)
795
795
 
796
- if i > 0:
796
+ if return_intermediates and i > 0:
797
797
  intermediate["pooling_inverse"] = inv
798
798
  intermediates.append(intermediate)
799
799
 
@@ -994,7 +994,7 @@ class KPFCNNClassification(ClassificationModel):
994
994
  pos: Tensor,
995
995
  batch: Tensor,
996
996
  return_intermediates: Literal[True],
997
- ) -> Tuple[Tensor, Tensor, Tensor, List[Dict[str, Tensor]]]: ...
997
+ ) -> Tuple[Tensor, Tensor, Tensor, List[PooledFeaturesDict]]: ...
998
998
 
999
999
  @overload
1000
1000
  def forward_features(
@@ -1291,7 +1291,7 @@ class KPFCNNSegmentation(SegmentationModel):
1291
1291
  pos: Tensor,
1292
1292
  batch: Tensor,
1293
1293
  return_intermediates: Literal[True],
1294
- ) -> Tuple[Tensor, Tensor, Tensor, List[Dict[str, Tensor]]]: ...
1294
+ ) -> Tuple[Tensor, Tensor, Tensor, List[PooledFeaturesDict]]: ...
1295
1295
 
1296
1296
  @overload
1297
1297
  def forward_features(
@@ -1331,20 +1331,19 @@ class KPFCNNSegmentation(SegmentationModel):
1331
1331
  else:
1332
1332
  x = self.stem(x)
1333
1333
 
1334
- intermediates = [{"x": x, "pos": pos, "batch": batch}]
1335
- x, pos, batch, encoder_intermediates = self.encoder(x, pos, batch, return_intermediates=True)
1336
- intermediates.extend(encoder_intermediates)
1334
+ if not return_intermediates:
1335
+ return self.encoder(x, pos, batch)
1337
1336
 
1338
- if return_intermediates:
1339
- return x, pos, batch, intermediates
1340
- return x, pos, batch
1337
+ skip: PooledFeaturesDict = {"x": x, "pos": pos, "batch": batch}
1338
+ x, pos, batch, intermediates = self.encoder(x, pos, batch, return_intermediates=True)
1339
+ return x, pos, batch, [skip, *intermediates]
1341
1340
 
1342
1341
  def forward_decoder(
1343
1342
  self,
1344
1343
  x: Tensor,
1345
1344
  pos: Tensor,
1346
1345
  batch: Tensor,
1347
- intermediates: List[Dict[str, Tensor]],
1346
+ intermediates: List[PooledFeaturesDict],
1348
1347
  ) -> Tensor:
1349
1348
  x, _, _ = self.decoder(x, pos, batch, intermediates)
1350
1349
  return x