r""" Randomly split a dataset into non-overlapping new datasets of given lengths. If a list of fractions that sum up to 1 is given, the lengths will be computed automatically as floor(frac * len(dataset)) for each fraction provided. After computing the lengths, if there are any
(dataset: Dataset[T], lengths: Sequence[Union[int, float]],
generator: Optional[Generator] = default_generator)
| 403 | |
| 404 | |
| 405 | def random_split(dataset: Dataset[T], lengths: Sequence[Union[int, float]], |
| 406 | generator: Optional[Generator] = default_generator) -> List[Subset[T]]: |
| 407 | r""" |
| 408 | Randomly split a dataset into non-overlapping new datasets of given lengths. |
| 409 | |
| 410 | If a list of fractions that sum up to 1 is given, |
| 411 | the lengths will be computed automatically as |
| 412 | floor(frac * len(dataset)) for each fraction provided. |
| 413 | |
| 414 | After computing the lengths, if there are any remainders, 1 count will be |
| 415 | distributed in round-robin fashion to the lengths |
| 416 | until there are no remainders left. |
| 417 | |
| 418 | Optionally fix the generator for reproducible results, e.g.: |
| 419 | |
| 420 | Example: |
| 421 | >>> # xdoctest: +SKIP |
| 422 | >>> generator1 = torch.Generator().manual_seed(42) |
| 423 | >>> generator2 = torch.Generator().manual_seed(42) |
| 424 | >>> random_split(range(10), [3, 7], generator=generator1) |
| 425 | >>> random_split(range(30), [0.3, 0.3, 0.4], generator=generator2) |
| 426 | |
| 427 | Args: |
| 428 | dataset (Dataset): Dataset to be split |
| 429 | lengths (sequence): lengths or fractions of splits to be produced |
| 430 | generator (Generator): Generator used for the random permutation. |
| 431 | """ |
| 432 | if math.isclose(sum(lengths), 1) and sum(lengths) <= 1: |
| 433 | subset_lengths: List[int] = [] |
| 434 | for i, frac in enumerate(lengths): |
| 435 | if frac < 0 or frac > 1: |
| 436 | raise ValueError(f"Fraction at index {i} is not between 0 and 1") |
| 437 | n_items_in_split = int( |
| 438 | math.floor(len(dataset) * frac) # type: ignore[arg-type] |
| 439 | ) |
| 440 | subset_lengths.append(n_items_in_split) |
| 441 | remainder = len(dataset) - sum(subset_lengths) # type: ignore[arg-type] |
| 442 | # add 1 to all the lengths in round-robin fashion until the remainder is 0 |
| 443 | for i in range(remainder): |
| 444 | idx_to_add_at = i % len(subset_lengths) |
| 445 | subset_lengths[idx_to_add_at] += 1 |
| 446 | lengths = subset_lengths |
| 447 | for i, length in enumerate(lengths): |
| 448 | if length == 0: |
| 449 | warnings.warn(f"Length of split at index {i} is 0. " |
| 450 | f"This might result in an empty dataset.") |
| 451 | |
| 452 | # Cannot verify that dataset is Sized |
| 453 | if sum(lengths) != len(dataset): # type: ignore[arg-type] |
| 454 | raise ValueError("Sum of input lengths does not equal the length of the input dataset!") |
| 455 | |
| 456 | indices = randperm(sum(lengths), generator=generator).tolist() # type: ignore[arg-type, call-overload] |
| 457 | return [Subset(dataset, indices[offset - length : offset]) for offset, length in zip(_accumulate(lengths), lengths)] |
searching dependent graphs…