torch-pointcloud 0.0.1__py3-none-any.whl
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.
- torch_pointcloud/__init__.py +23 -0
- torch_pointcloud/config.py +63 -0
- torch_pointcloud/datasets/__init__.py +18 -0
- torch_pointcloud/datasets/concat.py +161 -0
- torch_pointcloud/datasets/kitti.py +544 -0
- torch_pointcloud/datasets/mix.py +56 -0
- torch_pointcloud/datasets/modelnet.py +679 -0
- torch_pointcloud/datasets/nuscenes.py +849 -0
- torch_pointcloud/datasets/parislille3d.py +177 -0
- torch_pointcloud/datasets/pointcloud.py +78 -0
- torch_pointcloud/datasets/repeat.py +27 -0
- torch_pointcloud/datasets/s3dis.py +886 -0
- torch_pointcloud/datasets/scannet.py +1427 -0
- torch_pointcloud/datasets/scanobjectnn.py +238 -0
- torch_pointcloud/datasets/semantic3d.py +206 -0
- torch_pointcloud/datasets/semantickitti.py +417 -0
- torch_pointcloud/datasets/shapenetpart.py +326 -0
- torch_pointcloud/datasets/sunrgbd.py +487 -0
- torch_pointcloud/datasets/toronto3d.py +207 -0
- torch_pointcloud/datasets/utils.py +334 -0
- torch_pointcloud/inferers/__init__.py +10 -0
- torch_pointcloud/inferers/_utils.py +78 -0
- torch_pointcloud/inferers/inferer.py +88 -0
- torch_pointcloud/inferers/knn_window.py +355 -0
- torch_pointcloud/inferers/part_refinement.py +164 -0
- torch_pointcloud/inferers/potential_sphere.py +287 -0
- torch_pointcloud/inferers/simple.py +41 -0
- torch_pointcloud/inferers/sliding_window.py +498 -0
- torch_pointcloud/inferers/tta.py +221 -0
- torch_pointcloud/inferers/voxel_partition.py +157 -0
- torch_pointcloud/layers/__init__.py +101 -0
- torch_pointcloud/layers/_modules.py +42 -0
- torch_pointcloud/layers/act.py +31 -0
- torch_pointcloud/layers/affine.py +86 -0
- torch_pointcloud/layers/anchors.py +654 -0
- torch_pointcloud/layers/bev_backbone.py +210 -0
- torch_pointcloud/layers/conv2d_blocks.py +69 -0
- torch_pointcloud/layers/conv3d_blocks.py +66 -0
- torch_pointcloud/layers/dropouts.py +74 -0
- torch_pointcloud/layers/fps.py +41 -0
- torch_pointcloud/layers/geometric_affine.py +157 -0
- torch_pointcloud/layers/grid_pool.py +125 -0
- torch_pointcloud/layers/linear_blocks.py +75 -0
- torch_pointcloud/layers/norms.py +81 -0
- torch_pointcloud/layers/octree_attention.py +385 -0
- torch_pointcloud/layers/octree_blocks.py +178 -0
- torch_pointcloud/layers/pdnorm.py +81 -0
- torch_pointcloud/layers/point_patch_embed.py +77 -0
- torch_pointcloud/layers/pointconv.py +168 -0
- torch_pointcloud/layers/pointconv_sa.py +296 -0
- torch_pointcloud/layers/pointnet2_blocks.py +595 -0
- torch_pointcloud/layers/pointnext_blocks.py +400 -0
- torch_pointcloud/layers/pools.py +266 -0
- torch_pointcloud/layers/pvcnn_blocks.py +180 -0
- torch_pointcloud/layers/rope.py +75 -0
- torch_pointcloud/layers/serialized_attention.py +378 -0
- torch_pointcloud/layers/serialized_pool.py +219 -0
- torch_pointcloud/layers/spconv_blocks.py +241 -0
- torch_pointcloud/layers/tnet.py +221 -0
- torch_pointcloud/layers/transformer.py +172 -0
- torch_pointcloud/layers/vfe.py +161 -0
- torch_pointcloud/layers/view.py +27 -0
- torch_pointcloud/layers/xconv.py +164 -0
- torch_pointcloud/lightning/__init__.py +17 -0
- torch_pointcloud/lightning/callbacks.py +200 -0
- torch_pointcloud/lightning/datamodule.py +229 -0
- torch_pointcloud/lightning/metrics.py +445 -0
- torch_pointcloud/lightning/module.py +443 -0
- torch_pointcloud/losses/__init__.py +25 -0
- torch_pointcloud/losses/_utils.py +11 -0
- torch_pointcloud/losses/anchor.py +551 -0
- torch_pointcloud/losses/center.py +494 -0
- torch_pointcloud/losses/chamfer.py +58 -0
- torch_pointcloud/losses/detr3d.py +474 -0
- torch_pointcloud/losses/lovasz.py +76 -0
- torch_pointcloud/losses/pointrcnn.py +356 -0
- torch_pointcloud/losses/sum.py +25 -0
- torch_pointcloud/losses/transfusion.py +295 -0
- torch_pointcloud/losses/votenet.py +264 -0
- torch_pointcloud/models/__init__.py +39 -0
- torch_pointcloud/models/_base.py +249 -0
- torch_pointcloud/models/_registry.py +506 -0
- torch_pointcloud/models/concerto.py +383 -0
- torch_pointcloud/models/detr3d.py +1127 -0
- torch_pointcloud/models/dgcnn.py +929 -0
- torch_pointcloud/models/kpconv.py +1596 -0
- torch_pointcloud/models/lion.py +1368 -0
- torch_pointcloud/models/octformer.py +1267 -0
- torch_pointcloud/models/point_bert.py +1133 -0
- torch_pointcloud/models/point_m2ae.py +1325 -0
- torch_pointcloud/models/point_mae.py +1108 -0
- torch_pointcloud/models/point_mamba.py +1207 -0
- torch_pointcloud/models/point_transformer.py +1119 -0
- torch_pointcloud/models/point_transformer_v2.py +1281 -0
- torch_pointcloud/models/point_transformer_v3.py +1740 -0
- torch_pointcloud/models/pointcnn.py +637 -0
- torch_pointcloud/models/pointconv.py +333 -0
- torch_pointcloud/models/pointgpt.py +875 -0
- torch_pointcloud/models/pointmlp.py +1039 -0
- torch_pointcloud/models/pointnet.py +660 -0
- torch_pointcloud/models/pointnet2.py +1112 -0
- torch_pointcloud/models/pointnext.py +2090 -0
- torch_pointcloud/models/pointpillars.py +610 -0
- torch_pointcloud/models/pointrcnn.py +1111 -0
- torch_pointcloud/models/pvcnn.py +514 -0
- torch_pointcloud/models/pvcnn2.py +913 -0
- torch_pointcloud/models/randlanet.py +997 -0
- torch_pointcloud/models/second.py +658 -0
- torch_pointcloud/models/sonata.py +328 -0
- torch_pointcloud/models/spformer_unet.py +572 -0
- torch_pointcloud/models/sphereformer.py +883 -0
- torch_pointcloud/models/spunet.py +576 -0
- torch_pointcloud/models/spvcnn.py +1213 -0
- torch_pointcloud/models/utonia.py +351 -0
- torch_pointcloud/models/votenet.py +721 -0
- torch_pointcloud/models/voxel_mamba.py +834 -0
- torch_pointcloud/models/voxelnext.py +608 -0
- torch_pointcloud/py.typed +0 -0
- torch_pointcloud/transforms/__init__.py +3 -0
- torch_pointcloud/transforms/functional.py +1674 -0
- torch_pointcloud/transforms/transforms.py +4293 -0
- torch_pointcloud/utils/__init__.py +1 -0
- torch_pointcloud/utils/box3d.py +643 -0
- torch_pointcloud/utils/cluster.py +563 -0
- torch_pointcloud/utils/conversion.py +753 -0
- torch_pointcloud/utils/data.py +229 -0
- torch_pointcloud/utils/diffusion.py +179 -0
- torch_pointcloud/utils/ensemble.py +118 -0
- torch_pointcloud/utils/geometry.py +489 -0
- torch_pointcloud/utils/heatmap.py +277 -0
- torch_pointcloud/utils/hilbert.py +216 -0
- torch_pointcloud/utils/imports.py +334 -0
- torch_pointcloud/utils/io.py +110 -0
- torch_pointcloud/utils/metrics.py +1191 -0
- torch_pointcloud/utils/misc.py +80 -0
- torch_pointcloud/utils/neighbors.py +50 -0
- torch_pointcloud/utils/octree.py +212 -0
- torch_pointcloud/utils/ops.py +457 -0
- torch_pointcloud/utils/optim.py +92 -0
- torch_pointcloud/utils/random.py +63 -0
- torch_pointcloud/utils/serialization.py +110 -0
- torch_pointcloud/utils/state_dict.py +240 -0
- torch_pointcloud/utils/types.py +90 -0
- torch_pointcloud/utils/voxelization.py +274 -0
- torch_pointcloud-0.0.1.dist-info/METADATA +206 -0
- torch_pointcloud-0.0.1.dist-info/RECORD +149 -0
- torch_pointcloud-0.0.1.dist-info/WHEEL +4 -0
- torch_pointcloud-0.0.1.dist-info/licenses/LICENSE +201 -0
- torch_pointcloud-0.0.1.dist-info/licenses/THIRD_PARTY_NOTICES.md +87 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""PyTorch library for 3D point cloud deep learning: models, datasets, transforms, and pretrained weights."""
|
|
2
|
+
|
|
3
|
+
from importlib.metadata import version as _version
|
|
4
|
+
|
|
5
|
+
from . import config, datasets, inferers, layers, losses, models, transforms, utils
|
|
6
|
+
from .models import create_model, list_models, register_model
|
|
7
|
+
|
|
8
|
+
__version__ = _version("torch_pointcloud")
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"__version__",
|
|
12
|
+
"config",
|
|
13
|
+
"create_model",
|
|
14
|
+
"datasets",
|
|
15
|
+
"inferers",
|
|
16
|
+
"layers",
|
|
17
|
+
"list_models",
|
|
18
|
+
"losses",
|
|
19
|
+
"models",
|
|
20
|
+
"register_model",
|
|
21
|
+
"transforms",
|
|
22
|
+
"utils",
|
|
23
|
+
]
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""Environment-variable configuration of cache, model, and data directories and randomness defaults.
|
|
2
|
+
|
|
3
|
+
This module contains the following global variables for configuration:
|
|
4
|
+
|
|
5
|
+
| Variable | Description | Default |
|
|
6
|
+
|----------|-------------|---------|
|
|
7
|
+
| `HOME_DIR` | The home directory of the user. | `Path.home().as_posix()` |
|
|
8
|
+
| `CACHE_DIR` | The cache directory for the package. | `Path(HOME_DIR, ".cache", "torch-pointcloud").as_posix()` |
|
|
9
|
+
| `MODELS_DIR` | The directory for the models. | `Path(CACHE_DIR, "models").as_posix()` |
|
|
10
|
+
| `DATA_DIR` | The directory for the data. | `"data"` |
|
|
11
|
+
| `RANDOM_SEED` | The random seed for the package. | `None` |
|
|
12
|
+
| `FPS_RANDOM_START` | Whether to start the random seed from the current time. | `None` |
|
|
13
|
+
| `KNN_DENSE_BUDGET` | The dense budget for the KNN. | `16_000_000` |
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
import os
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
from typing import Optional
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def asbool(value: Optional[str]) -> Optional[bool]:
|
|
22
|
+
"""Parse an environment variable as a boolean.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
value: The raw variable value, or None when it is unset.
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
True when the value reads as `true`, `1`, `yes` or `y` (case-insensitive), False for anything
|
|
29
|
+
else, and None when the variable is unset.
|
|
30
|
+
"""
|
|
31
|
+
if value is None:
|
|
32
|
+
return None
|
|
33
|
+
|
|
34
|
+
return value.strip().lower() in ["true", "1", "yes", "y"]
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def asint(value: Optional[str]) -> Optional[int]:
|
|
38
|
+
"""Parse an environment variable as an integer.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
value: The raw variable value, or None when it is unset.
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
The parsed integer, or None when the variable is unset or does not parse.
|
|
45
|
+
"""
|
|
46
|
+
if value is None:
|
|
47
|
+
return None
|
|
48
|
+
|
|
49
|
+
try:
|
|
50
|
+
return int(value)
|
|
51
|
+
except ValueError:
|
|
52
|
+
return None
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
HOME_DIR = Path.home().as_posix()
|
|
56
|
+
CACHE_DIR = os.getenv("TORCH_POINTCLOUD_CACHE_DIR", Path(HOME_DIR, ".cache", "torch-pointcloud").as_posix())
|
|
57
|
+
MODELS_DIR = os.getenv("TORCH_POINTCLOUD_MODELS_DIR", Path(CACHE_DIR, "models").as_posix())
|
|
58
|
+
DATA_DIR = os.getenv("TORCH_POINTCLOUD_DATA_DIR", "data")
|
|
59
|
+
|
|
60
|
+
# Some variables to affect how random operations are performed.
|
|
61
|
+
RANDOM_SEED = asint(os.getenv("TORCH_POINTCLOUD_RANDOM_SEED", None))
|
|
62
|
+
FPS_RANDOM_START = asbool(os.getenv("TORCH_POINTCLOUD_FPS_RANDOM_START", None))
|
|
63
|
+
KNN_DENSE_BUDGET = asint(os.getenv("TORCH_POINTCLOUD_KNN_DENSE_BUDGET", None)) or 16_000_000
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Benchmark point cloud datasets with disk caching and download helpers."""
|
|
2
|
+
|
|
3
|
+
from .concat import ConcatDataset, SingleDatasetBatchSampler
|
|
4
|
+
from .kitti import KITTI
|
|
5
|
+
from .mix import MixDataset
|
|
6
|
+
from .modelnet import ModelNet10, ModelNet40, ModelNet40Hdf5, ModelNetNormalResampled
|
|
7
|
+
from .nuscenes import NuScenes, NuScenesMini
|
|
8
|
+
from .parislille3d import ParisLille3D
|
|
9
|
+
from .pointcloud import PointCloudDataset
|
|
10
|
+
from .repeat import RepeatDataset
|
|
11
|
+
from .s3dis import S3DIS, S3DISHdf5
|
|
12
|
+
from .scannet import ScanNet, ScanNet20, ScanNet200
|
|
13
|
+
from .scanobjectnn import ScanObjectNN
|
|
14
|
+
from .semantic3d import Semantic3D
|
|
15
|
+
from .semantickitti import SemanticKITTI
|
|
16
|
+
from .shapenetpart import ShapeNetPart
|
|
17
|
+
from .sunrgbd import SunRGBD
|
|
18
|
+
from .toronto3d import Toronto3D
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"""Concatenate several datasets into one flat index space for multi-dataset joint training."""
|
|
2
|
+
|
|
3
|
+
from bisect import bisect_right
|
|
4
|
+
from typing import Any, Iterator, List, Optional, Sequence
|
|
5
|
+
|
|
6
|
+
import torch
|
|
7
|
+
from torch.utils.data import Dataset, Sampler
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ConcatDataset(Dataset):
|
|
11
|
+
"""Concatenates several datasets into one flat index space.
|
|
12
|
+
|
|
13
|
+
Each child dataset keeps its own `transform`, so datasets from different domains (e.g. ScanNet and
|
|
14
|
+
S3DIS) train jointly while stamping their own condition key and mapping to their native label space.
|
|
15
|
+
Pair it with `SingleDatasetBatchSampler` to keep every batch single-domain so per-dataset
|
|
16
|
+
normalization statistics (BatchNorm, PDNorm) stay clean.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
datasets: The datasets to concatenate, in order. The first is treated as the main dataset by
|
|
20
|
+
`SingleDatasetBatchSampler` (its exhaustion ends the epoch).
|
|
21
|
+
|
|
22
|
+
Example:
|
|
23
|
+
```python
|
|
24
|
+
from torch_pointcloud.datasets import ConcatDataset, S3DIS, ScanNet20
|
|
25
|
+
|
|
26
|
+
dataset = ConcatDataset([ScanNet20(root, split="train"), S3DIS(root, areas=["Area_1"])])
|
|
27
|
+
len(dataset) # len(scannet) + len(s3dis)
|
|
28
|
+
dataset.sizes # [len(scannet), len(s3dis)]
|
|
29
|
+
```
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
def __init__(self, datasets: Sequence[Dataset]) -> None:
|
|
33
|
+
if len(datasets) == 0:
|
|
34
|
+
raise ValueError("ConcatDataset requires at least one dataset.")
|
|
35
|
+
self.datasets = list(datasets)
|
|
36
|
+
self.sizes = [len(d) for d in self.datasets] # type: ignore[arg-type]
|
|
37
|
+
self.cumulative_sizes: List[int] = []
|
|
38
|
+
total = 0
|
|
39
|
+
for size in self.sizes:
|
|
40
|
+
total += size
|
|
41
|
+
self.cumulative_sizes.append(total)
|
|
42
|
+
|
|
43
|
+
def __len__(self) -> int:
|
|
44
|
+
return self.cumulative_sizes[-1]
|
|
45
|
+
|
|
46
|
+
def __getitem__(self, index: int) -> Any:
|
|
47
|
+
if not -len(self) <= index < len(self):
|
|
48
|
+
raise IndexError(f"Index {index} is out of range for a dataset of length {len(self)}.")
|
|
49
|
+
if index < 0:
|
|
50
|
+
index += len(self)
|
|
51
|
+
dataset_index = bisect_right(self.cumulative_sizes, index)
|
|
52
|
+
start = self.cumulative_sizes[dataset_index - 1] if dataset_index > 0 else 0
|
|
53
|
+
return self.datasets[dataset_index][index - start]
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class SingleDatasetBatchSampler(Sampler[List[int]]):
|
|
57
|
+
"""Yields batches whose global indices all come from one dataset of a `ConcatDataset`.
|
|
58
|
+
|
|
59
|
+
Given the per-dataset sizes and one positive integer ratio per dataset, it partitions each dataset's
|
|
60
|
+
indices into batches of `batch_size` and interleaves the datasets round-robin weighted by the ratios.
|
|
61
|
+
Within a round the first dataset yields `ratios[0]` batches, the second `ratios[1]`, and so on. The
|
|
62
|
+
first (main) dataset drives the epoch length: when it
|
|
63
|
+
is exhausted the epoch ends, while the other datasets restart (reshuffled) as needed. Because every
|
|
64
|
+
yielded batch is drawn from a single dataset, per-batch normalization (BatchNorm, PDNorm) sees a
|
|
65
|
+
single domain.
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
sizes: Number of samples in each child dataset, in `ConcatDataset` order.
|
|
69
|
+
ratios: One positive integer sampling weight per dataset, aligned with `sizes`.
|
|
70
|
+
batch_size: Number of indices per batch.
|
|
71
|
+
shuffle: Shuffle each dataset's indices, reshuffling on restart.
|
|
72
|
+
drop_last: Drop each dataset's trailing partial batch.
|
|
73
|
+
generator: Optional `torch.Generator` for shuffling.
|
|
74
|
+
|
|
75
|
+
Shape:
|
|
76
|
+
Each yielded value is a `List[int]` of length `batch_size` (or fewer for a trailing batch when
|
|
77
|
+
`drop_last` is `False`).
|
|
78
|
+
|
|
79
|
+
Example:
|
|
80
|
+
```python
|
|
81
|
+
from torch.utils.data import DataLoader
|
|
82
|
+
|
|
83
|
+
from torch_pointcloud.datasets import ConcatDataset, SingleDatasetBatchSampler
|
|
84
|
+
|
|
85
|
+
dataset = ConcatDataset([scannet, s3dis])
|
|
86
|
+
sampler = SingleDatasetBatchSampler(dataset.sizes, ratios=[2, 1], batch_size=4)
|
|
87
|
+
loader = DataLoader(dataset, batch_sampler=sampler)
|
|
88
|
+
```
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
def __init__(
|
|
92
|
+
self,
|
|
93
|
+
sizes: Sequence[int],
|
|
94
|
+
ratios: Sequence[int],
|
|
95
|
+
batch_size: int,
|
|
96
|
+
shuffle: bool = True,
|
|
97
|
+
drop_last: bool = True,
|
|
98
|
+
generator: Optional[torch.Generator] = None,
|
|
99
|
+
) -> None:
|
|
100
|
+
if len(sizes) != len(ratios):
|
|
101
|
+
raise ValueError(f"sizes and ratios must have the same length, got {len(sizes)} and {len(ratios)}.")
|
|
102
|
+
if any(r <= 0 for r in ratios):
|
|
103
|
+
raise ValueError(f"ratios must be positive integers, got {list(ratios)}.")
|
|
104
|
+
if batch_size <= 0:
|
|
105
|
+
raise ValueError(f"batch_size must be positive, got {batch_size}.")
|
|
106
|
+
|
|
107
|
+
self.sizes = list(sizes)
|
|
108
|
+
self.ratios = list(ratios)
|
|
109
|
+
self.batch_size = batch_size
|
|
110
|
+
self.shuffle = shuffle
|
|
111
|
+
self.drop_last = drop_last
|
|
112
|
+
self.generator = generator
|
|
113
|
+
self.offsets: List[int] = [sum(self.sizes[:i]) for i in range(len(self.sizes))]
|
|
114
|
+
|
|
115
|
+
def _num_batches(self, size: int) -> int:
|
|
116
|
+
if self.drop_last:
|
|
117
|
+
return size // self.batch_size
|
|
118
|
+
return (size + self.batch_size - 1) // self.batch_size
|
|
119
|
+
|
|
120
|
+
def _batches(self, dataset_index: int) -> List[List[int]]:
|
|
121
|
+
size = self.sizes[dataset_index]
|
|
122
|
+
offset = self.offsets[dataset_index]
|
|
123
|
+
if self.shuffle:
|
|
124
|
+
order = torch.randperm(size, generator=self.generator).tolist()
|
|
125
|
+
else:
|
|
126
|
+
order = list(range(size))
|
|
127
|
+
|
|
128
|
+
indices = [offset + i for i in order]
|
|
129
|
+
batches = [indices[start : start + self.batch_size] for start in range(0, size, self.batch_size)]
|
|
130
|
+
|
|
131
|
+
if self.drop_last and batches and len(batches[-1]) < self.batch_size:
|
|
132
|
+
batches.pop()
|
|
133
|
+
return batches
|
|
134
|
+
|
|
135
|
+
def __len__(self) -> int:
|
|
136
|
+
main = self._num_batches(self.sizes[0])
|
|
137
|
+
if main == 0:
|
|
138
|
+
return 0
|
|
139
|
+
|
|
140
|
+
full_rounds, remainder = divmod(main, self.ratios[0])
|
|
141
|
+
per_round = self.ratios[0] + sum(
|
|
142
|
+
self.ratios[i] for i in range(1, len(self.sizes)) if self._num_batches(self.sizes[i]) > 0
|
|
143
|
+
)
|
|
144
|
+
return full_rounds * per_round + remainder
|
|
145
|
+
|
|
146
|
+
def __iter__(self) -> Iterator[List[int]]:
|
|
147
|
+
iterators = [iter(self._batches(i)) for i in range(len(self.sizes))]
|
|
148
|
+
while True:
|
|
149
|
+
for dataset_index, ratio in enumerate(self.ratios):
|
|
150
|
+
for _ in range(ratio):
|
|
151
|
+
batch = next(iterators[dataset_index], None)
|
|
152
|
+
if batch is None:
|
|
153
|
+
if dataset_index == 0:
|
|
154
|
+
return
|
|
155
|
+
|
|
156
|
+
iterators[dataset_index] = iter(self._batches(dataset_index))
|
|
157
|
+
batch = next(iterators[dataset_index], None)
|
|
158
|
+
if batch is None:
|
|
159
|
+
break
|
|
160
|
+
|
|
161
|
+
yield batch
|