Skip to content

Layoutvae

LayoutVAE Transformers-style package.

LayoutVAEConfig

Bases: PretrainedConfig

Configuration for LayoutVAE.

Parameters:

Name Type Description Default
dataset_name DatasetName | str

Dataset key. The first release supports PubLayNet.

publaynet
num_labels int

Public label vocabulary size.

5
internal_num_labels int

Internal label-set size including the empty label.

6
max_position_embeddings int | None

Maximum number of layout elements.

None
count_latent_dim int

Latent dimension for the count module.

32
bbox_latent_dim int

Latent dimension for the box module.

32
bbox_format BoxFormat | str

Internal box format.

ltwh
bbox_normalized bool

Whether internal boxes are normalized.

True
id2label Id2LabelMapping | None

Optional public ID-to-label mapping.

None
label2id dict[str, int] | None

Optional public label-to-ID mapping.

None
**kwargs str | int | float | bool | None

Extra PretrainedConfig keyword arguments.

{}

Raises:

Type Description
ValueError

If dataset_name is not supported.

Examples:

>>> LayoutVAEConfig().model_type
'layoutvae'
Source code in models/layoutvae/src/layoutvae/configuration_layoutvae.py
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
class LayoutVAEConfig(PretrainedConfig):
    """Configuration for LayoutVAE.

    Args:
        dataset_name: Dataset key. The first release supports PubLayNet.
        num_labels: Public label vocabulary size.
        internal_num_labels: Internal label-set size including the empty label.
        max_position_embeddings: Maximum number of layout elements.
        count_latent_dim: Latent dimension for the count module.
        bbox_latent_dim: Latent dimension for the box module.
        bbox_format: Internal box format.
        bbox_normalized: Whether internal boxes are normalized.
        id2label: Optional public ID-to-label mapping.
        label2id: Optional public label-to-ID mapping.
        **kwargs: Extra `PretrainedConfig` keyword arguments.

    Raises:
        ValueError: If `dataset_name` is not supported.

    Examples:
        >>> LayoutVAEConfig().model_type
        'layoutvae'
    """

    model_type = "layoutvae"

    def __init__(
        self,
        dataset_name: DatasetName | str = DatasetName.publaynet,
        num_labels: int = 5,
        internal_num_labels: int = 6,
        max_position_embeddings: int | None = None,
        count_latent_dim: int = 32,
        bbox_latent_dim: int = 32,
        bbox_format: BoxFormat | str = BoxFormat.ltwh,
        bbox_normalized: bool = True,
        id2label: Id2LabelMapping | None = None,
        label2id: dict[str, int] | None = None,
        **kwargs: str | int | float | bool | None,
    ) -> None:
        """Initialize a LayoutVAE config.

        Args:
            dataset_name: Dataset key. The first release supports PubLayNet.
            num_labels: Public label vocabulary size.
            internal_num_labels: Internal label-set size including the empty label.
            max_position_embeddings: Maximum number of generated elements.
            count_latent_dim: Latent dimension for the count module.
            bbox_latent_dim: Latent dimension for the box module.
            bbox_format: Internal box format.
            bbox_normalized: Whether internal boxes are normalized.
            id2label: Optional public ID-to-label mapping.
            label2id: Optional public label-to-ID mapping.
            **kwargs: Extra `PretrainedConfig` keyword arguments.

        Raises:
            ValueError: If `dataset_name` is not PubLayNet.

        Examples:
            >>> LayoutVAEConfig(dataset_name="publaynet").num_labels
            5
        """
        canonical_dataset = normalize_dataset_name(dataset_name)
        if canonical_dataset is not DatasetName.publaynet:
            raise ValueError("LayoutVAE v1 supports only dataset_name='publaynet'")

        raw_id2label = id2label or id2label_for_dataset(canonical_dataset)
        normalized_id2label = {int(k): v for k, v in raw_id2label.items()}
        normalized_label2id = label2id or label2id_for_dataset(canonical_dataset)
        super().__init__(id2label=normalized_id2label, label2id=normalized_label2id)
        for key, value in kwargs.items():
            setattr(self, key, value)
        self.dataset_name = str(canonical_dataset)
        self.num_labels = num_labels
        self.internal_num_labels = internal_num_labels
        self.max_position_embeddings = (
            max_position_embeddings or max_elements_for_dataset(canonical_dataset)
        )
        self.count_latent_dim = count_latent_dim
        self.bbox_latent_dim = bbox_latent_dim
        self.bbox_format = str(normalize_box_format(bbox_format))
        self.bbox_normalized = bbox_normalized
        self.architectures = ["LayoutVAEModel"]

__init__

__init__(
    dataset_name: DatasetName | str = DatasetName.publaynet,
    num_labels: int = 5,
    internal_num_labels: int = 6,
    max_position_embeddings: int | None = None,
    count_latent_dim: int = 32,
    bbox_latent_dim: int = 32,
    bbox_format: BoxFormat | str = BoxFormat.ltwh,
    bbox_normalized: bool = True,
    id2label: Id2LabelMapping | None = None,
    label2id: dict[str, int] | None = None,
    **kwargs: str | int | float | bool | None,
) -> None

Initialize a LayoutVAE config.

Parameters:

Name Type Description Default
dataset_name DatasetName | str

Dataset key. The first release supports PubLayNet.

publaynet
num_labels int

Public label vocabulary size.

5
internal_num_labels int

Internal label-set size including the empty label.

6
max_position_embeddings int | None

Maximum number of generated elements.

None
count_latent_dim int

Latent dimension for the count module.

32
bbox_latent_dim int

Latent dimension for the box module.

32
bbox_format BoxFormat | str

Internal box format.

ltwh
bbox_normalized bool

Whether internal boxes are normalized.

True
id2label Id2LabelMapping | None

Optional public ID-to-label mapping.

None
label2id dict[str, int] | None

Optional public label-to-ID mapping.

None
**kwargs str | int | float | bool | None

Extra PretrainedConfig keyword arguments.

{}

Raises:

Type Description
ValueError

If dataset_name is not PubLayNet.

Examples:

>>> LayoutVAEConfig(dataset_name="publaynet").num_labels
5
Source code in models/layoutvae/src/layoutvae/configuration_layoutvae.py
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
def __init__(
    self,
    dataset_name: DatasetName | str = DatasetName.publaynet,
    num_labels: int = 5,
    internal_num_labels: int = 6,
    max_position_embeddings: int | None = None,
    count_latent_dim: int = 32,
    bbox_latent_dim: int = 32,
    bbox_format: BoxFormat | str = BoxFormat.ltwh,
    bbox_normalized: bool = True,
    id2label: Id2LabelMapping | None = None,
    label2id: dict[str, int] | None = None,
    **kwargs: str | int | float | bool | None,
) -> None:
    """Initialize a LayoutVAE config.

    Args:
        dataset_name: Dataset key. The first release supports PubLayNet.
        num_labels: Public label vocabulary size.
        internal_num_labels: Internal label-set size including the empty label.
        max_position_embeddings: Maximum number of generated elements.
        count_latent_dim: Latent dimension for the count module.
        bbox_latent_dim: Latent dimension for the box module.
        bbox_format: Internal box format.
        bbox_normalized: Whether internal boxes are normalized.
        id2label: Optional public ID-to-label mapping.
        label2id: Optional public label-to-ID mapping.
        **kwargs: Extra `PretrainedConfig` keyword arguments.

    Raises:
        ValueError: If `dataset_name` is not PubLayNet.

    Examples:
        >>> LayoutVAEConfig(dataset_name="publaynet").num_labels
        5
    """
    canonical_dataset = normalize_dataset_name(dataset_name)
    if canonical_dataset is not DatasetName.publaynet:
        raise ValueError("LayoutVAE v1 supports only dataset_name='publaynet'")

    raw_id2label = id2label or id2label_for_dataset(canonical_dataset)
    normalized_id2label = {int(k): v for k, v in raw_id2label.items()}
    normalized_label2id = label2id or label2id_for_dataset(canonical_dataset)
    super().__init__(id2label=normalized_id2label, label2id=normalized_label2id)
    for key, value in kwargs.items():
        setattr(self, key, value)
    self.dataset_name = str(canonical_dataset)
    self.num_labels = num_labels
    self.internal_num_labels = internal_num_labels
    self.max_position_embeddings = (
        max_position_embeddings or max_elements_for_dataset(canonical_dataset)
    )
    self.count_latent_dim = count_latent_dim
    self.bbox_latent_dim = bbox_latent_dim
    self.bbox_format = str(normalize_box_format(bbox_format))
    self.bbox_normalized = bbox_normalized
    self.architectures = ["LayoutVAEModel"]

LayoutVAEModel

Bases: PreTrainedModel

Transformers-compatible LayoutVAE model.

Parameters:

Name Type Description Default
config LayoutVAEConfig

LayoutVAE configuration.

required

Examples:

>>> model = LayoutVAEModel(LayoutVAEConfig())
>>> model.config.model_type
'layoutvae'
Source code in models/layoutvae/src/layoutvae/modeling_layoutvae.py
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
class LayoutVAEModel(PreTrainedModel):
    """Transformers-compatible LayoutVAE model.

    Args:
        config: LayoutVAE configuration.

    Examples:
        >>> model = LayoutVAEModel(LayoutVAEConfig())
        >>> model.config.model_type
        'layoutvae'
    """

    config_class = LayoutVAEConfig
    base_model_prefix = "layoutvae"
    supports_gradient_checkpointing = False

    def __init__(self, config: LayoutVAEConfig) -> None:
        """Initialize LayoutVAE submodules."""
        super().__init__(config)
        self.countvae = CountVAEModel(
            config.internal_num_labels, config.count_latent_dim
        )
        self.bboxvae = BboxVAEModel(
            config.internal_num_labels,
            4,
            config.max_position_embeddings,
            config.bbox_latent_dim,
        )
        self.post_init()

    def forward(
        self,
        label_set: Float[torch.Tensor, "batch internal_labels"],
        *,
        count_latents: Float[torch.Tensor, "batch internal_labels latent"]
        | None = None,
        bbox_latents: Float[torch.Tensor, "batch elements latent"] | None = None,
        bbox_noise: Float[torch.Tensor, "batch elements 4"] | None = None,
        class_counts: Float[torch.Tensor, "batch internal_labels"] | None = None,
        count_samples: Float[torch.Tensor, "batch internal_labels"] | None = None,
        generator: torch.Generator | None = None,
        return_dict: bool = True,
    ) -> (
        LayoutVAEModelOutput
        | tuple[
            Float[torch.Tensor, "batch elements 4"],
            Float[torch.Tensor, "batch elements 4"],
            Int[torch.Tensor, "batch elements"],
            Bool[torch.Tensor, "batch elements"],
            Float[torch.Tensor, "batch internal_labels"],
            Int[torch.Tensor, "batch elements"],
        ]
    ):
        """Run label-conditioned layout generation.

        Args:
            label_set: Six-way label-set tensor.
            count_latents: Optional fixed count latents.
            bbox_latents: Optional fixed box latents.
            bbox_noise: Optional fixed output noise.
            class_counts: Optional fixed six-way class counts.
            count_samples: Optional fixed count samples.
            generator: Optional PyTorch random generator.
            return_dict: Whether to return a dataclass.

        Returns:
            Model output dataclass or tuple.

        Raises:
            ValueError: If shapes are invalid.

        Examples:
            >>> model = LayoutVAEModel(LayoutVAEConfig())
            >>> label_set = torch.tensor([[0, 1, 0, 0, 0, 1]], dtype=torch.float32)
            >>> out = model(label_set, class_counts=torch.tensor([[7, 1, 0, 0, 0, 1.]]))
            >>> tuple(out.bbox.shape)
            (1, 9, 4)
        """
        label_set = label_set.to(device=self.device, dtype=self.dtype)
        if label_set.ndim != 2 or label_set.shape[1] != self.config.internal_num_labels:
            raise ValueError(
                "label_set must have shape (batch, config.internal_num_labels)"
            )

        if class_counts is None:
            class_counts = self.countvae(
                label_set,
                latents=count_latents,
                count_samples=count_samples,
                generator=generator,
            )
            class_counts = self._normalize_counts(class_counts)
        else:
            class_counts = class_counts.to(
                device=label_set.device, dtype=label_set.dtype
            )
            if class_counts.shape != label_set.shape:
                raise ValueError("class_counts must match label_set shape")

        class_labels = self._labels_from_counts(class_counts)
        raw_ltwh = self.bboxvae(
            class_counts,
            class_labels,
            latents=bbox_latents,
            output_noise=bbox_noise,
            generator=generator,
        )
        internal_ids = torch.argmax(class_labels, dim=2).to(dtype=torch.long)
        labels = torch.clamp(internal_ids - 1, min=0)
        mask = internal_ids != INTERNAL_EMPTY_LABEL_ID
        public_bbox = clamp_boxes(ltwh_to_xywh(raw_ltwh))
        raw_ltwh = torch.where(mask.unsqueeze(-1), raw_ltwh, torch.zeros_like(raw_ltwh))
        public_bbox = torch.where(
            mask.unsqueeze(-1), public_bbox, torch.zeros_like(public_bbox)
        )
        if not return_dict:
            return raw_ltwh, public_bbox, labels, mask, class_counts, internal_ids
        return LayoutVAEModelOutput(
            raw_ltwh=raw_ltwh,
            bbox=public_bbox,
            labels=labels,
            mask=mask,
            class_counts=class_counts,
            label_set=label_set,
            internal_labels=internal_ids,
        )

    def _normalize_counts(
        self,
        class_counts: Float[torch.Tensor, "batch internal_labels"],
    ) -> Float[torch.Tensor, "batch internal_labels"]:
        counts = class_counts.clamp_min(0)
        denom = counts.sum(dim=1, keepdim=True).clamp_min(1)
        counts = torch.floor(self.config.max_position_embeddings * (counts / denom))
        totals = counts.sum(dim=1)
        shortfall = self.config.max_position_embeddings - totals
        counts[:, INTERNAL_EMPTY_LABEL_ID] = counts[
            :, INTERNAL_EMPTY_LABEL_ID
        ] + torch.clamp(shortfall, min=0)
        return counts

    def _labels_from_counts(
        self,
        class_counts: Float[torch.Tensor, "batch internal_labels"],
    ) -> Float[torch.Tensor, "batch elements internal_labels"]:
        labels = torch.zeros(
            (
                class_counts.shape[0],
                self.config.max_position_embeddings,
                self.config.internal_num_labels,
            ),
            device=class_counts.device,
            dtype=class_counts.dtype,
        )
        for batch_index, counts in enumerate(class_counts):
            position = 0
            for class_index in reversed(range(self.config.internal_num_labels)):
                count = int(counts[class_index].item())
                for _ in range(count):
                    if position >= self.config.max_position_embeddings:
                        break
                    labels[batch_index, position, class_index] = 1.0
                    position += 1
        return labels

__init__

__init__(config: LayoutVAEConfig) -> None

Initialize LayoutVAE submodules.

Source code in models/layoutvae/src/layoutvae/modeling_layoutvae.py
410
411
412
413
414
415
416
417
418
419
420
421
422
def __init__(self, config: LayoutVAEConfig) -> None:
    """Initialize LayoutVAE submodules."""
    super().__init__(config)
    self.countvae = CountVAEModel(
        config.internal_num_labels, config.count_latent_dim
    )
    self.bboxvae = BboxVAEModel(
        config.internal_num_labels,
        4,
        config.max_position_embeddings,
        config.bbox_latent_dim,
    )
    self.post_init()

forward

forward(
    label_set: Float[Tensor, "batch internal_labels"],
    *,
    count_latents: Float[
        Tensor, "batch internal_labels latent"
    ]
    | None = None,
    bbox_latents: Float[Tensor, "batch elements latent"]
    | None = None,
    bbox_noise: Float[Tensor, "batch elements 4"]
    | None = None,
    class_counts: Float[Tensor, "batch internal_labels"]
    | None = None,
    count_samples: Float[Tensor, "batch internal_labels"]
    | None = None,
    generator: Generator | None = None,
    return_dict: bool = True,
) -> (
    LayoutVAEModelOutput
    | tuple[
        Float[torch.Tensor, "batch elements 4"],
        Float[torch.Tensor, "batch elements 4"],
        Int[torch.Tensor, "batch elements"],
        Bool[torch.Tensor, "batch elements"],
        Float[torch.Tensor, "batch internal_labels"],
        Int[torch.Tensor, "batch elements"],
    ]
)

Run label-conditioned layout generation.

Parameters:

Name Type Description Default
label_set Float[Tensor, 'batch internal_labels']

Six-way label-set tensor.

required
count_latents Float[Tensor, 'batch internal_labels latent'] | None

Optional fixed count latents.

None
bbox_latents Float[Tensor, 'batch elements latent'] | None

Optional fixed box latents.

None
bbox_noise Float[Tensor, 'batch elements 4'] | None

Optional fixed output noise.

None
class_counts Float[Tensor, 'batch internal_labels'] | None

Optional fixed six-way class counts.

None
count_samples Float[Tensor, 'batch internal_labels'] | None

Optional fixed count samples.

None
generator Generator | None

Optional PyTorch random generator.

None
return_dict bool

Whether to return a dataclass.

True

Returns:

Type Description
LayoutVAEModelOutput | tuple[Float[Tensor, 'batch elements 4'], Float[Tensor, 'batch elements 4'], Int[Tensor, 'batch elements'], Bool[Tensor, 'batch elements'], Float[Tensor, 'batch internal_labels'], Int[Tensor, 'batch elements']]

Model output dataclass or tuple.

Raises:

Type Description
ValueError

If shapes are invalid.

Examples:

>>> model = LayoutVAEModel(LayoutVAEConfig())
>>> label_set = torch.tensor([[0, 1, 0, 0, 0, 1]], dtype=torch.float32)
>>> out = model(label_set, class_counts=torch.tensor([[7, 1, 0, 0, 0, 1.]]))
>>> tuple(out.bbox.shape)
(1, 9, 4)
Source code in models/layoutvae/src/layoutvae/modeling_layoutvae.py
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
def forward(
    self,
    label_set: Float[torch.Tensor, "batch internal_labels"],
    *,
    count_latents: Float[torch.Tensor, "batch internal_labels latent"]
    | None = None,
    bbox_latents: Float[torch.Tensor, "batch elements latent"] | None = None,
    bbox_noise: Float[torch.Tensor, "batch elements 4"] | None = None,
    class_counts: Float[torch.Tensor, "batch internal_labels"] | None = None,
    count_samples: Float[torch.Tensor, "batch internal_labels"] | None = None,
    generator: torch.Generator | None = None,
    return_dict: bool = True,
) -> (
    LayoutVAEModelOutput
    | tuple[
        Float[torch.Tensor, "batch elements 4"],
        Float[torch.Tensor, "batch elements 4"],
        Int[torch.Tensor, "batch elements"],
        Bool[torch.Tensor, "batch elements"],
        Float[torch.Tensor, "batch internal_labels"],
        Int[torch.Tensor, "batch elements"],
    ]
):
    """Run label-conditioned layout generation.

    Args:
        label_set: Six-way label-set tensor.
        count_latents: Optional fixed count latents.
        bbox_latents: Optional fixed box latents.
        bbox_noise: Optional fixed output noise.
        class_counts: Optional fixed six-way class counts.
        count_samples: Optional fixed count samples.
        generator: Optional PyTorch random generator.
        return_dict: Whether to return a dataclass.

    Returns:
        Model output dataclass or tuple.

    Raises:
        ValueError: If shapes are invalid.

    Examples:
        >>> model = LayoutVAEModel(LayoutVAEConfig())
        >>> label_set = torch.tensor([[0, 1, 0, 0, 0, 1]], dtype=torch.float32)
        >>> out = model(label_set, class_counts=torch.tensor([[7, 1, 0, 0, 0, 1.]]))
        >>> tuple(out.bbox.shape)
        (1, 9, 4)
    """
    label_set = label_set.to(device=self.device, dtype=self.dtype)
    if label_set.ndim != 2 or label_set.shape[1] != self.config.internal_num_labels:
        raise ValueError(
            "label_set must have shape (batch, config.internal_num_labels)"
        )

    if class_counts is None:
        class_counts = self.countvae(
            label_set,
            latents=count_latents,
            count_samples=count_samples,
            generator=generator,
        )
        class_counts = self._normalize_counts(class_counts)
    else:
        class_counts = class_counts.to(
            device=label_set.device, dtype=label_set.dtype
        )
        if class_counts.shape != label_set.shape:
            raise ValueError("class_counts must match label_set shape")

    class_labels = self._labels_from_counts(class_counts)
    raw_ltwh = self.bboxvae(
        class_counts,
        class_labels,
        latents=bbox_latents,
        output_noise=bbox_noise,
        generator=generator,
    )
    internal_ids = torch.argmax(class_labels, dim=2).to(dtype=torch.long)
    labels = torch.clamp(internal_ids - 1, min=0)
    mask = internal_ids != INTERNAL_EMPTY_LABEL_ID
    public_bbox = clamp_boxes(ltwh_to_xywh(raw_ltwh))
    raw_ltwh = torch.where(mask.unsqueeze(-1), raw_ltwh, torch.zeros_like(raw_ltwh))
    public_bbox = torch.where(
        mask.unsqueeze(-1), public_bbox, torch.zeros_like(public_bbox)
    )
    if not return_dict:
        return raw_ltwh, public_bbox, labels, mask, class_counts, internal_ids
    return LayoutVAEModelOutput(
        raw_ltwh=raw_ltwh,
        bbox=public_bbox,
        labels=labels,
        mask=mask,
        class_counts=class_counts,
        label_set=label_set,
        internal_labels=internal_ids,
    )

LayoutVAEModelOutput dataclass

Bases: ModelOutput

Raw LayoutVAE model output.

Parameters:

Name Type Description Default
raw_ltwh Float[Tensor, 'batch elements 4']

Internal normalized left-top-width-height boxes.

required
bbox Float[Tensor, 'batch elements 4']

Public normalized center xywh boxes.

cast(Float[Tensor, 'batch elements 4'], None)
labels Int[Tensor, 'batch elements']

Public label IDs.

cast(Int[Tensor, 'batch elements'], None)
mask Bool[Tensor, 'batch elements']

Valid-element mask.

cast(Bool[Tensor, 'batch elements'], None)
class_counts Float[Tensor, 'batch internal_labels']

Six-way class-count tensor.

cast(Float[Tensor, 'batch internal_labels'], None)
label_set Float[Tensor, 'batch internal_labels'] | None

Optional label-set input.

None
internal_labels Int[Tensor, 'batch elements'] | None

Optional six-way generated label IDs.

None

Examples:

>>> output = LayoutVAEModelOutput(
...     raw_ltwh=torch.zeros(1, 1, 4),
...     bbox=torch.zeros(1, 1, 4),
...     labels=torch.zeros(1, 1, dtype=torch.long),
...     mask=torch.ones(1, 1, dtype=torch.bool),
...     class_counts=torch.ones(1, 6),
... )
>>> tuple(output.bbox.shape)
(1, 1, 4)
Source code in models/layoutvae/src/layoutvae/modeling_layoutvae.py
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
@dataclass
class LayoutVAEModelOutput(ModelOutput):
    """Raw LayoutVAE model output.

    Args:
        raw_ltwh: Internal normalized left-top-width-height boxes.
        bbox: Public normalized center `xywh` boxes.
        labels: Public label IDs.
        mask: Valid-element mask.
        class_counts: Six-way class-count tensor.
        label_set: Optional label-set input.
        internal_labels: Optional six-way generated label IDs.

    Examples:
        >>> output = LayoutVAEModelOutput(
        ...     raw_ltwh=torch.zeros(1, 1, 4),
        ...     bbox=torch.zeros(1, 1, 4),
        ...     labels=torch.zeros(1, 1, dtype=torch.long),
        ...     mask=torch.ones(1, 1, dtype=torch.bool),
        ...     class_counts=torch.ones(1, 6),
        ... )
        >>> tuple(output.bbox.shape)
        (1, 1, 4)
    """

    raw_ltwh: Float[torch.Tensor, "batch elements 4"]
    bbox: Float[torch.Tensor, "batch elements 4"] = cast(
        Float[torch.Tensor, "batch elements 4"], None
    )
    labels: Int[torch.Tensor, "batch elements"] = cast(
        Int[torch.Tensor, "batch elements"], None
    )
    mask: Bool[torch.Tensor, "batch elements"] = cast(
        Bool[torch.Tensor, "batch elements"], None
    )
    class_counts: Float[torch.Tensor, "batch internal_labels"] = cast(
        Float[torch.Tensor, "batch internal_labels"], None
    )
    label_set: Float[torch.Tensor, "batch internal_labels"] | None = None
    internal_labels: Int[torch.Tensor, "batch elements"] | None = None

LayoutVAEPipeline

Bases: LayoutGenerationPipeline

Transformers pipeline for LayoutVAE label-conditioned generation.

Parameters:

Name Type Description Default
model LayoutVAEModel

LayoutVAE model instance.

required
processor LayoutVAEProcessor | None

Optional processor for label-set encoding.

None
config LayoutVAEConfig | None

Optional root pipeline config. Defaults to model.config.

None
device int | device | None

Optional torch device.

None
binary_output bool

Reserved compatibility flag.

False

Examples:

>>> model = LayoutVAEModel(LayoutVAEConfig())
>>> pipe = LayoutVAEPipeline(model=model)
>>> pipe.config.model_type
'layoutvae'
Source code in models/layoutvae/src/layoutvae/pipeline_layoutvae.py
179
180
181
182
183
184
185
186
187
188
189
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
274
275
276
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
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
class LayoutVAEPipeline(LayoutGenerationPipeline):
    """Transformers pipeline for LayoutVAE label-conditioned generation.

    Args:
        model: LayoutVAE model instance.
        processor: Optional processor for label-set encoding.
        config: Optional root pipeline config. Defaults to `model.config`.
        device: Optional torch device.
        binary_output: Reserved compatibility flag.

    Examples:
        >>> model = LayoutVAEModel(LayoutVAEConfig())
        >>> pipe = LayoutVAEPipeline(model=model)
        >>> pipe.config.model_type
        'layoutvae'
    """

    config_class: ClassVar[type[PretrainedConfig]] = LayoutVAEConfig
    component_specs: ClassVar[dict[str, PipelineComponentSpec]] = (
        model_processor_component_specs(
            model_loader=_load_model_component,
            processor_loader=_load_processor_component,
        )
    )

    config: LayoutVAEConfig
    model: LayoutVAEModel
    processor: LayoutVAEProcessor

    def __init__(
        self,
        model: LayoutVAEModel,
        processor: LayoutVAEProcessor | None = None,
        config: LayoutVAEConfig | None = None,
        device: int | torch.device | None = None,
        binary_output: bool = False,
    ) -> None:
        """Initialize a LayoutVAE pipeline."""
        _ = binary_output
        super().__init__(config or model.config)
        self.config = config or model.config
        self.model = model
        self.processor = processor or LayoutVAEProcessor(
            dataset_name=model.config.dataset_name,
            id2label=model.config.id2label,
        )
        if device is not None:
            self.to(_resolve_device(device))

    @classmethod
    def _from_pretrained_components(
        cls,
        *,
        config: PretrainedConfig,
        components: Mapping[str, PipelineComponent | None],
    ) -> LayoutVAEPipeline:
        """Build a pipeline from loaded root components."""
        return cls(
            config=cast(LayoutVAEConfig, config),
            model=cast(LayoutVAEModel, components["model"]),
            processor=cast(LayoutVAEProcessor, components["processor"]),
        )

    def _sanitize_parameters(
        self, **kwargs: LayoutVAEParam
    ) -> tuple[
        dict[str, LayoutVAEParam], dict[str, LayoutVAEParam], dict[str, LayoutVAEParam]
    ]:
        return {}, kwargs, {}

    def preprocess(
        self,
        input_: list[list[str | int]]
        | list[str | int]
        | Int[torch.Tensor, ...]
        | None = None,
        **preprocess_parameters: LayoutVAEParam,
    ) -> BatchEncoding:
        """Encode labels into model inputs."""
        labels = preprocess_parameters.pop("labels", input_)
        if labels is None:
            raise ValueError("labels are required for LayoutVAEPipeline")

        encoded = self.processor(
            cast(
                list[list[str | int]] | list[str | int] | Int[torch.Tensor, "..."],
                labels,
            )
        )
        encoded.update(preprocess_parameters)
        return encoded

    def _forward(
        self, model_inputs: dict[str, LayoutVAEParam], **forward_params: LayoutVAEParam
    ) -> LayoutGenerationOutput | LayoutVAEOutputDict:
        del forward_params
        label_set = torch.as_tensor(model_inputs.pop("label_set"), dtype=torch.float32)
        condition_type = cast(
            ConditionType | str, model_inputs.pop("condition_type", ConditionType.label)
        )
        options = _pop_generation_options(model_inputs)
        count_latents = cast(
            Float[torch.Tensor, "batch internal_labels latent"] | None,
            model_inputs.pop("count_latents", None),
        )
        bbox_latents = cast(
            Float[torch.Tensor, "batch elements latent"] | None,
            model_inputs.pop("bbox_latents", None),
        )
        bbox_noise = cast(
            Float[torch.Tensor, "batch elements 4"] | None,
            model_inputs.pop("bbox_noise", None),
        )
        class_counts = cast(
            Float[torch.Tensor, "batch internal_labels"] | None,
            model_inputs.pop("class_counts", None),
        )
        if model_inputs:
            unknown = ", ".join(sorted(model_inputs))
            raise ValueError(f"Unsupported generation kwargs: {unknown}")

        return self._generate(
            label_set=label_set,
            condition_type=condition_type,
            options=options,
            count_latents=count_latents,
            bbox_latents=bbox_latents,
            bbox_noise=bbox_noise,
            class_counts=class_counts,
        )

    def postprocess(
        self,
        model_outputs: LayoutGenerationOutput | LayoutVAEOutputDict,
        **kwargs: str | int | float | bool | None,
    ) -> LayoutGenerationOutput | LayoutVAEOutputDict:
        """Return generated layouts unchanged."""
        del kwargs
        return model_outputs

    @torch.no_grad()
    def __call__(
        self,
        labels: list[list[str | int]]
        | list[str | int]
        | Int[torch.Tensor, ...]
        | None = None,
        *,
        batch_size: int = 1,
        seed: int | None = None,
        generator: torch.Generator | None = None,
        condition_type: ConditionType | str = ConditionType.label,
        bbox: Float[torch.Tensor, "batch elements 4"] | None = None,
        mask: Bool[torch.Tensor, "batch elements"] | None = None,
        num_elements: int | list[int] | Int[torch.Tensor, "batch"] | None = None,
        box_format: BoxFormat | str = BoxFormat.xywh,
        normalized: bool = True,
        canvas_size: tuple[int, int] | None = None,
        num_inference_steps: int | None = None,
        output_type: OutputType | str = OutputType.dataclass,
        return_intermediates: bool = False,
        count_latents: Float[torch.Tensor, "batch internal_labels latent"]
        | None = None,
        bbox_latents: Float[torch.Tensor, "batch elements latent"] | None = None,
        bbox_noise: Float[torch.Tensor, "batch elements 4"] | None = None,
        class_counts: Float[torch.Tensor, "batch internal_labels"] | None = None,
    ) -> LayoutGenerationOutput | LayoutVAEOutputDict:  # ty: ignore[invalid-method-override]
        """Generate PubLayNet layouts from label conditions.

        Args:
            labels: Public PubLayNet label strings or IDs.
            batch_size: Used when `labels` is omitted.
            seed: Optional random seed used when `generator` is absent.
            generator: Optional PyTorch random generator. Takes precedence.
            condition_type: Condition type or alias. Only `label` is supported.
            bbox: Reserved compatibility argument.
            mask: Reserved compatibility argument.
            num_elements: Reserved compatibility argument.
            box_format: Reserved compatibility argument.
            normalized: Reserved compatibility argument.
            canvas_size: Reserved compatibility argument.
            num_inference_steps: Reserved compatibility argument.
            output_type: Return format.
            return_intermediates: Whether to include raw generation tensors.
            count_latents: Optional fixed count latents.
            bbox_latents: Optional fixed box latents.
            bbox_noise: Optional fixed box output noise.
            class_counts: Optional fixed class counts.

        Returns:
            Layout generation output.

        Raises:
            ValueError: If labels are missing or condition options are unsupported.

        Examples:
            >>> pipe = LayoutVAEPipeline(LayoutVAEModel(LayoutVAEConfig()))
            >>> out = pipe(labels=["text"], class_counts=torch.tensor([[8, 1, 0, 0, 0, 0.]]))
            >>> tuple(out.bbox.shape)
            (1, 9, 4)
        """
        if labels is None:
            if batch_size < 1:
                raise ValueError("batch_size must be positive")

            labels = [["text"] for _ in range(batch_size)]
        encoded = self.processor(labels)

        option_kwargs: GenerationOptionsKwargs = {}
        option_kwargs["bbox"] = bbox
        option_kwargs["mask"] = mask
        option_kwargs["num_elements"] = num_elements
        option_kwargs["box_format"] = box_format
        option_kwargs["normalized"] = normalized
        option_kwargs["canvas_size"] = canvas_size
        option_kwargs["seed"] = seed
        option_kwargs["generator"] = generator
        option_kwargs["num_inference_steps"] = num_inference_steps
        option_kwargs["output_type"] = output_type
        option_kwargs["return_intermediates"] = return_intermediates

        options = _make_generation_options(option_kwargs)

        return self._generate(
            label_set=cast(
                Float[torch.Tensor, "batch internal_labels"], encoded["label_set"]
            ),
            condition_type=condition_type,
            options=options,
            count_latents=count_latents,
            bbox_latents=bbox_latents,
            bbox_noise=bbox_noise,
            class_counts=class_counts,
        )

    def _generate(
        self,
        *,
        label_set: Float[torch.Tensor, "batch internal_labels"],
        condition_type: ConditionType | str,
        options: GenerationOptions,
        count_latents: Float[torch.Tensor, "batch internal_labels latent"] | None,
        bbox_latents: Float[torch.Tensor, "batch elements latent"] | None,
        bbox_noise: Float[torch.Tensor, "batch elements 4"] | None,
        class_counts: Float[torch.Tensor, "batch internal_labels"] | None,
    ) -> LayoutGenerationOutput | LayoutVAEOutputDict:
        _ = (
            options.bbox,
            options.labels,
            options.mask,
            options.num_elements,
            options.normalized,
            options.canvas_size,
            options.num_inference_steps,
        )
        normalize_box_format(options.box_format)
        canonical = normalize_condition_type(condition_type)
        if canonical is not ConditionType.label:
            raise ValueError(f"Unsupported condition_type for layoutvae: {canonical}")

        device = next(self.model.parameters()).device
        prepared_generator = self.prepare_generator(
            generator=options.generator,
            seed=options.seed,
            device=device,
        )
        out = self.model(
            label_set.to(device=device),
            count_latents=count_latents,
            bbox_latents=bbox_latents,
            bbox_noise=bbox_noise,
            class_counts=class_counts,
            generator=prepared_generator,
            return_dict=True,
        )
        assert isinstance(out, LayoutVAEModelOutput)
        intermediates = None
        if options.return_intermediates:
            intermediates = {
                "condition_type": canonical,
                "raw_ltwh": out.raw_ltwh.detach().cpu(),
                "internal_labels": out.internal_labels.detach().cpu()
                if out.internal_labels is not None
                else None,
                "class_counts": out.class_counts.detach().cpu(),
            }
        layout = LayoutGenerationOutput(
            bbox=out.bbox.detach().cpu(),
            labels=out.labels.detach().cpu(),
            mask=out.mask.detach().cpu(),
            id2label={
                int(k): v for k, v in cast(Id2Label, self.config.id2label).items()
            },
            intermediates=intermediates,
        )
        resolved_output_type = normalize_output_type(options.output_type)
        if resolved_output_type is OutputType.dict:
            return dict(layout)
        if resolved_output_type is OutputType.dataclass:
            return layout
        assert_never(resolved_output_type)

__init__

__init__(
    model: LayoutVAEModel,
    processor: LayoutVAEProcessor | None = None,
    config: LayoutVAEConfig | None = None,
    device: int | device | None = None,
    binary_output: bool = False,
) -> None

Initialize a LayoutVAE pipeline.

Source code in models/layoutvae/src/layoutvae/pipeline_layoutvae.py
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
def __init__(
    self,
    model: LayoutVAEModel,
    processor: LayoutVAEProcessor | None = None,
    config: LayoutVAEConfig | None = None,
    device: int | torch.device | None = None,
    binary_output: bool = False,
) -> None:
    """Initialize a LayoutVAE pipeline."""
    _ = binary_output
    super().__init__(config or model.config)
    self.config = config or model.config
    self.model = model
    self.processor = processor or LayoutVAEProcessor(
        dataset_name=model.config.dataset_name,
        id2label=model.config.id2label,
    )
    if device is not None:
        self.to(_resolve_device(device))

preprocess

preprocess(
    input_: list[list[str | int]]
    | list[str | int]
    | Int[Tensor, ...]
    | None = None,
    **preprocess_parameters: LayoutVAEParam,
) -> BatchEncoding

Encode labels into model inputs.

Source code in models/layoutvae/src/layoutvae/pipeline_layoutvae.py
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
def preprocess(
    self,
    input_: list[list[str | int]]
    | list[str | int]
    | Int[torch.Tensor, ...]
    | None = None,
    **preprocess_parameters: LayoutVAEParam,
) -> BatchEncoding:
    """Encode labels into model inputs."""
    labels = preprocess_parameters.pop("labels", input_)
    if labels is None:
        raise ValueError("labels are required for LayoutVAEPipeline")

    encoded = self.processor(
        cast(
            list[list[str | int]] | list[str | int] | Int[torch.Tensor, "..."],
            labels,
        )
    )
    encoded.update(preprocess_parameters)
    return encoded

postprocess

postprocess(
    model_outputs: LayoutGenerationOutput
    | LayoutVAEOutputDict,
    **kwargs: str | int | float | bool | None,
) -> LayoutGenerationOutput | LayoutVAEOutputDict

Return generated layouts unchanged.

Source code in models/layoutvae/src/layoutvae/pipeline_layoutvae.py
310
311
312
313
314
315
316
317
def postprocess(
    self,
    model_outputs: LayoutGenerationOutput | LayoutVAEOutputDict,
    **kwargs: str | int | float | bool | None,
) -> LayoutGenerationOutput | LayoutVAEOutputDict:
    """Return generated layouts unchanged."""
    del kwargs
    return model_outputs

__call__

__call__(
    labels: list[list[str | int]]
    | list[str | int]
    | Int[Tensor, ...]
    | None = None,
    *,
    batch_size: int = 1,
    seed: int | None = None,
    generator: Generator | None = None,
    condition_type: ConditionType
    | str = ConditionType.label,
    bbox: Float[Tensor, "batch elements 4"] | None = None,
    mask: Bool[Tensor, "batch elements"] | None = None,
    num_elements: int
    | list[int]
    | Int[Tensor, "batch"]
    | None = None,
    box_format: BoxFormat | str = BoxFormat.xywh,
    normalized: bool = True,
    canvas_size: tuple[int, int] | None = None,
    num_inference_steps: int | None = None,
    output_type: OutputType | str = OutputType.dataclass,
    return_intermediates: bool = False,
    count_latents: Float[
        Tensor, "batch internal_labels latent"
    ]
    | None = None,
    bbox_latents: Float[Tensor, "batch elements latent"]
    | None = None,
    bbox_noise: Float[Tensor, "batch elements 4"]
    | None = None,
    class_counts: Float[Tensor, "batch internal_labels"]
    | None = None,
) -> LayoutGenerationOutput | LayoutVAEOutputDict

Generate PubLayNet layouts from label conditions.

Parameters:

Name Type Description Default
labels list[list[str | int]] | list[str | int] | Int[Tensor, ...] | None

Public PubLayNet label strings or IDs.

None
batch_size int

Used when labels is omitted.

1
seed int | None

Optional random seed used when generator is absent.

None
generator Generator | None

Optional PyTorch random generator. Takes precedence.

None
condition_type ConditionType | str

Condition type or alias. Only label is supported.

label
bbox Float[Tensor, 'batch elements 4'] | None

Reserved compatibility argument.

None
mask Bool[Tensor, 'batch elements'] | None

Reserved compatibility argument.

None
num_elements int | list[int] | Int[Tensor, 'batch'] | None

Reserved compatibility argument.

None
box_format BoxFormat | str

Reserved compatibility argument.

xywh
normalized bool

Reserved compatibility argument.

True
canvas_size tuple[int, int] | None

Reserved compatibility argument.

None
num_inference_steps int | None

Reserved compatibility argument.

None
output_type OutputType | str

Return format.

dataclass
return_intermediates bool

Whether to include raw generation tensors.

False
count_latents Float[Tensor, 'batch internal_labels latent'] | None

Optional fixed count latents.

None
bbox_latents Float[Tensor, 'batch elements latent'] | None

Optional fixed box latents.

None
bbox_noise Float[Tensor, 'batch elements 4'] | None

Optional fixed box output noise.

None
class_counts Float[Tensor, 'batch internal_labels'] | None

Optional fixed class counts.

None

Returns:

Type Description
LayoutGenerationOutput | LayoutVAEOutputDict

Layout generation output.

Raises:

Type Description
ValueError

If labels are missing or condition options are unsupported.

Examples:

>>> pipe = LayoutVAEPipeline(LayoutVAEModel(LayoutVAEConfig()))
>>> out = pipe(labels=["text"], class_counts=torch.tensor([[8, 1, 0, 0, 0, 0.]]))
>>> tuple(out.bbox.shape)
(1, 9, 4)
Source code in models/layoutvae/src/layoutvae/pipeline_layoutvae.py
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
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
@torch.no_grad()
def __call__(
    self,
    labels: list[list[str | int]]
    | list[str | int]
    | Int[torch.Tensor, ...]
    | None = None,
    *,
    batch_size: int = 1,
    seed: int | None = None,
    generator: torch.Generator | None = None,
    condition_type: ConditionType | str = ConditionType.label,
    bbox: Float[torch.Tensor, "batch elements 4"] | None = None,
    mask: Bool[torch.Tensor, "batch elements"] | None = None,
    num_elements: int | list[int] | Int[torch.Tensor, "batch"] | None = None,
    box_format: BoxFormat | str = BoxFormat.xywh,
    normalized: bool = True,
    canvas_size: tuple[int, int] | None = None,
    num_inference_steps: int | None = None,
    output_type: OutputType | str = OutputType.dataclass,
    return_intermediates: bool = False,
    count_latents: Float[torch.Tensor, "batch internal_labels latent"]
    | None = None,
    bbox_latents: Float[torch.Tensor, "batch elements latent"] | None = None,
    bbox_noise: Float[torch.Tensor, "batch elements 4"] | None = None,
    class_counts: Float[torch.Tensor, "batch internal_labels"] | None = None,
) -> LayoutGenerationOutput | LayoutVAEOutputDict:  # ty: ignore[invalid-method-override]
    """Generate PubLayNet layouts from label conditions.

    Args:
        labels: Public PubLayNet label strings or IDs.
        batch_size: Used when `labels` is omitted.
        seed: Optional random seed used when `generator` is absent.
        generator: Optional PyTorch random generator. Takes precedence.
        condition_type: Condition type or alias. Only `label` is supported.
        bbox: Reserved compatibility argument.
        mask: Reserved compatibility argument.
        num_elements: Reserved compatibility argument.
        box_format: Reserved compatibility argument.
        normalized: Reserved compatibility argument.
        canvas_size: Reserved compatibility argument.
        num_inference_steps: Reserved compatibility argument.
        output_type: Return format.
        return_intermediates: Whether to include raw generation tensors.
        count_latents: Optional fixed count latents.
        bbox_latents: Optional fixed box latents.
        bbox_noise: Optional fixed box output noise.
        class_counts: Optional fixed class counts.

    Returns:
        Layout generation output.

    Raises:
        ValueError: If labels are missing or condition options are unsupported.

    Examples:
        >>> pipe = LayoutVAEPipeline(LayoutVAEModel(LayoutVAEConfig()))
        >>> out = pipe(labels=["text"], class_counts=torch.tensor([[8, 1, 0, 0, 0, 0.]]))
        >>> tuple(out.bbox.shape)
        (1, 9, 4)
    """
    if labels is None:
        if batch_size < 1:
            raise ValueError("batch_size must be positive")

        labels = [["text"] for _ in range(batch_size)]
    encoded = self.processor(labels)

    option_kwargs: GenerationOptionsKwargs = {}
    option_kwargs["bbox"] = bbox
    option_kwargs["mask"] = mask
    option_kwargs["num_elements"] = num_elements
    option_kwargs["box_format"] = box_format
    option_kwargs["normalized"] = normalized
    option_kwargs["canvas_size"] = canvas_size
    option_kwargs["seed"] = seed
    option_kwargs["generator"] = generator
    option_kwargs["num_inference_steps"] = num_inference_steps
    option_kwargs["output_type"] = output_type
    option_kwargs["return_intermediates"] = return_intermediates

    options = _make_generation_options(option_kwargs)

    return self._generate(
        label_set=cast(
            Float[torch.Tensor, "batch internal_labels"], encoded["label_set"]
        ),
        condition_type=condition_type,
        options=options,
        count_latents=count_latents,
        bbox_latents=bbox_latents,
        bbox_noise=bbox_noise,
        class_counts=class_counts,
    )

LayoutVAEProcessor

Bases: ProcessorMixin

Encode PubLayNet labels into LayoutVAE label sets.

Parameters:

Name Type Description Default
dataset_name DatasetName | str

Dataset key. The first release supports PubLayNet.

publaynet
id2label Id2LabelMapping | None

Optional public ID-to-label mapping.

None

Raises:

Type Description
ValueError

If the dataset is unsupported.

Examples:

>>> processor = LayoutVAEProcessor()
>>> processor.label2id["text"]
0
Source code in models/layoutvae/src/layoutvae/processing_layoutvae.py
 28
 29
 30
 31
 32
 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
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
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
class LayoutVAEProcessor(ProcessorMixin):
    """Encode PubLayNet labels into LayoutVAE label sets.

    Args:
        dataset_name: Dataset key. The first release supports PubLayNet.
        id2label: Optional public ID-to-label mapping.

    Raises:
        ValueError: If the dataset is unsupported.

    Examples:
        >>> processor = LayoutVAEProcessor()
        >>> processor.label2id["text"]
        0
    """

    config_name = "preprocessor_config.json"

    def __init__(
        self,
        dataset_name: DatasetName | str = DatasetName.publaynet,
        id2label: Id2LabelMapping | None = None,
    ) -> None:
        """Initialize the processor.

        Args:
            dataset_name: Dataset key. The first release supports PubLayNet.
            id2label: Optional public ID-to-label mapping.

        Raises:
            ValueError: If the dataset is unsupported.

        Examples:
            >>> LayoutVAEProcessor("publaynet").id2label[4]
            'figure'
        """
        self.chat_template = None
        canonical_dataset = normalize_dataset_name(dataset_name)
        if canonical_dataset is not DatasetName.publaynet:
            raise ValueError("LayoutVAEProcessor supports only PubLayNet")

        self.dataset_name = str(canonical_dataset)
        raw_id2label = id2label or id2label_for_dataset(canonical_dataset)
        self.id2label = {int(k): v for k, v in raw_id2label.items()}
        self.label2id = label2id_for_dataset(canonical_dataset)
        self.internal_id2label = {
            INTERNAL_EMPTY_LABEL_ID: "None",
            **{index + 1: label for index, label in self.id2label.items()},
        }

    def __call__(
        self,
        labels: list[list[str | int]] | list[str | int] | Int[torch.Tensor, "..."],
        *,
        return_tensors: Literal["pt"] = "pt",
    ) -> BatchEncoding:
        """Encode public labels as a six-way label-set tensor.

        Args:
            labels: Public label names or IDs. A flat list is treated as one row.
            return_tensors: Tensor framework. Only `pt` is supported.

        Returns:
            Batch encoding with `label_set`.

        Raises:
            ValueError: If labels are empty, unknown, or tensors are unsupported.

        Examples:
            >>> encoded = LayoutVAEProcessor()(["text", "figure"])
            >>> encoded["label_set"].tolist()
            [[0.0, 1.0, 0.0, 0.0, 0.0, 1.0]]
        """
        if return_tensors != "pt":
            raise ValueError("LayoutVAEProcessor only supports return_tensors='pt'")

        rows = self._normalize_rows(labels)
        label_set = torch.zeros(
            len(rows), len(self.internal_id2label), dtype=torch.float32
        )
        for row_index, row in enumerate(rows):
            for label in row:
                public_id = self._label_to_id(label)
                label_set[row_index, public_id + 1] = 1.0
        return BatchEncoding({"label_set": label_set})

    def public_from_internal(
        self,
        internal_labels: Int[torch.Tensor, "batch elements"],
    ) -> tuple[
        Int[torch.Tensor, "batch elements"], Bool[torch.Tensor, "batch elements"]
    ]:
        """Map six-way labels to public labels and validity masks.

        Args:
            internal_labels: Internal label IDs where zero marks empty slots.

        Returns:
            Public label IDs and mask tensors.

        Examples:
            >>> processor = LayoutVAEProcessor()
            >>> labels, mask = processor.public_from_internal(torch.tensor([[0, 1, 5]]))
            >>> labels.tolist(), mask.tolist()
            ([[0, 0, 4]], [[False, True, True]])
        """
        labels = torch.clamp(internal_labels.to(dtype=torch.long) - 1, min=0)
        mask = internal_labels.to(dtype=torch.long) != INTERNAL_EMPTY_LABEL_ID
        return labels, mask

    def batch_decode(
        self,
        bbox: Float[torch.Tensor, "batch elements 4"],
        labels: Int[torch.Tensor, "batch elements"],
        mask: Bool[torch.Tensor, "batch elements"] | None = None,
    ) -> list[list[DecodedLayoutRecord]]:
        """Decode layout tensors into records.

        Args:
            bbox: Public normalized center `xywh` boxes.
            labels: Public label IDs.
            mask: Optional valid-element mask.

        Returns:
            Nested records with label text, label ID, and box coordinates.

        Raises:
            KeyError: If a public label ID is unknown.

        Examples:
            >>> records = LayoutVAEProcessor().batch_decode(
            ...     torch.zeros(1, 1, 4), torch.tensor([[0]])
            ... )
            >>> records[0][0]["label"]
            'text'
        """
        bbox_t = torch.as_tensor(bbox, dtype=torch.float32)
        labels_t = torch.as_tensor(labels, dtype=torch.long)
        labels_t, bbox_t = self._ensure_batched(labels_t, bbox_t)
        mask_t = self._prepare_mask(mask, labels_t.shape)
        records: list[list[DecodedLayoutRecord]] = []
        for boxes, ids, valid in zip(bbox_t, labels_t, mask_t, strict=True):
            row: list[DecodedLayoutRecord] = []
            for box, label_id in zip(boxes[valid], ids[valid], strict=True):
                idx = int(label_id.item())
                row.append(
                    {
                        "label": self.id2label[idx],
                        "label_id": idx,
                        "bbox": box.tolist(),
                    }
                )
            records.append(row)
        return records

    def _ensure_batched(
        self, labels: Int[torch.Tensor, "..."], bbox: Float[torch.Tensor, "... 4"]
    ) -> tuple[
        Int[torch.Tensor, "batch elements"], Float[torch.Tensor, "batch elements 4"]
    ]:
        if labels.ndim != 1:
            return labels, bbox
        return labels.unsqueeze(0), bbox.unsqueeze(0)

    def _prepare_mask(
        self,
        mask: Bool[torch.Tensor, "batch elements"] | None,
        shape: torch.Size,
    ) -> Bool[torch.Tensor, "batch elements"]:
        if mask is None:
            return torch.ones(shape, dtype=torch.bool)
        mask_t = torch.as_tensor(mask, dtype=torch.bool)
        return mask_t.unsqueeze(0) if mask_t.ndim == 1 else mask_t

    def _normalize_rows(
        self,
        labels: list[list[str | int]] | list[str | int] | Int[torch.Tensor, "..."],
    ) -> list[list[str | int]]:
        if isinstance(labels, torch.Tensor):
            if labels.ndim == 0 or labels.ndim > 2:
                raise ValueError("labels tensor must have one or two dimensions")

            if labels.ndim == 1:
                return [[int(value) for value in labels.tolist()]]
            return [[int(value) for value in row] for row in labels.tolist()]
        if not labels:
            raise ValueError("labels must not be empty")

        contains_rows = [isinstance(item, list) for item in labels]
        if any(contains_rows) and not all(contains_rows):
            raise ValueError("labels must be a flat list or list of rows")

        if all(contains_rows):
            return [list(row) for row in cast(list[list[str | int]], labels)]
        return [list(cast(list[str | int], labels))]

    def _label_to_id(self, label: str | int) -> int:
        if not isinstance(label, int):
            if label in self.label2id:
                return self.label2id[label]
            raise ValueError(f"Unknown label: {label}")

        if 0 <= label < len(self.id2label):
            return label
        raise ValueError(f"Unknown label id: {label}")

__init__

__init__(
    dataset_name: DatasetName | str = DatasetName.publaynet,
    id2label: Id2LabelMapping | None = None,
) -> None

Initialize the processor.

Parameters:

Name Type Description Default
dataset_name DatasetName | str

Dataset key. The first release supports PubLayNet.

publaynet
id2label Id2LabelMapping | None

Optional public ID-to-label mapping.

None

Raises:

Type Description
ValueError

If the dataset is unsupported.

Examples:

>>> LayoutVAEProcessor("publaynet").id2label[4]
'figure'
Source code in models/layoutvae/src/layoutvae/processing_layoutvae.py
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
def __init__(
    self,
    dataset_name: DatasetName | str = DatasetName.publaynet,
    id2label: Id2LabelMapping | None = None,
) -> None:
    """Initialize the processor.

    Args:
        dataset_name: Dataset key. The first release supports PubLayNet.
        id2label: Optional public ID-to-label mapping.

    Raises:
        ValueError: If the dataset is unsupported.

    Examples:
        >>> LayoutVAEProcessor("publaynet").id2label[4]
        'figure'
    """
    self.chat_template = None
    canonical_dataset = normalize_dataset_name(dataset_name)
    if canonical_dataset is not DatasetName.publaynet:
        raise ValueError("LayoutVAEProcessor supports only PubLayNet")

    self.dataset_name = str(canonical_dataset)
    raw_id2label = id2label or id2label_for_dataset(canonical_dataset)
    self.id2label = {int(k): v for k, v in raw_id2label.items()}
    self.label2id = label2id_for_dataset(canonical_dataset)
    self.internal_id2label = {
        INTERNAL_EMPTY_LABEL_ID: "None",
        **{index + 1: label for index, label in self.id2label.items()},
    }

__call__

__call__(
    labels: list[list[str | int]]
    | list[str | int]
    | Int[Tensor, "..."],
    *,
    return_tensors: Literal["pt"] = "pt",
) -> BatchEncoding

Encode public labels as a six-way label-set tensor.

Parameters:

Name Type Description Default
labels list[list[str | int]] | list[str | int] | Int[Tensor, '...']

Public label names or IDs. A flat list is treated as one row.

required
return_tensors Literal['pt']

Tensor framework. Only pt is supported.

'pt'

Returns:

Type Description
BatchEncoding

Batch encoding with label_set.

Raises:

Type Description
ValueError

If labels are empty, unknown, or tensors are unsupported.

Examples:

>>> encoded = LayoutVAEProcessor()(["text", "figure"])
>>> encoded["label_set"].tolist()
[[0.0, 1.0, 0.0, 0.0, 0.0, 1.0]]
Source code in models/layoutvae/src/layoutvae/processing_layoutvae.py
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
def __call__(
    self,
    labels: list[list[str | int]] | list[str | int] | Int[torch.Tensor, "..."],
    *,
    return_tensors: Literal["pt"] = "pt",
) -> BatchEncoding:
    """Encode public labels as a six-way label-set tensor.

    Args:
        labels: Public label names or IDs. A flat list is treated as one row.
        return_tensors: Tensor framework. Only `pt` is supported.

    Returns:
        Batch encoding with `label_set`.

    Raises:
        ValueError: If labels are empty, unknown, or tensors are unsupported.

    Examples:
        >>> encoded = LayoutVAEProcessor()(["text", "figure"])
        >>> encoded["label_set"].tolist()
        [[0.0, 1.0, 0.0, 0.0, 0.0, 1.0]]
    """
    if return_tensors != "pt":
        raise ValueError("LayoutVAEProcessor only supports return_tensors='pt'")

    rows = self._normalize_rows(labels)
    label_set = torch.zeros(
        len(rows), len(self.internal_id2label), dtype=torch.float32
    )
    for row_index, row in enumerate(rows):
        for label in row:
            public_id = self._label_to_id(label)
            label_set[row_index, public_id + 1] = 1.0
    return BatchEncoding({"label_set": label_set})

public_from_internal

public_from_internal(
    internal_labels: Int[Tensor, "batch elements"],
) -> tuple[
    Int[torch.Tensor, "batch elements"],
    Bool[torch.Tensor, "batch elements"],
]

Map six-way labels to public labels and validity masks.

Parameters:

Name Type Description Default
internal_labels Int[Tensor, 'batch elements']

Internal label IDs where zero marks empty slots.

required

Returns:

Type Description
tuple[Int[Tensor, 'batch elements'], Bool[Tensor, 'batch elements']]

Public label IDs and mask tensors.

Examples:

>>> processor = LayoutVAEProcessor()
>>> labels, mask = processor.public_from_internal(torch.tensor([[0, 1, 5]]))
>>> labels.tolist(), mask.tolist()
([[0, 0, 4]], [[False, True, True]])
Source code in models/layoutvae/src/layoutvae/processing_layoutvae.py
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
def public_from_internal(
    self,
    internal_labels: Int[torch.Tensor, "batch elements"],
) -> tuple[
    Int[torch.Tensor, "batch elements"], Bool[torch.Tensor, "batch elements"]
]:
    """Map six-way labels to public labels and validity masks.

    Args:
        internal_labels: Internal label IDs where zero marks empty slots.

    Returns:
        Public label IDs and mask tensors.

    Examples:
        >>> processor = LayoutVAEProcessor()
        >>> labels, mask = processor.public_from_internal(torch.tensor([[0, 1, 5]]))
        >>> labels.tolist(), mask.tolist()
        ([[0, 0, 4]], [[False, True, True]])
    """
    labels = torch.clamp(internal_labels.to(dtype=torch.long) - 1, min=0)
    mask = internal_labels.to(dtype=torch.long) != INTERNAL_EMPTY_LABEL_ID
    return labels, mask

batch_decode

batch_decode(
    bbox: Float[Tensor, "batch elements 4"],
    labels: Int[Tensor, "batch elements"],
    mask: Bool[Tensor, "batch elements"] | None = None,
) -> list[list[DecodedLayoutRecord]]

Decode layout tensors into records.

Parameters:

Name Type Description Default
bbox Float[Tensor, 'batch elements 4']

Public normalized center xywh boxes.

required
labels Int[Tensor, 'batch elements']

Public label IDs.

required
mask Bool[Tensor, 'batch elements'] | None

Optional valid-element mask.

None

Returns:

Type Description
list[list[DecodedLayoutRecord]]

Nested records with label text, label ID, and box coordinates.

Raises:

Type Description
KeyError

If a public label ID is unknown.

Examples:

>>> records = LayoutVAEProcessor().batch_decode(
...     torch.zeros(1, 1, 4), torch.tensor([[0]])
... )
>>> records[0][0]["label"]
'text'
Source code in models/layoutvae/src/layoutvae/processing_layoutvae.py
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
def batch_decode(
    self,
    bbox: Float[torch.Tensor, "batch elements 4"],
    labels: Int[torch.Tensor, "batch elements"],
    mask: Bool[torch.Tensor, "batch elements"] | None = None,
) -> list[list[DecodedLayoutRecord]]:
    """Decode layout tensors into records.

    Args:
        bbox: Public normalized center `xywh` boxes.
        labels: Public label IDs.
        mask: Optional valid-element mask.

    Returns:
        Nested records with label text, label ID, and box coordinates.

    Raises:
        KeyError: If a public label ID is unknown.

    Examples:
        >>> records = LayoutVAEProcessor().batch_decode(
        ...     torch.zeros(1, 1, 4), torch.tensor([[0]])
        ... )
        >>> records[0][0]["label"]
        'text'
    """
    bbox_t = torch.as_tensor(bbox, dtype=torch.float32)
    labels_t = torch.as_tensor(labels, dtype=torch.long)
    labels_t, bbox_t = self._ensure_batched(labels_t, bbox_t)
    mask_t = self._prepare_mask(mask, labels_t.shape)
    records: list[list[DecodedLayoutRecord]] = []
    for boxes, ids, valid in zip(bbox_t, labels_t, mask_t, strict=True):
        row: list[DecodedLayoutRecord] = []
        for box, label_id in zip(boxes[valid], ids[valid], strict=True):
            idx = int(label_id.item())
            row.append(
                {
                    "label": self.id2label[idx],
                    "label_id": idx,
                    "bbox": box.tolist(),
                }
            )
        records.append(row)
    return records

configuration_layoutvae

Configuration objects for LayoutVAE checkpoints.

LayoutVAEConfig

Bases: PretrainedConfig

Configuration for LayoutVAE.

Parameters:

Name Type Description Default
dataset_name DatasetName | str

Dataset key. The first release supports PubLayNet.

publaynet
num_labels int

Public label vocabulary size.

5
internal_num_labels int

Internal label-set size including the empty label.

6
max_position_embeddings int | None

Maximum number of layout elements.

None
count_latent_dim int

Latent dimension for the count module.

32
bbox_latent_dim int

Latent dimension for the box module.

32
bbox_format BoxFormat | str

Internal box format.

ltwh
bbox_normalized bool

Whether internal boxes are normalized.

True
id2label Id2LabelMapping | None

Optional public ID-to-label mapping.

None
label2id dict[str, int] | None

Optional public label-to-ID mapping.

None
**kwargs str | int | float | bool | None

Extra PretrainedConfig keyword arguments.

{}

Raises:

Type Description
ValueError

If dataset_name is not supported.

Examples:

>>> LayoutVAEConfig().model_type
'layoutvae'
Source code in models/layoutvae/src/layoutvae/configuration_layoutvae.py
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
class LayoutVAEConfig(PretrainedConfig):
    """Configuration for LayoutVAE.

    Args:
        dataset_name: Dataset key. The first release supports PubLayNet.
        num_labels: Public label vocabulary size.
        internal_num_labels: Internal label-set size including the empty label.
        max_position_embeddings: Maximum number of layout elements.
        count_latent_dim: Latent dimension for the count module.
        bbox_latent_dim: Latent dimension for the box module.
        bbox_format: Internal box format.
        bbox_normalized: Whether internal boxes are normalized.
        id2label: Optional public ID-to-label mapping.
        label2id: Optional public label-to-ID mapping.
        **kwargs: Extra `PretrainedConfig` keyword arguments.

    Raises:
        ValueError: If `dataset_name` is not supported.

    Examples:
        >>> LayoutVAEConfig().model_type
        'layoutvae'
    """

    model_type = "layoutvae"

    def __init__(
        self,
        dataset_name: DatasetName | str = DatasetName.publaynet,
        num_labels: int = 5,
        internal_num_labels: int = 6,
        max_position_embeddings: int | None = None,
        count_latent_dim: int = 32,
        bbox_latent_dim: int = 32,
        bbox_format: BoxFormat | str = BoxFormat.ltwh,
        bbox_normalized: bool = True,
        id2label: Id2LabelMapping | None = None,
        label2id: dict[str, int] | None = None,
        **kwargs: str | int | float | bool | None,
    ) -> None:
        """Initialize a LayoutVAE config.

        Args:
            dataset_name: Dataset key. The first release supports PubLayNet.
            num_labels: Public label vocabulary size.
            internal_num_labels: Internal label-set size including the empty label.
            max_position_embeddings: Maximum number of generated elements.
            count_latent_dim: Latent dimension for the count module.
            bbox_latent_dim: Latent dimension for the box module.
            bbox_format: Internal box format.
            bbox_normalized: Whether internal boxes are normalized.
            id2label: Optional public ID-to-label mapping.
            label2id: Optional public label-to-ID mapping.
            **kwargs: Extra `PretrainedConfig` keyword arguments.

        Raises:
            ValueError: If `dataset_name` is not PubLayNet.

        Examples:
            >>> LayoutVAEConfig(dataset_name="publaynet").num_labels
            5
        """
        canonical_dataset = normalize_dataset_name(dataset_name)
        if canonical_dataset is not DatasetName.publaynet:
            raise ValueError("LayoutVAE v1 supports only dataset_name='publaynet'")

        raw_id2label = id2label or id2label_for_dataset(canonical_dataset)
        normalized_id2label = {int(k): v for k, v in raw_id2label.items()}
        normalized_label2id = label2id or label2id_for_dataset(canonical_dataset)
        super().__init__(id2label=normalized_id2label, label2id=normalized_label2id)
        for key, value in kwargs.items():
            setattr(self, key, value)
        self.dataset_name = str(canonical_dataset)
        self.num_labels = num_labels
        self.internal_num_labels = internal_num_labels
        self.max_position_embeddings = (
            max_position_embeddings or max_elements_for_dataset(canonical_dataset)
        )
        self.count_latent_dim = count_latent_dim
        self.bbox_latent_dim = bbox_latent_dim
        self.bbox_format = str(normalize_box_format(bbox_format))
        self.bbox_normalized = bbox_normalized
        self.architectures = ["LayoutVAEModel"]

__init__

__init__(
    dataset_name: DatasetName | str = DatasetName.publaynet,
    num_labels: int = 5,
    internal_num_labels: int = 6,
    max_position_embeddings: int | None = None,
    count_latent_dim: int = 32,
    bbox_latent_dim: int = 32,
    bbox_format: BoxFormat | str = BoxFormat.ltwh,
    bbox_normalized: bool = True,
    id2label: Id2LabelMapping | None = None,
    label2id: dict[str, int] | None = None,
    **kwargs: str | int | float | bool | None,
) -> None

Initialize a LayoutVAE config.

Parameters:

Name Type Description Default
dataset_name DatasetName | str

Dataset key. The first release supports PubLayNet.

publaynet
num_labels int

Public label vocabulary size.

5
internal_num_labels int

Internal label-set size including the empty label.

6
max_position_embeddings int | None

Maximum number of generated elements.

None
count_latent_dim int

Latent dimension for the count module.

32
bbox_latent_dim int

Latent dimension for the box module.

32
bbox_format BoxFormat | str

Internal box format.

ltwh
bbox_normalized bool

Whether internal boxes are normalized.

True
id2label Id2LabelMapping | None

Optional public ID-to-label mapping.

None
label2id dict[str, int] | None

Optional public label-to-ID mapping.

None
**kwargs str | int | float | bool | None

Extra PretrainedConfig keyword arguments.

{}

Raises:

Type Description
ValueError

If dataset_name is not PubLayNet.

Examples:

>>> LayoutVAEConfig(dataset_name="publaynet").num_labels
5
Source code in models/layoutvae/src/layoutvae/configuration_layoutvae.py
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
def __init__(
    self,
    dataset_name: DatasetName | str = DatasetName.publaynet,
    num_labels: int = 5,
    internal_num_labels: int = 6,
    max_position_embeddings: int | None = None,
    count_latent_dim: int = 32,
    bbox_latent_dim: int = 32,
    bbox_format: BoxFormat | str = BoxFormat.ltwh,
    bbox_normalized: bool = True,
    id2label: Id2LabelMapping | None = None,
    label2id: dict[str, int] | None = None,
    **kwargs: str | int | float | bool | None,
) -> None:
    """Initialize a LayoutVAE config.

    Args:
        dataset_name: Dataset key. The first release supports PubLayNet.
        num_labels: Public label vocabulary size.
        internal_num_labels: Internal label-set size including the empty label.
        max_position_embeddings: Maximum number of generated elements.
        count_latent_dim: Latent dimension for the count module.
        bbox_latent_dim: Latent dimension for the box module.
        bbox_format: Internal box format.
        bbox_normalized: Whether internal boxes are normalized.
        id2label: Optional public ID-to-label mapping.
        label2id: Optional public label-to-ID mapping.
        **kwargs: Extra `PretrainedConfig` keyword arguments.

    Raises:
        ValueError: If `dataset_name` is not PubLayNet.

    Examples:
        >>> LayoutVAEConfig(dataset_name="publaynet").num_labels
        5
    """
    canonical_dataset = normalize_dataset_name(dataset_name)
    if canonical_dataset is not DatasetName.publaynet:
        raise ValueError("LayoutVAE v1 supports only dataset_name='publaynet'")

    raw_id2label = id2label or id2label_for_dataset(canonical_dataset)
    normalized_id2label = {int(k): v for k, v in raw_id2label.items()}
    normalized_label2id = label2id or label2id_for_dataset(canonical_dataset)
    super().__init__(id2label=normalized_id2label, label2id=normalized_label2id)
    for key, value in kwargs.items():
        setattr(self, key, value)
    self.dataset_name = str(canonical_dataset)
    self.num_labels = num_labels
    self.internal_num_labels = internal_num_labels
    self.max_position_embeddings = (
        max_position_embeddings or max_elements_for_dataset(canonical_dataset)
    )
    self.count_latent_dim = count_latent_dim
    self.bbox_latent_dim = bbox_latent_dim
    self.bbox_format = str(normalize_box_format(bbox_format))
    self.bbox_normalized = bbox_normalized
    self.architectures = ["LayoutVAEModel"]

conversion

Conversion helpers for LayoutVAE checkpoint artifacts.

load_original_state_dicts

load_original_state_dicts(
    source_root: str | Path,
) -> tuple[
    dict[str, Shaped[torch.Tensor, "..."]],
    dict[str, Shaped[torch.Tensor, "..."]],
]

Load original checkpoint state dictionaries through a pickle shim.

Source code in models/layoutvae/src/layoutvae/conversion.py
23
24
25
26
27
28
29
30
31
def load_original_state_dicts(
    source_root: str | Path,
) -> tuple[
    dict[str, Shaped[torch.Tensor, "..."]],
    dict[str, Shaped[torch.Tensor, "..."]],
]:
    """Load original checkpoint state dictionaries through a pickle shim."""
    count, bbox = load_original_modules(source_root)
    return count.state_dict(), bbox.state_dict()

load_original_modules

load_original_modules(
    source_root: str | Path,
) -> tuple[torch.nn.Module, torch.nn.Module]

Load original checkpoint modules through a pickle shim.

Source code in models/layoutvae/src/layoutvae/conversion.py
34
35
36
37
38
39
40
41
42
43
def load_original_modules(
    source_root: str | Path,
) -> tuple[torch.nn.Module, torch.nn.Module]:
    """Load original checkpoint modules through a pickle shim."""
    root = Path(source_root)
    trained = root / "TrainedModel"
    source_dir = root / "Source"
    count = _load_pickled_module(trained / "countvae.h5", source_dir)
    bbox = _load_pickled_module(trained / "bboxvae.h5", source_dir)
    return count, bbox

build_default_config

build_default_config() -> LayoutVAEConfig

Return the fixed PubLayNet LayoutVAE configuration.

Returns:

Type Description
LayoutVAEConfig

PubLayNet LayoutVAE configuration.

Examples:

>>> build_default_config().dataset_name
'publaynet'
Source code in models/layoutvae/src/layoutvae/conversion.py
86
87
88
89
90
91
92
93
94
95
96
def build_default_config() -> LayoutVAEConfig:
    """Return the fixed PubLayNet LayoutVAE configuration.

    Returns:
        PubLayNet LayoutVAE configuration.

    Examples:
        >>> build_default_config().dataset_name
        'publaynet'
    """
    return LayoutVAEConfig()

convert_state_dicts

convert_state_dicts(
    *,
    count_state_dict: dict[str, Shaped[Tensor, "..."]],
    bbox_state_dict: dict[str, Shaped[Tensor, "..."]],
    output_dir: str | Path,
) -> Path

Convert count and box state dictionaries into HF files.

Parameters:

Name Type Description Default
count_state_dict dict[str, Shaped[Tensor, '...']]

State dictionary for LayoutVAEModel.countvae.

required
bbox_state_dict dict[str, Shaped[Tensor, '...']]

State dictionary for LayoutVAEModel.bboxvae.

required
output_dir str | Path

Directory where converted files are written.

required

Returns:

Type Description
Path

The output directory.

Raises:

Type Description
RuntimeError

If a state dictionary is incompatible.

ValueError

If output filenames would violate the HF artifact contract.

Source code in models/layoutvae/src/layoutvae/conversion.py
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
def convert_state_dicts(
    *,
    count_state_dict: dict[str, Shaped[torch.Tensor, "..."]],
    bbox_state_dict: dict[str, Shaped[torch.Tensor, "..."]],
    output_dir: str | Path,
) -> Path:
    """Convert count and box state dictionaries into HF files.

    Args:
        count_state_dict: State dictionary for `LayoutVAEModel.countvae`.
        bbox_state_dict: State dictionary for `LayoutVAEModel.bboxvae`.
        output_dir: Directory where converted files are written.

    Returns:
        The output directory.

    Raises:
        RuntimeError: If a state dictionary is incompatible.
        ValueError: If output filenames would violate the HF artifact contract.
    """
    target = Path(output_dir)
    if any((target / name).exists() for name in DISALLOWED_OUTPUT_NAMES):
        raise ValueError("output_dir contains non-HF checkpoint filenames")

    config = build_default_config()
    model = LayoutVAEModel(config)
    model.countvae.load_state_dict(count_state_dict, strict=True)
    model.bboxvae.load_state_dict(bbox_state_dict, strict=True)
    model.save_pretrained(target, safe_serialization=True)
    LayoutVAEProcessor(
        dataset_name=config.dataset_name,
        id2label=config.id2label,
    ).save_pretrained(str(target))
    processor_config = target / "processor_config.json"
    preprocessor_config = target / "preprocessor_config.json"
    if processor_config.exists():
        shutil.copyfile(processor_config, preprocessor_config)
    return target

model_card

Model-card helpers for LayoutVAE.

write_layoutvae_model_card

write_layoutvae_model_card(output_dir: str | Path) -> Path

Write a minimal Hub README for converted LayoutVAE artifacts.

Parameters:

Name Type Description Default
output_dir str | Path

Target checkpoint directory.

required

Returns:

Type Description
Path

Path to the written README.

Examples:

>>> import tempfile
>>> path = write_layoutvae_model_card(tempfile.mkdtemp())
>>> path.name
'README.md'
Source code in models/layoutvae/src/layoutvae/model_card.py
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
def write_layoutvae_model_card(output_dir: str | Path) -> Path:
    """Write a minimal Hub README for converted LayoutVAE artifacts.

    Args:
        output_dir: Target checkpoint directory.

    Returns:
        Path to the written README.

    Examples:
        >>> import tempfile
        >>> path = write_layoutvae_model_card(tempfile.mkdtemp())
        >>> path.name
        'README.md'
    """
    path = Path(output_dir) / "README.md"
    text = """---
license: mit
library_name: transformers
pipeline_tag: other
tags:
  - layout-generation
datasets:
  - creative-graphic-design/PubLayNet
---

# Model Card for LayoutVAE PubLayNet

LayoutVAE generates document layouts from PubLayNet label sets.
"""
    path.write_text(text, encoding="utf-8")
    return path

modeling_layoutvae

PyTorch model classes for LayoutVAE.

OutputType

Bases: StrEnum

Supported generation output formats.

Source code in models/layoutvae/src/layoutvae/modeling_layoutvae.py
23
24
25
26
27
class OutputType(StrEnum):
    """Supported generation output formats."""

    dataclass = auto()
    dict = auto()

LayoutVAEModelOutput dataclass

Bases: ModelOutput

Raw LayoutVAE model output.

Parameters:

Name Type Description Default
raw_ltwh Float[Tensor, 'batch elements 4']

Internal normalized left-top-width-height boxes.

required
bbox Float[Tensor, 'batch elements 4']

Public normalized center xywh boxes.

cast(Float[Tensor, 'batch elements 4'], None)
labels Int[Tensor, 'batch elements']

Public label IDs.

cast(Int[Tensor, 'batch elements'], None)
mask Bool[Tensor, 'batch elements']

Valid-element mask.

cast(Bool[Tensor, 'batch elements'], None)
class_counts Float[Tensor, 'batch internal_labels']

Six-way class-count tensor.

cast(Float[Tensor, 'batch internal_labels'], None)
label_set Float[Tensor, 'batch internal_labels'] | None

Optional label-set input.

None
internal_labels Int[Tensor, 'batch elements'] | None

Optional six-way generated label IDs.

None

Examples:

>>> output = LayoutVAEModelOutput(
...     raw_ltwh=torch.zeros(1, 1, 4),
...     bbox=torch.zeros(1, 1, 4),
...     labels=torch.zeros(1, 1, dtype=torch.long),
...     mask=torch.ones(1, 1, dtype=torch.bool),
...     class_counts=torch.ones(1, 6),
... )
>>> tuple(output.bbox.shape)
(1, 1, 4)
Source code in models/layoutvae/src/layoutvae/modeling_layoutvae.py
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
@dataclass
class LayoutVAEModelOutput(ModelOutput):
    """Raw LayoutVAE model output.

    Args:
        raw_ltwh: Internal normalized left-top-width-height boxes.
        bbox: Public normalized center `xywh` boxes.
        labels: Public label IDs.
        mask: Valid-element mask.
        class_counts: Six-way class-count tensor.
        label_set: Optional label-set input.
        internal_labels: Optional six-way generated label IDs.

    Examples:
        >>> output = LayoutVAEModelOutput(
        ...     raw_ltwh=torch.zeros(1, 1, 4),
        ...     bbox=torch.zeros(1, 1, 4),
        ...     labels=torch.zeros(1, 1, dtype=torch.long),
        ...     mask=torch.ones(1, 1, dtype=torch.bool),
        ...     class_counts=torch.ones(1, 6),
        ... )
        >>> tuple(output.bbox.shape)
        (1, 1, 4)
    """

    raw_ltwh: Float[torch.Tensor, "batch elements 4"]
    bbox: Float[torch.Tensor, "batch elements 4"] = cast(
        Float[torch.Tensor, "batch elements 4"], None
    )
    labels: Int[torch.Tensor, "batch elements"] = cast(
        Int[torch.Tensor, "batch elements"], None
    )
    mask: Bool[torch.Tensor, "batch elements"] = cast(
        Bool[torch.Tensor, "batch elements"], None
    )
    class_counts: Float[torch.Tensor, "batch internal_labels"] = cast(
        Float[torch.Tensor, "batch internal_labels"], None
    )
    label_set: Float[torch.Tensor, "batch internal_labels"] | None = None
    internal_labels: Int[torch.Tensor, "batch elements"] | None = None

FCBlock

Bases: Module

Two-layer fully connected block used by the encoders.

Source code in models/layoutvae/src/layoutvae/modeling_layoutvae.py
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
class FCBlock(nn.Module):
    """Two-layer fully connected block used by the encoders."""

    def __init__(self, n_class: int) -> None:
        """Initialize the block.

        Args:
            n_class: Input dimension.
        """
        super().__init__()
        self.seq = nn.Sequential(
            nn.Linear(n_class, 128),
            nn.ReLU(),
            nn.Linear(128, 128),
            nn.ReLU(),
        )

    def forward(
        self, inputs: Float[torch.Tensor, "batch features"]
    ) -> Float[torch.Tensor, "batch 128"]:
        """Run the block."""
        return self.seq(inputs)

__init__

__init__(n_class: int) -> None

Initialize the block.

Parameters:

Name Type Description Default
n_class int

Input dimension.

required
Source code in models/layoutvae/src/layoutvae/modeling_layoutvae.py
 98
 99
100
101
102
103
104
105
106
107
108
109
110
def __init__(self, n_class: int) -> None:
    """Initialize the block.

    Args:
        n_class: Input dimension.
    """
    super().__init__()
    self.seq = nn.Sequential(
        nn.Linear(n_class, 128),
        nn.ReLU(),
        nn.Linear(128, 128),
        nn.ReLU(),
    )

forward

forward(
    inputs: Float[Tensor, "batch features"],
) -> Float[torch.Tensor, "batch 128"]

Run the block.

Source code in models/layoutvae/src/layoutvae/modeling_layoutvae.py
112
113
114
115
116
def forward(
    self, inputs: Float[torch.Tensor, "batch features"]
) -> Float[torch.Tensor, "batch 128"]:
    """Run the block."""
    return self.seq(inputs)

Embeder

Bases: Module

Count module embedding network.

Source code in models/layoutvae/src/layoutvae/modeling_layoutvae.py
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
class Embeder(nn.Module):
    """Count module embedding network."""

    def __init__(self, n_class: int) -> None:
        """Initialize the embedding network."""
        super().__init__()
        self.fcb1 = FCBlock(n_class)
        self.fcb2 = FCBlock(n_class)
        self.fcb3 = FCBlock(n_class)
        self.fc = nn.Linear(128 * 3, 128)

    def forward(
        self,
        inputs: tuple[
            Float[torch.Tensor, "batch internal_labels"],
            Float[torch.Tensor, "batch internal_labels"],
            Float[torch.Tensor, "batch internal_labels"],
        ],
    ) -> Float[torch.Tensor, "batch 128"]:
        """Embed label-set, current-label, and previous-count tensors."""
        in1, in2, in3 = inputs
        return self.fc(torch.cat((self.fcb1(in1), self.fcb2(in2), self.fcb3(in3)), 1))

__init__

__init__(n_class: int) -> None

Initialize the embedding network.

Source code in models/layoutvae/src/layoutvae/modeling_layoutvae.py
122
123
124
125
126
127
128
def __init__(self, n_class: int) -> None:
    """Initialize the embedding network."""
    super().__init__()
    self.fcb1 = FCBlock(n_class)
    self.fcb2 = FCBlock(n_class)
    self.fcb3 = FCBlock(n_class)
    self.fc = nn.Linear(128 * 3, 128)

forward

forward(
    inputs: tuple[
        Float[Tensor, "batch internal_labels"],
        Float[Tensor, "batch internal_labels"],
        Float[Tensor, "batch internal_labels"],
    ],
) -> Float[torch.Tensor, "batch 128"]

Embed label-set, current-label, and previous-count tensors.

Source code in models/layoutvae/src/layoutvae/modeling_layoutvae.py
130
131
132
133
134
135
136
137
138
139
140
def forward(
    self,
    inputs: tuple[
        Float[torch.Tensor, "batch internal_labels"],
        Float[torch.Tensor, "batch internal_labels"],
        Float[torch.Tensor, "batch internal_labels"],
    ],
) -> Float[torch.Tensor, "batch 128"]:
    """Embed label-set, current-label, and previous-count tensors."""
    in1, in2, in3 = inputs
    return self.fc(torch.cat((self.fcb1(in1), self.fcb2(in2), self.fcb3(in3)), 1))

Encoder

Bases: Module

Gaussian posterior encoder.

Source code in models/layoutvae/src/layoutvae/modeling_layoutvae.py
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
class Encoder(nn.Module):
    """Gaussian posterior encoder."""

    def __init__(self, in_dim: int = 1, latent_dim: int = 32) -> None:
        """Initialize the encoder."""
        super().__init__()
        self.act = nn.ReLU()
        self.fc1 = nn.Linear(in_dim, 128)
        self.fc2 = nn.Linear(128, 128)
        self.fc3 = nn.Linear(256, latent_dim)
        self.fc4 = nn.Linear(latent_dim, latent_dim)
        self.fc5 = nn.Linear(latent_dim, latent_dim)

    def forward(
        self,
        inputs: tuple[
            Float[torch.Tensor, "batch input_features"],
            Float[torch.Tensor, "batch 128"],
        ],
    ) -> tuple[
        Float[torch.Tensor, "batch latent"],
        Float[torch.Tensor, "batch latent"],
    ]:
        """Encode a target tensor and conditional embedding."""
        in1, in2 = inputs
        out = self.act(self.fc1(in1))
        out = torch.cat((self.fc2(out), in2), 1)
        out = self.act(self.fc3(out))
        return self.fc4(out), self.fc5(out)

__init__

__init__(in_dim: int = 1, latent_dim: int = 32) -> None

Initialize the encoder.

Source code in models/layoutvae/src/layoutvae/modeling_layoutvae.py
146
147
148
149
150
151
152
153
154
def __init__(self, in_dim: int = 1, latent_dim: int = 32) -> None:
    """Initialize the encoder."""
    super().__init__()
    self.act = nn.ReLU()
    self.fc1 = nn.Linear(in_dim, 128)
    self.fc2 = nn.Linear(128, 128)
    self.fc3 = nn.Linear(256, latent_dim)
    self.fc4 = nn.Linear(latent_dim, latent_dim)
    self.fc5 = nn.Linear(latent_dim, latent_dim)

forward

forward(
    inputs: tuple[
        Float[Tensor, "batch input_features"],
        Float[Tensor, "batch 128"],
    ],
) -> tuple[
    Float[torch.Tensor, "batch latent"],
    Float[torch.Tensor, "batch latent"],
]

Encode a target tensor and conditional embedding.

Source code in models/layoutvae/src/layoutvae/modeling_layoutvae.py
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
def forward(
    self,
    inputs: tuple[
        Float[torch.Tensor, "batch input_features"],
        Float[torch.Tensor, "batch 128"],
    ],
) -> tuple[
    Float[torch.Tensor, "batch latent"],
    Float[torch.Tensor, "batch latent"],
]:
    """Encode a target tensor and conditional embedding."""
    in1, in2 = inputs
    out = self.act(self.fc1(in1))
    out = torch.cat((self.fc2(out), in2), 1)
    out = self.act(self.fc3(out))
    return self.fc4(out), self.fc5(out)

Prior

Bases: Module

Conditional Gaussian prior network.

Source code in models/layoutvae/src/layoutvae/modeling_layoutvae.py
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
class Prior(nn.Module):
    """Conditional Gaussian prior network."""

    def __init__(self, latent_dim: int = 32) -> None:
        """Initialize the prior."""
        super().__init__()
        self.act = nn.ReLU()
        self.fc1 = nn.Linear(128, latent_dim)
        self.fc2 = nn.Linear(latent_dim, latent_dim)
        self.fc3 = nn.Linear(latent_dim, latent_dim)

    def forward(
        self, inputs: Float[torch.Tensor, "batch 128"]
    ) -> tuple[
        Float[torch.Tensor, "batch latent"],
        Float[torch.Tensor, "batch latent"],
    ]:
        """Predict latent mean and log variance."""
        out = self.act(self.fc1(inputs))
        return self.fc2(out), self.fc3(out)

__init__

__init__(latent_dim: int = 32) -> None

Initialize the prior.

Source code in models/layoutvae/src/layoutvae/modeling_layoutvae.py
177
178
179
180
181
182
183
def __init__(self, latent_dim: int = 32) -> None:
    """Initialize the prior."""
    super().__init__()
    self.act = nn.ReLU()
    self.fc1 = nn.Linear(128, latent_dim)
    self.fc2 = nn.Linear(latent_dim, latent_dim)
    self.fc3 = nn.Linear(latent_dim, latent_dim)

forward

forward(
    inputs: Float[Tensor, "batch 128"],
) -> tuple[
    Float[torch.Tensor, "batch latent"],
    Float[torch.Tensor, "batch latent"],
]

Predict latent mean and log variance.

Source code in models/layoutvae/src/layoutvae/modeling_layoutvae.py
185
186
187
188
189
190
191
192
193
def forward(
    self, inputs: Float[torch.Tensor, "batch 128"]
) -> tuple[
    Float[torch.Tensor, "batch latent"],
    Float[torch.Tensor, "batch latent"],
]:
    """Predict latent mean and log variance."""
    out = self.act(self.fc1(inputs))
    return self.fc2(out), self.fc3(out)

Decoder

Bases: Module

Conditional decoder network.

Source code in models/layoutvae/src/layoutvae/modeling_layoutvae.py
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
class Decoder(nn.Module):
    """Conditional decoder network."""

    def __init__(self, output_dim: int, latent_dim: int = 32) -> None:
        """Initialize the decoder."""
        super().__init__()
        self.act = nn.ReLU()
        self.fc1 = nn.Linear(128 + latent_dim, 128)
        self.fc2 = nn.Linear(128, 64)
        self.fc3 = nn.Linear(64, output_dim)

    def forward(
        self,
        inputs: tuple[
            Float[torch.Tensor, "batch 128"],
            Float[torch.Tensor, "batch latent"],
        ],
    ) -> Float[torch.Tensor, "batch output"]:
        """Decode from an embedding and latent tensor."""
        in1, in2 = inputs
        out = self.act(self.fc1(torch.cat((in1, in2), 1)))
        out = self.act(self.fc2(out))
        return self.fc3(out)

__init__

__init__(output_dim: int, latent_dim: int = 32) -> None

Initialize the decoder.

Source code in models/layoutvae/src/layoutvae/modeling_layoutvae.py
199
200
201
202
203
204
205
def __init__(self, output_dim: int, latent_dim: int = 32) -> None:
    """Initialize the decoder."""
    super().__init__()
    self.act = nn.ReLU()
    self.fc1 = nn.Linear(128 + latent_dim, 128)
    self.fc2 = nn.Linear(128, 64)
    self.fc3 = nn.Linear(64, output_dim)

forward

forward(
    inputs: tuple[
        Float[Tensor, "batch 128"],
        Float[Tensor, "batch latent"],
    ],
) -> Float[torch.Tensor, "batch output"]

Decode from an embedding and latent tensor.

Source code in models/layoutvae/src/layoutvae/modeling_layoutvae.py
207
208
209
210
211
212
213
214
215
216
217
218
def forward(
    self,
    inputs: tuple[
        Float[torch.Tensor, "batch 128"],
        Float[torch.Tensor, "batch latent"],
    ],
) -> Float[torch.Tensor, "batch output"]:
    """Decode from an embedding and latent tensor."""
    in1, in2 = inputs
    out = self.act(self.fc1(torch.cat((in1, in2), 1)))
    out = self.act(self.fc2(out))
    return self.fc3(out)

EmbedBbox

Bases: Module

Autoregressive box embedding network.

Source code in models/layoutvae/src/layoutvae/modeling_layoutvae.py
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
class EmbedBbox(nn.Module):
    """Autoregressive box embedding network."""

    def __init__(self, n_class: int) -> None:
        """Initialize the box embedding network."""
        super().__init__()
        self.fcb1 = FCBlock(n_class)
        self.fcb2 = FCBlock(n_class)
        self.seq1 = nn.Sequential(nn.Linear(128, 128), nn.ReLU())
        self.n_class = n_class
        self.fc = nn.Linear(128 * 3, 128)
        self.lstm = nn.LSTM(n_class + 4, hidden_size=128)

    def forward(
        self,
        inputs: tuple[
            Float[torch.Tensor, "batch internal_labels"],
            Float[torch.Tensor, "batch internal_labels"],
            Float[torch.Tensor, "history batch features"],
        ],
    ) -> Float[torch.Tensor, "batch 128"]:
        """Embed counts, current label, and previous elements."""
        in1, in2, in3 = inputs
        _, (h_0, _c_0) = self.lstm(in3)
        hn = h_0.view(-1, 128)
        return self.fc(torch.cat((self.fcb1(in1), self.fcb2(in2), self.seq1(hn)), 1))

__init__

__init__(n_class: int) -> None

Initialize the box embedding network.

Source code in models/layoutvae/src/layoutvae/modeling_layoutvae.py
224
225
226
227
228
229
230
231
232
def __init__(self, n_class: int) -> None:
    """Initialize the box embedding network."""
    super().__init__()
    self.fcb1 = FCBlock(n_class)
    self.fcb2 = FCBlock(n_class)
    self.seq1 = nn.Sequential(nn.Linear(128, 128), nn.ReLU())
    self.n_class = n_class
    self.fc = nn.Linear(128 * 3, 128)
    self.lstm = nn.LSTM(n_class + 4, hidden_size=128)

forward

forward(
    inputs: tuple[
        Float[Tensor, "batch internal_labels"],
        Float[Tensor, "batch internal_labels"],
        Float[Tensor, "history batch features"],
    ],
) -> Float[torch.Tensor, "batch 128"]

Embed counts, current label, and previous elements.

Source code in models/layoutvae/src/layoutvae/modeling_layoutvae.py
234
235
236
237
238
239
240
241
242
243
244
245
246
def forward(
    self,
    inputs: tuple[
        Float[torch.Tensor, "batch internal_labels"],
        Float[torch.Tensor, "batch internal_labels"],
        Float[torch.Tensor, "history batch features"],
    ],
) -> Float[torch.Tensor, "batch 128"]:
    """Embed counts, current label, and previous elements."""
    in1, in2, in3 = inputs
    _, (h_0, _c_0) = self.lstm(in3)
    hn = h_0.view(-1, 128)
    return self.fc(torch.cat((self.fcb1(in1), self.fcb2(in2), self.seq1(hn)), 1))

CountVAEModel

Bases: Module

Autoregressive count module.

Source code in models/layoutvae/src/layoutvae/modeling_layoutvae.py
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
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
class CountVAEModel(nn.Module):
    """Autoregressive count module."""

    def __init__(self, n_class: int, latent_dim: int = 32) -> None:
        """Initialize the count module."""
        super().__init__()
        self.encoder = Encoder(latent_dim=latent_dim)
        self.prior = Prior(latent_dim=latent_dim)
        self.decoder = Decoder(1, latent_dim=latent_dim)
        self.embeder = Embeder(n_class)
        self.n_class = n_class

    def forward(
        self,
        label_set: Float[torch.Tensor, "batch internal_labels"],
        *,
        latents: Float[torch.Tensor, "batch internal_labels latent"] | None = None,
        count_samples: Float[torch.Tensor, "batch internal_labels"] | None = None,
        generator: torch.Generator | None = None,
    ) -> Float[torch.Tensor, "batch internal_labels"]:
        """Generate class counts from a label set."""
        previous_counts = torch.zeros_like(label_set)
        samples = (
            count_samples.to(device=label_set.device, dtype=label_set.dtype)
            if count_samples is not None
            else None
        )
        for i in range(self.n_class):
            current_label = torch.zeros_like(previous_counts)
            x_i = label_set[..., i]
            current_label[..., i] = x_i
            embedding = self.embeder((label_set, current_label, previous_counts))
            mu, logvar = self.prior(embedding)
            z = (
                latents[:, i, :].to(device=label_set.device, dtype=label_set.dtype)
                if latents is not None
                else _sample_diag_gaussian(mu, logvar, generator=generator)
            )
            rate = torch.exp(self.decoder((embedding, z)))
            q = (
                samples[:, i].view(-1, 1)
                if samples is not None
                else torch.poisson(rate, generator=generator)
            )
            previous_counts = previous_counts + current_label * (
                q.view(-1, 1) + x_i.view(-1, 1)
            )
        return previous_counts

__init__

__init__(n_class: int, latent_dim: int = 32) -> None

Initialize the count module.

Source code in models/layoutvae/src/layoutvae/modeling_layoutvae.py
265
266
267
268
269
270
271
272
def __init__(self, n_class: int, latent_dim: int = 32) -> None:
    """Initialize the count module."""
    super().__init__()
    self.encoder = Encoder(latent_dim=latent_dim)
    self.prior = Prior(latent_dim=latent_dim)
    self.decoder = Decoder(1, latent_dim=latent_dim)
    self.embeder = Embeder(n_class)
    self.n_class = n_class

forward

forward(
    label_set: Float[Tensor, "batch internal_labels"],
    *,
    latents: Float[Tensor, "batch internal_labels latent"]
    | None = None,
    count_samples: Float[Tensor, "batch internal_labels"]
    | None = None,
    generator: Generator | None = None,
) -> Float[torch.Tensor, "batch internal_labels"]

Generate class counts from a label set.

Source code in models/layoutvae/src/layoutvae/modeling_layoutvae.py
274
275
276
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
def forward(
    self,
    label_set: Float[torch.Tensor, "batch internal_labels"],
    *,
    latents: Float[torch.Tensor, "batch internal_labels latent"] | None = None,
    count_samples: Float[torch.Tensor, "batch internal_labels"] | None = None,
    generator: torch.Generator | None = None,
) -> Float[torch.Tensor, "batch internal_labels"]:
    """Generate class counts from a label set."""
    previous_counts = torch.zeros_like(label_set)
    samples = (
        count_samples.to(device=label_set.device, dtype=label_set.dtype)
        if count_samples is not None
        else None
    )
    for i in range(self.n_class):
        current_label = torch.zeros_like(previous_counts)
        x_i = label_set[..., i]
        current_label[..., i] = x_i
        embedding = self.embeder((label_set, current_label, previous_counts))
        mu, logvar = self.prior(embedding)
        z = (
            latents[:, i, :].to(device=label_set.device, dtype=label_set.dtype)
            if latents is not None
            else _sample_diag_gaussian(mu, logvar, generator=generator)
        )
        rate = torch.exp(self.decoder((embedding, z)))
        q = (
            samples[:, i].view(-1, 1)
            if samples is not None
            else torch.poisson(rate, generator=generator)
        )
        previous_counts = previous_counts + current_label * (
            q.view(-1, 1) + x_i.view(-1, 1)
        )
    return previous_counts

BboxVAEModel

Bases: Module

Autoregressive bounding-box module.

Source code in models/layoutvae/src/layoutvae/modeling_layoutvae.py
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
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
class BboxVAEModel(nn.Module):
    """Autoregressive bounding-box module."""

    def __init__(
        self,
        n_class: int,
        n_dim: int,
        max_box: int,
        latent_dim: int = 32,
    ) -> None:
        """Initialize the box module."""
        super().__init__()
        self.embeder = EmbedBbox(n_class)
        self.encoder = Encoder(n_dim, latent_dim=latent_dim)
        self.decoder = Decoder(n_dim, latent_dim=latent_dim)
        self.prior = Prior(latent_dim=latent_dim)
        self.n_dim = n_dim
        self.n_class = n_class
        self.max_box = max_box

    def forward(
        self,
        box_counts: Float[torch.Tensor, "batch internal_labels"],
        box_label: Float[torch.Tensor, "batch elements internal_labels"],
        *,
        latents: Float[torch.Tensor, "batch elements latent"] | None = None,
        output_noise: Float[torch.Tensor, "batch elements 4"] | None = None,
        generator: torch.Generator | None = None,
    ) -> Float[torch.Tensor, "batch elements 4"]:
        """Generate normalized left-top-width-height boxes."""
        boxes = []
        prev_label = torch.zeros(
            (1, box_label.shape[0], self.n_class),
            device=box_label.device,
            dtype=box_label.dtype,
        )
        prev_box = torch.zeros(
            (1, box_label.shape[0], 4),
            device=box_label.device,
            dtype=box_label.dtype,
        )
        for i in range(self.max_box):
            if i == 0:
                prev_label = torch.zeros(
                    (1, *box_label[..., i, :].shape),
                    device=box_label.device,
                    dtype=box_label.dtype,
                )
                prev_box = torch.zeros(
                    (1, box_label.shape[0], 4),
                    device=box_label.device,
                    dtype=box_label.dtype,
                )
            current_label = box_label[..., i, :].view(-1, self.n_class)
            embedding = self.embeder(
                (box_counts, current_label, torch.cat([prev_label, prev_box], dim=2))
            )
            mu, logvar = self.prior(embedding)
            z = (
                latents[:, i, :].to(device=box_label.device, dtype=box_label.dtype)
                if latents is not None
                else _sample_diag_gaussian(mu, logvar, generator=generator)
            )
            decoded = self.decoder((embedding, z))
            if output_noise is None:
                eps = torch.rand(
                    decoded.shape,
                    generator=generator,
                    device=decoded.device,
                    dtype=decoded.dtype,
                )
                box = decoded + eps * 0.02
            else:
                box = decoded + output_noise[:, i, :].to(
                    device=decoded.device, dtype=decoded.dtype
                )
            prev_box = torch.cat([prev_box, torch.unsqueeze(box, 0)])
            prev_label = torch.cat([prev_label, torch.unsqueeze(current_label, 0)])
            boxes.append(box)
        return torch.stack(boxes, dim=1)

__init__

__init__(
    n_class: int,
    n_dim: int,
    max_box: int,
    latent_dim: int = 32,
) -> None

Initialize the box module.

Source code in models/layoutvae/src/layoutvae/modeling_layoutvae.py
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
def __init__(
    self,
    n_class: int,
    n_dim: int,
    max_box: int,
    latent_dim: int = 32,
) -> None:
    """Initialize the box module."""
    super().__init__()
    self.embeder = EmbedBbox(n_class)
    self.encoder = Encoder(n_dim, latent_dim=latent_dim)
    self.decoder = Decoder(n_dim, latent_dim=latent_dim)
    self.prior = Prior(latent_dim=latent_dim)
    self.n_dim = n_dim
    self.n_class = n_class
    self.max_box = max_box

forward

forward(
    box_counts: Float[Tensor, "batch internal_labels"],
    box_label: Float[
        Tensor, "batch elements internal_labels"
    ],
    *,
    latents: Float[Tensor, "batch elements latent"]
    | None = None,
    output_noise: Float[Tensor, "batch elements 4"]
    | None = None,
    generator: Generator | None = None,
) -> Float[torch.Tensor, "batch elements 4"]

Generate normalized left-top-width-height boxes.

Source code in models/layoutvae/src/layoutvae/modeling_layoutvae.py
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
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
def forward(
    self,
    box_counts: Float[torch.Tensor, "batch internal_labels"],
    box_label: Float[torch.Tensor, "batch elements internal_labels"],
    *,
    latents: Float[torch.Tensor, "batch elements latent"] | None = None,
    output_noise: Float[torch.Tensor, "batch elements 4"] | None = None,
    generator: torch.Generator | None = None,
) -> Float[torch.Tensor, "batch elements 4"]:
    """Generate normalized left-top-width-height boxes."""
    boxes = []
    prev_label = torch.zeros(
        (1, box_label.shape[0], self.n_class),
        device=box_label.device,
        dtype=box_label.dtype,
    )
    prev_box = torch.zeros(
        (1, box_label.shape[0], 4),
        device=box_label.device,
        dtype=box_label.dtype,
    )
    for i in range(self.max_box):
        if i == 0:
            prev_label = torch.zeros(
                (1, *box_label[..., i, :].shape),
                device=box_label.device,
                dtype=box_label.dtype,
            )
            prev_box = torch.zeros(
                (1, box_label.shape[0], 4),
                device=box_label.device,
                dtype=box_label.dtype,
            )
        current_label = box_label[..., i, :].view(-1, self.n_class)
        embedding = self.embeder(
            (box_counts, current_label, torch.cat([prev_label, prev_box], dim=2))
        )
        mu, logvar = self.prior(embedding)
        z = (
            latents[:, i, :].to(device=box_label.device, dtype=box_label.dtype)
            if latents is not None
            else _sample_diag_gaussian(mu, logvar, generator=generator)
        )
        decoded = self.decoder((embedding, z))
        if output_noise is None:
            eps = torch.rand(
                decoded.shape,
                generator=generator,
                device=decoded.device,
                dtype=decoded.dtype,
            )
            box = decoded + eps * 0.02
        else:
            box = decoded + output_noise[:, i, :].to(
                device=decoded.device, dtype=decoded.dtype
            )
        prev_box = torch.cat([prev_box, torch.unsqueeze(box, 0)])
        prev_label = torch.cat([prev_label, torch.unsqueeze(current_label, 0)])
        boxes.append(box)
    return torch.stack(boxes, dim=1)

LayoutVAEModel

Bases: PreTrainedModel

Transformers-compatible LayoutVAE model.

Parameters:

Name Type Description Default
config LayoutVAEConfig

LayoutVAE configuration.

required

Examples:

>>> model = LayoutVAEModel(LayoutVAEConfig())
>>> model.config.model_type
'layoutvae'
Source code in models/layoutvae/src/layoutvae/modeling_layoutvae.py
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
class LayoutVAEModel(PreTrainedModel):
    """Transformers-compatible LayoutVAE model.

    Args:
        config: LayoutVAE configuration.

    Examples:
        >>> model = LayoutVAEModel(LayoutVAEConfig())
        >>> model.config.model_type
        'layoutvae'
    """

    config_class = LayoutVAEConfig
    base_model_prefix = "layoutvae"
    supports_gradient_checkpointing = False

    def __init__(self, config: LayoutVAEConfig) -> None:
        """Initialize LayoutVAE submodules."""
        super().__init__(config)
        self.countvae = CountVAEModel(
            config.internal_num_labels, config.count_latent_dim
        )
        self.bboxvae = BboxVAEModel(
            config.internal_num_labels,
            4,
            config.max_position_embeddings,
            config.bbox_latent_dim,
        )
        self.post_init()

    def forward(
        self,
        label_set: Float[torch.Tensor, "batch internal_labels"],
        *,
        count_latents: Float[torch.Tensor, "batch internal_labels latent"]
        | None = None,
        bbox_latents: Float[torch.Tensor, "batch elements latent"] | None = None,
        bbox_noise: Float[torch.Tensor, "batch elements 4"] | None = None,
        class_counts: Float[torch.Tensor, "batch internal_labels"] | None = None,
        count_samples: Float[torch.Tensor, "batch internal_labels"] | None = None,
        generator: torch.Generator | None = None,
        return_dict: bool = True,
    ) -> (
        LayoutVAEModelOutput
        | tuple[
            Float[torch.Tensor, "batch elements 4"],
            Float[torch.Tensor, "batch elements 4"],
            Int[torch.Tensor, "batch elements"],
            Bool[torch.Tensor, "batch elements"],
            Float[torch.Tensor, "batch internal_labels"],
            Int[torch.Tensor, "batch elements"],
        ]
    ):
        """Run label-conditioned layout generation.

        Args:
            label_set: Six-way label-set tensor.
            count_latents: Optional fixed count latents.
            bbox_latents: Optional fixed box latents.
            bbox_noise: Optional fixed output noise.
            class_counts: Optional fixed six-way class counts.
            count_samples: Optional fixed count samples.
            generator: Optional PyTorch random generator.
            return_dict: Whether to return a dataclass.

        Returns:
            Model output dataclass or tuple.

        Raises:
            ValueError: If shapes are invalid.

        Examples:
            >>> model = LayoutVAEModel(LayoutVAEConfig())
            >>> label_set = torch.tensor([[0, 1, 0, 0, 0, 1]], dtype=torch.float32)
            >>> out = model(label_set, class_counts=torch.tensor([[7, 1, 0, 0, 0, 1.]]))
            >>> tuple(out.bbox.shape)
            (1, 9, 4)
        """
        label_set = label_set.to(device=self.device, dtype=self.dtype)
        if label_set.ndim != 2 or label_set.shape[1] != self.config.internal_num_labels:
            raise ValueError(
                "label_set must have shape (batch, config.internal_num_labels)"
            )

        if class_counts is None:
            class_counts = self.countvae(
                label_set,
                latents=count_latents,
                count_samples=count_samples,
                generator=generator,
            )
            class_counts = self._normalize_counts(class_counts)
        else:
            class_counts = class_counts.to(
                device=label_set.device, dtype=label_set.dtype
            )
            if class_counts.shape != label_set.shape:
                raise ValueError("class_counts must match label_set shape")

        class_labels = self._labels_from_counts(class_counts)
        raw_ltwh = self.bboxvae(
            class_counts,
            class_labels,
            latents=bbox_latents,
            output_noise=bbox_noise,
            generator=generator,
        )
        internal_ids = torch.argmax(class_labels, dim=2).to(dtype=torch.long)
        labels = torch.clamp(internal_ids - 1, min=0)
        mask = internal_ids != INTERNAL_EMPTY_LABEL_ID
        public_bbox = clamp_boxes(ltwh_to_xywh(raw_ltwh))
        raw_ltwh = torch.where(mask.unsqueeze(-1), raw_ltwh, torch.zeros_like(raw_ltwh))
        public_bbox = torch.where(
            mask.unsqueeze(-1), public_bbox, torch.zeros_like(public_bbox)
        )
        if not return_dict:
            return raw_ltwh, public_bbox, labels, mask, class_counts, internal_ids
        return LayoutVAEModelOutput(
            raw_ltwh=raw_ltwh,
            bbox=public_bbox,
            labels=labels,
            mask=mask,
            class_counts=class_counts,
            label_set=label_set,
            internal_labels=internal_ids,
        )

    def _normalize_counts(
        self,
        class_counts: Float[torch.Tensor, "batch internal_labels"],
    ) -> Float[torch.Tensor, "batch internal_labels"]:
        counts = class_counts.clamp_min(0)
        denom = counts.sum(dim=1, keepdim=True).clamp_min(1)
        counts = torch.floor(self.config.max_position_embeddings * (counts / denom))
        totals = counts.sum(dim=1)
        shortfall = self.config.max_position_embeddings - totals
        counts[:, INTERNAL_EMPTY_LABEL_ID] = counts[
            :, INTERNAL_EMPTY_LABEL_ID
        ] + torch.clamp(shortfall, min=0)
        return counts

    def _labels_from_counts(
        self,
        class_counts: Float[torch.Tensor, "batch internal_labels"],
    ) -> Float[torch.Tensor, "batch elements internal_labels"]:
        labels = torch.zeros(
            (
                class_counts.shape[0],
                self.config.max_position_embeddings,
                self.config.internal_num_labels,
            ),
            device=class_counts.device,
            dtype=class_counts.dtype,
        )
        for batch_index, counts in enumerate(class_counts):
            position = 0
            for class_index in reversed(range(self.config.internal_num_labels)):
                count = int(counts[class_index].item())
                for _ in range(count):
                    if position >= self.config.max_position_embeddings:
                        break
                    labels[batch_index, position, class_index] = 1.0
                    position += 1
        return labels

__init__

__init__(config: LayoutVAEConfig) -> None

Initialize LayoutVAE submodules.

Source code in models/layoutvae/src/layoutvae/modeling_layoutvae.py
410
411
412
413
414
415
416
417
418
419
420
421
422
def __init__(self, config: LayoutVAEConfig) -> None:
    """Initialize LayoutVAE submodules."""
    super().__init__(config)
    self.countvae = CountVAEModel(
        config.internal_num_labels, config.count_latent_dim
    )
    self.bboxvae = BboxVAEModel(
        config.internal_num_labels,
        4,
        config.max_position_embeddings,
        config.bbox_latent_dim,
    )
    self.post_init()

forward

forward(
    label_set: Float[Tensor, "batch internal_labels"],
    *,
    count_latents: Float[
        Tensor, "batch internal_labels latent"
    ]
    | None = None,
    bbox_latents: Float[Tensor, "batch elements latent"]
    | None = None,
    bbox_noise: Float[Tensor, "batch elements 4"]
    | None = None,
    class_counts: Float[Tensor, "batch internal_labels"]
    | None = None,
    count_samples: Float[Tensor, "batch internal_labels"]
    | None = None,
    generator: Generator | None = None,
    return_dict: bool = True,
) -> (
    LayoutVAEModelOutput
    | tuple[
        Float[torch.Tensor, "batch elements 4"],
        Float[torch.Tensor, "batch elements 4"],
        Int[torch.Tensor, "batch elements"],
        Bool[torch.Tensor, "batch elements"],
        Float[torch.Tensor, "batch internal_labels"],
        Int[torch.Tensor, "batch elements"],
    ]
)

Run label-conditioned layout generation.

Parameters:

Name Type Description Default
label_set Float[Tensor, 'batch internal_labels']

Six-way label-set tensor.

required
count_latents Float[Tensor, 'batch internal_labels latent'] | None

Optional fixed count latents.

None
bbox_latents Float[Tensor, 'batch elements latent'] | None

Optional fixed box latents.

None
bbox_noise Float[Tensor, 'batch elements 4'] | None

Optional fixed output noise.

None
class_counts Float[Tensor, 'batch internal_labels'] | None

Optional fixed six-way class counts.

None
count_samples Float[Tensor, 'batch internal_labels'] | None

Optional fixed count samples.

None
generator Generator | None

Optional PyTorch random generator.

None
return_dict bool

Whether to return a dataclass.

True

Returns:

Type Description
LayoutVAEModelOutput | tuple[Float[Tensor, 'batch elements 4'], Float[Tensor, 'batch elements 4'], Int[Tensor, 'batch elements'], Bool[Tensor, 'batch elements'], Float[Tensor, 'batch internal_labels'], Int[Tensor, 'batch elements']]

Model output dataclass or tuple.

Raises:

Type Description
ValueError

If shapes are invalid.

Examples:

>>> model = LayoutVAEModel(LayoutVAEConfig())
>>> label_set = torch.tensor([[0, 1, 0, 0, 0, 1]], dtype=torch.float32)
>>> out = model(label_set, class_counts=torch.tensor([[7, 1, 0, 0, 0, 1.]]))
>>> tuple(out.bbox.shape)
(1, 9, 4)
Source code in models/layoutvae/src/layoutvae/modeling_layoutvae.py
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
def forward(
    self,
    label_set: Float[torch.Tensor, "batch internal_labels"],
    *,
    count_latents: Float[torch.Tensor, "batch internal_labels latent"]
    | None = None,
    bbox_latents: Float[torch.Tensor, "batch elements latent"] | None = None,
    bbox_noise: Float[torch.Tensor, "batch elements 4"] | None = None,
    class_counts: Float[torch.Tensor, "batch internal_labels"] | None = None,
    count_samples: Float[torch.Tensor, "batch internal_labels"] | None = None,
    generator: torch.Generator | None = None,
    return_dict: bool = True,
) -> (
    LayoutVAEModelOutput
    | tuple[
        Float[torch.Tensor, "batch elements 4"],
        Float[torch.Tensor, "batch elements 4"],
        Int[torch.Tensor, "batch elements"],
        Bool[torch.Tensor, "batch elements"],
        Float[torch.Tensor, "batch internal_labels"],
        Int[torch.Tensor, "batch elements"],
    ]
):
    """Run label-conditioned layout generation.

    Args:
        label_set: Six-way label-set tensor.
        count_latents: Optional fixed count latents.
        bbox_latents: Optional fixed box latents.
        bbox_noise: Optional fixed output noise.
        class_counts: Optional fixed six-way class counts.
        count_samples: Optional fixed count samples.
        generator: Optional PyTorch random generator.
        return_dict: Whether to return a dataclass.

    Returns:
        Model output dataclass or tuple.

    Raises:
        ValueError: If shapes are invalid.

    Examples:
        >>> model = LayoutVAEModel(LayoutVAEConfig())
        >>> label_set = torch.tensor([[0, 1, 0, 0, 0, 1]], dtype=torch.float32)
        >>> out = model(label_set, class_counts=torch.tensor([[7, 1, 0, 0, 0, 1.]]))
        >>> tuple(out.bbox.shape)
        (1, 9, 4)
    """
    label_set = label_set.to(device=self.device, dtype=self.dtype)
    if label_set.ndim != 2 or label_set.shape[1] != self.config.internal_num_labels:
        raise ValueError(
            "label_set must have shape (batch, config.internal_num_labels)"
        )

    if class_counts is None:
        class_counts = self.countvae(
            label_set,
            latents=count_latents,
            count_samples=count_samples,
            generator=generator,
        )
        class_counts = self._normalize_counts(class_counts)
    else:
        class_counts = class_counts.to(
            device=label_set.device, dtype=label_set.dtype
        )
        if class_counts.shape != label_set.shape:
            raise ValueError("class_counts must match label_set shape")

    class_labels = self._labels_from_counts(class_counts)
    raw_ltwh = self.bboxvae(
        class_counts,
        class_labels,
        latents=bbox_latents,
        output_noise=bbox_noise,
        generator=generator,
    )
    internal_ids = torch.argmax(class_labels, dim=2).to(dtype=torch.long)
    labels = torch.clamp(internal_ids - 1, min=0)
    mask = internal_ids != INTERNAL_EMPTY_LABEL_ID
    public_bbox = clamp_boxes(ltwh_to_xywh(raw_ltwh))
    raw_ltwh = torch.where(mask.unsqueeze(-1), raw_ltwh, torch.zeros_like(raw_ltwh))
    public_bbox = torch.where(
        mask.unsqueeze(-1), public_bbox, torch.zeros_like(public_bbox)
    )
    if not return_dict:
        return raw_ltwh, public_bbox, labels, mask, class_counts, internal_ids
    return LayoutVAEModelOutput(
        raw_ltwh=raw_ltwh,
        bbox=public_bbox,
        labels=labels,
        mask=mask,
        class_counts=class_counts,
        label_set=label_set,
        internal_labels=internal_ids,
    )

normalize_output_type

normalize_output_type(
    output_type: OutputType | str,
) -> OutputType

Normalize a public output type.

Parameters:

Name Type Description Default
output_type OutputType | str

Output type enum or string.

required

Returns:

Type Description
OutputType

Normalized output type enum.

Raises:

Type Description
ValueError

If the value is unsupported.

Examples:

>>> str(normalize_output_type("dict"))
'dict'
Source code in models/layoutvae/src/layoutvae/modeling_layoutvae.py
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
def normalize_output_type(output_type: OutputType | str) -> OutputType:
    """Normalize a public output type.

    Args:
        output_type: Output type enum or string.

    Returns:
        Normalized output type enum.

    Raises:
        ValueError: If the value is unsupported.

    Examples:
        >>> str(normalize_output_type("dict"))
        'dict'
    """
    return normalize_enum_value(
        output_type,
        OutputType,
        option_name="output_type",
    )

pipeline_layoutvae

Pipeline interface for LayoutVAE layout generation.

GenerationOptions dataclass

Common generation options accepted by the pipeline.

Source code in models/layoutvae/src/layoutvae/pipeline_layoutvae.py
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
@dataclass(frozen=True)
class GenerationOptions:
    """Common generation options accepted by the pipeline."""

    bbox: Float[torch.Tensor, "batch elements 4"] | None = None
    labels: Int[torch.Tensor, "batch elements"] | None = None
    mask: Bool[torch.Tensor, "batch elements"] | None = None
    num_elements: int | list[int] | Int[torch.Tensor, "batch"] | None = None
    box_format: BoxFormat | str = BoxFormat.xywh
    normalized: bool = True
    canvas_size: tuple[int, int] | None = None
    seed: int | None = None
    generator: torch.Generator | None = None
    num_inference_steps: int | None = None
    output_type: OutputType | str = OutputType.dataclass
    return_intermediates: bool = False

GenerationOptionsKwargs

Bases: TypedDict

Keyword dictionary used to avoid repeated call-site scaffolding.

Source code in models/layoutvae/src/layoutvae/pipeline_layoutvae.py
75
76
77
78
79
80
81
82
83
84
85
86
87
88
class GenerationOptionsKwargs(TypedDict, total=False):
    """Keyword dictionary used to avoid repeated call-site scaffolding."""

    bbox: Float[torch.Tensor, "batch elements 4"] | None
    mask: Bool[torch.Tensor, "batch elements"] | None
    num_elements: int | list[int] | Int[torch.Tensor, "batch"] | None
    box_format: BoxFormat | str
    normalized: bool
    canvas_size: tuple[int, int] | None
    seed: int | None
    generator: torch.Generator | None
    num_inference_steps: int | None
    output_type: OutputType | str
    return_intermediates: bool

LayoutVAEPipeline

Bases: LayoutGenerationPipeline

Transformers pipeline for LayoutVAE label-conditioned generation.

Parameters:

Name Type Description Default
model LayoutVAEModel

LayoutVAE model instance.

required
processor LayoutVAEProcessor | None

Optional processor for label-set encoding.

None
config LayoutVAEConfig | None

Optional root pipeline config. Defaults to model.config.

None
device int | device | None

Optional torch device.

None
binary_output bool

Reserved compatibility flag.

False

Examples:

>>> model = LayoutVAEModel(LayoutVAEConfig())
>>> pipe = LayoutVAEPipeline(model=model)
>>> pipe.config.model_type
'layoutvae'
Source code in models/layoutvae/src/layoutvae/pipeline_layoutvae.py
179
180
181
182
183
184
185
186
187
188
189
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
274
275
276
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
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
class LayoutVAEPipeline(LayoutGenerationPipeline):
    """Transformers pipeline for LayoutVAE label-conditioned generation.

    Args:
        model: LayoutVAE model instance.
        processor: Optional processor for label-set encoding.
        config: Optional root pipeline config. Defaults to `model.config`.
        device: Optional torch device.
        binary_output: Reserved compatibility flag.

    Examples:
        >>> model = LayoutVAEModel(LayoutVAEConfig())
        >>> pipe = LayoutVAEPipeline(model=model)
        >>> pipe.config.model_type
        'layoutvae'
    """

    config_class: ClassVar[type[PretrainedConfig]] = LayoutVAEConfig
    component_specs: ClassVar[dict[str, PipelineComponentSpec]] = (
        model_processor_component_specs(
            model_loader=_load_model_component,
            processor_loader=_load_processor_component,
        )
    )

    config: LayoutVAEConfig
    model: LayoutVAEModel
    processor: LayoutVAEProcessor

    def __init__(
        self,
        model: LayoutVAEModel,
        processor: LayoutVAEProcessor | None = None,
        config: LayoutVAEConfig | None = None,
        device: int | torch.device | None = None,
        binary_output: bool = False,
    ) -> None:
        """Initialize a LayoutVAE pipeline."""
        _ = binary_output
        super().__init__(config or model.config)
        self.config = config or model.config
        self.model = model
        self.processor = processor or LayoutVAEProcessor(
            dataset_name=model.config.dataset_name,
            id2label=model.config.id2label,
        )
        if device is not None:
            self.to(_resolve_device(device))

    @classmethod
    def _from_pretrained_components(
        cls,
        *,
        config: PretrainedConfig,
        components: Mapping[str, PipelineComponent | None],
    ) -> LayoutVAEPipeline:
        """Build a pipeline from loaded root components."""
        return cls(
            config=cast(LayoutVAEConfig, config),
            model=cast(LayoutVAEModel, components["model"]),
            processor=cast(LayoutVAEProcessor, components["processor"]),
        )

    def _sanitize_parameters(
        self, **kwargs: LayoutVAEParam
    ) -> tuple[
        dict[str, LayoutVAEParam], dict[str, LayoutVAEParam], dict[str, LayoutVAEParam]
    ]:
        return {}, kwargs, {}

    def preprocess(
        self,
        input_: list[list[str | int]]
        | list[str | int]
        | Int[torch.Tensor, ...]
        | None = None,
        **preprocess_parameters: LayoutVAEParam,
    ) -> BatchEncoding:
        """Encode labels into model inputs."""
        labels = preprocess_parameters.pop("labels", input_)
        if labels is None:
            raise ValueError("labels are required for LayoutVAEPipeline")

        encoded = self.processor(
            cast(
                list[list[str | int]] | list[str | int] | Int[torch.Tensor, "..."],
                labels,
            )
        )
        encoded.update(preprocess_parameters)
        return encoded

    def _forward(
        self, model_inputs: dict[str, LayoutVAEParam], **forward_params: LayoutVAEParam
    ) -> LayoutGenerationOutput | LayoutVAEOutputDict:
        del forward_params
        label_set = torch.as_tensor(model_inputs.pop("label_set"), dtype=torch.float32)
        condition_type = cast(
            ConditionType | str, model_inputs.pop("condition_type", ConditionType.label)
        )
        options = _pop_generation_options(model_inputs)
        count_latents = cast(
            Float[torch.Tensor, "batch internal_labels latent"] | None,
            model_inputs.pop("count_latents", None),
        )
        bbox_latents = cast(
            Float[torch.Tensor, "batch elements latent"] | None,
            model_inputs.pop("bbox_latents", None),
        )
        bbox_noise = cast(
            Float[torch.Tensor, "batch elements 4"] | None,
            model_inputs.pop("bbox_noise", None),
        )
        class_counts = cast(
            Float[torch.Tensor, "batch internal_labels"] | None,
            model_inputs.pop("class_counts", None),
        )
        if model_inputs:
            unknown = ", ".join(sorted(model_inputs))
            raise ValueError(f"Unsupported generation kwargs: {unknown}")

        return self._generate(
            label_set=label_set,
            condition_type=condition_type,
            options=options,
            count_latents=count_latents,
            bbox_latents=bbox_latents,
            bbox_noise=bbox_noise,
            class_counts=class_counts,
        )

    def postprocess(
        self,
        model_outputs: LayoutGenerationOutput | LayoutVAEOutputDict,
        **kwargs: str | int | float | bool | None,
    ) -> LayoutGenerationOutput | LayoutVAEOutputDict:
        """Return generated layouts unchanged."""
        del kwargs
        return model_outputs

    @torch.no_grad()
    def __call__(
        self,
        labels: list[list[str | int]]
        | list[str | int]
        | Int[torch.Tensor, ...]
        | None = None,
        *,
        batch_size: int = 1,
        seed: int | None = None,
        generator: torch.Generator | None = None,
        condition_type: ConditionType | str = ConditionType.label,
        bbox: Float[torch.Tensor, "batch elements 4"] | None = None,
        mask: Bool[torch.Tensor, "batch elements"] | None = None,
        num_elements: int | list[int] | Int[torch.Tensor, "batch"] | None = None,
        box_format: BoxFormat | str = BoxFormat.xywh,
        normalized: bool = True,
        canvas_size: tuple[int, int] | None = None,
        num_inference_steps: int | None = None,
        output_type: OutputType | str = OutputType.dataclass,
        return_intermediates: bool = False,
        count_latents: Float[torch.Tensor, "batch internal_labels latent"]
        | None = None,
        bbox_latents: Float[torch.Tensor, "batch elements latent"] | None = None,
        bbox_noise: Float[torch.Tensor, "batch elements 4"] | None = None,
        class_counts: Float[torch.Tensor, "batch internal_labels"] | None = None,
    ) -> LayoutGenerationOutput | LayoutVAEOutputDict:  # ty: ignore[invalid-method-override]
        """Generate PubLayNet layouts from label conditions.

        Args:
            labels: Public PubLayNet label strings or IDs.
            batch_size: Used when `labels` is omitted.
            seed: Optional random seed used when `generator` is absent.
            generator: Optional PyTorch random generator. Takes precedence.
            condition_type: Condition type or alias. Only `label` is supported.
            bbox: Reserved compatibility argument.
            mask: Reserved compatibility argument.
            num_elements: Reserved compatibility argument.
            box_format: Reserved compatibility argument.
            normalized: Reserved compatibility argument.
            canvas_size: Reserved compatibility argument.
            num_inference_steps: Reserved compatibility argument.
            output_type: Return format.
            return_intermediates: Whether to include raw generation tensors.
            count_latents: Optional fixed count latents.
            bbox_latents: Optional fixed box latents.
            bbox_noise: Optional fixed box output noise.
            class_counts: Optional fixed class counts.

        Returns:
            Layout generation output.

        Raises:
            ValueError: If labels are missing or condition options are unsupported.

        Examples:
            >>> pipe = LayoutVAEPipeline(LayoutVAEModel(LayoutVAEConfig()))
            >>> out = pipe(labels=["text"], class_counts=torch.tensor([[8, 1, 0, 0, 0, 0.]]))
            >>> tuple(out.bbox.shape)
            (1, 9, 4)
        """
        if labels is None:
            if batch_size < 1:
                raise ValueError("batch_size must be positive")

            labels = [["text"] for _ in range(batch_size)]
        encoded = self.processor(labels)

        option_kwargs: GenerationOptionsKwargs = {}
        option_kwargs["bbox"] = bbox
        option_kwargs["mask"] = mask
        option_kwargs["num_elements"] = num_elements
        option_kwargs["box_format"] = box_format
        option_kwargs["normalized"] = normalized
        option_kwargs["canvas_size"] = canvas_size
        option_kwargs["seed"] = seed
        option_kwargs["generator"] = generator
        option_kwargs["num_inference_steps"] = num_inference_steps
        option_kwargs["output_type"] = output_type
        option_kwargs["return_intermediates"] = return_intermediates

        options = _make_generation_options(option_kwargs)

        return self._generate(
            label_set=cast(
                Float[torch.Tensor, "batch internal_labels"], encoded["label_set"]
            ),
            condition_type=condition_type,
            options=options,
            count_latents=count_latents,
            bbox_latents=bbox_latents,
            bbox_noise=bbox_noise,
            class_counts=class_counts,
        )

    def _generate(
        self,
        *,
        label_set: Float[torch.Tensor, "batch internal_labels"],
        condition_type: ConditionType | str,
        options: GenerationOptions,
        count_latents: Float[torch.Tensor, "batch internal_labels latent"] | None,
        bbox_latents: Float[torch.Tensor, "batch elements latent"] | None,
        bbox_noise: Float[torch.Tensor, "batch elements 4"] | None,
        class_counts: Float[torch.Tensor, "batch internal_labels"] | None,
    ) -> LayoutGenerationOutput | LayoutVAEOutputDict:
        _ = (
            options.bbox,
            options.labels,
            options.mask,
            options.num_elements,
            options.normalized,
            options.canvas_size,
            options.num_inference_steps,
        )
        normalize_box_format(options.box_format)
        canonical = normalize_condition_type(condition_type)
        if canonical is not ConditionType.label:
            raise ValueError(f"Unsupported condition_type for layoutvae: {canonical}")

        device = next(self.model.parameters()).device
        prepared_generator = self.prepare_generator(
            generator=options.generator,
            seed=options.seed,
            device=device,
        )
        out = self.model(
            label_set.to(device=device),
            count_latents=count_latents,
            bbox_latents=bbox_latents,
            bbox_noise=bbox_noise,
            class_counts=class_counts,
            generator=prepared_generator,
            return_dict=True,
        )
        assert isinstance(out, LayoutVAEModelOutput)
        intermediates = None
        if options.return_intermediates:
            intermediates = {
                "condition_type": canonical,
                "raw_ltwh": out.raw_ltwh.detach().cpu(),
                "internal_labels": out.internal_labels.detach().cpu()
                if out.internal_labels is not None
                else None,
                "class_counts": out.class_counts.detach().cpu(),
            }
        layout = LayoutGenerationOutput(
            bbox=out.bbox.detach().cpu(),
            labels=out.labels.detach().cpu(),
            mask=out.mask.detach().cpu(),
            id2label={
                int(k): v for k, v in cast(Id2Label, self.config.id2label).items()
            },
            intermediates=intermediates,
        )
        resolved_output_type = normalize_output_type(options.output_type)
        if resolved_output_type is OutputType.dict:
            return dict(layout)
        if resolved_output_type is OutputType.dataclass:
            return layout
        assert_never(resolved_output_type)

__init__

__init__(
    model: LayoutVAEModel,
    processor: LayoutVAEProcessor | None = None,
    config: LayoutVAEConfig | None = None,
    device: int | device | None = None,
    binary_output: bool = False,
) -> None

Initialize a LayoutVAE pipeline.

Source code in models/layoutvae/src/layoutvae/pipeline_layoutvae.py
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
def __init__(
    self,
    model: LayoutVAEModel,
    processor: LayoutVAEProcessor | None = None,
    config: LayoutVAEConfig | None = None,
    device: int | torch.device | None = None,
    binary_output: bool = False,
) -> None:
    """Initialize a LayoutVAE pipeline."""
    _ = binary_output
    super().__init__(config or model.config)
    self.config = config or model.config
    self.model = model
    self.processor = processor or LayoutVAEProcessor(
        dataset_name=model.config.dataset_name,
        id2label=model.config.id2label,
    )
    if device is not None:
        self.to(_resolve_device(device))

preprocess

preprocess(
    input_: list[list[str | int]]
    | list[str | int]
    | Int[Tensor, ...]
    | None = None,
    **preprocess_parameters: LayoutVAEParam,
) -> BatchEncoding

Encode labels into model inputs.

Source code in models/layoutvae/src/layoutvae/pipeline_layoutvae.py
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
def preprocess(
    self,
    input_: list[list[str | int]]
    | list[str | int]
    | Int[torch.Tensor, ...]
    | None = None,
    **preprocess_parameters: LayoutVAEParam,
) -> BatchEncoding:
    """Encode labels into model inputs."""
    labels = preprocess_parameters.pop("labels", input_)
    if labels is None:
        raise ValueError("labels are required for LayoutVAEPipeline")

    encoded = self.processor(
        cast(
            list[list[str | int]] | list[str | int] | Int[torch.Tensor, "..."],
            labels,
        )
    )
    encoded.update(preprocess_parameters)
    return encoded

postprocess

postprocess(
    model_outputs: LayoutGenerationOutput
    | LayoutVAEOutputDict,
    **kwargs: str | int | float | bool | None,
) -> LayoutGenerationOutput | LayoutVAEOutputDict

Return generated layouts unchanged.

Source code in models/layoutvae/src/layoutvae/pipeline_layoutvae.py
310
311
312
313
314
315
316
317
def postprocess(
    self,
    model_outputs: LayoutGenerationOutput | LayoutVAEOutputDict,
    **kwargs: str | int | float | bool | None,
) -> LayoutGenerationOutput | LayoutVAEOutputDict:
    """Return generated layouts unchanged."""
    del kwargs
    return model_outputs

__call__

__call__(
    labels: list[list[str | int]]
    | list[str | int]
    | Int[Tensor, ...]
    | None = None,
    *,
    batch_size: int = 1,
    seed: int | None = None,
    generator: Generator | None = None,
    condition_type: ConditionType
    | str = ConditionType.label,
    bbox: Float[Tensor, "batch elements 4"] | None = None,
    mask: Bool[Tensor, "batch elements"] | None = None,
    num_elements: int
    | list[int]
    | Int[Tensor, "batch"]
    | None = None,
    box_format: BoxFormat | str = BoxFormat.xywh,
    normalized: bool = True,
    canvas_size: tuple[int, int] | None = None,
    num_inference_steps: int | None = None,
    output_type: OutputType | str = OutputType.dataclass,
    return_intermediates: bool = False,
    count_latents: Float[
        Tensor, "batch internal_labels latent"
    ]
    | None = None,
    bbox_latents: Float[Tensor, "batch elements latent"]
    | None = None,
    bbox_noise: Float[Tensor, "batch elements 4"]
    | None = None,
    class_counts: Float[Tensor, "batch internal_labels"]
    | None = None,
) -> LayoutGenerationOutput | LayoutVAEOutputDict

Generate PubLayNet layouts from label conditions.

Parameters:

Name Type Description Default
labels list[list[str | int]] | list[str | int] | Int[Tensor, ...] | None

Public PubLayNet label strings or IDs.

None
batch_size int

Used when labels is omitted.

1
seed int | None

Optional random seed used when generator is absent.

None
generator Generator | None

Optional PyTorch random generator. Takes precedence.

None
condition_type ConditionType | str

Condition type or alias. Only label is supported.

label
bbox Float[Tensor, 'batch elements 4'] | None

Reserved compatibility argument.

None
mask Bool[Tensor, 'batch elements'] | None

Reserved compatibility argument.

None
num_elements int | list[int] | Int[Tensor, 'batch'] | None

Reserved compatibility argument.

None
box_format BoxFormat | str

Reserved compatibility argument.

xywh
normalized bool

Reserved compatibility argument.

True
canvas_size tuple[int, int] | None

Reserved compatibility argument.

None
num_inference_steps int | None

Reserved compatibility argument.

None
output_type OutputType | str

Return format.

dataclass
return_intermediates bool

Whether to include raw generation tensors.

False
count_latents Float[Tensor, 'batch internal_labels latent'] | None

Optional fixed count latents.

None
bbox_latents Float[Tensor, 'batch elements latent'] | None

Optional fixed box latents.

None
bbox_noise Float[Tensor, 'batch elements 4'] | None

Optional fixed box output noise.

None
class_counts Float[Tensor, 'batch internal_labels'] | None

Optional fixed class counts.

None

Returns:

Type Description
LayoutGenerationOutput | LayoutVAEOutputDict

Layout generation output.

Raises:

Type Description
ValueError

If labels are missing or condition options are unsupported.

Examples:

>>> pipe = LayoutVAEPipeline(LayoutVAEModel(LayoutVAEConfig()))
>>> out = pipe(labels=["text"], class_counts=torch.tensor([[8, 1, 0, 0, 0, 0.]]))
>>> tuple(out.bbox.shape)
(1, 9, 4)
Source code in models/layoutvae/src/layoutvae/pipeline_layoutvae.py
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
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
@torch.no_grad()
def __call__(
    self,
    labels: list[list[str | int]]
    | list[str | int]
    | Int[torch.Tensor, ...]
    | None = None,
    *,
    batch_size: int = 1,
    seed: int | None = None,
    generator: torch.Generator | None = None,
    condition_type: ConditionType | str = ConditionType.label,
    bbox: Float[torch.Tensor, "batch elements 4"] | None = None,
    mask: Bool[torch.Tensor, "batch elements"] | None = None,
    num_elements: int | list[int] | Int[torch.Tensor, "batch"] | None = None,
    box_format: BoxFormat | str = BoxFormat.xywh,
    normalized: bool = True,
    canvas_size: tuple[int, int] | None = None,
    num_inference_steps: int | None = None,
    output_type: OutputType | str = OutputType.dataclass,
    return_intermediates: bool = False,
    count_latents: Float[torch.Tensor, "batch internal_labels latent"]
    | None = None,
    bbox_latents: Float[torch.Tensor, "batch elements latent"] | None = None,
    bbox_noise: Float[torch.Tensor, "batch elements 4"] | None = None,
    class_counts: Float[torch.Tensor, "batch internal_labels"] | None = None,
) -> LayoutGenerationOutput | LayoutVAEOutputDict:  # ty: ignore[invalid-method-override]
    """Generate PubLayNet layouts from label conditions.

    Args:
        labels: Public PubLayNet label strings or IDs.
        batch_size: Used when `labels` is omitted.
        seed: Optional random seed used when `generator` is absent.
        generator: Optional PyTorch random generator. Takes precedence.
        condition_type: Condition type or alias. Only `label` is supported.
        bbox: Reserved compatibility argument.
        mask: Reserved compatibility argument.
        num_elements: Reserved compatibility argument.
        box_format: Reserved compatibility argument.
        normalized: Reserved compatibility argument.
        canvas_size: Reserved compatibility argument.
        num_inference_steps: Reserved compatibility argument.
        output_type: Return format.
        return_intermediates: Whether to include raw generation tensors.
        count_latents: Optional fixed count latents.
        bbox_latents: Optional fixed box latents.
        bbox_noise: Optional fixed box output noise.
        class_counts: Optional fixed class counts.

    Returns:
        Layout generation output.

    Raises:
        ValueError: If labels are missing or condition options are unsupported.

    Examples:
        >>> pipe = LayoutVAEPipeline(LayoutVAEModel(LayoutVAEConfig()))
        >>> out = pipe(labels=["text"], class_counts=torch.tensor([[8, 1, 0, 0, 0, 0.]]))
        >>> tuple(out.bbox.shape)
        (1, 9, 4)
    """
    if labels is None:
        if batch_size < 1:
            raise ValueError("batch_size must be positive")

        labels = [["text"] for _ in range(batch_size)]
    encoded = self.processor(labels)

    option_kwargs: GenerationOptionsKwargs = {}
    option_kwargs["bbox"] = bbox
    option_kwargs["mask"] = mask
    option_kwargs["num_elements"] = num_elements
    option_kwargs["box_format"] = box_format
    option_kwargs["normalized"] = normalized
    option_kwargs["canvas_size"] = canvas_size
    option_kwargs["seed"] = seed
    option_kwargs["generator"] = generator
    option_kwargs["num_inference_steps"] = num_inference_steps
    option_kwargs["output_type"] = output_type
    option_kwargs["return_intermediates"] = return_intermediates

    options = _make_generation_options(option_kwargs)

    return self._generate(
        label_set=cast(
            Float[torch.Tensor, "batch internal_labels"], encoded["label_set"]
        ),
        condition_type=condition_type,
        options=options,
        count_latents=count_latents,
        bbox_latents=bbox_latents,
        bbox_noise=bbox_noise,
        class_counts=class_counts,
    )

processing_layoutvae

Processor for LayoutVAE label-set encoding and layout decoding.

DecodedLayoutRecord

Bases: TypedDict

One decoded LayoutVAE record.

Source code in models/layoutvae/src/layoutvae/processing_layoutvae.py
20
21
22
23
24
25
class DecodedLayoutRecord(TypedDict):
    """One decoded LayoutVAE record."""

    label: str
    label_id: int
    bbox: list[float]

LayoutVAEProcessor

Bases: ProcessorMixin

Encode PubLayNet labels into LayoutVAE label sets.

Parameters:

Name Type Description Default
dataset_name DatasetName | str

Dataset key. The first release supports PubLayNet.

publaynet
id2label Id2LabelMapping | None

Optional public ID-to-label mapping.

None

Raises:

Type Description
ValueError

If the dataset is unsupported.

Examples:

>>> processor = LayoutVAEProcessor()
>>> processor.label2id["text"]
0
Source code in models/layoutvae/src/layoutvae/processing_layoutvae.py
 28
 29
 30
 31
 32
 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
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
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
class LayoutVAEProcessor(ProcessorMixin):
    """Encode PubLayNet labels into LayoutVAE label sets.

    Args:
        dataset_name: Dataset key. The first release supports PubLayNet.
        id2label: Optional public ID-to-label mapping.

    Raises:
        ValueError: If the dataset is unsupported.

    Examples:
        >>> processor = LayoutVAEProcessor()
        >>> processor.label2id["text"]
        0
    """

    config_name = "preprocessor_config.json"

    def __init__(
        self,
        dataset_name: DatasetName | str = DatasetName.publaynet,
        id2label: Id2LabelMapping | None = None,
    ) -> None:
        """Initialize the processor.

        Args:
            dataset_name: Dataset key. The first release supports PubLayNet.
            id2label: Optional public ID-to-label mapping.

        Raises:
            ValueError: If the dataset is unsupported.

        Examples:
            >>> LayoutVAEProcessor("publaynet").id2label[4]
            'figure'
        """
        self.chat_template = None
        canonical_dataset = normalize_dataset_name(dataset_name)
        if canonical_dataset is not DatasetName.publaynet:
            raise ValueError("LayoutVAEProcessor supports only PubLayNet")

        self.dataset_name = str(canonical_dataset)
        raw_id2label = id2label or id2label_for_dataset(canonical_dataset)
        self.id2label = {int(k): v for k, v in raw_id2label.items()}
        self.label2id = label2id_for_dataset(canonical_dataset)
        self.internal_id2label = {
            INTERNAL_EMPTY_LABEL_ID: "None",
            **{index + 1: label for index, label in self.id2label.items()},
        }

    def __call__(
        self,
        labels: list[list[str | int]] | list[str | int] | Int[torch.Tensor, "..."],
        *,
        return_tensors: Literal["pt"] = "pt",
    ) -> BatchEncoding:
        """Encode public labels as a six-way label-set tensor.

        Args:
            labels: Public label names or IDs. A flat list is treated as one row.
            return_tensors: Tensor framework. Only `pt` is supported.

        Returns:
            Batch encoding with `label_set`.

        Raises:
            ValueError: If labels are empty, unknown, or tensors are unsupported.

        Examples:
            >>> encoded = LayoutVAEProcessor()(["text", "figure"])
            >>> encoded["label_set"].tolist()
            [[0.0, 1.0, 0.0, 0.0, 0.0, 1.0]]
        """
        if return_tensors != "pt":
            raise ValueError("LayoutVAEProcessor only supports return_tensors='pt'")

        rows = self._normalize_rows(labels)
        label_set = torch.zeros(
            len(rows), len(self.internal_id2label), dtype=torch.float32
        )
        for row_index, row in enumerate(rows):
            for label in row:
                public_id = self._label_to_id(label)
                label_set[row_index, public_id + 1] = 1.0
        return BatchEncoding({"label_set": label_set})

    def public_from_internal(
        self,
        internal_labels: Int[torch.Tensor, "batch elements"],
    ) -> tuple[
        Int[torch.Tensor, "batch elements"], Bool[torch.Tensor, "batch elements"]
    ]:
        """Map six-way labels to public labels and validity masks.

        Args:
            internal_labels: Internal label IDs where zero marks empty slots.

        Returns:
            Public label IDs and mask tensors.

        Examples:
            >>> processor = LayoutVAEProcessor()
            >>> labels, mask = processor.public_from_internal(torch.tensor([[0, 1, 5]]))
            >>> labels.tolist(), mask.tolist()
            ([[0, 0, 4]], [[False, True, True]])
        """
        labels = torch.clamp(internal_labels.to(dtype=torch.long) - 1, min=0)
        mask = internal_labels.to(dtype=torch.long) != INTERNAL_EMPTY_LABEL_ID
        return labels, mask

    def batch_decode(
        self,
        bbox: Float[torch.Tensor, "batch elements 4"],
        labels: Int[torch.Tensor, "batch elements"],
        mask: Bool[torch.Tensor, "batch elements"] | None = None,
    ) -> list[list[DecodedLayoutRecord]]:
        """Decode layout tensors into records.

        Args:
            bbox: Public normalized center `xywh` boxes.
            labels: Public label IDs.
            mask: Optional valid-element mask.

        Returns:
            Nested records with label text, label ID, and box coordinates.

        Raises:
            KeyError: If a public label ID is unknown.

        Examples:
            >>> records = LayoutVAEProcessor().batch_decode(
            ...     torch.zeros(1, 1, 4), torch.tensor([[0]])
            ... )
            >>> records[0][0]["label"]
            'text'
        """
        bbox_t = torch.as_tensor(bbox, dtype=torch.float32)
        labels_t = torch.as_tensor(labels, dtype=torch.long)
        labels_t, bbox_t = self._ensure_batched(labels_t, bbox_t)
        mask_t = self._prepare_mask(mask, labels_t.shape)
        records: list[list[DecodedLayoutRecord]] = []
        for boxes, ids, valid in zip(bbox_t, labels_t, mask_t, strict=True):
            row: list[DecodedLayoutRecord] = []
            for box, label_id in zip(boxes[valid], ids[valid], strict=True):
                idx = int(label_id.item())
                row.append(
                    {
                        "label": self.id2label[idx],
                        "label_id": idx,
                        "bbox": box.tolist(),
                    }
                )
            records.append(row)
        return records

    def _ensure_batched(
        self, labels: Int[torch.Tensor, "..."], bbox: Float[torch.Tensor, "... 4"]
    ) -> tuple[
        Int[torch.Tensor, "batch elements"], Float[torch.Tensor, "batch elements 4"]
    ]:
        if labels.ndim != 1:
            return labels, bbox
        return labels.unsqueeze(0), bbox.unsqueeze(0)

    def _prepare_mask(
        self,
        mask: Bool[torch.Tensor, "batch elements"] | None,
        shape: torch.Size,
    ) -> Bool[torch.Tensor, "batch elements"]:
        if mask is None:
            return torch.ones(shape, dtype=torch.bool)
        mask_t = torch.as_tensor(mask, dtype=torch.bool)
        return mask_t.unsqueeze(0) if mask_t.ndim == 1 else mask_t

    def _normalize_rows(
        self,
        labels: list[list[str | int]] | list[str | int] | Int[torch.Tensor, "..."],
    ) -> list[list[str | int]]:
        if isinstance(labels, torch.Tensor):
            if labels.ndim == 0 or labels.ndim > 2:
                raise ValueError("labels tensor must have one or two dimensions")

            if labels.ndim == 1:
                return [[int(value) for value in labels.tolist()]]
            return [[int(value) for value in row] for row in labels.tolist()]
        if not labels:
            raise ValueError("labels must not be empty")

        contains_rows = [isinstance(item, list) for item in labels]
        if any(contains_rows) and not all(contains_rows):
            raise ValueError("labels must be a flat list or list of rows")

        if all(contains_rows):
            return [list(row) for row in cast(list[list[str | int]], labels)]
        return [list(cast(list[str | int], labels))]

    def _label_to_id(self, label: str | int) -> int:
        if not isinstance(label, int):
            if label in self.label2id:
                return self.label2id[label]
            raise ValueError(f"Unknown label: {label}")

        if 0 <= label < len(self.id2label):
            return label
        raise ValueError(f"Unknown label id: {label}")

__init__

__init__(
    dataset_name: DatasetName | str = DatasetName.publaynet,
    id2label: Id2LabelMapping | None = None,
) -> None

Initialize the processor.

Parameters:

Name Type Description Default
dataset_name DatasetName | str

Dataset key. The first release supports PubLayNet.

publaynet
id2label Id2LabelMapping | None

Optional public ID-to-label mapping.

None

Raises:

Type Description
ValueError

If the dataset is unsupported.

Examples:

>>> LayoutVAEProcessor("publaynet").id2label[4]
'figure'
Source code in models/layoutvae/src/layoutvae/processing_layoutvae.py
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
def __init__(
    self,
    dataset_name: DatasetName | str = DatasetName.publaynet,
    id2label: Id2LabelMapping | None = None,
) -> None:
    """Initialize the processor.

    Args:
        dataset_name: Dataset key. The first release supports PubLayNet.
        id2label: Optional public ID-to-label mapping.

    Raises:
        ValueError: If the dataset is unsupported.

    Examples:
        >>> LayoutVAEProcessor("publaynet").id2label[4]
        'figure'
    """
    self.chat_template = None
    canonical_dataset = normalize_dataset_name(dataset_name)
    if canonical_dataset is not DatasetName.publaynet:
        raise ValueError("LayoutVAEProcessor supports only PubLayNet")

    self.dataset_name = str(canonical_dataset)
    raw_id2label = id2label or id2label_for_dataset(canonical_dataset)
    self.id2label = {int(k): v for k, v in raw_id2label.items()}
    self.label2id = label2id_for_dataset(canonical_dataset)
    self.internal_id2label = {
        INTERNAL_EMPTY_LABEL_ID: "None",
        **{index + 1: label for index, label in self.id2label.items()},
    }

__call__

__call__(
    labels: list[list[str | int]]
    | list[str | int]
    | Int[Tensor, "..."],
    *,
    return_tensors: Literal["pt"] = "pt",
) -> BatchEncoding

Encode public labels as a six-way label-set tensor.

Parameters:

Name Type Description Default
labels list[list[str | int]] | list[str | int] | Int[Tensor, '...']

Public label names or IDs. A flat list is treated as one row.

required
return_tensors Literal['pt']

Tensor framework. Only pt is supported.

'pt'

Returns:

Type Description
BatchEncoding

Batch encoding with label_set.

Raises:

Type Description
ValueError

If labels are empty, unknown, or tensors are unsupported.

Examples:

>>> encoded = LayoutVAEProcessor()(["text", "figure"])
>>> encoded["label_set"].tolist()
[[0.0, 1.0, 0.0, 0.0, 0.0, 1.0]]
Source code in models/layoutvae/src/layoutvae/processing_layoutvae.py
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
def __call__(
    self,
    labels: list[list[str | int]] | list[str | int] | Int[torch.Tensor, "..."],
    *,
    return_tensors: Literal["pt"] = "pt",
) -> BatchEncoding:
    """Encode public labels as a six-way label-set tensor.

    Args:
        labels: Public label names or IDs. A flat list is treated as one row.
        return_tensors: Tensor framework. Only `pt` is supported.

    Returns:
        Batch encoding with `label_set`.

    Raises:
        ValueError: If labels are empty, unknown, or tensors are unsupported.

    Examples:
        >>> encoded = LayoutVAEProcessor()(["text", "figure"])
        >>> encoded["label_set"].tolist()
        [[0.0, 1.0, 0.0, 0.0, 0.0, 1.0]]
    """
    if return_tensors != "pt":
        raise ValueError("LayoutVAEProcessor only supports return_tensors='pt'")

    rows = self._normalize_rows(labels)
    label_set = torch.zeros(
        len(rows), len(self.internal_id2label), dtype=torch.float32
    )
    for row_index, row in enumerate(rows):
        for label in row:
            public_id = self._label_to_id(label)
            label_set[row_index, public_id + 1] = 1.0
    return BatchEncoding({"label_set": label_set})

public_from_internal

public_from_internal(
    internal_labels: Int[Tensor, "batch elements"],
) -> tuple[
    Int[torch.Tensor, "batch elements"],
    Bool[torch.Tensor, "batch elements"],
]

Map six-way labels to public labels and validity masks.

Parameters:

Name Type Description Default
internal_labels Int[Tensor, 'batch elements']

Internal label IDs where zero marks empty slots.

required

Returns:

Type Description
tuple[Int[Tensor, 'batch elements'], Bool[Tensor, 'batch elements']]

Public label IDs and mask tensors.

Examples:

>>> processor = LayoutVAEProcessor()
>>> labels, mask = processor.public_from_internal(torch.tensor([[0, 1, 5]]))
>>> labels.tolist(), mask.tolist()
([[0, 0, 4]], [[False, True, True]])
Source code in models/layoutvae/src/layoutvae/processing_layoutvae.py
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
def public_from_internal(
    self,
    internal_labels: Int[torch.Tensor, "batch elements"],
) -> tuple[
    Int[torch.Tensor, "batch elements"], Bool[torch.Tensor, "batch elements"]
]:
    """Map six-way labels to public labels and validity masks.

    Args:
        internal_labels: Internal label IDs where zero marks empty slots.

    Returns:
        Public label IDs and mask tensors.

    Examples:
        >>> processor = LayoutVAEProcessor()
        >>> labels, mask = processor.public_from_internal(torch.tensor([[0, 1, 5]]))
        >>> labels.tolist(), mask.tolist()
        ([[0, 0, 4]], [[False, True, True]])
    """
    labels = torch.clamp(internal_labels.to(dtype=torch.long) - 1, min=0)
    mask = internal_labels.to(dtype=torch.long) != INTERNAL_EMPTY_LABEL_ID
    return labels, mask

batch_decode

batch_decode(
    bbox: Float[Tensor, "batch elements 4"],
    labels: Int[Tensor, "batch elements"],
    mask: Bool[Tensor, "batch elements"] | None = None,
) -> list[list[DecodedLayoutRecord]]

Decode layout tensors into records.

Parameters:

Name Type Description Default
bbox Float[Tensor, 'batch elements 4']

Public normalized center xywh boxes.

required
labels Int[Tensor, 'batch elements']

Public label IDs.

required
mask Bool[Tensor, 'batch elements'] | None

Optional valid-element mask.

None

Returns:

Type Description
list[list[DecodedLayoutRecord]]

Nested records with label text, label ID, and box coordinates.

Raises:

Type Description
KeyError

If a public label ID is unknown.

Examples:

>>> records = LayoutVAEProcessor().batch_decode(
...     torch.zeros(1, 1, 4), torch.tensor([[0]])
... )
>>> records[0][0]["label"]
'text'
Source code in models/layoutvae/src/layoutvae/processing_layoutvae.py
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
def batch_decode(
    self,
    bbox: Float[torch.Tensor, "batch elements 4"],
    labels: Int[torch.Tensor, "batch elements"],
    mask: Bool[torch.Tensor, "batch elements"] | None = None,
) -> list[list[DecodedLayoutRecord]]:
    """Decode layout tensors into records.

    Args:
        bbox: Public normalized center `xywh` boxes.
        labels: Public label IDs.
        mask: Optional valid-element mask.

    Returns:
        Nested records with label text, label ID, and box coordinates.

    Raises:
        KeyError: If a public label ID is unknown.

    Examples:
        >>> records = LayoutVAEProcessor().batch_decode(
        ...     torch.zeros(1, 1, 4), torch.tensor([[0]])
        ... )
        >>> records[0][0]["label"]
        'text'
    """
    bbox_t = torch.as_tensor(bbox, dtype=torch.float32)
    labels_t = torch.as_tensor(labels, dtype=torch.long)
    labels_t, bbox_t = self._ensure_batched(labels_t, bbox_t)
    mask_t = self._prepare_mask(mask, labels_t.shape)
    records: list[list[DecodedLayoutRecord]] = []
    for boxes, ids, valid in zip(bbox_t, labels_t, mask_t, strict=True):
        row: list[DecodedLayoutRecord] = []
        for box, label_id in zip(boxes[valid], ids[valid], strict=True):
            idx = int(label_id.item())
            row.append(
                {
                    "label": self.id2label[idx],
                    "label_id": idx,
                    "bbox": box.tolist(),
                }
            )
        records.append(row)
    return records