Skip to content

Layout corrector

Public Layout-Corrector pipeline, model, config, and sampling exports.

CorrectorPositionEmbedding

Bases: StrEnum

Supported original position-embedding modes.

Source code in models/layout-corrector/src/layout_corrector/configuration_layout_corrector.py
35
36
37
38
39
40
41
42
class CorrectorPositionEmbedding(StrEnum):
    """Supported original position-embedding modes."""

    default = auto()
    none = auto()
    pos_enc = auto()
    shuffle_pos_enc = auto()
    shuffle = auto()

CorrectorReconType

Bases: StrEnum

Supported Layout-Corrector reconstruction targets.

Source code in models/layout-corrector/src/layout_corrector/configuration_layout_corrector.py
21
22
23
24
25
class CorrectorReconType(StrEnum):
    """Supported Layout-Corrector reconstruction targets."""

    x_0 = auto()
    x_t_minus_1 = "x_t-1"

CorrectorTarget

Bases: StrEnum

Supported Layout-Corrector confidence targets.

Source code in models/layout-corrector/src/layout_corrector/configuration_layout_corrector.py
28
29
30
31
32
class CorrectorTarget(StrEnum):
    """Supported Layout-Corrector confidence targets."""

    mask = auto()
    recon_acc = auto()

CorrectorTransformerType

Bases: StrEnum

Supported corrector transformer variants.

Source code in models/layout-corrector/src/layout_corrector/configuration_layout_corrector.py
45
46
47
48
class CorrectorTransformerType(StrEnum):
    """Supported corrector transformer variants."""

    aggregated = auto()

LayoutCorrectorConfig

Bases: ConfigMixin

Configuration for the Layout-Corrector transformer.

Parameters:

Name Type Description Default
dataset_name DatasetName | str

Dataset key or alias used for labels.

required
vocab_size int

LayoutDM vocabulary size expected by the corrector.

required
id2label dict[int | str, str] | None

Optional class-id mapping. When omitted, the shared registry is used.

None
max_seq_length int

Maximum number of layout elements.

25
num_attributes_per_element int

Number of token attributes per element.

5
hidden_size int

Transformer hidden dimension.

464
num_attention_heads int

Number of attention heads.

8
num_hidden_layers int

Number of transformer layers.

4
intermediate_size int

Feed-forward hidden dimension.

1856
dropout float

Dropout probability.

0.0
timestep_type str | None

Timestep conditioning type.

'adalayernorm'
num_timesteps int

Number of diffusion training timesteps.

100
recon_type CorrectorReconType | str

Reconstruction target used by the corrector.

x_t_minus_1
target CorrectorTarget | str

Confidence target type.

recon_acc
attr_loss_weights tuple[float, float, float, float, float]

Per-attribute loss weights.

(1.0, 1.0, 1.0, 1.0, 1.0)
use_padding_as_vocab bool

Whether padding is part of the modeled vocabulary.

True
pos_emb CorrectorPositionEmbedding | str

Position embedding mode from the original implementation.

none
transformer_type CorrectorTransformerType | str

Corrector transformer variant.

aggregated
corrector_steps int

Number of correction passes per selected timestep.

1
corrector_t_list tuple[int, ...]

Explicit timesteps where the corrector is applied.

(10, 20, 30)
corrector_mask_mode CorrectorMaskMode | str

Strategy for selecting tokens to remask.

thresh
corrector_mask_threshold float

Confidence threshold for threshold masking.

0.7
corrector_temperature float

Temperature used for corrector resampling.

1.0
use_gumbel_noise bool

Whether to perturb confidence logits.

True
gumbel_temperature float

Temperature for confidence Gumbel noise.

1.0
time_adaptive_temperature bool

Whether to scale noise by timestep ratio.

False

Raises:

Type Description
ValueError

If a supplied dataset, shape, or option is unsupported.

Examples:

>>> cfg = LayoutCorrectorConfig(dataset_name="publaynet", vocab_size=100)
>>> cfg.max_token_length
125
Source code in models/layout-corrector/src/layout_corrector/configuration_layout_corrector.py
 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
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
class LayoutCorrectorConfig(ConfigMixin):
    """Configuration for the Layout-Corrector transformer.

    Args:
        dataset_name: Dataset key or alias used for labels.
        vocab_size: LayoutDM vocabulary size expected by the corrector.
        id2label: Optional class-id mapping. When omitted, the shared registry is used.
        max_seq_length: Maximum number of layout elements.
        num_attributes_per_element: Number of token attributes per element.
        hidden_size: Transformer hidden dimension.
        num_attention_heads: Number of attention heads.
        num_hidden_layers: Number of transformer layers.
        intermediate_size: Feed-forward hidden dimension.
        dropout: Dropout probability.
        timestep_type: Timestep conditioning type.
        num_timesteps: Number of diffusion training timesteps.
        recon_type: Reconstruction target used by the corrector.
        target: Confidence target type.
        attr_loss_weights: Per-attribute loss weights.
        use_padding_as_vocab: Whether padding is part of the modeled vocabulary.
        pos_emb: Position embedding mode from the original implementation.
        transformer_type: Corrector transformer variant.
        corrector_steps: Number of correction passes per selected timestep.
        corrector_t_list: Explicit timesteps where the corrector is applied.
        corrector_mask_mode: Strategy for selecting tokens to remask.
        corrector_mask_threshold: Confidence threshold for threshold masking.
        corrector_temperature: Temperature used for corrector resampling.
        use_gumbel_noise: Whether to perturb confidence logits.
        gumbel_temperature: Temperature for confidence Gumbel noise.
        time_adaptive_temperature: Whether to scale noise by timestep ratio.

    Raises:
        ValueError: If a supplied dataset, shape, or option is unsupported.

    Examples:
        >>> cfg = LayoutCorrectorConfig(dataset_name="publaynet", vocab_size=100)
        >>> cfg.max_token_length
        125
    """

    config_name = "corrector_config.json"

    @register_to_config
    def __init__(
        self,
        *,
        dataset_name: DatasetName | str,
        vocab_size: int,
        id2label: dict[int | str, str] | None = None,
        max_seq_length: int = 25,
        num_attributes_per_element: int = 5,
        hidden_size: int = 464,
        num_attention_heads: int = 8,
        num_hidden_layers: int = 4,
        intermediate_size: int = 1856,
        dropout: float = 0.0,
        timestep_type: str | None = "adalayernorm",
        num_timesteps: int = 100,
        recon_type: CorrectorReconType | str = CorrectorReconType.x_t_minus_1,
        target: CorrectorTarget | str = CorrectorTarget.recon_acc,
        attr_loss_weights: tuple[float, float, float, float, float] = (
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
        ),
        use_padding_as_vocab: bool = True,
        pos_emb: CorrectorPositionEmbedding | str = CorrectorPositionEmbedding.none,
        transformer_type: CorrectorTransformerType | str = (
            CorrectorTransformerType.aggregated
        ),
        corrector_steps: int = 1,
        corrector_t_list: tuple[int, ...] = (10, 20, 30),
        corrector_mask_mode: CorrectorMaskMode | str = CorrectorMaskMode.thresh,
        corrector_mask_threshold: float = 0.7,
        corrector_temperature: float = 1.0,
        use_gumbel_noise: bool = True,
        gumbel_temperature: float = 1.0,
        time_adaptive_temperature: bool = False,
    ) -> None:
        """Initialize a Layout-Corrector config.

        Args:
            dataset_name: Dataset key or alias used for labels.
            vocab_size: LayoutDM vocabulary size expected by the corrector.
            id2label: Optional class-id mapping.
            max_seq_length: Maximum number of layout elements.
            num_attributes_per_element: Number of token attributes per element.
            hidden_size: Transformer hidden dimension.
            num_attention_heads: Number of attention heads.
            num_hidden_layers: Number of transformer layers.
            intermediate_size: Feed-forward hidden dimension.
            dropout: Dropout probability.
            timestep_type: Timestep conditioning type.
            num_timesteps: Number of diffusion training timesteps.
            recon_type: Reconstruction target used by the corrector.
            target: Confidence target type.
            attr_loss_weights: Per-attribute loss weights.
            use_padding_as_vocab: Whether padding is part of the modeled vocabulary.
            pos_emb: Position embedding mode.
            transformer_type: Corrector transformer variant.
            corrector_steps: Number of correction passes per selected timestep.
            corrector_t_list: Explicit timesteps where the corrector is applied.
            corrector_mask_mode: Strategy for selecting tokens to remask.
            corrector_mask_threshold: Confidence threshold for threshold masking.
            corrector_temperature: Temperature used for corrector resampling.
            use_gumbel_noise: Whether to perturb confidence logits.
            gumbel_temperature: Temperature for confidence Gumbel noise.
            time_adaptive_temperature: Whether to scale noise by timestep ratio.

        Raises:
            ValueError: If a supplied dataset, shape, or option is unsupported.

        Examples:
            >>> cfg = LayoutCorrectorConfig(dataset_name="publaynet", vocab_size=100)
            >>> cfg.max_token_length
            125
        """
        try:
            dataset_name = str(normalize_dataset_name(dataset_name))
        except ValueError:
            if id2label is None:
                raise

            dataset_name = str(dataset_name)
        self.register_to_config(dataset_name=dataset_name)
        if vocab_size <= 0:
            raise ValueError("vocab_size must be positive")

        if max_seq_length <= 0:
            raise ValueError("max_seq_length must be positive")

        if num_attributes_per_element != 5:
            raise ValueError("Layout-Corrector supports 5 attributes per element")

        if num_timesteps <= 0:
            raise ValueError("num_timesteps must be positive")

        recon_type, target, transformer_type, pos_emb = (
            normalize_corrector_core_options(
                recon_type,
                target,
                transformer_type,
                pos_emb,
            )
        )
        if len(attr_loss_weights) != num_attributes_per_element:
            raise ValueError("attr_loss_weights must match num_attributes_per_element")

        if corrector_steps <= 0:
            raise ValueError("corrector_steps must be positive")

        try:
            corrector_mask_mode = normalize_corrector_mask_mode(corrector_mask_mode)
        except ValueError as exc:
            raise ValueError(
                f"Unsupported corrector_mask_mode: {corrector_mask_mode}"
            ) from exc

        if not 0.0 <= corrector_mask_threshold <= 1.0:
            raise ValueError("corrector_mask_threshold must be in [0, 1]")

        self.register_to_config(
            dataset_name=dataset_name,
            recon_type=str(recon_type),
            target=str(target),
            pos_emb=str(pos_emb),
            transformer_type=str(transformer_type),
            corrector_mask_mode=str(corrector_mask_mode),
        )

        self.dataset_name = dataset_name
        raw_id2label = id2label or id2label_for_dataset(dataset_name)
        self.id2label = {int(k): v for k, v in raw_id2label.items()}
        self.vocab_size = vocab_size
        self.max_seq_length = max_seq_length
        self.num_attributes_per_element = num_attributes_per_element
        self.hidden_size = hidden_size
        self.num_attention_heads = num_attention_heads
        self.num_hidden_layers = num_hidden_layers
        self.intermediate_size = intermediate_size
        self.dropout = dropout
        self.timestep_type = timestep_type
        self.num_timesteps = num_timesteps

        self.recon_type = str(recon_type)
        self.target = str(target)
        self.attr_loss_weights = tuple(float(v) for v in attr_loss_weights)
        self.use_padding_as_vocab = use_padding_as_vocab
        self.pos_emb = str(pos_emb)
        self.transformer_type = str(transformer_type)

        self.corrector_steps = corrector_steps
        self.corrector_t_list = tuple(int(v) for v in corrector_t_list)
        self.corrector_mask_mode = str(corrector_mask_mode)
        self.corrector_mask_threshold = corrector_mask_threshold
        self.corrector_temperature = corrector_temperature
        self.use_gumbel_noise = use_gumbel_noise
        self.gumbel_temperature = gumbel_temperature
        self.time_adaptive_temperature = time_adaptive_temperature

    @property
    def max_token_length(self) -> int:
        """Return the flattened token length for one layout sequence.

        Returns:
            Maximum token count after flattening element attributes.

        Examples:
            >>> LayoutCorrectorConfig(dataset_name="publaynet", vocab_size=100).max_token_length
            125
        """
        return self.max_seq_length * self.num_attributes_per_element

max_token_length property

max_token_length: int

Return the flattened token length for one layout sequence.

Returns:

Type Description
int

Maximum token count after flattening element attributes.

Examples:

>>> LayoutCorrectorConfig(dataset_name="publaynet", vocab_size=100).max_token_length
125

__init__

__init__(
    *,
    dataset_name: DatasetName | str,
    vocab_size: int,
    id2label: dict[int | str, str] | None = None,
    max_seq_length: int = 25,
    num_attributes_per_element: int = 5,
    hidden_size: int = 464,
    num_attention_heads: int = 8,
    num_hidden_layers: int = 4,
    intermediate_size: int = 1856,
    dropout: float = 0.0,
    timestep_type: str | None = "adalayernorm",
    num_timesteps: int = 100,
    recon_type: CorrectorReconType
    | str = CorrectorReconType.x_t_minus_1,
    target: CorrectorTarget
    | str = CorrectorTarget.recon_acc,
    attr_loss_weights: tuple[
        float, float, float, float, float
    ] = (1.0, 1.0, 1.0, 1.0, 1.0),
    use_padding_as_vocab: bool = True,
    pos_emb: CorrectorPositionEmbedding
    | str = CorrectorPositionEmbedding.none,
    transformer_type: CorrectorTransformerType
    | str = CorrectorTransformerType.aggregated,
    corrector_steps: int = 1,
    corrector_t_list: tuple[int, ...] = (10, 20, 30),
    corrector_mask_mode: CorrectorMaskMode
    | str = CorrectorMaskMode.thresh,
    corrector_mask_threshold: float = 0.7,
    corrector_temperature: float = 1.0,
    use_gumbel_noise: bool = True,
    gumbel_temperature: float = 1.0,
    time_adaptive_temperature: bool = False,
) -> None

Initialize a Layout-Corrector config.

Parameters:

Name Type Description Default
dataset_name DatasetName | str

Dataset key or alias used for labels.

required
vocab_size int

LayoutDM vocabulary size expected by the corrector.

required
id2label dict[int | str, str] | None

Optional class-id mapping.

None
max_seq_length int

Maximum number of layout elements.

25
num_attributes_per_element int

Number of token attributes per element.

5
hidden_size int

Transformer hidden dimension.

464
num_attention_heads int

Number of attention heads.

8
num_hidden_layers int

Number of transformer layers.

4
intermediate_size int

Feed-forward hidden dimension.

1856
dropout float

Dropout probability.

0.0
timestep_type str | None

Timestep conditioning type.

'adalayernorm'
num_timesteps int

Number of diffusion training timesteps.

100
recon_type CorrectorReconType | str

Reconstruction target used by the corrector.

x_t_minus_1
target CorrectorTarget | str

Confidence target type.

recon_acc
attr_loss_weights tuple[float, float, float, float, float]

Per-attribute loss weights.

(1.0, 1.0, 1.0, 1.0, 1.0)
use_padding_as_vocab bool

Whether padding is part of the modeled vocabulary.

True
pos_emb CorrectorPositionEmbedding | str

Position embedding mode.

none
transformer_type CorrectorTransformerType | str

Corrector transformer variant.

aggregated
corrector_steps int

Number of correction passes per selected timestep.

1
corrector_t_list tuple[int, ...]

Explicit timesteps where the corrector is applied.

(10, 20, 30)
corrector_mask_mode CorrectorMaskMode | str

Strategy for selecting tokens to remask.

thresh
corrector_mask_threshold float

Confidence threshold for threshold masking.

0.7
corrector_temperature float

Temperature used for corrector resampling.

1.0
use_gumbel_noise bool

Whether to perturb confidence logits.

True
gumbel_temperature float

Temperature for confidence Gumbel noise.

1.0
time_adaptive_temperature bool

Whether to scale noise by timestep ratio.

False

Raises:

Type Description
ValueError

If a supplied dataset, shape, or option is unsupported.

Examples:

>>> cfg = LayoutCorrectorConfig(dataset_name="publaynet", vocab_size=100)
>>> cfg.max_token_length
125
Source code in models/layout-corrector/src/layout_corrector/configuration_layout_corrector.py
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
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
@register_to_config
def __init__(
    self,
    *,
    dataset_name: DatasetName | str,
    vocab_size: int,
    id2label: dict[int | str, str] | None = None,
    max_seq_length: int = 25,
    num_attributes_per_element: int = 5,
    hidden_size: int = 464,
    num_attention_heads: int = 8,
    num_hidden_layers: int = 4,
    intermediate_size: int = 1856,
    dropout: float = 0.0,
    timestep_type: str | None = "adalayernorm",
    num_timesteps: int = 100,
    recon_type: CorrectorReconType | str = CorrectorReconType.x_t_minus_1,
    target: CorrectorTarget | str = CorrectorTarget.recon_acc,
    attr_loss_weights: tuple[float, float, float, float, float] = (
        1.0,
        1.0,
        1.0,
        1.0,
        1.0,
    ),
    use_padding_as_vocab: bool = True,
    pos_emb: CorrectorPositionEmbedding | str = CorrectorPositionEmbedding.none,
    transformer_type: CorrectorTransformerType | str = (
        CorrectorTransformerType.aggregated
    ),
    corrector_steps: int = 1,
    corrector_t_list: tuple[int, ...] = (10, 20, 30),
    corrector_mask_mode: CorrectorMaskMode | str = CorrectorMaskMode.thresh,
    corrector_mask_threshold: float = 0.7,
    corrector_temperature: float = 1.0,
    use_gumbel_noise: bool = True,
    gumbel_temperature: float = 1.0,
    time_adaptive_temperature: bool = False,
) -> None:
    """Initialize a Layout-Corrector config.

    Args:
        dataset_name: Dataset key or alias used for labels.
        vocab_size: LayoutDM vocabulary size expected by the corrector.
        id2label: Optional class-id mapping.
        max_seq_length: Maximum number of layout elements.
        num_attributes_per_element: Number of token attributes per element.
        hidden_size: Transformer hidden dimension.
        num_attention_heads: Number of attention heads.
        num_hidden_layers: Number of transformer layers.
        intermediate_size: Feed-forward hidden dimension.
        dropout: Dropout probability.
        timestep_type: Timestep conditioning type.
        num_timesteps: Number of diffusion training timesteps.
        recon_type: Reconstruction target used by the corrector.
        target: Confidence target type.
        attr_loss_weights: Per-attribute loss weights.
        use_padding_as_vocab: Whether padding is part of the modeled vocabulary.
        pos_emb: Position embedding mode.
        transformer_type: Corrector transformer variant.
        corrector_steps: Number of correction passes per selected timestep.
        corrector_t_list: Explicit timesteps where the corrector is applied.
        corrector_mask_mode: Strategy for selecting tokens to remask.
        corrector_mask_threshold: Confidence threshold for threshold masking.
        corrector_temperature: Temperature used for corrector resampling.
        use_gumbel_noise: Whether to perturb confidence logits.
        gumbel_temperature: Temperature for confidence Gumbel noise.
        time_adaptive_temperature: Whether to scale noise by timestep ratio.

    Raises:
        ValueError: If a supplied dataset, shape, or option is unsupported.

    Examples:
        >>> cfg = LayoutCorrectorConfig(dataset_name="publaynet", vocab_size=100)
        >>> cfg.max_token_length
        125
    """
    try:
        dataset_name = str(normalize_dataset_name(dataset_name))
    except ValueError:
        if id2label is None:
            raise

        dataset_name = str(dataset_name)
    self.register_to_config(dataset_name=dataset_name)
    if vocab_size <= 0:
        raise ValueError("vocab_size must be positive")

    if max_seq_length <= 0:
        raise ValueError("max_seq_length must be positive")

    if num_attributes_per_element != 5:
        raise ValueError("Layout-Corrector supports 5 attributes per element")

    if num_timesteps <= 0:
        raise ValueError("num_timesteps must be positive")

    recon_type, target, transformer_type, pos_emb = (
        normalize_corrector_core_options(
            recon_type,
            target,
            transformer_type,
            pos_emb,
        )
    )
    if len(attr_loss_weights) != num_attributes_per_element:
        raise ValueError("attr_loss_weights must match num_attributes_per_element")

    if corrector_steps <= 0:
        raise ValueError("corrector_steps must be positive")

    try:
        corrector_mask_mode = normalize_corrector_mask_mode(corrector_mask_mode)
    except ValueError as exc:
        raise ValueError(
            f"Unsupported corrector_mask_mode: {corrector_mask_mode}"
        ) from exc

    if not 0.0 <= corrector_mask_threshold <= 1.0:
        raise ValueError("corrector_mask_threshold must be in [0, 1]")

    self.register_to_config(
        dataset_name=dataset_name,
        recon_type=str(recon_type),
        target=str(target),
        pos_emb=str(pos_emb),
        transformer_type=str(transformer_type),
        corrector_mask_mode=str(corrector_mask_mode),
    )

    self.dataset_name = dataset_name
    raw_id2label = id2label or id2label_for_dataset(dataset_name)
    self.id2label = {int(k): v for k, v in raw_id2label.items()}
    self.vocab_size = vocab_size
    self.max_seq_length = max_seq_length
    self.num_attributes_per_element = num_attributes_per_element
    self.hidden_size = hidden_size
    self.num_attention_heads = num_attention_heads
    self.num_hidden_layers = num_hidden_layers
    self.intermediate_size = intermediate_size
    self.dropout = dropout
    self.timestep_type = timestep_type
    self.num_timesteps = num_timesteps

    self.recon_type = str(recon_type)
    self.target = str(target)
    self.attr_loss_weights = tuple(float(v) for v in attr_loss_weights)
    self.use_padding_as_vocab = use_padding_as_vocab
    self.pos_emb = str(pos_emb)
    self.transformer_type = str(transformer_type)

    self.corrector_steps = corrector_steps
    self.corrector_t_list = tuple(int(v) for v in corrector_t_list)
    self.corrector_mask_mode = str(corrector_mask_mode)
    self.corrector_mask_threshold = corrector_mask_threshold
    self.corrector_temperature = corrector_temperature
    self.use_gumbel_noise = use_gumbel_noise
    self.gumbel_temperature = gumbel_temperature
    self.time_adaptive_temperature = time_adaptive_temperature

LayoutCorrectorModel

Bases: ModelMixin, ConfigMixin

Diffusers-compatible Layout-Corrector confidence model.

Source code in models/layout-corrector/src/layout_corrector/modeling_layout_corrector.py
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
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
class LayoutCorrectorModel(ModelMixin, ConfigMixin):
    """Diffusers-compatible Layout-Corrector confidence model."""

    config_name = "corrector_config.json"

    @register_to_config
    def __init__(
        self,
        *,
        dataset_name: str,
        vocab_size: int,
        id2label: dict[int | str, str] | None = None,
        max_seq_length: int = 25,
        num_attributes_per_element: int = 5,
        hidden_size: int = 464,
        num_attention_heads: int = 8,
        num_hidden_layers: int = 4,
        intermediate_size: int = 1856,
        dropout: float = 0.0,
        timestep_type: TimestepEmbeddingType | str | None = "adalayernorm",
        num_timesteps: int = 100,
        recon_type: CorrectorReconType | str = CorrectorReconType.x_t_minus_1,
        target: CorrectorTarget | str = CorrectorTarget.recon_acc,
        attr_loss_weights: tuple[float, ...] = (1.0, 1.0, 1.0, 1.0, 1.0),
        use_padding_as_vocab: bool = True,
        pos_emb: CorrectorPositionEmbedding | str = CorrectorPositionEmbedding.none,
        transformer_type: CorrectorTransformerType | str = (
            CorrectorTransformerType.aggregated
        ),
        corrector_steps: int = 1,
        corrector_t_list: tuple[int, ...] = (10, 20, 30),
        corrector_mask_mode: CorrectorMaskMode | str = CorrectorMaskMode.thresh,
        corrector_mask_threshold: float = 0.7,
        corrector_temperature: float = 1.0,
        use_gumbel_noise: bool = True,
        gumbel_temperature: float = 1.0,
        time_adaptive_temperature: bool = False,
    ) -> None:
        """Initialize a Layout-Corrector model.

        Args:
            dataset_name: Dataset key or alias used for labels.
            vocab_size: LayoutDM vocabulary size.
            id2label: Optional class-id mapping.
            max_seq_length: Maximum number of elements.
            num_attributes_per_element: Number of token attributes per element.
            hidden_size: Transformer hidden dimension.
            num_attention_heads: Number of attention heads.
            num_hidden_layers: Number of transformer layers.
            intermediate_size: Feed-forward hidden dimension.
            dropout: Dropout probability.
            timestep_type: Timestep conditioning type.
            num_timesteps: Number of diffusion timesteps.
            recon_type: Reconstruction target.
            target: Confidence target type.
            attr_loss_weights: Per-attribute loss weights.
            use_padding_as_vocab: Whether padding is modeled as a vocabulary token.
            pos_emb: Position embedding mode.
            transformer_type: Corrector transformer type.
            corrector_steps: Number of correction passes.
            corrector_t_list: Explicit correction timesteps.
            corrector_mask_mode: Token remasking mode.
            corrector_mask_threshold: Threshold for confidence remasking.
            corrector_temperature: Corrector sampling temperature.
            use_gumbel_noise: Whether confidence logits receive Gumbel noise.
            gumbel_temperature: Confidence-noise temperature.
            time_adaptive_temperature: Whether to scale noise by timestep ratio.

        Raises:
            ValueError: If reconstruction, target, or transformer options are
                unsupported.
        """
        super().__init__()
        recon_type, target, transformer_type, pos_emb = (
            normalize_corrector_core_options(
                recon_type,
                target,
                transformer_type,
                pos_emb,
            )
        )
        try:
            corrector_mask_mode = normalize_corrector_mask_mode(corrector_mask_mode)
        except ValueError as exc:
            raise ValueError(
                f"Unsupported corrector_mask_mode: {corrector_mask_mode}"
            ) from exc

        try:
            dataset_name = str(normalize_dataset_name(dataset_name))
        except ValueError:
            if id2label is None:
                raise

            dataset_name = str(dataset_name)
        normalized_id2label = {
            int(k): v
            for k, v in (id2label or id2label_for_dataset(dataset_name)).items()
        }
        self.register_to_config(
            dataset_name=dataset_name,
            id2label=normalized_id2label,
            corrector_t_list=tuple(corrector_t_list),
            attr_loss_weights=tuple(attr_loss_weights),
            recon_type=str(recon_type),
            target=str(target),
            pos_emb=str(pos_emb),
            transformer_type=str(transformer_type),
            corrector_mask_mode=str(corrector_mask_mode),
        )
        self.vocab_size = vocab_size
        self.id2label = normalized_id2label
        self.recon_type = recon_type
        self.corrector_steps = corrector_steps
        self.corrector_t_list = tuple(corrector_t_list)
        self.corrector_mask_mode = corrector_mask_mode
        self.corrector_mask_threshold = corrector_mask_threshold
        self.corrector_temperature = corrector_temperature
        self.use_padding_as_vocab = use_padding_as_vocab
        self.use_gumbel_noise = use_gumbel_noise
        self.gumbel_temperature = gumbel_temperature
        self.time_adaptive_temperature = time_adaptive_temperature
        self.model = AggregatedCategoricalTransformer(
            vocab_size=vocab_size,
            max_token_length=max_seq_length * num_attributes_per_element,
            hidden_size=hidden_size,
            num_attention_heads=num_attention_heads,
            num_hidden_layers=num_hidden_layers,
            intermediate_size=intermediate_size,
            dropout=dropout,
            timestep_type=timestep_type,
            pos_emb=pos_emb,
            num_attributes_per_element=num_attributes_per_element,
            num_timesteps=num_timesteps,
        )

    def forward(
        self,
        input_ids: Int[torch.Tensor, "batch tokens"],
        timesteps: Int[torch.Tensor, "batch"],
        padding_mask: Bool[torch.Tensor, "batch tokens"] | None = None,
    ) -> LayoutCorrectorOutput:
        """Run the corrector model.

        Args:
            input_ids: Flattened token ids.
            timesteps: Diffusion timestep tensor.
            padding_mask: Optional padding mask.

        Returns:
            `LayoutCorrectorOutput` containing token confidence logits.
        """
        src_key_padding_mask = None if self.use_padding_as_vocab else padding_mask
        logits = self.model(
            input_ids,
            timestep=timesteps,
            src_key_padding_mask=src_key_padding_mask,
        ).squeeze(-1)
        if not self.use_padding_as_vocab and padding_mask is not None:
            logits = logits.masked_fill(padding_mask, 1000.0)
        return LayoutCorrectorOutput(logits=logits)

    def calc_confidence_score(
        self,
        input_ids: Int[torch.Tensor, "batch tokens"],
        timesteps: Int[torch.Tensor, "batch"],
        padding_mask: Bool[torch.Tensor, "batch tokens"] | None = None,
    ) -> Float[torch.Tensor, "batch tokens"]:
        """Return confidence logits for token remasking.

        Args:
            input_ids: Flattened token ids.
            timesteps: Diffusion timestep tensor.
            padding_mask: Optional padding mask.

        Returns:
            Confidence logits shaped `(batch, tokens)`.
        """
        return self(
            input_ids=input_ids,
            timesteps=timesteps,
            padding_mask=padding_mask,
        ).logits

__init__

__init__(
    *,
    dataset_name: str,
    vocab_size: int,
    id2label: dict[int | str, str] | None = None,
    max_seq_length: int = 25,
    num_attributes_per_element: int = 5,
    hidden_size: int = 464,
    num_attention_heads: int = 8,
    num_hidden_layers: int = 4,
    intermediate_size: int = 1856,
    dropout: float = 0.0,
    timestep_type: TimestepEmbeddingType
    | str
    | None = "adalayernorm",
    num_timesteps: int = 100,
    recon_type: CorrectorReconType
    | str = CorrectorReconType.x_t_minus_1,
    target: CorrectorTarget
    | str = CorrectorTarget.recon_acc,
    attr_loss_weights: tuple[float, ...] = (
        1.0,
        1.0,
        1.0,
        1.0,
        1.0,
    ),
    use_padding_as_vocab: bool = True,
    pos_emb: CorrectorPositionEmbedding
    | str = CorrectorPositionEmbedding.none,
    transformer_type: CorrectorTransformerType
    | str = CorrectorTransformerType.aggregated,
    corrector_steps: int = 1,
    corrector_t_list: tuple[int, ...] = (10, 20, 30),
    corrector_mask_mode: CorrectorMaskMode
    | str = CorrectorMaskMode.thresh,
    corrector_mask_threshold: float = 0.7,
    corrector_temperature: float = 1.0,
    use_gumbel_noise: bool = True,
    gumbel_temperature: float = 1.0,
    time_adaptive_temperature: bool = False,
) -> None

Initialize a Layout-Corrector model.

Parameters:

Name Type Description Default
dataset_name str

Dataset key or alias used for labels.

required
vocab_size int

LayoutDM vocabulary size.

required
id2label dict[int | str, str] | None

Optional class-id mapping.

None
max_seq_length int

Maximum number of elements.

25
num_attributes_per_element int

Number of token attributes per element.

5
hidden_size int

Transformer hidden dimension.

464
num_attention_heads int

Number of attention heads.

8
num_hidden_layers int

Number of transformer layers.

4
intermediate_size int

Feed-forward hidden dimension.

1856
dropout float

Dropout probability.

0.0
timestep_type TimestepEmbeddingType | str | None

Timestep conditioning type.

'adalayernorm'
num_timesteps int

Number of diffusion timesteps.

100
recon_type CorrectorReconType | str

Reconstruction target.

x_t_minus_1
target CorrectorTarget | str

Confidence target type.

recon_acc
attr_loss_weights tuple[float, ...]

Per-attribute loss weights.

(1.0, 1.0, 1.0, 1.0, 1.0)
use_padding_as_vocab bool

Whether padding is modeled as a vocabulary token.

True
pos_emb CorrectorPositionEmbedding | str

Position embedding mode.

none
transformer_type CorrectorTransformerType | str

Corrector transformer type.

aggregated
corrector_steps int

Number of correction passes.

1
corrector_t_list tuple[int, ...]

Explicit correction timesteps.

(10, 20, 30)
corrector_mask_mode CorrectorMaskMode | str

Token remasking mode.

thresh
corrector_mask_threshold float

Threshold for confidence remasking.

0.7
corrector_temperature float

Corrector sampling temperature.

1.0
use_gumbel_noise bool

Whether confidence logits receive Gumbel noise.

True
gumbel_temperature float

Confidence-noise temperature.

1.0
time_adaptive_temperature bool

Whether to scale noise by timestep ratio.

False

Raises:

Type Description
ValueError

If reconstruction, target, or transformer options are unsupported.

Source code in models/layout-corrector/src/layout_corrector/modeling_layout_corrector.py
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
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
@register_to_config
def __init__(
    self,
    *,
    dataset_name: str,
    vocab_size: int,
    id2label: dict[int | str, str] | None = None,
    max_seq_length: int = 25,
    num_attributes_per_element: int = 5,
    hidden_size: int = 464,
    num_attention_heads: int = 8,
    num_hidden_layers: int = 4,
    intermediate_size: int = 1856,
    dropout: float = 0.0,
    timestep_type: TimestepEmbeddingType | str | None = "adalayernorm",
    num_timesteps: int = 100,
    recon_type: CorrectorReconType | str = CorrectorReconType.x_t_minus_1,
    target: CorrectorTarget | str = CorrectorTarget.recon_acc,
    attr_loss_weights: tuple[float, ...] = (1.0, 1.0, 1.0, 1.0, 1.0),
    use_padding_as_vocab: bool = True,
    pos_emb: CorrectorPositionEmbedding | str = CorrectorPositionEmbedding.none,
    transformer_type: CorrectorTransformerType | str = (
        CorrectorTransformerType.aggregated
    ),
    corrector_steps: int = 1,
    corrector_t_list: tuple[int, ...] = (10, 20, 30),
    corrector_mask_mode: CorrectorMaskMode | str = CorrectorMaskMode.thresh,
    corrector_mask_threshold: float = 0.7,
    corrector_temperature: float = 1.0,
    use_gumbel_noise: bool = True,
    gumbel_temperature: float = 1.0,
    time_adaptive_temperature: bool = False,
) -> None:
    """Initialize a Layout-Corrector model.

    Args:
        dataset_name: Dataset key or alias used for labels.
        vocab_size: LayoutDM vocabulary size.
        id2label: Optional class-id mapping.
        max_seq_length: Maximum number of elements.
        num_attributes_per_element: Number of token attributes per element.
        hidden_size: Transformer hidden dimension.
        num_attention_heads: Number of attention heads.
        num_hidden_layers: Number of transformer layers.
        intermediate_size: Feed-forward hidden dimension.
        dropout: Dropout probability.
        timestep_type: Timestep conditioning type.
        num_timesteps: Number of diffusion timesteps.
        recon_type: Reconstruction target.
        target: Confidence target type.
        attr_loss_weights: Per-attribute loss weights.
        use_padding_as_vocab: Whether padding is modeled as a vocabulary token.
        pos_emb: Position embedding mode.
        transformer_type: Corrector transformer type.
        corrector_steps: Number of correction passes.
        corrector_t_list: Explicit correction timesteps.
        corrector_mask_mode: Token remasking mode.
        corrector_mask_threshold: Threshold for confidence remasking.
        corrector_temperature: Corrector sampling temperature.
        use_gumbel_noise: Whether confidence logits receive Gumbel noise.
        gumbel_temperature: Confidence-noise temperature.
        time_adaptive_temperature: Whether to scale noise by timestep ratio.

    Raises:
        ValueError: If reconstruction, target, or transformer options are
            unsupported.
    """
    super().__init__()
    recon_type, target, transformer_type, pos_emb = (
        normalize_corrector_core_options(
            recon_type,
            target,
            transformer_type,
            pos_emb,
        )
    )
    try:
        corrector_mask_mode = normalize_corrector_mask_mode(corrector_mask_mode)
    except ValueError as exc:
        raise ValueError(
            f"Unsupported corrector_mask_mode: {corrector_mask_mode}"
        ) from exc

    try:
        dataset_name = str(normalize_dataset_name(dataset_name))
    except ValueError:
        if id2label is None:
            raise

        dataset_name = str(dataset_name)
    normalized_id2label = {
        int(k): v
        for k, v in (id2label or id2label_for_dataset(dataset_name)).items()
    }
    self.register_to_config(
        dataset_name=dataset_name,
        id2label=normalized_id2label,
        corrector_t_list=tuple(corrector_t_list),
        attr_loss_weights=tuple(attr_loss_weights),
        recon_type=str(recon_type),
        target=str(target),
        pos_emb=str(pos_emb),
        transformer_type=str(transformer_type),
        corrector_mask_mode=str(corrector_mask_mode),
    )
    self.vocab_size = vocab_size
    self.id2label = normalized_id2label
    self.recon_type = recon_type
    self.corrector_steps = corrector_steps
    self.corrector_t_list = tuple(corrector_t_list)
    self.corrector_mask_mode = corrector_mask_mode
    self.corrector_mask_threshold = corrector_mask_threshold
    self.corrector_temperature = corrector_temperature
    self.use_padding_as_vocab = use_padding_as_vocab
    self.use_gumbel_noise = use_gumbel_noise
    self.gumbel_temperature = gumbel_temperature
    self.time_adaptive_temperature = time_adaptive_temperature
    self.model = AggregatedCategoricalTransformer(
        vocab_size=vocab_size,
        max_token_length=max_seq_length * num_attributes_per_element,
        hidden_size=hidden_size,
        num_attention_heads=num_attention_heads,
        num_hidden_layers=num_hidden_layers,
        intermediate_size=intermediate_size,
        dropout=dropout,
        timestep_type=timestep_type,
        pos_emb=pos_emb,
        num_attributes_per_element=num_attributes_per_element,
        num_timesteps=num_timesteps,
    )

forward

forward(
    input_ids: Int[Tensor, "batch tokens"],
    timesteps: Int[Tensor, "batch"],
    padding_mask: Bool[Tensor, "batch tokens"]
    | None = None,
) -> LayoutCorrectorOutput

Run the corrector model.

Parameters:

Name Type Description Default
input_ids Int[Tensor, 'batch tokens']

Flattened token ids.

required
timesteps Int[Tensor, 'batch']

Diffusion timestep tensor.

required
padding_mask Bool[Tensor, 'batch tokens'] | None

Optional padding mask.

None

Returns:

Type Description
LayoutCorrectorOutput

LayoutCorrectorOutput containing token confidence logits.

Source code in models/layout-corrector/src/layout_corrector/modeling_layout_corrector.py
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
def forward(
    self,
    input_ids: Int[torch.Tensor, "batch tokens"],
    timesteps: Int[torch.Tensor, "batch"],
    padding_mask: Bool[torch.Tensor, "batch tokens"] | None = None,
) -> LayoutCorrectorOutput:
    """Run the corrector model.

    Args:
        input_ids: Flattened token ids.
        timesteps: Diffusion timestep tensor.
        padding_mask: Optional padding mask.

    Returns:
        `LayoutCorrectorOutput` containing token confidence logits.
    """
    src_key_padding_mask = None if self.use_padding_as_vocab else padding_mask
    logits = self.model(
        input_ids,
        timestep=timesteps,
        src_key_padding_mask=src_key_padding_mask,
    ).squeeze(-1)
    if not self.use_padding_as_vocab and padding_mask is not None:
        logits = logits.masked_fill(padding_mask, 1000.0)
    return LayoutCorrectorOutput(logits=logits)

calc_confidence_score

calc_confidence_score(
    input_ids: Int[Tensor, "batch tokens"],
    timesteps: Int[Tensor, "batch"],
    padding_mask: Bool[Tensor, "batch tokens"]
    | None = None,
) -> Float[torch.Tensor, "batch tokens"]

Return confidence logits for token remasking.

Parameters:

Name Type Description Default
input_ids Int[Tensor, 'batch tokens']

Flattened token ids.

required
timesteps Int[Tensor, 'batch']

Diffusion timestep tensor.

required
padding_mask Bool[Tensor, 'batch tokens'] | None

Optional padding mask.

None

Returns:

Type Description
Float[Tensor, 'batch tokens']

Confidence logits shaped (batch, tokens).

Source code in models/layout-corrector/src/layout_corrector/modeling_layout_corrector.py
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
def calc_confidence_score(
    self,
    input_ids: Int[torch.Tensor, "batch tokens"],
    timesteps: Int[torch.Tensor, "batch"],
    padding_mask: Bool[torch.Tensor, "batch tokens"] | None = None,
) -> Float[torch.Tensor, "batch tokens"]:
    """Return confidence logits for token remasking.

    Args:
        input_ids: Flattened token ids.
        timesteps: Diffusion timestep tensor.
        padding_mask: Optional padding mask.

    Returns:
        Confidence logits shaped `(batch, tokens)`.
    """
    return self(
        input_ids=input_ids,
        timesteps=timesteps,
        padding_mask=padding_mask,
    ).logits

LayoutCorrectorOutput dataclass

Bases: BaseOutput

Output container for Layout-Corrector confidence logits.

Parameters:

Name Type Description Default
logits Float[Tensor, 'batch tokens']

Token confidence logits shaped (batch, tokens).

required
Source code in models/layout-corrector/src/layout_corrector/modeling_layout_corrector.py
32
33
34
35
36
37
38
39
40
@dataclass
class LayoutCorrectorOutput(BaseOutput):
    """Output container for Layout-Corrector confidence logits.

    Args:
        logits: Token confidence logits shaped `(batch, tokens)`.
    """

    logits: Float[torch.Tensor, "batch tokens"]

LayoutCorrectorPipeline

Bases: DiffusionPipeline

Diffusers pipeline that applies Layout-Corrector during LayoutDM sampling.

Parameters:

Name Type Description Default
layout_dm LayoutDMPipeline

Base LayoutDM pipeline.

required
corrector LayoutCorrectorModel

Corrector model used to score and remask tokens.

required
processor LayoutDMProcessor | None

Optional processor for conditional layout inputs.

None

Raises:

Type Description
ValueError

Pipeline construction does not raise directly.

Examples:

>>> LayoutCorrectorPipeline.from_pretrained
<bound method...
Source code in models/layout-corrector/src/layout_corrector/pipeline_layout_corrector.py
 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
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
480
481
482
483
484
485
class LayoutCorrectorPipeline(DiffusionPipeline):
    """Diffusers pipeline that applies Layout-Corrector during LayoutDM sampling.

    Args:
        layout_dm: Base LayoutDM pipeline.
        corrector: Corrector model used to score and remask tokens.
        processor: Optional processor for conditional layout inputs.

    Raises:
        ValueError: Pipeline construction does not raise directly.

    Examples:
        >>> LayoutCorrectorPipeline.from_pretrained  # doctest: +ELLIPSIS
        <bound method...
    """

    model_cpu_offload_seq: ClassVar[str] = "layout_dm.denoiser->corrector"

    def __init__(
        self,
        layout_dm: LayoutDMPipeline,
        corrector: LayoutCorrectorModel,
        processor: LayoutDMProcessor | None = None,
    ) -> None:
        """Initialize the composite pipeline.

        Args:
            layout_dm: Base LayoutDM pipeline.
            corrector: Confidence model used to remask low-confidence tokens.
            processor: Optional processor for conditional inputs.
        """
        super().__init__()
        self.register_modules(layout_dm=layout_dm, corrector=corrector)
        self.layout_dm = layout_dm
        self.corrector = corrector
        self.processor = processor or layout_dm.processor
        self.corrector.eval()

    @torch.no_grad()
    def __call__(
        self,
        *,
        batch_size: int = 1,
        seed: int | None = None,
        generator: torch.Generator | None = None,
        condition_type: ConditionType | str = ConditionType.unconditional,
        labels: Int[torch.Tensor, "batch elements"]
        | Int[np.ndarray, "batch elements"]
        | list[ArrayLikeInput]
        | None = None,
        bbox: Float[torch.Tensor, "batch elements 4"]
        | Float[np.ndarray, "batch elements 4"]
        | list[ArrayLikeInput]
        | None = None,
        mask: Bool[torch.Tensor, "batch elements"]
        | Bool[np.ndarray, "batch elements"]
        | list[ArrayLikeInput]
        | 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,
        sampling: SamplingMode | str = SamplingMode.random,
        temperature: float = 1.0,
        top_k: int = 5,
        top_p: float = 0.9,
        corrector_steps: int | None = None,
        corrector_t_list: Sequence[int] | None = None,
        corrector_start: int = -1,
        corrector_end: int = -1,
        corrector_mask_mode: CorrectorMaskMode | str | None = None,
        corrector_mask_threshold: float | None = None,
        corrector_temperature: float | None = None,
        use_gumbel_noise: bool | None = None,
        gumbel_temperature: float | None = None,
        time_adaptive_temperature: bool | None = None,
        output_type: OutputType | str = OutputType.dataclass,
        return_intermediates: bool = False,
    ) -> (
        LayoutGenerationOutput
        | dict[
            str,
            Float[torch.Tensor, "batch elements 4"]
            | Int[torch.Tensor, "batch elements"]
            | Bool[torch.Tensor, "batch elements"]
            | Int[torch.Tensor, "batch tokens"]
            | Float[torch.Tensor, "steps batch tokens"]
            | list[Int[torch.Tensor, "batch tokens"]]
            | dict[int, str]
            | dict[str, str]
            | None,
        ]
    ):
        """Generate layouts with optional Layout-Corrector guidance.

        Args:
            batch_size: Number of layouts to sample for unconditional generation.
            seed: Optional seed used when `generator` is not supplied.
            generator: Optional PyTorch generator.
            condition_type: Condition mode such as `"unconditional"` or `"label"`.
            labels: Optional class ids for conditional generation.
            bbox: Optional boxes for conditional generation.
            mask: Optional element mask for conditional generation.
            num_elements: Reserved for future element-count conditioning.
            box_format: Coordinate format for conditional boxes.
            normalized: Whether conditional boxes are normalized.
            canvas_size: Pixel canvas used when `normalized=False`.
            num_inference_steps: Optional inference timestep count.
            sampling: Base LayoutDM sampling strategy.
            temperature: Base sampling temperature.
            top_k: Top-k cutoff for top-k sampling.
            top_p: Nucleus cutoff for top-p sampling.
            corrector_steps: Optional override for correction passes.
            corrector_t_list: Optional explicit correction timesteps.
            corrector_start: Range start for correction when no list is supplied.
            corrector_end: Range end for correction when no list is supplied.
            corrector_mask_mode: Optional override for remasking mode.
            corrector_mask_threshold: Optional threshold override.
            corrector_temperature: Optional confidence temperature override.
            use_gumbel_noise: Optional confidence-noise override.
            gumbel_temperature: Optional confidence-noise temperature override.
            time_adaptive_temperature: Optional adaptive-noise override.
            output_type: `"dataclass"` or `"dict"`.
            return_intermediates: Whether to include scores and trajectory.

        Returns:
            `LayoutGenerationOutput` by default, or a dictionary when requested.

        Raises:
            ValueError: If conditional generation is missing `bbox` or `labels`, or
                if `output_type` is unsupported.

        Examples:
            >>> LayoutCorrectorPipeline.__call__  # doctest: +ELLIPSIS
            <function...
        """
        _ = num_elements
        if generator is None and seed is not None:
            generator = torch.Generator(device=self.device).manual_seed(seed)
        canonical = normalize_condition_type(condition_type)
        condition = None
        if canonical != "unconditional":
            missing_inputs = [
                name
                for name, value in (("bbox", bbox), ("labels", labels))
                if value is None
            ]
            if missing_inputs:
                raise ValueError(
                    "bbox and labels are required "
                    f"for condition_type={condition_type}; "
                    f"missing {', '.join(missing_inputs)}"
                )

            processor_inputs = {
                "bbox": bbox,
                "labels": labels,
                "mask": mask,
                "box_format": box_format,
                "normalized": normalized,
                "canvas_size": canvas_size,
            }
            processed = self.processor(**processor_inputs)
            decoded_input = self.layout_dm.tokenizer.decode_layout(
                processed["input_ids"]
            )
            condition = build_condition(
                self.layout_dm.tokenizer,
                cond_type=canonical,
                bbox=decoded_input["bbox"],
                labels=decoded_input["labels"],
                mask=decoded_input["mask"],
            )
            batch_size = condition.input_ids.shape[0]

        corrector_cfg = LayoutCorrectorSamplingConfig(
            sampling=sampling,
            temperature=temperature,
            top_k=top_k,
            top_p=top_p,
            num_inference_steps=num_inference_steps,
            corrector_steps=corrector_steps or self.corrector.corrector_steps,
            corrector_t_list=tuple(
                self.corrector.corrector_t_list
                if corrector_t_list is None
                else corrector_t_list
            ),
            corrector_start=corrector_start,
            corrector_end=corrector_end,
            corrector_mask_mode=corrector_mask_mode
            or self.corrector.corrector_mask_mode,
            corrector_mask_threshold=corrector_mask_threshold
            if corrector_mask_threshold is not None
            else self.corrector.corrector_mask_threshold,
            corrector_temperature=corrector_temperature
            if corrector_temperature is not None
            else self.corrector.corrector_temperature,
            use_gumbel_noise=use_gumbel_noise
            if use_gumbel_noise is not None
            else self.corrector.use_gumbel_noise,
            gumbel_temperature=gumbel_temperature
            if gumbel_temperature is not None
            else self.corrector.gumbel_temperature,
            time_adaptive_temperature=time_adaptive_temperature
            if time_adaptive_temperature is not None
            else self.corrector.time_adaptive_temperature,
        )
        sampling_cfg = LayoutDMSamplingConfig(
            name=sampling,
            temperature=temperature,
            top_k=top_k,
            top_p=top_p,
            num_inference_steps=num_inference_steps,
        )
        self.layout_dm.scheduler.set_timesteps(num_inference_steps, device=self.device)
        sample = self.layout_dm.scheduler.initial_sample(
            batch_size,
            self.layout_dm.tokenizer.config.max_token_length,
            device=self.device,
            condition=condition,
        )
        trajectory = [] if return_intermediates else None
        scores = [] if return_intermediates else None
        previous_timestep = self.layout_dm.scheduler.config.num_timesteps
        for timestep in self.layout_dm.scheduler.timesteps:
            timestep_value = int(timestep.item())
            timestep_batch = torch.full(
                (batch_size,),
                timestep_value,
                device=self.device,
                dtype=torch.long,
            )
            if should_apply_corrector(timestep_value, corrector_cfg):
                sample, confidence = self._step_with_corrector(
                    sample=sample,
                    timestep_batch=timestep_batch,
                    condition=condition,
                    sampling=corrector_cfg,
                    generator=generator,
                )
                if scores is not None and confidence is not None:
                    scores.append(confidence.detach().cpu())
            else:
                input_ids = log_onehot_to_index(sample)
                logits = self.layout_dm.denoiser(
                    input_ids=input_ids, timesteps=timestep_batch
                ).logits
                sample = self.layout_dm.scheduler.step(
                    logits,
                    timestep_batch,
                    sample,
                    previous_timestep=previous_timestep,
                    sampling=sampling_cfg,
                    condition=condition,
                    generator=generator,
                ).prev_sample
            previous_timestep = timestep_value
            if trajectory is not None:
                trajectory.append(log_onehot_to_index(sample).detach().cpu())

        sequences = log_onehot_to_index(sample).detach().cpu()
        decoded = self.layout_dm.tokenizer.decode_layout(sequences)
        output = LayoutGenerationOutput(
            bbox=decoded["bbox"],
            labels=decoded["labels"],
            mask=decoded["mask"],
            id2label=dict(self.corrector.id2label),
            sequences=sequences,
            scores=torch.stack(scores) if scores else None,
            trajectory=trajectory,
            intermediates={"condition_type": canonical}
            if return_intermediates
            else None,
        )
        normalized_output_type = normalize_output_type(output_type)
        if normalized_output_type is OutputType.dict:
            return dict(output)
        if normalized_output_type is OutputType.dataclass:
            return output
        assert_never(normalized_output_type)

    generate = __call__

    def _step_with_corrector(
        self,
        *,
        sample: Float[torch.Tensor, "batch vocab tokens"],
        timestep_batch: Int[torch.Tensor, "batch"],
        condition: LayoutDMCondition | None,
        sampling: LayoutCorrectorSamplingConfig,
        generator: torch.Generator | None,
    ) -> tuple[
        Float[torch.Tensor, "batch vocab tokens"],
        Float[torch.Tensor, "batch tokens"] | None,
    ]:
        confidence = None
        current = sample
        for _ in range(sampling.corrector_steps):
            input_ids = log_onehot_to_index(current)
            denoiser_logits = self.layout_dm.denoiser(
                input_ids=input_ids, timesteps=timestep_batch
            ).logits
            model_log_prob = self.layout_dm.scheduler.predict_start(denoiser_logits)
            if self.corrector.recon_type is CorrectorReconType.x_t_minus_1:
                model_log_prob = self.layout_dm.scheduler.q_posterior(
                    model_log_prob, current, timestep_batch
                )
                model_log_prob[:, self.layout_dm.tokenizer.mask_token_id, :] = -70.0
            if self.layout_dm.scheduler.token_mask is not None:
                valid = self.layout_dm.scheduler.token_mask.to(
                    model_log_prob.device
                ).T.unsqueeze(0)
                model_log_prob = model_log_prob.masked_fill(~valid, -70.0)
            if condition is not None:
                strong_mask = condition.mask.to(model_log_prob.device).unsqueeze(1)
                strong_log_prob = index_to_log_onehot(
                    condition.input_ids.to(model_log_prob.device),
                    self.layout_dm.scheduler.vocab_size,
                )
                model_log_prob = torch.where(
                    strong_mask, strong_log_prob, model_log_prob
                )
            x0_recon_ids = torch.multinomial(
                (model_log_prob.permute(0, 2, 1) / sampling.temperature)
                .softmax(dim=-1)
                .reshape(-1, model_log_prob.size(1)),
                1,
                generator=generator,
            ).reshape(model_log_prob.shape[0], model_log_prob.shape[-1])
            confidence = self.corrector.calc_confidence_score(
                x0_recon_ids,
                timestep_batch,
                padding_mask=x0_recon_ids == self.layout_dm.tokenizer.pad_token_id,
            )
            adjusted = confidence
            mask_ratio = self._mask_ratio(timestep_batch)
            if sampling.use_gumbel_noise:
                adjusted = add_confidence_gumbel_noise(
                    adjusted,
                    timestep=timestep_batch,
                    mask_ratio=mask_ratio,
                    temperature=sampling.gumbel_temperature,
                    time_adaptive_temperature=sampling.time_adaptive_temperature,
                    generator=generator,
                )
            remask = select_tokens_to_remask(
                adjusted,
                mask_ratio=mask_ratio,
                mode=sampling.corrector_mask_mode,
                threshold=sampling.corrector_mask_threshold,
                temperature=sampling.corrector_temperature,
            )
            x0_recon_ids = x0_recon_ids.masked_fill(
                remask, self.layout_dm.tokenizer.mask_token_id
            )
            if condition is not None:
                x0_recon_ids = torch.where(
                    condition.mask.to(x0_recon_ids.device),
                    condition.input_ids.to(x0_recon_ids.device),
                    x0_recon_ids,
                )
            current = index_to_log_onehot(
                x0_recon_ids, self.layout_dm.scheduler.vocab_size
            )
        return current, confidence

    def _mask_ratio(self, timestep_batch: Int[torch.Tensor, "batch"]) -> float:
        timestep = int(timestep_batch[0].item())
        timestep = max(0, min(timestep, self.layout_dm.scheduler.config.num_timesteps))
        if timestep == 0:
            return 0.0
        return float(timestep / self.layout_dm.scheduler.config.num_timesteps)

    def save_pretrained(
        self, save_directory: str | Path, *, safe_serialization: bool = True
    ) -> None:
        """Save the nested LayoutDM pipeline and corrector model.

        Args:
            save_directory: Destination directory.
            safe_serialization: Whether to save weights as safetensors.

        Returns:
            None.

        Raises:
            OSError: If files cannot be written.

        Examples:
            >>> LayoutCorrectorPipeline.save_pretrained  # doctest: +ELLIPSIS
            <function...
        """
        save_path = Path(save_directory)
        save_path.mkdir(parents=True, exist_ok=True)
        self.layout_dm.save_pretrained(
            save_path / "layout_dm", safe_serialization=safe_serialization
        )
        self.corrector.save_pretrained(
            save_path / "corrector", safe_serialization=safe_serialization
        )

    @classmethod
    def from_pretrained(
        cls,
        pretrained_model_name_or_path: str | Path,
        *,
        processor: LayoutDMProcessor | None = None,
    ) -> "LayoutCorrectorPipeline":
        """Load a Layout-Corrector pipeline from a saved directory.

        Args:
            pretrained_model_name_or_path: Directory containing `layout_dm/` and
                `corrector/` subdirectories.
            processor: Optional processor override.

        Returns:
            Loaded `LayoutCorrectorPipeline`.

        Raises:
            OSError: If nested component files are missing.

        Examples:
            >>> LayoutCorrectorPipeline.from_pretrained  # doctest: +ELLIPSIS
            <bound method...
        """
        path = Path(pretrained_model_name_or_path)
        layout_dm = LayoutDMPipeline.from_pretrained(path / "layout_dm")
        corrector = LayoutCorrectorModel.from_pretrained(path / "corrector")
        return cls(layout_dm=layout_dm, corrector=corrector, processor=processor)

__init__

__init__(
    layout_dm: LayoutDMPipeline,
    corrector: LayoutCorrectorModel,
    processor: LayoutDMProcessor | None = None,
) -> None

Initialize the composite pipeline.

Parameters:

Name Type Description Default
layout_dm LayoutDMPipeline

Base LayoutDM pipeline.

required
corrector LayoutCorrectorModel

Confidence model used to remask low-confidence tokens.

required
processor LayoutDMProcessor | None

Optional processor for conditional inputs.

None
Source code in models/layout-corrector/src/layout_corrector/pipeline_layout_corrector.py
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
def __init__(
    self,
    layout_dm: LayoutDMPipeline,
    corrector: LayoutCorrectorModel,
    processor: LayoutDMProcessor | None = None,
) -> None:
    """Initialize the composite pipeline.

    Args:
        layout_dm: Base LayoutDM pipeline.
        corrector: Confidence model used to remask low-confidence tokens.
        processor: Optional processor for conditional inputs.
    """
    super().__init__()
    self.register_modules(layout_dm=layout_dm, corrector=corrector)
    self.layout_dm = layout_dm
    self.corrector = corrector
    self.processor = processor or layout_dm.processor
    self.corrector.eval()

__call__

__call__(
    *,
    batch_size: int = 1,
    seed: int | None = None,
    generator: Generator | None = None,
    condition_type: ConditionType
    | str = ConditionType.unconditional,
    labels: Int[Tensor, "batch elements"]
    | Int[ndarray, "batch elements"]
    | list[ArrayLikeInput]
    | None = None,
    bbox: Float[Tensor, "batch elements 4"]
    | Float[ndarray, "batch elements 4"]
    | list[ArrayLikeInput]
    | None = None,
    mask: Bool[Tensor, "batch elements"]
    | Bool[ndarray, "batch elements"]
    | list[ArrayLikeInput]
    | 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,
    sampling: SamplingMode | str = SamplingMode.random,
    temperature: float = 1.0,
    top_k: int = 5,
    top_p: float = 0.9,
    corrector_steps: int | None = None,
    corrector_t_list: Sequence[int] | None = None,
    corrector_start: int = -1,
    corrector_end: int = -1,
    corrector_mask_mode: CorrectorMaskMode
    | str
    | None = None,
    corrector_mask_threshold: float | None = None,
    corrector_temperature: float | None = None,
    use_gumbel_noise: bool | None = None,
    gumbel_temperature: float | None = None,
    time_adaptive_temperature: bool | None = None,
    output_type: OutputType | str = OutputType.dataclass,
    return_intermediates: bool = False,
) -> (
    LayoutGenerationOutput
    | dict[
        str,
        Float[torch.Tensor, "batch elements 4"]
        | Int[torch.Tensor, "batch elements"]
        | Bool[torch.Tensor, "batch elements"]
        | Int[torch.Tensor, "batch tokens"]
        | Float[torch.Tensor, "steps batch tokens"]
        | list[Int[torch.Tensor, "batch tokens"]]
        | dict[int, str]
        | dict[str, str]
        | None,
    ]
)

Generate layouts with optional Layout-Corrector guidance.

Parameters:

Name Type Description Default
batch_size int

Number of layouts to sample for unconditional generation.

1
seed int | None

Optional seed used when generator is not supplied.

None
generator Generator | None

Optional PyTorch generator.

None
condition_type ConditionType | str

Condition mode such as "unconditional" or "label".

unconditional
labels Int[Tensor, 'batch elements'] | Int[ndarray, 'batch elements'] | list[ArrayLikeInput] | None

Optional class ids for conditional generation.

None
bbox Float[Tensor, 'batch elements 4'] | Float[ndarray, 'batch elements 4'] | list[ArrayLikeInput] | None

Optional boxes for conditional generation.

None
mask Bool[Tensor, 'batch elements'] | Bool[ndarray, 'batch elements'] | list[ArrayLikeInput] | None

Optional element mask for conditional generation.

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

Reserved for future element-count conditioning.

None
box_format BoxFormat | str

Coordinate format for conditional boxes.

xywh
normalized bool

Whether conditional boxes are normalized.

True
canvas_size tuple[int, int] | None

Pixel canvas used when normalized=False.

None
num_inference_steps int | None

Optional inference timestep count.

None
sampling SamplingMode | str

Base LayoutDM sampling strategy.

random
temperature float

Base sampling temperature.

1.0
top_k int

Top-k cutoff for top-k sampling.

5
top_p float

Nucleus cutoff for top-p sampling.

0.9
corrector_steps int | None

Optional override for correction passes.

None
corrector_t_list Sequence[int] | None

Optional explicit correction timesteps.

None
corrector_start int

Range start for correction when no list is supplied.

-1
corrector_end int

Range end for correction when no list is supplied.

-1
corrector_mask_mode CorrectorMaskMode | str | None

Optional override for remasking mode.

None
corrector_mask_threshold float | None

Optional threshold override.

None
corrector_temperature float | None

Optional confidence temperature override.

None
use_gumbel_noise bool | None

Optional confidence-noise override.

None
gumbel_temperature float | None

Optional confidence-noise temperature override.

None
time_adaptive_temperature bool | None

Optional adaptive-noise override.

None
output_type OutputType | str

"dataclass" or "dict".

dataclass
return_intermediates bool

Whether to include scores and trajectory.

False

Returns:

Type Description
LayoutGenerationOutput | dict[str, Float[Tensor, 'batch elements 4'] | Int[Tensor, 'batch elements'] | Bool[Tensor, 'batch elements'] | Int[Tensor, 'batch tokens'] | Float[Tensor, 'steps batch tokens'] | list[Int[Tensor, 'batch tokens']] | dict[int, str] | dict[str, str] | None]

LayoutGenerationOutput by default, or a dictionary when requested.

Raises:

Type Description
ValueError

If conditional generation is missing bbox or labels, or if output_type is unsupported.

Examples:

>>> LayoutCorrectorPipeline.__call__
<function...
Source code in models/layout-corrector/src/layout_corrector/pipeline_layout_corrector.py
 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
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
@torch.no_grad()
def __call__(
    self,
    *,
    batch_size: int = 1,
    seed: int | None = None,
    generator: torch.Generator | None = None,
    condition_type: ConditionType | str = ConditionType.unconditional,
    labels: Int[torch.Tensor, "batch elements"]
    | Int[np.ndarray, "batch elements"]
    | list[ArrayLikeInput]
    | None = None,
    bbox: Float[torch.Tensor, "batch elements 4"]
    | Float[np.ndarray, "batch elements 4"]
    | list[ArrayLikeInput]
    | None = None,
    mask: Bool[torch.Tensor, "batch elements"]
    | Bool[np.ndarray, "batch elements"]
    | list[ArrayLikeInput]
    | 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,
    sampling: SamplingMode | str = SamplingMode.random,
    temperature: float = 1.0,
    top_k: int = 5,
    top_p: float = 0.9,
    corrector_steps: int | None = None,
    corrector_t_list: Sequence[int] | None = None,
    corrector_start: int = -1,
    corrector_end: int = -1,
    corrector_mask_mode: CorrectorMaskMode | str | None = None,
    corrector_mask_threshold: float | None = None,
    corrector_temperature: float | None = None,
    use_gumbel_noise: bool | None = None,
    gumbel_temperature: float | None = None,
    time_adaptive_temperature: bool | None = None,
    output_type: OutputType | str = OutputType.dataclass,
    return_intermediates: bool = False,
) -> (
    LayoutGenerationOutput
    | dict[
        str,
        Float[torch.Tensor, "batch elements 4"]
        | Int[torch.Tensor, "batch elements"]
        | Bool[torch.Tensor, "batch elements"]
        | Int[torch.Tensor, "batch tokens"]
        | Float[torch.Tensor, "steps batch tokens"]
        | list[Int[torch.Tensor, "batch tokens"]]
        | dict[int, str]
        | dict[str, str]
        | None,
    ]
):
    """Generate layouts with optional Layout-Corrector guidance.

    Args:
        batch_size: Number of layouts to sample for unconditional generation.
        seed: Optional seed used when `generator` is not supplied.
        generator: Optional PyTorch generator.
        condition_type: Condition mode such as `"unconditional"` or `"label"`.
        labels: Optional class ids for conditional generation.
        bbox: Optional boxes for conditional generation.
        mask: Optional element mask for conditional generation.
        num_elements: Reserved for future element-count conditioning.
        box_format: Coordinate format for conditional boxes.
        normalized: Whether conditional boxes are normalized.
        canvas_size: Pixel canvas used when `normalized=False`.
        num_inference_steps: Optional inference timestep count.
        sampling: Base LayoutDM sampling strategy.
        temperature: Base sampling temperature.
        top_k: Top-k cutoff for top-k sampling.
        top_p: Nucleus cutoff for top-p sampling.
        corrector_steps: Optional override for correction passes.
        corrector_t_list: Optional explicit correction timesteps.
        corrector_start: Range start for correction when no list is supplied.
        corrector_end: Range end for correction when no list is supplied.
        corrector_mask_mode: Optional override for remasking mode.
        corrector_mask_threshold: Optional threshold override.
        corrector_temperature: Optional confidence temperature override.
        use_gumbel_noise: Optional confidence-noise override.
        gumbel_temperature: Optional confidence-noise temperature override.
        time_adaptive_temperature: Optional adaptive-noise override.
        output_type: `"dataclass"` or `"dict"`.
        return_intermediates: Whether to include scores and trajectory.

    Returns:
        `LayoutGenerationOutput` by default, or a dictionary when requested.

    Raises:
        ValueError: If conditional generation is missing `bbox` or `labels`, or
            if `output_type` is unsupported.

    Examples:
        >>> LayoutCorrectorPipeline.__call__  # doctest: +ELLIPSIS
        <function...
    """
    _ = num_elements
    if generator is None and seed is not None:
        generator = torch.Generator(device=self.device).manual_seed(seed)
    canonical = normalize_condition_type(condition_type)
    condition = None
    if canonical != "unconditional":
        missing_inputs = [
            name
            for name, value in (("bbox", bbox), ("labels", labels))
            if value is None
        ]
        if missing_inputs:
            raise ValueError(
                "bbox and labels are required "
                f"for condition_type={condition_type}; "
                f"missing {', '.join(missing_inputs)}"
            )

        processor_inputs = {
            "bbox": bbox,
            "labels": labels,
            "mask": mask,
            "box_format": box_format,
            "normalized": normalized,
            "canvas_size": canvas_size,
        }
        processed = self.processor(**processor_inputs)
        decoded_input = self.layout_dm.tokenizer.decode_layout(
            processed["input_ids"]
        )
        condition = build_condition(
            self.layout_dm.tokenizer,
            cond_type=canonical,
            bbox=decoded_input["bbox"],
            labels=decoded_input["labels"],
            mask=decoded_input["mask"],
        )
        batch_size = condition.input_ids.shape[0]

    corrector_cfg = LayoutCorrectorSamplingConfig(
        sampling=sampling,
        temperature=temperature,
        top_k=top_k,
        top_p=top_p,
        num_inference_steps=num_inference_steps,
        corrector_steps=corrector_steps or self.corrector.corrector_steps,
        corrector_t_list=tuple(
            self.corrector.corrector_t_list
            if corrector_t_list is None
            else corrector_t_list
        ),
        corrector_start=corrector_start,
        corrector_end=corrector_end,
        corrector_mask_mode=corrector_mask_mode
        or self.corrector.corrector_mask_mode,
        corrector_mask_threshold=corrector_mask_threshold
        if corrector_mask_threshold is not None
        else self.corrector.corrector_mask_threshold,
        corrector_temperature=corrector_temperature
        if corrector_temperature is not None
        else self.corrector.corrector_temperature,
        use_gumbel_noise=use_gumbel_noise
        if use_gumbel_noise is not None
        else self.corrector.use_gumbel_noise,
        gumbel_temperature=gumbel_temperature
        if gumbel_temperature is not None
        else self.corrector.gumbel_temperature,
        time_adaptive_temperature=time_adaptive_temperature
        if time_adaptive_temperature is not None
        else self.corrector.time_adaptive_temperature,
    )
    sampling_cfg = LayoutDMSamplingConfig(
        name=sampling,
        temperature=temperature,
        top_k=top_k,
        top_p=top_p,
        num_inference_steps=num_inference_steps,
    )
    self.layout_dm.scheduler.set_timesteps(num_inference_steps, device=self.device)
    sample = self.layout_dm.scheduler.initial_sample(
        batch_size,
        self.layout_dm.tokenizer.config.max_token_length,
        device=self.device,
        condition=condition,
    )
    trajectory = [] if return_intermediates else None
    scores = [] if return_intermediates else None
    previous_timestep = self.layout_dm.scheduler.config.num_timesteps
    for timestep in self.layout_dm.scheduler.timesteps:
        timestep_value = int(timestep.item())
        timestep_batch = torch.full(
            (batch_size,),
            timestep_value,
            device=self.device,
            dtype=torch.long,
        )
        if should_apply_corrector(timestep_value, corrector_cfg):
            sample, confidence = self._step_with_corrector(
                sample=sample,
                timestep_batch=timestep_batch,
                condition=condition,
                sampling=corrector_cfg,
                generator=generator,
            )
            if scores is not None and confidence is not None:
                scores.append(confidence.detach().cpu())
        else:
            input_ids = log_onehot_to_index(sample)
            logits = self.layout_dm.denoiser(
                input_ids=input_ids, timesteps=timestep_batch
            ).logits
            sample = self.layout_dm.scheduler.step(
                logits,
                timestep_batch,
                sample,
                previous_timestep=previous_timestep,
                sampling=sampling_cfg,
                condition=condition,
                generator=generator,
            ).prev_sample
        previous_timestep = timestep_value
        if trajectory is not None:
            trajectory.append(log_onehot_to_index(sample).detach().cpu())

    sequences = log_onehot_to_index(sample).detach().cpu()
    decoded = self.layout_dm.tokenizer.decode_layout(sequences)
    output = LayoutGenerationOutput(
        bbox=decoded["bbox"],
        labels=decoded["labels"],
        mask=decoded["mask"],
        id2label=dict(self.corrector.id2label),
        sequences=sequences,
        scores=torch.stack(scores) if scores else None,
        trajectory=trajectory,
        intermediates={"condition_type": canonical}
        if return_intermediates
        else None,
    )
    normalized_output_type = normalize_output_type(output_type)
    if normalized_output_type is OutputType.dict:
        return dict(output)
    if normalized_output_type is OutputType.dataclass:
        return output
    assert_never(normalized_output_type)

save_pretrained

save_pretrained(
    save_directory: str | Path,
    *,
    safe_serialization: bool = True,
) -> None

Save the nested LayoutDM pipeline and corrector model.

Parameters:

Name Type Description Default
save_directory str | Path

Destination directory.

required
safe_serialization bool

Whether to save weights as safetensors.

True

Returns:

Type Description
None

None.

Raises:

Type Description
OSError

If files cannot be written.

Examples:

>>> LayoutCorrectorPipeline.save_pretrained
<function...
Source code in models/layout-corrector/src/layout_corrector/pipeline_layout_corrector.py
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
def save_pretrained(
    self, save_directory: str | Path, *, safe_serialization: bool = True
) -> None:
    """Save the nested LayoutDM pipeline and corrector model.

    Args:
        save_directory: Destination directory.
        safe_serialization: Whether to save weights as safetensors.

    Returns:
        None.

    Raises:
        OSError: If files cannot be written.

    Examples:
        >>> LayoutCorrectorPipeline.save_pretrained  # doctest: +ELLIPSIS
        <function...
    """
    save_path = Path(save_directory)
    save_path.mkdir(parents=True, exist_ok=True)
    self.layout_dm.save_pretrained(
        save_path / "layout_dm", safe_serialization=safe_serialization
    )
    self.corrector.save_pretrained(
        save_path / "corrector", safe_serialization=safe_serialization
    )

from_pretrained classmethod

from_pretrained(
    pretrained_model_name_or_path: str | Path,
    *,
    processor: LayoutDMProcessor | None = None,
) -> "LayoutCorrectorPipeline"

Load a Layout-Corrector pipeline from a saved directory.

Parameters:

Name Type Description Default
pretrained_model_name_or_path str | Path

Directory containing layout_dm/ and corrector/ subdirectories.

required
processor LayoutDMProcessor | None

Optional processor override.

None

Returns:

Type Description
'LayoutCorrectorPipeline'

Loaded LayoutCorrectorPipeline.

Raises:

Type Description
OSError

If nested component files are missing.

Examples:

>>> LayoutCorrectorPipeline.from_pretrained
<bound method...
Source code in models/layout-corrector/src/layout_corrector/pipeline_layout_corrector.py
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
@classmethod
def from_pretrained(
    cls,
    pretrained_model_name_or_path: str | Path,
    *,
    processor: LayoutDMProcessor | None = None,
) -> "LayoutCorrectorPipeline":
    """Load a Layout-Corrector pipeline from a saved directory.

    Args:
        pretrained_model_name_or_path: Directory containing `layout_dm/` and
            `corrector/` subdirectories.
        processor: Optional processor override.

    Returns:
        Loaded `LayoutCorrectorPipeline`.

    Raises:
        OSError: If nested component files are missing.

    Examples:
        >>> LayoutCorrectorPipeline.from_pretrained  # doctest: +ELLIPSIS
        <bound method...
    """
    path = Path(pretrained_model_name_or_path)
    layout_dm = LayoutDMPipeline.from_pretrained(path / "layout_dm")
    corrector = LayoutCorrectorModel.from_pretrained(path / "corrector")
    return cls(layout_dm=layout_dm, corrector=corrector, processor=processor)

CorrectorMaskMode

Bases: StrEnum

Supported token remasking modes for Layout-Corrector.

Source code in models/layout-corrector/src/layout_corrector/sampling.py
20
21
22
23
24
class CorrectorMaskMode(StrEnum):
    """Supported token remasking modes for Layout-Corrector."""

    thresh = auto()
    topk = auto()

LayoutCorrectorSamplingConfig dataclass

Sampling options for Layout-Corrector-guided diffusion.

Parameters:

Name Type Description Default
sampling SamplingMode | str

Base LayoutDM sampling strategy.

random
temperature float

Base sampling temperature.

1.0
top_k int

Top-k cutoff for top-k sampling.

5
top_p float

Nucleus cutoff for top-p sampling.

0.9
num_inference_steps int | None

Optional inference timestep count.

None
corrector_steps int

Number of correction passes per selected timestep.

1
corrector_t_list tuple[int, ...]

Explicit timesteps where the corrector is applied.

(10, 20, 30)
corrector_start int

Start timestep for range-based correction.

-1
corrector_end int

End timestep for range-based correction.

-1
corrector_mask_mode CorrectorMaskMode | str

Strategy for selecting tokens to remask.

thresh
corrector_mask_threshold float

Confidence threshold for threshold masking.

0.7
corrector_temperature float

Temperature used for confidence masking.

1.0
use_gumbel_noise bool

Whether to perturb confidence logits.

True
gumbel_temperature float

Temperature for confidence Gumbel noise.

1.0
time_adaptive_temperature bool

Whether to scale noise by timestep ratio.

False

Raises:

Type Description
ValueError

Construction does not raise directly.

Examples:

>>> LayoutCorrectorSamplingConfig(corrector_t_list=(10,)).corrector_t_list
(10,)
Source code in models/layout-corrector/src/layout_corrector/sampling.py
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
@dataclass
class LayoutCorrectorSamplingConfig:
    """Sampling options for Layout-Corrector-guided diffusion.

    Args:
        sampling: Base LayoutDM sampling strategy.
        temperature: Base sampling temperature.
        top_k: Top-k cutoff for top-k sampling.
        top_p: Nucleus cutoff for top-p sampling.
        num_inference_steps: Optional inference timestep count.
        corrector_steps: Number of correction passes per selected timestep.
        corrector_t_list: Explicit timesteps where the corrector is applied.
        corrector_start: Start timestep for range-based correction.
        corrector_end: End timestep for range-based correction.
        corrector_mask_mode: Strategy for selecting tokens to remask.
        corrector_mask_threshold: Confidence threshold for threshold masking.
        corrector_temperature: Temperature used for confidence masking.
        use_gumbel_noise: Whether to perturb confidence logits.
        gumbel_temperature: Temperature for confidence Gumbel noise.
        time_adaptive_temperature: Whether to scale noise by timestep ratio.

    Raises:
        ValueError: Construction does not raise directly.

    Examples:
        >>> LayoutCorrectorSamplingConfig(corrector_t_list=(10,)).corrector_t_list
        (10,)
    """

    sampling: SamplingMode | str = SamplingMode.random
    temperature: float = 1.0
    top_k: int = 5
    top_p: float = 0.9
    num_inference_steps: int | None = None
    corrector_steps: int = 1
    corrector_t_list: tuple[int, ...] = (10, 20, 30)
    corrector_start: int = -1
    corrector_end: int = -1
    corrector_mask_mode: CorrectorMaskMode | str = CorrectorMaskMode.thresh
    corrector_mask_threshold: float = 0.7
    corrector_temperature: float = 1.0
    use_gumbel_noise: bool = True
    gumbel_temperature: float = 1.0
    time_adaptive_temperature: bool = False

    def __post_init__(self) -> None:
        """Normalize public string modes to enum values."""
        self.sampling = normalize_sampling_mode(self.sampling)
        self.corrector_mask_mode = normalize_corrector_mask_mode(
            self.corrector_mask_mode
        )

__post_init__

__post_init__() -> None

Normalize public string modes to enum values.

Source code in models/layout-corrector/src/layout_corrector/sampling.py
86
87
88
89
90
91
def __post_init__(self) -> None:
    """Normalize public string modes to enum values."""
    self.sampling = normalize_sampling_mode(self.sampling)
    self.corrector_mask_mode = normalize_corrector_mask_mode(
        self.corrector_mask_mode
    )

configuration_layout_corrector

Configuration objects for Layout-Corrector models.

CorrectorReconType

Bases: StrEnum

Supported Layout-Corrector reconstruction targets.

Source code in models/layout-corrector/src/layout_corrector/configuration_layout_corrector.py
21
22
23
24
25
class CorrectorReconType(StrEnum):
    """Supported Layout-Corrector reconstruction targets."""

    x_0 = auto()
    x_t_minus_1 = "x_t-1"

CorrectorTarget

Bases: StrEnum

Supported Layout-Corrector confidence targets.

Source code in models/layout-corrector/src/layout_corrector/configuration_layout_corrector.py
28
29
30
31
32
class CorrectorTarget(StrEnum):
    """Supported Layout-Corrector confidence targets."""

    mask = auto()
    recon_acc = auto()

CorrectorPositionEmbedding

Bases: StrEnum

Supported original position-embedding modes.

Source code in models/layout-corrector/src/layout_corrector/configuration_layout_corrector.py
35
36
37
38
39
40
41
42
class CorrectorPositionEmbedding(StrEnum):
    """Supported original position-embedding modes."""

    default = auto()
    none = auto()
    pos_enc = auto()
    shuffle_pos_enc = auto()
    shuffle = auto()

CorrectorTransformerType

Bases: StrEnum

Supported corrector transformer variants.

Source code in models/layout-corrector/src/layout_corrector/configuration_layout_corrector.py
45
46
47
48
class CorrectorTransformerType(StrEnum):
    """Supported corrector transformer variants."""

    aggregated = auto()

LayoutCorrectorConfig

Bases: ConfigMixin

Configuration for the Layout-Corrector transformer.

Parameters:

Name Type Description Default
dataset_name DatasetName | str

Dataset key or alias used for labels.

required
vocab_size int

LayoutDM vocabulary size expected by the corrector.

required
id2label dict[int | str, str] | None

Optional class-id mapping. When omitted, the shared registry is used.

None
max_seq_length int

Maximum number of layout elements.

25
num_attributes_per_element int

Number of token attributes per element.

5
hidden_size int

Transformer hidden dimension.

464
num_attention_heads int

Number of attention heads.

8
num_hidden_layers int

Number of transformer layers.

4
intermediate_size int

Feed-forward hidden dimension.

1856
dropout float

Dropout probability.

0.0
timestep_type str | None

Timestep conditioning type.

'adalayernorm'
num_timesteps int

Number of diffusion training timesteps.

100
recon_type CorrectorReconType | str

Reconstruction target used by the corrector.

x_t_minus_1
target CorrectorTarget | str

Confidence target type.

recon_acc
attr_loss_weights tuple[float, float, float, float, float]

Per-attribute loss weights.

(1.0, 1.0, 1.0, 1.0, 1.0)
use_padding_as_vocab bool

Whether padding is part of the modeled vocabulary.

True
pos_emb CorrectorPositionEmbedding | str

Position embedding mode from the original implementation.

none
transformer_type CorrectorTransformerType | str

Corrector transformer variant.

aggregated
corrector_steps int

Number of correction passes per selected timestep.

1
corrector_t_list tuple[int, ...]

Explicit timesteps where the corrector is applied.

(10, 20, 30)
corrector_mask_mode CorrectorMaskMode | str

Strategy for selecting tokens to remask.

thresh
corrector_mask_threshold float

Confidence threshold for threshold masking.

0.7
corrector_temperature float

Temperature used for corrector resampling.

1.0
use_gumbel_noise bool

Whether to perturb confidence logits.

True
gumbel_temperature float

Temperature for confidence Gumbel noise.

1.0
time_adaptive_temperature bool

Whether to scale noise by timestep ratio.

False

Raises:

Type Description
ValueError

If a supplied dataset, shape, or option is unsupported.

Examples:

>>> cfg = LayoutCorrectorConfig(dataset_name="publaynet", vocab_size=100)
>>> cfg.max_token_length
125
Source code in models/layout-corrector/src/layout_corrector/configuration_layout_corrector.py
 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
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
class LayoutCorrectorConfig(ConfigMixin):
    """Configuration for the Layout-Corrector transformer.

    Args:
        dataset_name: Dataset key or alias used for labels.
        vocab_size: LayoutDM vocabulary size expected by the corrector.
        id2label: Optional class-id mapping. When omitted, the shared registry is used.
        max_seq_length: Maximum number of layout elements.
        num_attributes_per_element: Number of token attributes per element.
        hidden_size: Transformer hidden dimension.
        num_attention_heads: Number of attention heads.
        num_hidden_layers: Number of transformer layers.
        intermediate_size: Feed-forward hidden dimension.
        dropout: Dropout probability.
        timestep_type: Timestep conditioning type.
        num_timesteps: Number of diffusion training timesteps.
        recon_type: Reconstruction target used by the corrector.
        target: Confidence target type.
        attr_loss_weights: Per-attribute loss weights.
        use_padding_as_vocab: Whether padding is part of the modeled vocabulary.
        pos_emb: Position embedding mode from the original implementation.
        transformer_type: Corrector transformer variant.
        corrector_steps: Number of correction passes per selected timestep.
        corrector_t_list: Explicit timesteps where the corrector is applied.
        corrector_mask_mode: Strategy for selecting tokens to remask.
        corrector_mask_threshold: Confidence threshold for threshold masking.
        corrector_temperature: Temperature used for corrector resampling.
        use_gumbel_noise: Whether to perturb confidence logits.
        gumbel_temperature: Temperature for confidence Gumbel noise.
        time_adaptive_temperature: Whether to scale noise by timestep ratio.

    Raises:
        ValueError: If a supplied dataset, shape, or option is unsupported.

    Examples:
        >>> cfg = LayoutCorrectorConfig(dataset_name="publaynet", vocab_size=100)
        >>> cfg.max_token_length
        125
    """

    config_name = "corrector_config.json"

    @register_to_config
    def __init__(
        self,
        *,
        dataset_name: DatasetName | str,
        vocab_size: int,
        id2label: dict[int | str, str] | None = None,
        max_seq_length: int = 25,
        num_attributes_per_element: int = 5,
        hidden_size: int = 464,
        num_attention_heads: int = 8,
        num_hidden_layers: int = 4,
        intermediate_size: int = 1856,
        dropout: float = 0.0,
        timestep_type: str | None = "adalayernorm",
        num_timesteps: int = 100,
        recon_type: CorrectorReconType | str = CorrectorReconType.x_t_minus_1,
        target: CorrectorTarget | str = CorrectorTarget.recon_acc,
        attr_loss_weights: tuple[float, float, float, float, float] = (
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
        ),
        use_padding_as_vocab: bool = True,
        pos_emb: CorrectorPositionEmbedding | str = CorrectorPositionEmbedding.none,
        transformer_type: CorrectorTransformerType | str = (
            CorrectorTransformerType.aggregated
        ),
        corrector_steps: int = 1,
        corrector_t_list: tuple[int, ...] = (10, 20, 30),
        corrector_mask_mode: CorrectorMaskMode | str = CorrectorMaskMode.thresh,
        corrector_mask_threshold: float = 0.7,
        corrector_temperature: float = 1.0,
        use_gumbel_noise: bool = True,
        gumbel_temperature: float = 1.0,
        time_adaptive_temperature: bool = False,
    ) -> None:
        """Initialize a Layout-Corrector config.

        Args:
            dataset_name: Dataset key or alias used for labels.
            vocab_size: LayoutDM vocabulary size expected by the corrector.
            id2label: Optional class-id mapping.
            max_seq_length: Maximum number of layout elements.
            num_attributes_per_element: Number of token attributes per element.
            hidden_size: Transformer hidden dimension.
            num_attention_heads: Number of attention heads.
            num_hidden_layers: Number of transformer layers.
            intermediate_size: Feed-forward hidden dimension.
            dropout: Dropout probability.
            timestep_type: Timestep conditioning type.
            num_timesteps: Number of diffusion training timesteps.
            recon_type: Reconstruction target used by the corrector.
            target: Confidence target type.
            attr_loss_weights: Per-attribute loss weights.
            use_padding_as_vocab: Whether padding is part of the modeled vocabulary.
            pos_emb: Position embedding mode.
            transformer_type: Corrector transformer variant.
            corrector_steps: Number of correction passes per selected timestep.
            corrector_t_list: Explicit timesteps where the corrector is applied.
            corrector_mask_mode: Strategy for selecting tokens to remask.
            corrector_mask_threshold: Confidence threshold for threshold masking.
            corrector_temperature: Temperature used for corrector resampling.
            use_gumbel_noise: Whether to perturb confidence logits.
            gumbel_temperature: Temperature for confidence Gumbel noise.
            time_adaptive_temperature: Whether to scale noise by timestep ratio.

        Raises:
            ValueError: If a supplied dataset, shape, or option is unsupported.

        Examples:
            >>> cfg = LayoutCorrectorConfig(dataset_name="publaynet", vocab_size=100)
            >>> cfg.max_token_length
            125
        """
        try:
            dataset_name = str(normalize_dataset_name(dataset_name))
        except ValueError:
            if id2label is None:
                raise

            dataset_name = str(dataset_name)
        self.register_to_config(dataset_name=dataset_name)
        if vocab_size <= 0:
            raise ValueError("vocab_size must be positive")

        if max_seq_length <= 0:
            raise ValueError("max_seq_length must be positive")

        if num_attributes_per_element != 5:
            raise ValueError("Layout-Corrector supports 5 attributes per element")

        if num_timesteps <= 0:
            raise ValueError("num_timesteps must be positive")

        recon_type, target, transformer_type, pos_emb = (
            normalize_corrector_core_options(
                recon_type,
                target,
                transformer_type,
                pos_emb,
            )
        )
        if len(attr_loss_weights) != num_attributes_per_element:
            raise ValueError("attr_loss_weights must match num_attributes_per_element")

        if corrector_steps <= 0:
            raise ValueError("corrector_steps must be positive")

        try:
            corrector_mask_mode = normalize_corrector_mask_mode(corrector_mask_mode)
        except ValueError as exc:
            raise ValueError(
                f"Unsupported corrector_mask_mode: {corrector_mask_mode}"
            ) from exc

        if not 0.0 <= corrector_mask_threshold <= 1.0:
            raise ValueError("corrector_mask_threshold must be in [0, 1]")

        self.register_to_config(
            dataset_name=dataset_name,
            recon_type=str(recon_type),
            target=str(target),
            pos_emb=str(pos_emb),
            transformer_type=str(transformer_type),
            corrector_mask_mode=str(corrector_mask_mode),
        )

        self.dataset_name = dataset_name
        raw_id2label = id2label or id2label_for_dataset(dataset_name)
        self.id2label = {int(k): v for k, v in raw_id2label.items()}
        self.vocab_size = vocab_size
        self.max_seq_length = max_seq_length
        self.num_attributes_per_element = num_attributes_per_element
        self.hidden_size = hidden_size
        self.num_attention_heads = num_attention_heads
        self.num_hidden_layers = num_hidden_layers
        self.intermediate_size = intermediate_size
        self.dropout = dropout
        self.timestep_type = timestep_type
        self.num_timesteps = num_timesteps

        self.recon_type = str(recon_type)
        self.target = str(target)
        self.attr_loss_weights = tuple(float(v) for v in attr_loss_weights)
        self.use_padding_as_vocab = use_padding_as_vocab
        self.pos_emb = str(pos_emb)
        self.transformer_type = str(transformer_type)

        self.corrector_steps = corrector_steps
        self.corrector_t_list = tuple(int(v) for v in corrector_t_list)
        self.corrector_mask_mode = str(corrector_mask_mode)
        self.corrector_mask_threshold = corrector_mask_threshold
        self.corrector_temperature = corrector_temperature
        self.use_gumbel_noise = use_gumbel_noise
        self.gumbel_temperature = gumbel_temperature
        self.time_adaptive_temperature = time_adaptive_temperature

    @property
    def max_token_length(self) -> int:
        """Return the flattened token length for one layout sequence.

        Returns:
            Maximum token count after flattening element attributes.

        Examples:
            >>> LayoutCorrectorConfig(dataset_name="publaynet", vocab_size=100).max_token_length
            125
        """
        return self.max_seq_length * self.num_attributes_per_element

max_token_length property

max_token_length: int

Return the flattened token length for one layout sequence.

Returns:

Type Description
int

Maximum token count after flattening element attributes.

Examples:

>>> LayoutCorrectorConfig(dataset_name="publaynet", vocab_size=100).max_token_length
125

__init__

__init__(
    *,
    dataset_name: DatasetName | str,
    vocab_size: int,
    id2label: dict[int | str, str] | None = None,
    max_seq_length: int = 25,
    num_attributes_per_element: int = 5,
    hidden_size: int = 464,
    num_attention_heads: int = 8,
    num_hidden_layers: int = 4,
    intermediate_size: int = 1856,
    dropout: float = 0.0,
    timestep_type: str | None = "adalayernorm",
    num_timesteps: int = 100,
    recon_type: CorrectorReconType
    | str = CorrectorReconType.x_t_minus_1,
    target: CorrectorTarget
    | str = CorrectorTarget.recon_acc,
    attr_loss_weights: tuple[
        float, float, float, float, float
    ] = (1.0, 1.0, 1.0, 1.0, 1.0),
    use_padding_as_vocab: bool = True,
    pos_emb: CorrectorPositionEmbedding
    | str = CorrectorPositionEmbedding.none,
    transformer_type: CorrectorTransformerType
    | str = CorrectorTransformerType.aggregated,
    corrector_steps: int = 1,
    corrector_t_list: tuple[int, ...] = (10, 20, 30),
    corrector_mask_mode: CorrectorMaskMode
    | str = CorrectorMaskMode.thresh,
    corrector_mask_threshold: float = 0.7,
    corrector_temperature: float = 1.0,
    use_gumbel_noise: bool = True,
    gumbel_temperature: float = 1.0,
    time_adaptive_temperature: bool = False,
) -> None

Initialize a Layout-Corrector config.

Parameters:

Name Type Description Default
dataset_name DatasetName | str

Dataset key or alias used for labels.

required
vocab_size int

LayoutDM vocabulary size expected by the corrector.

required
id2label dict[int | str, str] | None

Optional class-id mapping.

None
max_seq_length int

Maximum number of layout elements.

25
num_attributes_per_element int

Number of token attributes per element.

5
hidden_size int

Transformer hidden dimension.

464
num_attention_heads int

Number of attention heads.

8
num_hidden_layers int

Number of transformer layers.

4
intermediate_size int

Feed-forward hidden dimension.

1856
dropout float

Dropout probability.

0.0
timestep_type str | None

Timestep conditioning type.

'adalayernorm'
num_timesteps int

Number of diffusion training timesteps.

100
recon_type CorrectorReconType | str

Reconstruction target used by the corrector.

x_t_minus_1
target CorrectorTarget | str

Confidence target type.

recon_acc
attr_loss_weights tuple[float, float, float, float, float]

Per-attribute loss weights.

(1.0, 1.0, 1.0, 1.0, 1.0)
use_padding_as_vocab bool

Whether padding is part of the modeled vocabulary.

True
pos_emb CorrectorPositionEmbedding | str

Position embedding mode.

none
transformer_type CorrectorTransformerType | str

Corrector transformer variant.

aggregated
corrector_steps int

Number of correction passes per selected timestep.

1
corrector_t_list tuple[int, ...]

Explicit timesteps where the corrector is applied.

(10, 20, 30)
corrector_mask_mode CorrectorMaskMode | str

Strategy for selecting tokens to remask.

thresh
corrector_mask_threshold float

Confidence threshold for threshold masking.

0.7
corrector_temperature float

Temperature used for corrector resampling.

1.0
use_gumbel_noise bool

Whether to perturb confidence logits.

True
gumbel_temperature float

Temperature for confidence Gumbel noise.

1.0
time_adaptive_temperature bool

Whether to scale noise by timestep ratio.

False

Raises:

Type Description
ValueError

If a supplied dataset, shape, or option is unsupported.

Examples:

>>> cfg = LayoutCorrectorConfig(dataset_name="publaynet", vocab_size=100)
>>> cfg.max_token_length
125
Source code in models/layout-corrector/src/layout_corrector/configuration_layout_corrector.py
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
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
@register_to_config
def __init__(
    self,
    *,
    dataset_name: DatasetName | str,
    vocab_size: int,
    id2label: dict[int | str, str] | None = None,
    max_seq_length: int = 25,
    num_attributes_per_element: int = 5,
    hidden_size: int = 464,
    num_attention_heads: int = 8,
    num_hidden_layers: int = 4,
    intermediate_size: int = 1856,
    dropout: float = 0.0,
    timestep_type: str | None = "adalayernorm",
    num_timesteps: int = 100,
    recon_type: CorrectorReconType | str = CorrectorReconType.x_t_minus_1,
    target: CorrectorTarget | str = CorrectorTarget.recon_acc,
    attr_loss_weights: tuple[float, float, float, float, float] = (
        1.0,
        1.0,
        1.0,
        1.0,
        1.0,
    ),
    use_padding_as_vocab: bool = True,
    pos_emb: CorrectorPositionEmbedding | str = CorrectorPositionEmbedding.none,
    transformer_type: CorrectorTransformerType | str = (
        CorrectorTransformerType.aggregated
    ),
    corrector_steps: int = 1,
    corrector_t_list: tuple[int, ...] = (10, 20, 30),
    corrector_mask_mode: CorrectorMaskMode | str = CorrectorMaskMode.thresh,
    corrector_mask_threshold: float = 0.7,
    corrector_temperature: float = 1.0,
    use_gumbel_noise: bool = True,
    gumbel_temperature: float = 1.0,
    time_adaptive_temperature: bool = False,
) -> None:
    """Initialize a Layout-Corrector config.

    Args:
        dataset_name: Dataset key or alias used for labels.
        vocab_size: LayoutDM vocabulary size expected by the corrector.
        id2label: Optional class-id mapping.
        max_seq_length: Maximum number of layout elements.
        num_attributes_per_element: Number of token attributes per element.
        hidden_size: Transformer hidden dimension.
        num_attention_heads: Number of attention heads.
        num_hidden_layers: Number of transformer layers.
        intermediate_size: Feed-forward hidden dimension.
        dropout: Dropout probability.
        timestep_type: Timestep conditioning type.
        num_timesteps: Number of diffusion training timesteps.
        recon_type: Reconstruction target used by the corrector.
        target: Confidence target type.
        attr_loss_weights: Per-attribute loss weights.
        use_padding_as_vocab: Whether padding is part of the modeled vocabulary.
        pos_emb: Position embedding mode.
        transformer_type: Corrector transformer variant.
        corrector_steps: Number of correction passes per selected timestep.
        corrector_t_list: Explicit timesteps where the corrector is applied.
        corrector_mask_mode: Strategy for selecting tokens to remask.
        corrector_mask_threshold: Confidence threshold for threshold masking.
        corrector_temperature: Temperature used for corrector resampling.
        use_gumbel_noise: Whether to perturb confidence logits.
        gumbel_temperature: Temperature for confidence Gumbel noise.
        time_adaptive_temperature: Whether to scale noise by timestep ratio.

    Raises:
        ValueError: If a supplied dataset, shape, or option is unsupported.

    Examples:
        >>> cfg = LayoutCorrectorConfig(dataset_name="publaynet", vocab_size=100)
        >>> cfg.max_token_length
        125
    """
    try:
        dataset_name = str(normalize_dataset_name(dataset_name))
    except ValueError:
        if id2label is None:
            raise

        dataset_name = str(dataset_name)
    self.register_to_config(dataset_name=dataset_name)
    if vocab_size <= 0:
        raise ValueError("vocab_size must be positive")

    if max_seq_length <= 0:
        raise ValueError("max_seq_length must be positive")

    if num_attributes_per_element != 5:
        raise ValueError("Layout-Corrector supports 5 attributes per element")

    if num_timesteps <= 0:
        raise ValueError("num_timesteps must be positive")

    recon_type, target, transformer_type, pos_emb = (
        normalize_corrector_core_options(
            recon_type,
            target,
            transformer_type,
            pos_emb,
        )
    )
    if len(attr_loss_weights) != num_attributes_per_element:
        raise ValueError("attr_loss_weights must match num_attributes_per_element")

    if corrector_steps <= 0:
        raise ValueError("corrector_steps must be positive")

    try:
        corrector_mask_mode = normalize_corrector_mask_mode(corrector_mask_mode)
    except ValueError as exc:
        raise ValueError(
            f"Unsupported corrector_mask_mode: {corrector_mask_mode}"
        ) from exc

    if not 0.0 <= corrector_mask_threshold <= 1.0:
        raise ValueError("corrector_mask_threshold must be in [0, 1]")

    self.register_to_config(
        dataset_name=dataset_name,
        recon_type=str(recon_type),
        target=str(target),
        pos_emb=str(pos_emb),
        transformer_type=str(transformer_type),
        corrector_mask_mode=str(corrector_mask_mode),
    )

    self.dataset_name = dataset_name
    raw_id2label = id2label or id2label_for_dataset(dataset_name)
    self.id2label = {int(k): v for k, v in raw_id2label.items()}
    self.vocab_size = vocab_size
    self.max_seq_length = max_seq_length
    self.num_attributes_per_element = num_attributes_per_element
    self.hidden_size = hidden_size
    self.num_attention_heads = num_attention_heads
    self.num_hidden_layers = num_hidden_layers
    self.intermediate_size = intermediate_size
    self.dropout = dropout
    self.timestep_type = timestep_type
    self.num_timesteps = num_timesteps

    self.recon_type = str(recon_type)
    self.target = str(target)
    self.attr_loss_weights = tuple(float(v) for v in attr_loss_weights)
    self.use_padding_as_vocab = use_padding_as_vocab
    self.pos_emb = str(pos_emb)
    self.transformer_type = str(transformer_type)

    self.corrector_steps = corrector_steps
    self.corrector_t_list = tuple(int(v) for v in corrector_t_list)
    self.corrector_mask_mode = str(corrector_mask_mode)
    self.corrector_mask_threshold = corrector_mask_threshold
    self.corrector_temperature = corrector_temperature
    self.use_gumbel_noise = use_gumbel_noise
    self.gumbel_temperature = gumbel_temperature
    self.time_adaptive_temperature = time_adaptive_temperature

normalize_corrector_core_options

normalize_corrector_core_options(
    recon_type: CorrectorReconType | str,
    target: CorrectorTarget | str,
    transformer_type: CorrectorTransformerType | str,
    pos_emb: CorrectorPositionEmbedding | str,
) -> tuple[
    CorrectorReconType,
    CorrectorTarget,
    CorrectorTransformerType,
    CorrectorPositionEmbedding,
]

Normalize shared Layout-Corrector enum options.

Source code in models/layout-corrector/src/layout_corrector/configuration_layout_corrector.py
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
def normalize_corrector_core_options(
    recon_type: CorrectorReconType | str,
    target: CorrectorTarget | str,
    transformer_type: CorrectorTransformerType | str,
    pos_emb: CorrectorPositionEmbedding | str,
) -> tuple[
    CorrectorReconType,
    CorrectorTarget,
    CorrectorTransformerType,
    CorrectorPositionEmbedding,
]:
    """Normalize shared Layout-Corrector enum options."""
    try:
        normalized_recon_type = CorrectorReconType(recon_type)
    except ValueError as exc:
        raise ValueError(f"Unsupported recon_type: {recon_type}") from exc

    try:
        normalized_target = CorrectorTarget(target)
    except ValueError as exc:
        raise ValueError(f"Unsupported target: {target}") from exc

    try:
        normalized_transformer_type = CorrectorTransformerType(transformer_type)
    except ValueError as exc:
        raise ValueError("Only transformer_type='aggregated' is supported") from exc

    try:
        normalized_pos_emb = CorrectorPositionEmbedding(pos_emb)
    except ValueError as exc:
        raise ValueError(f"Unsupported pos_emb: {pos_emb}") from exc

    return (
        normalized_recon_type,
        normalized_target,
        normalized_transformer_type,
        normalized_pos_emb,
    )

conversion

Conversion helpers for original Layout-Corrector checkpoints.

LayoutDMPipelineLike

Bases: Protocol

Nested LayoutDM pipeline surface needed during conversion.

Source code in models/layout-corrector/src/layout_corrector/conversion.py
39
40
41
42
43
class LayoutDMPipelineLike(Protocol):
    """Nested LayoutDM pipeline surface needed during conversion."""

    tokenizer: _LayoutDMTokenizerLike
    scheduler: _LayoutDMSchedulerLike

CompatibilityKey

Bases: StrEnum

LayoutDM fields that must match the converted corrector config.

Source code in models/layout-corrector/src/layout_corrector/conversion.py
46
47
48
49
50
51
52
class CompatibilityKey(StrEnum):
    """LayoutDM fields that must match the converted corrector config."""

    vocab_size = auto()
    max_seq_length = auto()
    num_attributes_per_element = auto()
    num_timesteps = auto()

OriginalDatasetConfig

Bases: TypedDict

Dataset section of the original Layout-Corrector YAML.

Source code in models/layout-corrector/src/layout_corrector/conversion.py
55
56
57
58
class OriginalDatasetConfig(TypedDict, total=False):
    """Dataset section of the original Layout-Corrector YAML."""

    max_seq_length: int

OriginalDataConfig

Bases: TypedDict

Data section of the original Layout-Corrector YAML.

Source code in models/layout-corrector/src/layout_corrector/conversion.py
61
62
63
64
class OriginalDataConfig(TypedDict, total=False):
    """Data section of the original Layout-Corrector YAML."""

    var_order: str

OriginalModelConfig

Bases: TypedDict

Model section of the original Layout-Corrector YAML.

Source code in models/layout-corrector/src/layout_corrector/conversion.py
67
68
69
70
71
72
73
74
75
76
class OriginalModelConfig(TypedDict, total=False):
    """Model section of the original Layout-Corrector YAML."""

    num_timesteps: int
    recon_type: str
    target: str
    attr_loss_weights: list[float]
    use_padding_as_vocab: bool
    pos_emb: str
    transformer_type: str

OriginalEncoderLayerConfig

Bases: TypedDict

Backbone encoder-layer section of the original YAML.

Source code in models/layout-corrector/src/layout_corrector/conversion.py
79
80
81
82
83
84
class OriginalEncoderLayerConfig(TypedDict, total=False):
    """Backbone encoder-layer section of the original YAML."""

    nhead: int
    dropout: float
    timestep_type: str

OriginalBackboneConfig

Bases: TypedDict

Backbone section of the original Layout-Corrector YAML.

Source code in models/layout-corrector/src/layout_corrector/conversion.py
87
88
89
90
91
class OriginalBackboneConfig(TypedDict, total=False):
    """Backbone section of the original Layout-Corrector YAML."""

    num_layers: int
    encoder_layer: OriginalEncoderLayerConfig

OriginalConfig

Bases: TypedDict

Typed shape for the original Layout-Corrector YAML.

Source code in models/layout-corrector/src/layout_corrector/conversion.py
 94
 95
 96
 97
 98
 99
100
class OriginalConfig(TypedDict):
    """Typed shape for the original Layout-Corrector YAML."""

    data: OriginalDataConfig
    dataset: OriginalDatasetConfig
    model: OriginalModelConfig
    backbone: OriginalBackboneConfig

remap_corrector_key

remap_corrector_key(key: str) -> str

Map an original checkpoint key to the converted module key.

Parameters:

Name Type Description Default
key str

Original state-dict key.

required

Returns:

Type Description
str

Key accepted by AggregatedCategoricalTransformer.

Raises:

Type Description
ValueError

If the key does not use an expected original prefix.

Source code in models/layout-corrector/src/layout_corrector/conversion.py
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
def remap_corrector_key(key: str) -> str:
    """Map an original checkpoint key to the converted module key.

    Args:
        key: Original state-dict key.

    Returns:
        Key accepted by `AggregatedCategoricalTransformer`.

    Raises:
        ValueError: If the key does not use an expected original prefix.
    """
    for prefix in _ORIGINAL_KEY_PREFIXES:
        if key.startswith(prefix):
            return key.removeprefix(prefix)
    raise ValueError(f"Unexpected corrector checkpoint key: {key}")

split_original_corrector_state_dict

split_original_corrector_state_dict(
    state_dict: dict[str, Shaped[Tensor, "..."]],
) -> dict[str, Shaped[torch.Tensor, "..."]]

Strip original wrapper prefixes from a corrector state dict.

Parameters:

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

Original checkpoint state dictionary.

required

Returns:

Type Description
dict[str, Shaped[Tensor, '...']]

Converted state dictionary.

Source code in models/layout-corrector/src/layout_corrector/conversion.py
121
122
123
124
125
126
127
128
129
130
131
132
def split_original_corrector_state_dict(
    state_dict: dict[str, Shaped[torch.Tensor, "..."]],
) -> dict[str, Shaped[torch.Tensor, "..."]]:
    """Strip original wrapper prefixes from a corrector state dict.

    Args:
        state_dict: Original checkpoint state dictionary.

    Returns:
        Converted state dictionary.
    """
    return {remap_corrector_key(key): value for key, value in state_dict.items()}

load_original_corrector_state_dict

load_original_corrector_state_dict(
    path: str | Path,
) -> dict[str, Shaped[torch.Tensor, "..."]]

Load and remap an original corrector checkpoint.

Parameters:

Name Type Description Default
path str | Path

Path to best_model.pt.

required

Returns:

Type Description
dict[str, Shaped[Tensor, '...']]

Converted state dictionary.

Source code in models/layout-corrector/src/layout_corrector/conversion.py
135
136
137
138
139
140
141
142
143
144
145
146
147
148
def load_original_corrector_state_dict(
    path: str | Path,
) -> dict[str, Shaped[torch.Tensor, "..."]]:
    """Load and remap an original corrector checkpoint.

    Args:
        path: Path to `best_model.pt`.

    Returns:
        Converted state dictionary.
    """
    state = torch.load(path, map_location="cpu")
    raw = state.get("state_dict", state)
    return split_original_corrector_state_dict(raw)

corrector_config_from_original

corrector_config_from_original(
    *,
    dataset: str,
    config_path: str | Path,
    state_dict: dict[str, Shaped[Tensor, "..."]],
    layout_dm: LayoutDMPipelineLike,
) -> LayoutCorrectorConfig

Build a Layout-Corrector config from original files.

Parameters:

Name Type Description Default
dataset str

Dataset key or alias.

required
config_path str | Path

Original config.yaml path.

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

Converted corrector state dictionary.

required
layout_dm LayoutDMPipelineLike

Nested LayoutDM pipeline used for compatibility checks.

required

Returns:

Type Description
LayoutCorrectorConfig

Converted Layout-Corrector config.

Source code in models/layout-corrector/src/layout_corrector/conversion.py
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
def corrector_config_from_original(
    *,
    dataset: str,
    config_path: str | Path,
    state_dict: dict[str, Shaped[torch.Tensor, "..."]],
    layout_dm: LayoutDMPipelineLike,
) -> LayoutCorrectorConfig:
    """Build a Layout-Corrector config from original files.

    Args:
        dataset: Dataset key or alias.
        config_path: Original `config.yaml` path.
        state_dict: Converted corrector state dictionary.
        layout_dm: Nested LayoutDM pipeline used for compatibility checks.

    Returns:
        Converted Layout-Corrector config.
    """
    with Path(config_path).open() as f:
        original_config = cast(OriginalConfig, yaml.safe_load(f))
    data_cfg = original_config["data"]
    model_cfg = original_config["model"]
    layer_cfg = original_config["backbone"]["encoder_layer"]
    hidden_size = int(state_dict["cat_emb.weight"].shape[1])
    intermediate_size = int(state_dict["backbone.layers.0.linear1.weight"].shape[0])
    normalized_dataset = (
        str(normalize_dataset_name(dataset))
        if dataset not in _CRELLO_DATASET_ALIASES
        else CRELLO_BBOX_DATASET
    )
    id2label = (
        getattr(getattr(layout_dm, "tokenizer").config, "id2label")
        if normalized_dataset == CRELLO_BBOX_DATASET
        else None
    )
    return LayoutCorrectorConfig(
        dataset_name=normalized_dataset,
        id2label=id2label,
        vocab_size=int(state_dict["cat_emb.weight"].shape[0]),
        max_seq_length=int(original_config["dataset"].get("max_seq_length", 25)),
        num_attributes_per_element=len(
            data_cfg.get("var_order", _DEFAULT_VAR_ORDER).split("-")
        ),
        hidden_size=hidden_size,
        num_attention_heads=int(layer_cfg.get("nhead", 8)),
        num_hidden_layers=int(original_config["backbone"].get("num_layers", 4)),
        intermediate_size=intermediate_size,
        dropout=float(layer_cfg.get("dropout", 0.0)),
        timestep_type=layer_cfg.get("timestep_type", "adalayernorm"),
        num_timesteps=int(model_cfg.get("num_timesteps", 100)),
        recon_type=model_cfg.get("recon_type", "x_t-1"),
        target=model_cfg.get("target", "recon_acc"),
        attr_loss_weights=tuple(
            float(v) for v in model_cfg.get("attr_loss_weights", [1, 1, 1, 1, 1])
        ),
        use_padding_as_vocab=bool(model_cfg.get("use_padding_as_vocab", True)),
        pos_emb=model_cfg.get("pos_emb", "none"),
        transformer_type=model_cfg.get("transformer_type", "aggregated"),
    )

build_corrector_from_original

build_corrector_from_original(
    *,
    dataset: str,
    checkpoint_dir: str | Path,
    layout_dm: LayoutDMPipelineLike,
) -> LayoutCorrectorModel

Build a LayoutCorrectorModel from an original checkpoint directory.

Parameters:

Name Type Description Default
dataset str

Dataset key or alias.

required
checkpoint_dir str | Path

Directory containing best_model.pt and config.yaml.

required
layout_dm LayoutDMPipelineLike

Nested LayoutDM pipeline paired with the corrector.

required

Returns:

Type Description
LayoutCorrectorModel

Loaded and eval-mode corrector model.

Source code in models/layout-corrector/src/layout_corrector/conversion.py
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
def build_corrector_from_original(
    *,
    dataset: str,
    checkpoint_dir: str | Path,
    layout_dm: LayoutDMPipelineLike,
) -> LayoutCorrectorModel:
    """Build a `LayoutCorrectorModel` from an original checkpoint directory.

    Args:
        dataset: Dataset key or alias.
        checkpoint_dir: Directory containing `best_model.pt` and `config.yaml`.
        layout_dm: Nested LayoutDM pipeline paired with the corrector.

    Returns:
        Loaded and eval-mode corrector model.
    """
    checkpoint_dir = Path(checkpoint_dir)
    state_dict = load_original_corrector_state_dict(checkpoint_dir / "best_model.pt")
    config = corrector_config_from_original(
        dataset=dataset,
        config_path=checkpoint_dir / "config.yaml",
        state_dict=state_dict,
        layout_dm=layout_dm,
    )
    validate_layout_dm_compatibility(layout_dm=layout_dm, corrector_config=config)
    corrector = LayoutCorrectorModel(**config.config)
    corrector.model.load_state_dict(state_dict, strict=True)
    corrector.eval()
    return corrector

discover_seed_dirs

discover_seed_dirs(job_dir: str | Path) -> list[Path]

Discover corrector seed directories under an original job directory.

Parameters:

Name Type Description Default
job_dir str | Path

Seed directory or parent directory containing seed subdirectories.

required

Returns:

Type Description
list[Path]

Sorted list of directories containing config.yaml.

Source code in models/layout-corrector/src/layout_corrector/conversion.py
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
def discover_seed_dirs(job_dir: str | Path) -> list[Path]:
    """Discover corrector seed directories under an original job directory.

    Args:
        job_dir: Seed directory or parent directory containing seed subdirectories.

    Returns:
        Sorted list of directories containing `config.yaml`.
    """
    path = Path(job_dir)
    if (path / "config.yaml").is_file():
        return [path]
    return sorted(
        child for child in path.iterdir() if (child / "config.yaml").is_file()
    )

validate_layout_dm_compatibility

validate_layout_dm_compatibility(
    *,
    layout_dm: LayoutDMPipelineLike,
    corrector_config: LayoutCorrectorConfig,
) -> None

Validate that a corrector config matches its nested LayoutDM pipeline.

Parameters:

Name Type Description Default
layout_dm LayoutDMPipelineLike

Nested LayoutDM pipeline.

required
corrector_config LayoutCorrectorConfig

Corrector config to compare.

required

Raises:

Type Description
ValueError

If a shared tokenizer or scheduler field differs.

Source code in models/layout-corrector/src/layout_corrector/conversion.py
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
def validate_layout_dm_compatibility(
    *,
    layout_dm: LayoutDMPipelineLike,
    corrector_config: LayoutCorrectorConfig,
) -> None:
    """Validate that a corrector config matches its nested LayoutDM pipeline.

    Args:
        layout_dm: Nested LayoutDM pipeline.
        corrector_config: Corrector config to compare.

    Raises:
        ValueError: If a shared tokenizer or scheduler field differs.
    """
    tokenizer_config = getattr(layout_dm, "tokenizer").config
    scheduler_config = getattr(layout_dm, "scheduler").config
    checks: dict[CompatibilityKey, int] = {
        CompatibilityKey.vocab_size: tokenizer_config.vocab_size,
        CompatibilityKey.max_seq_length: tokenizer_config.max_seq_length,
        CompatibilityKey.num_attributes_per_element: (
            tokenizer_config.num_attributes_per_element
        ),
        CompatibilityKey.num_timesteps: scheduler_config.num_timesteps,
    }
    for key, value in checks.items():
        field = str(key)
        if getattr(corrector_config, field) != value:
            raise ValueError(
                f"LayoutDM/{field} mismatch: corrector={getattr(corrector_config, field)} "
                f"layout_dm={value}"
            )

model_card

Model-card builders for converted Layout-Corrector checkpoints.

LayoutCorrectorCardDataset

Bases: StrEnum

Canonical datasets used in Layout-Corrector model-card metadata.

Source code in models/layout-corrector/src/layout_corrector/model_card.py
19
20
21
22
23
24
class LayoutCorrectorCardDataset(StrEnum):
    """Canonical datasets used in Layout-Corrector model-card metadata."""

    rico25 = auto()
    publaynet = auto()
    crello = auto()

LayoutCorrectorCardValue

Bases: StrEnum

Closed metadata and tag values emitted by Layout-Corrector cards.

Source code in models/layout-corrector/src/layout_corrector/model_card.py
27
28
29
30
31
32
33
34
class LayoutCorrectorCardValue(StrEnum):
    """Closed metadata and tag values emitted by Layout-Corrector cards."""

    license = "mit"
    library = "diffusers"
    pipeline_tag = "unconditional-layout-generation"
    layout_generation_tag = "layout-generation"
    layout_corrector_tag = "layout-corrector"

layout_corrector_model_card

layout_corrector_model_card(
    *,
    dataset: str,
    parity_metrics: Sequence[ParityMetricInput]
    | None = None,
) -> ModelCard

Build the Layout-Corrector model card for a converted checkpoint.

Source code in models/layout-corrector/src/layout_corrector/model_card.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
 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
def layout_corrector_model_card(
    *,
    dataset: str,
    parity_metrics: Sequence[ParityMetricInput] | None = None,
) -> ModelCard:
    """Build the Layout-Corrector model card for a converted checkpoint."""
    dataset_name = _normalize_model_card_dataset(dataset)
    dataset_id = _DATASET_IDS[dataset_name]
    model_id = f"{_MODEL_ID_PREFIX}-{dataset_name}"
    metrics = parity_metrics or [
        ParityMetric(
            dataset=str(dataset_name),
            tokenizer_exact="checked in reference parity",
            deterministic_exact="not applicable",
            logits_max_abs=0.0,
            logits_max_rel=0.0,
        )
    ]
    how_to_use = f"""
from layout_corrector import LayoutCorrectorModel, LayoutCorrectorPipeline
from layout_dm import LayoutDMPipeline

layout_dm = LayoutDMPipeline.from_pretrained("{model_id}", subfolder="layout_dm")
corrector = LayoutCorrectorModel.from_pretrained("{model_id}", subfolder="corrector")
pipe = LayoutCorrectorPipeline(layout_dm=layout_dm, corrector=corrector)
out = pipe(batch_size=1, seed=0, sampling="deterministic")
print(out.bbox, out.labels, out.mask)
"""
    return build_layout_model_card(
        model_id=model_id,
        model_name=f"Layout-Corrector {dataset_name}",
        dataset_ids=[dataset_id],
        license=str(LayoutCorrectorCardValue.license),
        library_name=str(LayoutCorrectorCardValue.library),
        pipeline_tag=str(LayoutCorrectorCardValue.pipeline_tag),
        tags=[
            str(LayoutCorrectorCardValue.layout_generation_tag),
            str(LayoutCorrectorCardValue.layout_corrector_tag),
            str(LayoutCorrectorCardValue.library),
            str(dataset_name),
        ],
        model_details=(
            "Layout-Corrector is a training-free corrector module for discrete "
            "diffusion layout generators such as LayoutDM. This Diffusers-format "
            "checkpoint pairs a converted LayoutDM generator with the released "
            "Layout-Corrector confidence model, which scores intermediate "
            "reconstructed layout tokens, re-masks low-confidence tokens, and "
            "lets LayoutDM regenerate those positions during sampling."
        ),
        intended_uses=(
            "Use this checkpoint for research and evaluation of controllable "
            "layout generation and Layout-Corrector sampling behavior."
        ),
        limitations=(
            "The model predicts layout structure only. Generated boxes and labels "
            "require downstream validation before use in design or document "
            "processing workflows."
        ),
        how_to_use=how_to_use,
        training_data=(
            f"The original checkpoint was trained on `{dataset_id}` using the "
            "preprocessing released with the original Layout-Corrector starter kit."
        ),
        parity_metrics=metrics,
        citation_bibtex=_LAYOUT_CORRECTOR_BIBTEX,
        original_implementation_url=_ORIGINAL_IMPLEMENTATION_URL,
    )

modeling_layout_corrector

Layout-Corrector confidence model components.

LayoutCorrectorOutput dataclass

Bases: BaseOutput

Output container for Layout-Corrector confidence logits.

Parameters:

Name Type Description Default
logits Float[Tensor, 'batch tokens']

Token confidence logits shaped (batch, tokens).

required
Source code in models/layout-corrector/src/layout_corrector/modeling_layout_corrector.py
32
33
34
35
36
37
38
39
40
@dataclass
class LayoutCorrectorOutput(BaseOutput):
    """Output container for Layout-Corrector confidence logits.

    Args:
        logits: Token confidence logits shaped `(batch, tokens)`.
    """

    logits: Float[torch.Tensor, "batch tokens"]

AggregatedCategoricalTransformer

Bases: Module

Aggregated-token transformer used by the original Layout-Corrector model.

Source code in models/layout-corrector/src/layout_corrector/modeling_layout_corrector.py
 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
class AggregatedCategoricalTransformer(nn.Module):
    """Aggregated-token transformer used by the original Layout-Corrector model."""

    def __init__(
        self,
        *,
        vocab_size: int,
        max_token_length: int,
        hidden_size: int,
        num_attention_heads: int,
        num_hidden_layers: int,
        intermediate_size: int,
        dropout: float,
        timestep_type: TimestepEmbeddingType | str | None,
        pos_emb: CorrectorPositionEmbedding | str,
        num_attributes_per_element: int,
        num_timesteps: int,
    ) -> None:
        """Initialize the aggregated categorical transformer.

        Args:
            vocab_size: Number of token ids.
            max_token_length: Flattened token sequence length.
            hidden_size: Transformer hidden dimension.
            num_attention_heads: Number of attention heads.
            num_hidden_layers: Number of transformer layers.
            intermediate_size: Feed-forward hidden dimension.
            dropout: Dropout probability.
            timestep_type: Timestep conditioning type.
            pos_emb: Position embedding mode.
            num_attributes_per_element: Number of attributes per layout element.
            num_timesteps: Diffusion timestep count.

        Raises:
            ValueError: If `max_token_length` is not divisible by attributes per
                element.
        """
        super().__init__()
        if max_token_length % num_attributes_per_element:
            raise ValueError(
                "max_token_length must divide by num_attributes_per_element"
            )

        self.num_attributes_per_element = num_attributes_per_element
        self.cat_emb = nn.Embedding(vocab_size, hidden_size)
        self.drop = nn.Dropout(dropout)
        self.enc = nn.Sequential(
            nn.Linear(num_attributes_per_element * hidden_size, hidden_size),
            nn.ReLU(),
        )
        layer = Block(
            d_model=hidden_size,
            nhead=num_attention_heads,
            dim_feedforward=intermediate_size,
            dropout=dropout,
            batch_first=True,
            norm_first=True,
            diffusion_step=num_timesteps,
            timestep_type=timestep_type,
        )
        self.backbone = TransformerEncoder(layer, num_hidden_layers)
        self.dec = nn.Sequential(
            nn.Linear(hidden_size, num_attributes_per_element * hidden_size),
            nn.ReLU(),
        )
        self.pos_emb = None
        if CorrectorPositionEmbedding(pos_emb) is not CorrectorPositionEmbedding.none:
            self.pos_emb = ElementPositionalEmbedding(
                hidden_size,
                max_token_length // num_attributes_per_element,
                n_attr_per_elem=1,
            )
        self.head = nn.Sequential(
            nn.LayerNorm(hidden_size),
            nn.Linear(hidden_size, 1, bias=False),
        )

    def forward(
        self,
        input_ids: Int[torch.Tensor, "batch tokens"],
        *,
        timestep: Int[torch.Tensor, "batch"] | None = None,
        src_key_padding_mask: Bool[torch.Tensor, "batch tokens"] | None = None,
    ) -> Float[torch.Tensor, "batch tokens 1"]:
        """Predict token confidence logits.

        Args:
            input_ids: Flattened token ids.
            timestep: Optional diffusion timestep tensor.
            src_key_padding_mask: Optional padding mask.

        Returns:
            Confidence logits shaped `(batch, tokens, 1)`.
        """
        batch_size, token_length = input_ids.shape
        step = self.num_attributes_per_element
        hidden = self.drop(self.cat_emb(input_ids))
        hidden = hidden.reshape(
            batch_size, token_length // step, step * hidden.size(-1)
        )
        hidden = self.enc(hidden)
        if self.pos_emb is not None:
            hidden = hidden + self.pos_emb(hidden)
        if src_key_padding_mask is not None:
            element_padding_mask = src_key_padding_mask.reshape(
                batch_size, token_length // step, step
            ).any(dim=-1)
        else:
            element_padding_mask = None
        hidden = self.backbone(
            hidden,
            src_key_padding_mask=element_padding_mask,
            timestep=timestep,
        )
        hidden = self.dec(hidden)
        hidden = hidden.reshape(batch_size, token_length, -1)
        return self.head(hidden)

__init__

__init__(
    *,
    vocab_size: int,
    max_token_length: int,
    hidden_size: int,
    num_attention_heads: int,
    num_hidden_layers: int,
    intermediate_size: int,
    dropout: float,
    timestep_type: TimestepEmbeddingType | str | None,
    pos_emb: CorrectorPositionEmbedding | str,
    num_attributes_per_element: int,
    num_timesteps: int,
) -> None

Initialize the aggregated categorical transformer.

Parameters:

Name Type Description Default
vocab_size int

Number of token ids.

required
max_token_length int

Flattened token sequence length.

required
hidden_size int

Transformer hidden dimension.

required
num_attention_heads int

Number of attention heads.

required
num_hidden_layers int

Number of transformer layers.

required
intermediate_size int

Feed-forward hidden dimension.

required
dropout float

Dropout probability.

required
timestep_type TimestepEmbeddingType | str | None

Timestep conditioning type.

required
pos_emb CorrectorPositionEmbedding | str

Position embedding mode.

required
num_attributes_per_element int

Number of attributes per layout element.

required
num_timesteps int

Diffusion timestep count.

required

Raises:

Type Description
ValueError

If max_token_length is not divisible by attributes per element.

Source code in models/layout-corrector/src/layout_corrector/modeling_layout_corrector.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
 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
def __init__(
    self,
    *,
    vocab_size: int,
    max_token_length: int,
    hidden_size: int,
    num_attention_heads: int,
    num_hidden_layers: int,
    intermediate_size: int,
    dropout: float,
    timestep_type: TimestepEmbeddingType | str | None,
    pos_emb: CorrectorPositionEmbedding | str,
    num_attributes_per_element: int,
    num_timesteps: int,
) -> None:
    """Initialize the aggregated categorical transformer.

    Args:
        vocab_size: Number of token ids.
        max_token_length: Flattened token sequence length.
        hidden_size: Transformer hidden dimension.
        num_attention_heads: Number of attention heads.
        num_hidden_layers: Number of transformer layers.
        intermediate_size: Feed-forward hidden dimension.
        dropout: Dropout probability.
        timestep_type: Timestep conditioning type.
        pos_emb: Position embedding mode.
        num_attributes_per_element: Number of attributes per layout element.
        num_timesteps: Diffusion timestep count.

    Raises:
        ValueError: If `max_token_length` is not divisible by attributes per
            element.
    """
    super().__init__()
    if max_token_length % num_attributes_per_element:
        raise ValueError(
            "max_token_length must divide by num_attributes_per_element"
        )

    self.num_attributes_per_element = num_attributes_per_element
    self.cat_emb = nn.Embedding(vocab_size, hidden_size)
    self.drop = nn.Dropout(dropout)
    self.enc = nn.Sequential(
        nn.Linear(num_attributes_per_element * hidden_size, hidden_size),
        nn.ReLU(),
    )
    layer = Block(
        d_model=hidden_size,
        nhead=num_attention_heads,
        dim_feedforward=intermediate_size,
        dropout=dropout,
        batch_first=True,
        norm_first=True,
        diffusion_step=num_timesteps,
        timestep_type=timestep_type,
    )
    self.backbone = TransformerEncoder(layer, num_hidden_layers)
    self.dec = nn.Sequential(
        nn.Linear(hidden_size, num_attributes_per_element * hidden_size),
        nn.ReLU(),
    )
    self.pos_emb = None
    if CorrectorPositionEmbedding(pos_emb) is not CorrectorPositionEmbedding.none:
        self.pos_emb = ElementPositionalEmbedding(
            hidden_size,
            max_token_length // num_attributes_per_element,
            n_attr_per_elem=1,
        )
    self.head = nn.Sequential(
        nn.LayerNorm(hidden_size),
        nn.Linear(hidden_size, 1, bias=False),
    )

forward

forward(
    input_ids: Int[Tensor, "batch tokens"],
    *,
    timestep: Int[Tensor, "batch"] | None = None,
    src_key_padding_mask: Bool[Tensor, "batch tokens"]
    | None = None,
) -> Float[torch.Tensor, "batch tokens 1"]

Predict token confidence logits.

Parameters:

Name Type Description Default
input_ids Int[Tensor, 'batch tokens']

Flattened token ids.

required
timestep Int[Tensor, 'batch'] | None

Optional diffusion timestep tensor.

None
src_key_padding_mask Bool[Tensor, 'batch tokens'] | None

Optional padding mask.

None

Returns:

Type Description
Float[Tensor, 'batch tokens 1']

Confidence logits shaped (batch, tokens, 1).

Source code in models/layout-corrector/src/layout_corrector/modeling_layout_corrector.py
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
def forward(
    self,
    input_ids: Int[torch.Tensor, "batch tokens"],
    *,
    timestep: Int[torch.Tensor, "batch"] | None = None,
    src_key_padding_mask: Bool[torch.Tensor, "batch tokens"] | None = None,
) -> Float[torch.Tensor, "batch tokens 1"]:
    """Predict token confidence logits.

    Args:
        input_ids: Flattened token ids.
        timestep: Optional diffusion timestep tensor.
        src_key_padding_mask: Optional padding mask.

    Returns:
        Confidence logits shaped `(batch, tokens, 1)`.
    """
    batch_size, token_length = input_ids.shape
    step = self.num_attributes_per_element
    hidden = self.drop(self.cat_emb(input_ids))
    hidden = hidden.reshape(
        batch_size, token_length // step, step * hidden.size(-1)
    )
    hidden = self.enc(hidden)
    if self.pos_emb is not None:
        hidden = hidden + self.pos_emb(hidden)
    if src_key_padding_mask is not None:
        element_padding_mask = src_key_padding_mask.reshape(
            batch_size, token_length // step, step
        ).any(dim=-1)
    else:
        element_padding_mask = None
    hidden = self.backbone(
        hidden,
        src_key_padding_mask=element_padding_mask,
        timestep=timestep,
    )
    hidden = self.dec(hidden)
    hidden = hidden.reshape(batch_size, token_length, -1)
    return self.head(hidden)

LayoutCorrectorModel

Bases: ModelMixin, ConfigMixin

Diffusers-compatible Layout-Corrector confidence model.

Source code in models/layout-corrector/src/layout_corrector/modeling_layout_corrector.py
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
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
class LayoutCorrectorModel(ModelMixin, ConfigMixin):
    """Diffusers-compatible Layout-Corrector confidence model."""

    config_name = "corrector_config.json"

    @register_to_config
    def __init__(
        self,
        *,
        dataset_name: str,
        vocab_size: int,
        id2label: dict[int | str, str] | None = None,
        max_seq_length: int = 25,
        num_attributes_per_element: int = 5,
        hidden_size: int = 464,
        num_attention_heads: int = 8,
        num_hidden_layers: int = 4,
        intermediate_size: int = 1856,
        dropout: float = 0.0,
        timestep_type: TimestepEmbeddingType | str | None = "adalayernorm",
        num_timesteps: int = 100,
        recon_type: CorrectorReconType | str = CorrectorReconType.x_t_minus_1,
        target: CorrectorTarget | str = CorrectorTarget.recon_acc,
        attr_loss_weights: tuple[float, ...] = (1.0, 1.0, 1.0, 1.0, 1.0),
        use_padding_as_vocab: bool = True,
        pos_emb: CorrectorPositionEmbedding | str = CorrectorPositionEmbedding.none,
        transformer_type: CorrectorTransformerType | str = (
            CorrectorTransformerType.aggregated
        ),
        corrector_steps: int = 1,
        corrector_t_list: tuple[int, ...] = (10, 20, 30),
        corrector_mask_mode: CorrectorMaskMode | str = CorrectorMaskMode.thresh,
        corrector_mask_threshold: float = 0.7,
        corrector_temperature: float = 1.0,
        use_gumbel_noise: bool = True,
        gumbel_temperature: float = 1.0,
        time_adaptive_temperature: bool = False,
    ) -> None:
        """Initialize a Layout-Corrector model.

        Args:
            dataset_name: Dataset key or alias used for labels.
            vocab_size: LayoutDM vocabulary size.
            id2label: Optional class-id mapping.
            max_seq_length: Maximum number of elements.
            num_attributes_per_element: Number of token attributes per element.
            hidden_size: Transformer hidden dimension.
            num_attention_heads: Number of attention heads.
            num_hidden_layers: Number of transformer layers.
            intermediate_size: Feed-forward hidden dimension.
            dropout: Dropout probability.
            timestep_type: Timestep conditioning type.
            num_timesteps: Number of diffusion timesteps.
            recon_type: Reconstruction target.
            target: Confidence target type.
            attr_loss_weights: Per-attribute loss weights.
            use_padding_as_vocab: Whether padding is modeled as a vocabulary token.
            pos_emb: Position embedding mode.
            transformer_type: Corrector transformer type.
            corrector_steps: Number of correction passes.
            corrector_t_list: Explicit correction timesteps.
            corrector_mask_mode: Token remasking mode.
            corrector_mask_threshold: Threshold for confidence remasking.
            corrector_temperature: Corrector sampling temperature.
            use_gumbel_noise: Whether confidence logits receive Gumbel noise.
            gumbel_temperature: Confidence-noise temperature.
            time_adaptive_temperature: Whether to scale noise by timestep ratio.

        Raises:
            ValueError: If reconstruction, target, or transformer options are
                unsupported.
        """
        super().__init__()
        recon_type, target, transformer_type, pos_emb = (
            normalize_corrector_core_options(
                recon_type,
                target,
                transformer_type,
                pos_emb,
            )
        )
        try:
            corrector_mask_mode = normalize_corrector_mask_mode(corrector_mask_mode)
        except ValueError as exc:
            raise ValueError(
                f"Unsupported corrector_mask_mode: {corrector_mask_mode}"
            ) from exc

        try:
            dataset_name = str(normalize_dataset_name(dataset_name))
        except ValueError:
            if id2label is None:
                raise

            dataset_name = str(dataset_name)
        normalized_id2label = {
            int(k): v
            for k, v in (id2label or id2label_for_dataset(dataset_name)).items()
        }
        self.register_to_config(
            dataset_name=dataset_name,
            id2label=normalized_id2label,
            corrector_t_list=tuple(corrector_t_list),
            attr_loss_weights=tuple(attr_loss_weights),
            recon_type=str(recon_type),
            target=str(target),
            pos_emb=str(pos_emb),
            transformer_type=str(transformer_type),
            corrector_mask_mode=str(corrector_mask_mode),
        )
        self.vocab_size = vocab_size
        self.id2label = normalized_id2label
        self.recon_type = recon_type
        self.corrector_steps = corrector_steps
        self.corrector_t_list = tuple(corrector_t_list)
        self.corrector_mask_mode = corrector_mask_mode
        self.corrector_mask_threshold = corrector_mask_threshold
        self.corrector_temperature = corrector_temperature
        self.use_padding_as_vocab = use_padding_as_vocab
        self.use_gumbel_noise = use_gumbel_noise
        self.gumbel_temperature = gumbel_temperature
        self.time_adaptive_temperature = time_adaptive_temperature
        self.model = AggregatedCategoricalTransformer(
            vocab_size=vocab_size,
            max_token_length=max_seq_length * num_attributes_per_element,
            hidden_size=hidden_size,
            num_attention_heads=num_attention_heads,
            num_hidden_layers=num_hidden_layers,
            intermediate_size=intermediate_size,
            dropout=dropout,
            timestep_type=timestep_type,
            pos_emb=pos_emb,
            num_attributes_per_element=num_attributes_per_element,
            num_timesteps=num_timesteps,
        )

    def forward(
        self,
        input_ids: Int[torch.Tensor, "batch tokens"],
        timesteps: Int[torch.Tensor, "batch"],
        padding_mask: Bool[torch.Tensor, "batch tokens"] | None = None,
    ) -> LayoutCorrectorOutput:
        """Run the corrector model.

        Args:
            input_ids: Flattened token ids.
            timesteps: Diffusion timestep tensor.
            padding_mask: Optional padding mask.

        Returns:
            `LayoutCorrectorOutput` containing token confidence logits.
        """
        src_key_padding_mask = None if self.use_padding_as_vocab else padding_mask
        logits = self.model(
            input_ids,
            timestep=timesteps,
            src_key_padding_mask=src_key_padding_mask,
        ).squeeze(-1)
        if not self.use_padding_as_vocab and padding_mask is not None:
            logits = logits.masked_fill(padding_mask, 1000.0)
        return LayoutCorrectorOutput(logits=logits)

    def calc_confidence_score(
        self,
        input_ids: Int[torch.Tensor, "batch tokens"],
        timesteps: Int[torch.Tensor, "batch"],
        padding_mask: Bool[torch.Tensor, "batch tokens"] | None = None,
    ) -> Float[torch.Tensor, "batch tokens"]:
        """Return confidence logits for token remasking.

        Args:
            input_ids: Flattened token ids.
            timesteps: Diffusion timestep tensor.
            padding_mask: Optional padding mask.

        Returns:
            Confidence logits shaped `(batch, tokens)`.
        """
        return self(
            input_ids=input_ids,
            timesteps=timesteps,
            padding_mask=padding_mask,
        ).logits

__init__

__init__(
    *,
    dataset_name: str,
    vocab_size: int,
    id2label: dict[int | str, str] | None = None,
    max_seq_length: int = 25,
    num_attributes_per_element: int = 5,
    hidden_size: int = 464,
    num_attention_heads: int = 8,
    num_hidden_layers: int = 4,
    intermediate_size: int = 1856,
    dropout: float = 0.0,
    timestep_type: TimestepEmbeddingType
    | str
    | None = "adalayernorm",
    num_timesteps: int = 100,
    recon_type: CorrectorReconType
    | str = CorrectorReconType.x_t_minus_1,
    target: CorrectorTarget
    | str = CorrectorTarget.recon_acc,
    attr_loss_weights: tuple[float, ...] = (
        1.0,
        1.0,
        1.0,
        1.0,
        1.0,
    ),
    use_padding_as_vocab: bool = True,
    pos_emb: CorrectorPositionEmbedding
    | str = CorrectorPositionEmbedding.none,
    transformer_type: CorrectorTransformerType
    | str = CorrectorTransformerType.aggregated,
    corrector_steps: int = 1,
    corrector_t_list: tuple[int, ...] = (10, 20, 30),
    corrector_mask_mode: CorrectorMaskMode
    | str = CorrectorMaskMode.thresh,
    corrector_mask_threshold: float = 0.7,
    corrector_temperature: float = 1.0,
    use_gumbel_noise: bool = True,
    gumbel_temperature: float = 1.0,
    time_adaptive_temperature: bool = False,
) -> None

Initialize a Layout-Corrector model.

Parameters:

Name Type Description Default
dataset_name str

Dataset key or alias used for labels.

required
vocab_size int

LayoutDM vocabulary size.

required
id2label dict[int | str, str] | None

Optional class-id mapping.

None
max_seq_length int

Maximum number of elements.

25
num_attributes_per_element int

Number of token attributes per element.

5
hidden_size int

Transformer hidden dimension.

464
num_attention_heads int

Number of attention heads.

8
num_hidden_layers int

Number of transformer layers.

4
intermediate_size int

Feed-forward hidden dimension.

1856
dropout float

Dropout probability.

0.0
timestep_type TimestepEmbeddingType | str | None

Timestep conditioning type.

'adalayernorm'
num_timesteps int

Number of diffusion timesteps.

100
recon_type CorrectorReconType | str

Reconstruction target.

x_t_minus_1
target CorrectorTarget | str

Confidence target type.

recon_acc
attr_loss_weights tuple[float, ...]

Per-attribute loss weights.

(1.0, 1.0, 1.0, 1.0, 1.0)
use_padding_as_vocab bool

Whether padding is modeled as a vocabulary token.

True
pos_emb CorrectorPositionEmbedding | str

Position embedding mode.

none
transformer_type CorrectorTransformerType | str

Corrector transformer type.

aggregated
corrector_steps int

Number of correction passes.

1
corrector_t_list tuple[int, ...]

Explicit correction timesteps.

(10, 20, 30)
corrector_mask_mode CorrectorMaskMode | str

Token remasking mode.

thresh
corrector_mask_threshold float

Threshold for confidence remasking.

0.7
corrector_temperature float

Corrector sampling temperature.

1.0
use_gumbel_noise bool

Whether confidence logits receive Gumbel noise.

True
gumbel_temperature float

Confidence-noise temperature.

1.0
time_adaptive_temperature bool

Whether to scale noise by timestep ratio.

False

Raises:

Type Description
ValueError

If reconstruction, target, or transformer options are unsupported.

Source code in models/layout-corrector/src/layout_corrector/modeling_layout_corrector.py
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
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
@register_to_config
def __init__(
    self,
    *,
    dataset_name: str,
    vocab_size: int,
    id2label: dict[int | str, str] | None = None,
    max_seq_length: int = 25,
    num_attributes_per_element: int = 5,
    hidden_size: int = 464,
    num_attention_heads: int = 8,
    num_hidden_layers: int = 4,
    intermediate_size: int = 1856,
    dropout: float = 0.0,
    timestep_type: TimestepEmbeddingType | str | None = "adalayernorm",
    num_timesteps: int = 100,
    recon_type: CorrectorReconType | str = CorrectorReconType.x_t_minus_1,
    target: CorrectorTarget | str = CorrectorTarget.recon_acc,
    attr_loss_weights: tuple[float, ...] = (1.0, 1.0, 1.0, 1.0, 1.0),
    use_padding_as_vocab: bool = True,
    pos_emb: CorrectorPositionEmbedding | str = CorrectorPositionEmbedding.none,
    transformer_type: CorrectorTransformerType | str = (
        CorrectorTransformerType.aggregated
    ),
    corrector_steps: int = 1,
    corrector_t_list: tuple[int, ...] = (10, 20, 30),
    corrector_mask_mode: CorrectorMaskMode | str = CorrectorMaskMode.thresh,
    corrector_mask_threshold: float = 0.7,
    corrector_temperature: float = 1.0,
    use_gumbel_noise: bool = True,
    gumbel_temperature: float = 1.0,
    time_adaptive_temperature: bool = False,
) -> None:
    """Initialize a Layout-Corrector model.

    Args:
        dataset_name: Dataset key or alias used for labels.
        vocab_size: LayoutDM vocabulary size.
        id2label: Optional class-id mapping.
        max_seq_length: Maximum number of elements.
        num_attributes_per_element: Number of token attributes per element.
        hidden_size: Transformer hidden dimension.
        num_attention_heads: Number of attention heads.
        num_hidden_layers: Number of transformer layers.
        intermediate_size: Feed-forward hidden dimension.
        dropout: Dropout probability.
        timestep_type: Timestep conditioning type.
        num_timesteps: Number of diffusion timesteps.
        recon_type: Reconstruction target.
        target: Confidence target type.
        attr_loss_weights: Per-attribute loss weights.
        use_padding_as_vocab: Whether padding is modeled as a vocabulary token.
        pos_emb: Position embedding mode.
        transformer_type: Corrector transformer type.
        corrector_steps: Number of correction passes.
        corrector_t_list: Explicit correction timesteps.
        corrector_mask_mode: Token remasking mode.
        corrector_mask_threshold: Threshold for confidence remasking.
        corrector_temperature: Corrector sampling temperature.
        use_gumbel_noise: Whether confidence logits receive Gumbel noise.
        gumbel_temperature: Confidence-noise temperature.
        time_adaptive_temperature: Whether to scale noise by timestep ratio.

    Raises:
        ValueError: If reconstruction, target, or transformer options are
            unsupported.
    """
    super().__init__()
    recon_type, target, transformer_type, pos_emb = (
        normalize_corrector_core_options(
            recon_type,
            target,
            transformer_type,
            pos_emb,
        )
    )
    try:
        corrector_mask_mode = normalize_corrector_mask_mode(corrector_mask_mode)
    except ValueError as exc:
        raise ValueError(
            f"Unsupported corrector_mask_mode: {corrector_mask_mode}"
        ) from exc

    try:
        dataset_name = str(normalize_dataset_name(dataset_name))
    except ValueError:
        if id2label is None:
            raise

        dataset_name = str(dataset_name)
    normalized_id2label = {
        int(k): v
        for k, v in (id2label or id2label_for_dataset(dataset_name)).items()
    }
    self.register_to_config(
        dataset_name=dataset_name,
        id2label=normalized_id2label,
        corrector_t_list=tuple(corrector_t_list),
        attr_loss_weights=tuple(attr_loss_weights),
        recon_type=str(recon_type),
        target=str(target),
        pos_emb=str(pos_emb),
        transformer_type=str(transformer_type),
        corrector_mask_mode=str(corrector_mask_mode),
    )
    self.vocab_size = vocab_size
    self.id2label = normalized_id2label
    self.recon_type = recon_type
    self.corrector_steps = corrector_steps
    self.corrector_t_list = tuple(corrector_t_list)
    self.corrector_mask_mode = corrector_mask_mode
    self.corrector_mask_threshold = corrector_mask_threshold
    self.corrector_temperature = corrector_temperature
    self.use_padding_as_vocab = use_padding_as_vocab
    self.use_gumbel_noise = use_gumbel_noise
    self.gumbel_temperature = gumbel_temperature
    self.time_adaptive_temperature = time_adaptive_temperature
    self.model = AggregatedCategoricalTransformer(
        vocab_size=vocab_size,
        max_token_length=max_seq_length * num_attributes_per_element,
        hidden_size=hidden_size,
        num_attention_heads=num_attention_heads,
        num_hidden_layers=num_hidden_layers,
        intermediate_size=intermediate_size,
        dropout=dropout,
        timestep_type=timestep_type,
        pos_emb=pos_emb,
        num_attributes_per_element=num_attributes_per_element,
        num_timesteps=num_timesteps,
    )

forward

forward(
    input_ids: Int[Tensor, "batch tokens"],
    timesteps: Int[Tensor, "batch"],
    padding_mask: Bool[Tensor, "batch tokens"]
    | None = None,
) -> LayoutCorrectorOutput

Run the corrector model.

Parameters:

Name Type Description Default
input_ids Int[Tensor, 'batch tokens']

Flattened token ids.

required
timesteps Int[Tensor, 'batch']

Diffusion timestep tensor.

required
padding_mask Bool[Tensor, 'batch tokens'] | None

Optional padding mask.

None

Returns:

Type Description
LayoutCorrectorOutput

LayoutCorrectorOutput containing token confidence logits.

Source code in models/layout-corrector/src/layout_corrector/modeling_layout_corrector.py
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
def forward(
    self,
    input_ids: Int[torch.Tensor, "batch tokens"],
    timesteps: Int[torch.Tensor, "batch"],
    padding_mask: Bool[torch.Tensor, "batch tokens"] | None = None,
) -> LayoutCorrectorOutput:
    """Run the corrector model.

    Args:
        input_ids: Flattened token ids.
        timesteps: Diffusion timestep tensor.
        padding_mask: Optional padding mask.

    Returns:
        `LayoutCorrectorOutput` containing token confidence logits.
    """
    src_key_padding_mask = None if self.use_padding_as_vocab else padding_mask
    logits = self.model(
        input_ids,
        timestep=timesteps,
        src_key_padding_mask=src_key_padding_mask,
    ).squeeze(-1)
    if not self.use_padding_as_vocab and padding_mask is not None:
        logits = logits.masked_fill(padding_mask, 1000.0)
    return LayoutCorrectorOutput(logits=logits)

calc_confidence_score

calc_confidence_score(
    input_ids: Int[Tensor, "batch tokens"],
    timesteps: Int[Tensor, "batch"],
    padding_mask: Bool[Tensor, "batch tokens"]
    | None = None,
) -> Float[torch.Tensor, "batch tokens"]

Return confidence logits for token remasking.

Parameters:

Name Type Description Default
input_ids Int[Tensor, 'batch tokens']

Flattened token ids.

required
timesteps Int[Tensor, 'batch']

Diffusion timestep tensor.

required
padding_mask Bool[Tensor, 'batch tokens'] | None

Optional padding mask.

None

Returns:

Type Description
Float[Tensor, 'batch tokens']

Confidence logits shaped (batch, tokens).

Source code in models/layout-corrector/src/layout_corrector/modeling_layout_corrector.py
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
def calc_confidence_score(
    self,
    input_ids: Int[torch.Tensor, "batch tokens"],
    timesteps: Int[torch.Tensor, "batch"],
    padding_mask: Bool[torch.Tensor, "batch tokens"] | None = None,
) -> Float[torch.Tensor, "batch tokens"]:
    """Return confidence logits for token remasking.

    Args:
        input_ids: Flattened token ids.
        timesteps: Diffusion timestep tensor.
        padding_mask: Optional padding mask.

    Returns:
        Confidence logits shaped `(batch, tokens)`.
    """
    return self(
        input_ids=input_ids,
        timesteps=timesteps,
        padding_mask=padding_mask,
    ).logits

pipeline_layout_corrector

Diffusers pipeline wrapper for Layout-Corrector guided generation.

OutputType

Bases: StrEnum

Supported Layout-Corrector pipeline output formats.

Source code in models/layout-corrector/src/layout_corrector/pipeline_layout_corrector.py
39
40
41
42
43
class OutputType(StrEnum):
    """Supported Layout-Corrector pipeline output formats."""

    dataclass = auto()
    dict = auto()

LayoutCorrectorPipeline

Bases: DiffusionPipeline

Diffusers pipeline that applies Layout-Corrector during LayoutDM sampling.

Parameters:

Name Type Description Default
layout_dm LayoutDMPipeline

Base LayoutDM pipeline.

required
corrector LayoutCorrectorModel

Corrector model used to score and remask tokens.

required
processor LayoutDMProcessor | None

Optional processor for conditional layout inputs.

None

Raises:

Type Description
ValueError

Pipeline construction does not raise directly.

Examples:

>>> LayoutCorrectorPipeline.from_pretrained
<bound method...
Source code in models/layout-corrector/src/layout_corrector/pipeline_layout_corrector.py
 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
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
480
481
482
483
484
485
class LayoutCorrectorPipeline(DiffusionPipeline):
    """Diffusers pipeline that applies Layout-Corrector during LayoutDM sampling.

    Args:
        layout_dm: Base LayoutDM pipeline.
        corrector: Corrector model used to score and remask tokens.
        processor: Optional processor for conditional layout inputs.

    Raises:
        ValueError: Pipeline construction does not raise directly.

    Examples:
        >>> LayoutCorrectorPipeline.from_pretrained  # doctest: +ELLIPSIS
        <bound method...
    """

    model_cpu_offload_seq: ClassVar[str] = "layout_dm.denoiser->corrector"

    def __init__(
        self,
        layout_dm: LayoutDMPipeline,
        corrector: LayoutCorrectorModel,
        processor: LayoutDMProcessor | None = None,
    ) -> None:
        """Initialize the composite pipeline.

        Args:
            layout_dm: Base LayoutDM pipeline.
            corrector: Confidence model used to remask low-confidence tokens.
            processor: Optional processor for conditional inputs.
        """
        super().__init__()
        self.register_modules(layout_dm=layout_dm, corrector=corrector)
        self.layout_dm = layout_dm
        self.corrector = corrector
        self.processor = processor or layout_dm.processor
        self.corrector.eval()

    @torch.no_grad()
    def __call__(
        self,
        *,
        batch_size: int = 1,
        seed: int | None = None,
        generator: torch.Generator | None = None,
        condition_type: ConditionType | str = ConditionType.unconditional,
        labels: Int[torch.Tensor, "batch elements"]
        | Int[np.ndarray, "batch elements"]
        | list[ArrayLikeInput]
        | None = None,
        bbox: Float[torch.Tensor, "batch elements 4"]
        | Float[np.ndarray, "batch elements 4"]
        | list[ArrayLikeInput]
        | None = None,
        mask: Bool[torch.Tensor, "batch elements"]
        | Bool[np.ndarray, "batch elements"]
        | list[ArrayLikeInput]
        | 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,
        sampling: SamplingMode | str = SamplingMode.random,
        temperature: float = 1.0,
        top_k: int = 5,
        top_p: float = 0.9,
        corrector_steps: int | None = None,
        corrector_t_list: Sequence[int] | None = None,
        corrector_start: int = -1,
        corrector_end: int = -1,
        corrector_mask_mode: CorrectorMaskMode | str | None = None,
        corrector_mask_threshold: float | None = None,
        corrector_temperature: float | None = None,
        use_gumbel_noise: bool | None = None,
        gumbel_temperature: float | None = None,
        time_adaptive_temperature: bool | None = None,
        output_type: OutputType | str = OutputType.dataclass,
        return_intermediates: bool = False,
    ) -> (
        LayoutGenerationOutput
        | dict[
            str,
            Float[torch.Tensor, "batch elements 4"]
            | Int[torch.Tensor, "batch elements"]
            | Bool[torch.Tensor, "batch elements"]
            | Int[torch.Tensor, "batch tokens"]
            | Float[torch.Tensor, "steps batch tokens"]
            | list[Int[torch.Tensor, "batch tokens"]]
            | dict[int, str]
            | dict[str, str]
            | None,
        ]
    ):
        """Generate layouts with optional Layout-Corrector guidance.

        Args:
            batch_size: Number of layouts to sample for unconditional generation.
            seed: Optional seed used when `generator` is not supplied.
            generator: Optional PyTorch generator.
            condition_type: Condition mode such as `"unconditional"` or `"label"`.
            labels: Optional class ids for conditional generation.
            bbox: Optional boxes for conditional generation.
            mask: Optional element mask for conditional generation.
            num_elements: Reserved for future element-count conditioning.
            box_format: Coordinate format for conditional boxes.
            normalized: Whether conditional boxes are normalized.
            canvas_size: Pixel canvas used when `normalized=False`.
            num_inference_steps: Optional inference timestep count.
            sampling: Base LayoutDM sampling strategy.
            temperature: Base sampling temperature.
            top_k: Top-k cutoff for top-k sampling.
            top_p: Nucleus cutoff for top-p sampling.
            corrector_steps: Optional override for correction passes.
            corrector_t_list: Optional explicit correction timesteps.
            corrector_start: Range start for correction when no list is supplied.
            corrector_end: Range end for correction when no list is supplied.
            corrector_mask_mode: Optional override for remasking mode.
            corrector_mask_threshold: Optional threshold override.
            corrector_temperature: Optional confidence temperature override.
            use_gumbel_noise: Optional confidence-noise override.
            gumbel_temperature: Optional confidence-noise temperature override.
            time_adaptive_temperature: Optional adaptive-noise override.
            output_type: `"dataclass"` or `"dict"`.
            return_intermediates: Whether to include scores and trajectory.

        Returns:
            `LayoutGenerationOutput` by default, or a dictionary when requested.

        Raises:
            ValueError: If conditional generation is missing `bbox` or `labels`, or
                if `output_type` is unsupported.

        Examples:
            >>> LayoutCorrectorPipeline.__call__  # doctest: +ELLIPSIS
            <function...
        """
        _ = num_elements
        if generator is None and seed is not None:
            generator = torch.Generator(device=self.device).manual_seed(seed)
        canonical = normalize_condition_type(condition_type)
        condition = None
        if canonical != "unconditional":
            missing_inputs = [
                name
                for name, value in (("bbox", bbox), ("labels", labels))
                if value is None
            ]
            if missing_inputs:
                raise ValueError(
                    "bbox and labels are required "
                    f"for condition_type={condition_type}; "
                    f"missing {', '.join(missing_inputs)}"
                )

            processor_inputs = {
                "bbox": bbox,
                "labels": labels,
                "mask": mask,
                "box_format": box_format,
                "normalized": normalized,
                "canvas_size": canvas_size,
            }
            processed = self.processor(**processor_inputs)
            decoded_input = self.layout_dm.tokenizer.decode_layout(
                processed["input_ids"]
            )
            condition = build_condition(
                self.layout_dm.tokenizer,
                cond_type=canonical,
                bbox=decoded_input["bbox"],
                labels=decoded_input["labels"],
                mask=decoded_input["mask"],
            )
            batch_size = condition.input_ids.shape[0]

        corrector_cfg = LayoutCorrectorSamplingConfig(
            sampling=sampling,
            temperature=temperature,
            top_k=top_k,
            top_p=top_p,
            num_inference_steps=num_inference_steps,
            corrector_steps=corrector_steps or self.corrector.corrector_steps,
            corrector_t_list=tuple(
                self.corrector.corrector_t_list
                if corrector_t_list is None
                else corrector_t_list
            ),
            corrector_start=corrector_start,
            corrector_end=corrector_end,
            corrector_mask_mode=corrector_mask_mode
            or self.corrector.corrector_mask_mode,
            corrector_mask_threshold=corrector_mask_threshold
            if corrector_mask_threshold is not None
            else self.corrector.corrector_mask_threshold,
            corrector_temperature=corrector_temperature
            if corrector_temperature is not None
            else self.corrector.corrector_temperature,
            use_gumbel_noise=use_gumbel_noise
            if use_gumbel_noise is not None
            else self.corrector.use_gumbel_noise,
            gumbel_temperature=gumbel_temperature
            if gumbel_temperature is not None
            else self.corrector.gumbel_temperature,
            time_adaptive_temperature=time_adaptive_temperature
            if time_adaptive_temperature is not None
            else self.corrector.time_adaptive_temperature,
        )
        sampling_cfg = LayoutDMSamplingConfig(
            name=sampling,
            temperature=temperature,
            top_k=top_k,
            top_p=top_p,
            num_inference_steps=num_inference_steps,
        )
        self.layout_dm.scheduler.set_timesteps(num_inference_steps, device=self.device)
        sample = self.layout_dm.scheduler.initial_sample(
            batch_size,
            self.layout_dm.tokenizer.config.max_token_length,
            device=self.device,
            condition=condition,
        )
        trajectory = [] if return_intermediates else None
        scores = [] if return_intermediates else None
        previous_timestep = self.layout_dm.scheduler.config.num_timesteps
        for timestep in self.layout_dm.scheduler.timesteps:
            timestep_value = int(timestep.item())
            timestep_batch = torch.full(
                (batch_size,),
                timestep_value,
                device=self.device,
                dtype=torch.long,
            )
            if should_apply_corrector(timestep_value, corrector_cfg):
                sample, confidence = self._step_with_corrector(
                    sample=sample,
                    timestep_batch=timestep_batch,
                    condition=condition,
                    sampling=corrector_cfg,
                    generator=generator,
                )
                if scores is not None and confidence is not None:
                    scores.append(confidence.detach().cpu())
            else:
                input_ids = log_onehot_to_index(sample)
                logits = self.layout_dm.denoiser(
                    input_ids=input_ids, timesteps=timestep_batch
                ).logits
                sample = self.layout_dm.scheduler.step(
                    logits,
                    timestep_batch,
                    sample,
                    previous_timestep=previous_timestep,
                    sampling=sampling_cfg,
                    condition=condition,
                    generator=generator,
                ).prev_sample
            previous_timestep = timestep_value
            if trajectory is not None:
                trajectory.append(log_onehot_to_index(sample).detach().cpu())

        sequences = log_onehot_to_index(sample).detach().cpu()
        decoded = self.layout_dm.tokenizer.decode_layout(sequences)
        output = LayoutGenerationOutput(
            bbox=decoded["bbox"],
            labels=decoded["labels"],
            mask=decoded["mask"],
            id2label=dict(self.corrector.id2label),
            sequences=sequences,
            scores=torch.stack(scores) if scores else None,
            trajectory=trajectory,
            intermediates={"condition_type": canonical}
            if return_intermediates
            else None,
        )
        normalized_output_type = normalize_output_type(output_type)
        if normalized_output_type is OutputType.dict:
            return dict(output)
        if normalized_output_type is OutputType.dataclass:
            return output
        assert_never(normalized_output_type)

    generate = __call__

    def _step_with_corrector(
        self,
        *,
        sample: Float[torch.Tensor, "batch vocab tokens"],
        timestep_batch: Int[torch.Tensor, "batch"],
        condition: LayoutDMCondition | None,
        sampling: LayoutCorrectorSamplingConfig,
        generator: torch.Generator | None,
    ) -> tuple[
        Float[torch.Tensor, "batch vocab tokens"],
        Float[torch.Tensor, "batch tokens"] | None,
    ]:
        confidence = None
        current = sample
        for _ in range(sampling.corrector_steps):
            input_ids = log_onehot_to_index(current)
            denoiser_logits = self.layout_dm.denoiser(
                input_ids=input_ids, timesteps=timestep_batch
            ).logits
            model_log_prob = self.layout_dm.scheduler.predict_start(denoiser_logits)
            if self.corrector.recon_type is CorrectorReconType.x_t_minus_1:
                model_log_prob = self.layout_dm.scheduler.q_posterior(
                    model_log_prob, current, timestep_batch
                )
                model_log_prob[:, self.layout_dm.tokenizer.mask_token_id, :] = -70.0
            if self.layout_dm.scheduler.token_mask is not None:
                valid = self.layout_dm.scheduler.token_mask.to(
                    model_log_prob.device
                ).T.unsqueeze(0)
                model_log_prob = model_log_prob.masked_fill(~valid, -70.0)
            if condition is not None:
                strong_mask = condition.mask.to(model_log_prob.device).unsqueeze(1)
                strong_log_prob = index_to_log_onehot(
                    condition.input_ids.to(model_log_prob.device),
                    self.layout_dm.scheduler.vocab_size,
                )
                model_log_prob = torch.where(
                    strong_mask, strong_log_prob, model_log_prob
                )
            x0_recon_ids = torch.multinomial(
                (model_log_prob.permute(0, 2, 1) / sampling.temperature)
                .softmax(dim=-1)
                .reshape(-1, model_log_prob.size(1)),
                1,
                generator=generator,
            ).reshape(model_log_prob.shape[0], model_log_prob.shape[-1])
            confidence = self.corrector.calc_confidence_score(
                x0_recon_ids,
                timestep_batch,
                padding_mask=x0_recon_ids == self.layout_dm.tokenizer.pad_token_id,
            )
            adjusted = confidence
            mask_ratio = self._mask_ratio(timestep_batch)
            if sampling.use_gumbel_noise:
                adjusted = add_confidence_gumbel_noise(
                    adjusted,
                    timestep=timestep_batch,
                    mask_ratio=mask_ratio,
                    temperature=sampling.gumbel_temperature,
                    time_adaptive_temperature=sampling.time_adaptive_temperature,
                    generator=generator,
                )
            remask = select_tokens_to_remask(
                adjusted,
                mask_ratio=mask_ratio,
                mode=sampling.corrector_mask_mode,
                threshold=sampling.corrector_mask_threshold,
                temperature=sampling.corrector_temperature,
            )
            x0_recon_ids = x0_recon_ids.masked_fill(
                remask, self.layout_dm.tokenizer.mask_token_id
            )
            if condition is not None:
                x0_recon_ids = torch.where(
                    condition.mask.to(x0_recon_ids.device),
                    condition.input_ids.to(x0_recon_ids.device),
                    x0_recon_ids,
                )
            current = index_to_log_onehot(
                x0_recon_ids, self.layout_dm.scheduler.vocab_size
            )
        return current, confidence

    def _mask_ratio(self, timestep_batch: Int[torch.Tensor, "batch"]) -> float:
        timestep = int(timestep_batch[0].item())
        timestep = max(0, min(timestep, self.layout_dm.scheduler.config.num_timesteps))
        if timestep == 0:
            return 0.0
        return float(timestep / self.layout_dm.scheduler.config.num_timesteps)

    def save_pretrained(
        self, save_directory: str | Path, *, safe_serialization: bool = True
    ) -> None:
        """Save the nested LayoutDM pipeline and corrector model.

        Args:
            save_directory: Destination directory.
            safe_serialization: Whether to save weights as safetensors.

        Returns:
            None.

        Raises:
            OSError: If files cannot be written.

        Examples:
            >>> LayoutCorrectorPipeline.save_pretrained  # doctest: +ELLIPSIS
            <function...
        """
        save_path = Path(save_directory)
        save_path.mkdir(parents=True, exist_ok=True)
        self.layout_dm.save_pretrained(
            save_path / "layout_dm", safe_serialization=safe_serialization
        )
        self.corrector.save_pretrained(
            save_path / "corrector", safe_serialization=safe_serialization
        )

    @classmethod
    def from_pretrained(
        cls,
        pretrained_model_name_or_path: str | Path,
        *,
        processor: LayoutDMProcessor | None = None,
    ) -> "LayoutCorrectorPipeline":
        """Load a Layout-Corrector pipeline from a saved directory.

        Args:
            pretrained_model_name_or_path: Directory containing `layout_dm/` and
                `corrector/` subdirectories.
            processor: Optional processor override.

        Returns:
            Loaded `LayoutCorrectorPipeline`.

        Raises:
            OSError: If nested component files are missing.

        Examples:
            >>> LayoutCorrectorPipeline.from_pretrained  # doctest: +ELLIPSIS
            <bound method...
        """
        path = Path(pretrained_model_name_or_path)
        layout_dm = LayoutDMPipeline.from_pretrained(path / "layout_dm")
        corrector = LayoutCorrectorModel.from_pretrained(path / "corrector")
        return cls(layout_dm=layout_dm, corrector=corrector, processor=processor)

__init__

__init__(
    layout_dm: LayoutDMPipeline,
    corrector: LayoutCorrectorModel,
    processor: LayoutDMProcessor | None = None,
) -> None

Initialize the composite pipeline.

Parameters:

Name Type Description Default
layout_dm LayoutDMPipeline

Base LayoutDM pipeline.

required
corrector LayoutCorrectorModel

Confidence model used to remask low-confidence tokens.

required
processor LayoutDMProcessor | None

Optional processor for conditional inputs.

None
Source code in models/layout-corrector/src/layout_corrector/pipeline_layout_corrector.py
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
def __init__(
    self,
    layout_dm: LayoutDMPipeline,
    corrector: LayoutCorrectorModel,
    processor: LayoutDMProcessor | None = None,
) -> None:
    """Initialize the composite pipeline.

    Args:
        layout_dm: Base LayoutDM pipeline.
        corrector: Confidence model used to remask low-confidence tokens.
        processor: Optional processor for conditional inputs.
    """
    super().__init__()
    self.register_modules(layout_dm=layout_dm, corrector=corrector)
    self.layout_dm = layout_dm
    self.corrector = corrector
    self.processor = processor or layout_dm.processor
    self.corrector.eval()

__call__

__call__(
    *,
    batch_size: int = 1,
    seed: int | None = None,
    generator: Generator | None = None,
    condition_type: ConditionType
    | str = ConditionType.unconditional,
    labels: Int[Tensor, "batch elements"]
    | Int[ndarray, "batch elements"]
    | list[ArrayLikeInput]
    | None = None,
    bbox: Float[Tensor, "batch elements 4"]
    | Float[ndarray, "batch elements 4"]
    | list[ArrayLikeInput]
    | None = None,
    mask: Bool[Tensor, "batch elements"]
    | Bool[ndarray, "batch elements"]
    | list[ArrayLikeInput]
    | 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,
    sampling: SamplingMode | str = SamplingMode.random,
    temperature: float = 1.0,
    top_k: int = 5,
    top_p: float = 0.9,
    corrector_steps: int | None = None,
    corrector_t_list: Sequence[int] | None = None,
    corrector_start: int = -1,
    corrector_end: int = -1,
    corrector_mask_mode: CorrectorMaskMode
    | str
    | None = None,
    corrector_mask_threshold: float | None = None,
    corrector_temperature: float | None = None,
    use_gumbel_noise: bool | None = None,
    gumbel_temperature: float | None = None,
    time_adaptive_temperature: bool | None = None,
    output_type: OutputType | str = OutputType.dataclass,
    return_intermediates: bool = False,
) -> (
    LayoutGenerationOutput
    | dict[
        str,
        Float[torch.Tensor, "batch elements 4"]
        | Int[torch.Tensor, "batch elements"]
        | Bool[torch.Tensor, "batch elements"]
        | Int[torch.Tensor, "batch tokens"]
        | Float[torch.Tensor, "steps batch tokens"]
        | list[Int[torch.Tensor, "batch tokens"]]
        | dict[int, str]
        | dict[str, str]
        | None,
    ]
)

Generate layouts with optional Layout-Corrector guidance.

Parameters:

Name Type Description Default
batch_size int

Number of layouts to sample for unconditional generation.

1
seed int | None

Optional seed used when generator is not supplied.

None
generator Generator | None

Optional PyTorch generator.

None
condition_type ConditionType | str

Condition mode such as "unconditional" or "label".

unconditional
labels Int[Tensor, 'batch elements'] | Int[ndarray, 'batch elements'] | list[ArrayLikeInput] | None

Optional class ids for conditional generation.

None
bbox Float[Tensor, 'batch elements 4'] | Float[ndarray, 'batch elements 4'] | list[ArrayLikeInput] | None

Optional boxes for conditional generation.

None
mask Bool[Tensor, 'batch elements'] | Bool[ndarray, 'batch elements'] | list[ArrayLikeInput] | None

Optional element mask for conditional generation.

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

Reserved for future element-count conditioning.

None
box_format BoxFormat | str

Coordinate format for conditional boxes.

xywh
normalized bool

Whether conditional boxes are normalized.

True
canvas_size tuple[int, int] | None

Pixel canvas used when normalized=False.

None
num_inference_steps int | None

Optional inference timestep count.

None
sampling SamplingMode | str

Base LayoutDM sampling strategy.

random
temperature float

Base sampling temperature.

1.0
top_k int

Top-k cutoff for top-k sampling.

5
top_p float

Nucleus cutoff for top-p sampling.

0.9
corrector_steps int | None

Optional override for correction passes.

None
corrector_t_list Sequence[int] | None

Optional explicit correction timesteps.

None
corrector_start int

Range start for correction when no list is supplied.

-1
corrector_end int

Range end for correction when no list is supplied.

-1
corrector_mask_mode CorrectorMaskMode | str | None

Optional override for remasking mode.

None
corrector_mask_threshold float | None

Optional threshold override.

None
corrector_temperature float | None

Optional confidence temperature override.

None
use_gumbel_noise bool | None

Optional confidence-noise override.

None
gumbel_temperature float | None

Optional confidence-noise temperature override.

None
time_adaptive_temperature bool | None

Optional adaptive-noise override.

None
output_type OutputType | str

"dataclass" or "dict".

dataclass
return_intermediates bool

Whether to include scores and trajectory.

False

Returns:

Type Description
LayoutGenerationOutput | dict[str, Float[Tensor, 'batch elements 4'] | Int[Tensor, 'batch elements'] | Bool[Tensor, 'batch elements'] | Int[Tensor, 'batch tokens'] | Float[Tensor, 'steps batch tokens'] | list[Int[Tensor, 'batch tokens']] | dict[int, str] | dict[str, str] | None]

LayoutGenerationOutput by default, or a dictionary when requested.

Raises:

Type Description
ValueError

If conditional generation is missing bbox or labels, or if output_type is unsupported.

Examples:

>>> LayoutCorrectorPipeline.__call__
<function...
Source code in models/layout-corrector/src/layout_corrector/pipeline_layout_corrector.py
 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
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
@torch.no_grad()
def __call__(
    self,
    *,
    batch_size: int = 1,
    seed: int | None = None,
    generator: torch.Generator | None = None,
    condition_type: ConditionType | str = ConditionType.unconditional,
    labels: Int[torch.Tensor, "batch elements"]
    | Int[np.ndarray, "batch elements"]
    | list[ArrayLikeInput]
    | None = None,
    bbox: Float[torch.Tensor, "batch elements 4"]
    | Float[np.ndarray, "batch elements 4"]
    | list[ArrayLikeInput]
    | None = None,
    mask: Bool[torch.Tensor, "batch elements"]
    | Bool[np.ndarray, "batch elements"]
    | list[ArrayLikeInput]
    | 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,
    sampling: SamplingMode | str = SamplingMode.random,
    temperature: float = 1.0,
    top_k: int = 5,
    top_p: float = 0.9,
    corrector_steps: int | None = None,
    corrector_t_list: Sequence[int] | None = None,
    corrector_start: int = -1,
    corrector_end: int = -1,
    corrector_mask_mode: CorrectorMaskMode | str | None = None,
    corrector_mask_threshold: float | None = None,
    corrector_temperature: float | None = None,
    use_gumbel_noise: bool | None = None,
    gumbel_temperature: float | None = None,
    time_adaptive_temperature: bool | None = None,
    output_type: OutputType | str = OutputType.dataclass,
    return_intermediates: bool = False,
) -> (
    LayoutGenerationOutput
    | dict[
        str,
        Float[torch.Tensor, "batch elements 4"]
        | Int[torch.Tensor, "batch elements"]
        | Bool[torch.Tensor, "batch elements"]
        | Int[torch.Tensor, "batch tokens"]
        | Float[torch.Tensor, "steps batch tokens"]
        | list[Int[torch.Tensor, "batch tokens"]]
        | dict[int, str]
        | dict[str, str]
        | None,
    ]
):
    """Generate layouts with optional Layout-Corrector guidance.

    Args:
        batch_size: Number of layouts to sample for unconditional generation.
        seed: Optional seed used when `generator` is not supplied.
        generator: Optional PyTorch generator.
        condition_type: Condition mode such as `"unconditional"` or `"label"`.
        labels: Optional class ids for conditional generation.
        bbox: Optional boxes for conditional generation.
        mask: Optional element mask for conditional generation.
        num_elements: Reserved for future element-count conditioning.
        box_format: Coordinate format for conditional boxes.
        normalized: Whether conditional boxes are normalized.
        canvas_size: Pixel canvas used when `normalized=False`.
        num_inference_steps: Optional inference timestep count.
        sampling: Base LayoutDM sampling strategy.
        temperature: Base sampling temperature.
        top_k: Top-k cutoff for top-k sampling.
        top_p: Nucleus cutoff for top-p sampling.
        corrector_steps: Optional override for correction passes.
        corrector_t_list: Optional explicit correction timesteps.
        corrector_start: Range start for correction when no list is supplied.
        corrector_end: Range end for correction when no list is supplied.
        corrector_mask_mode: Optional override for remasking mode.
        corrector_mask_threshold: Optional threshold override.
        corrector_temperature: Optional confidence temperature override.
        use_gumbel_noise: Optional confidence-noise override.
        gumbel_temperature: Optional confidence-noise temperature override.
        time_adaptive_temperature: Optional adaptive-noise override.
        output_type: `"dataclass"` or `"dict"`.
        return_intermediates: Whether to include scores and trajectory.

    Returns:
        `LayoutGenerationOutput` by default, or a dictionary when requested.

    Raises:
        ValueError: If conditional generation is missing `bbox` or `labels`, or
            if `output_type` is unsupported.

    Examples:
        >>> LayoutCorrectorPipeline.__call__  # doctest: +ELLIPSIS
        <function...
    """
    _ = num_elements
    if generator is None and seed is not None:
        generator = torch.Generator(device=self.device).manual_seed(seed)
    canonical = normalize_condition_type(condition_type)
    condition = None
    if canonical != "unconditional":
        missing_inputs = [
            name
            for name, value in (("bbox", bbox), ("labels", labels))
            if value is None
        ]
        if missing_inputs:
            raise ValueError(
                "bbox and labels are required "
                f"for condition_type={condition_type}; "
                f"missing {', '.join(missing_inputs)}"
            )

        processor_inputs = {
            "bbox": bbox,
            "labels": labels,
            "mask": mask,
            "box_format": box_format,
            "normalized": normalized,
            "canvas_size": canvas_size,
        }
        processed = self.processor(**processor_inputs)
        decoded_input = self.layout_dm.tokenizer.decode_layout(
            processed["input_ids"]
        )
        condition = build_condition(
            self.layout_dm.tokenizer,
            cond_type=canonical,
            bbox=decoded_input["bbox"],
            labels=decoded_input["labels"],
            mask=decoded_input["mask"],
        )
        batch_size = condition.input_ids.shape[0]

    corrector_cfg = LayoutCorrectorSamplingConfig(
        sampling=sampling,
        temperature=temperature,
        top_k=top_k,
        top_p=top_p,
        num_inference_steps=num_inference_steps,
        corrector_steps=corrector_steps or self.corrector.corrector_steps,
        corrector_t_list=tuple(
            self.corrector.corrector_t_list
            if corrector_t_list is None
            else corrector_t_list
        ),
        corrector_start=corrector_start,
        corrector_end=corrector_end,
        corrector_mask_mode=corrector_mask_mode
        or self.corrector.corrector_mask_mode,
        corrector_mask_threshold=corrector_mask_threshold
        if corrector_mask_threshold is not None
        else self.corrector.corrector_mask_threshold,
        corrector_temperature=corrector_temperature
        if corrector_temperature is not None
        else self.corrector.corrector_temperature,
        use_gumbel_noise=use_gumbel_noise
        if use_gumbel_noise is not None
        else self.corrector.use_gumbel_noise,
        gumbel_temperature=gumbel_temperature
        if gumbel_temperature is not None
        else self.corrector.gumbel_temperature,
        time_adaptive_temperature=time_adaptive_temperature
        if time_adaptive_temperature is not None
        else self.corrector.time_adaptive_temperature,
    )
    sampling_cfg = LayoutDMSamplingConfig(
        name=sampling,
        temperature=temperature,
        top_k=top_k,
        top_p=top_p,
        num_inference_steps=num_inference_steps,
    )
    self.layout_dm.scheduler.set_timesteps(num_inference_steps, device=self.device)
    sample = self.layout_dm.scheduler.initial_sample(
        batch_size,
        self.layout_dm.tokenizer.config.max_token_length,
        device=self.device,
        condition=condition,
    )
    trajectory = [] if return_intermediates else None
    scores = [] if return_intermediates else None
    previous_timestep = self.layout_dm.scheduler.config.num_timesteps
    for timestep in self.layout_dm.scheduler.timesteps:
        timestep_value = int(timestep.item())
        timestep_batch = torch.full(
            (batch_size,),
            timestep_value,
            device=self.device,
            dtype=torch.long,
        )
        if should_apply_corrector(timestep_value, corrector_cfg):
            sample, confidence = self._step_with_corrector(
                sample=sample,
                timestep_batch=timestep_batch,
                condition=condition,
                sampling=corrector_cfg,
                generator=generator,
            )
            if scores is not None and confidence is not None:
                scores.append(confidence.detach().cpu())
        else:
            input_ids = log_onehot_to_index(sample)
            logits = self.layout_dm.denoiser(
                input_ids=input_ids, timesteps=timestep_batch
            ).logits
            sample = self.layout_dm.scheduler.step(
                logits,
                timestep_batch,
                sample,
                previous_timestep=previous_timestep,
                sampling=sampling_cfg,
                condition=condition,
                generator=generator,
            ).prev_sample
        previous_timestep = timestep_value
        if trajectory is not None:
            trajectory.append(log_onehot_to_index(sample).detach().cpu())

    sequences = log_onehot_to_index(sample).detach().cpu()
    decoded = self.layout_dm.tokenizer.decode_layout(sequences)
    output = LayoutGenerationOutput(
        bbox=decoded["bbox"],
        labels=decoded["labels"],
        mask=decoded["mask"],
        id2label=dict(self.corrector.id2label),
        sequences=sequences,
        scores=torch.stack(scores) if scores else None,
        trajectory=trajectory,
        intermediates={"condition_type": canonical}
        if return_intermediates
        else None,
    )
    normalized_output_type = normalize_output_type(output_type)
    if normalized_output_type is OutputType.dict:
        return dict(output)
    if normalized_output_type is OutputType.dataclass:
        return output
    assert_never(normalized_output_type)

save_pretrained

save_pretrained(
    save_directory: str | Path,
    *,
    safe_serialization: bool = True,
) -> None

Save the nested LayoutDM pipeline and corrector model.

Parameters:

Name Type Description Default
save_directory str | Path

Destination directory.

required
safe_serialization bool

Whether to save weights as safetensors.

True

Returns:

Type Description
None

None.

Raises:

Type Description
OSError

If files cannot be written.

Examples:

>>> LayoutCorrectorPipeline.save_pretrained
<function...
Source code in models/layout-corrector/src/layout_corrector/pipeline_layout_corrector.py
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
def save_pretrained(
    self, save_directory: str | Path, *, safe_serialization: bool = True
) -> None:
    """Save the nested LayoutDM pipeline and corrector model.

    Args:
        save_directory: Destination directory.
        safe_serialization: Whether to save weights as safetensors.

    Returns:
        None.

    Raises:
        OSError: If files cannot be written.

    Examples:
        >>> LayoutCorrectorPipeline.save_pretrained  # doctest: +ELLIPSIS
        <function...
    """
    save_path = Path(save_directory)
    save_path.mkdir(parents=True, exist_ok=True)
    self.layout_dm.save_pretrained(
        save_path / "layout_dm", safe_serialization=safe_serialization
    )
    self.corrector.save_pretrained(
        save_path / "corrector", safe_serialization=safe_serialization
    )

from_pretrained classmethod

from_pretrained(
    pretrained_model_name_or_path: str | Path,
    *,
    processor: LayoutDMProcessor | None = None,
) -> "LayoutCorrectorPipeline"

Load a Layout-Corrector pipeline from a saved directory.

Parameters:

Name Type Description Default
pretrained_model_name_or_path str | Path

Directory containing layout_dm/ and corrector/ subdirectories.

required
processor LayoutDMProcessor | None

Optional processor override.

None

Returns:

Type Description
'LayoutCorrectorPipeline'

Loaded LayoutCorrectorPipeline.

Raises:

Type Description
OSError

If nested component files are missing.

Examples:

>>> LayoutCorrectorPipeline.from_pretrained
<bound method...
Source code in models/layout-corrector/src/layout_corrector/pipeline_layout_corrector.py
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
@classmethod
def from_pretrained(
    cls,
    pretrained_model_name_or_path: str | Path,
    *,
    processor: LayoutDMProcessor | None = None,
) -> "LayoutCorrectorPipeline":
    """Load a Layout-Corrector pipeline from a saved directory.

    Args:
        pretrained_model_name_or_path: Directory containing `layout_dm/` and
            `corrector/` subdirectories.
        processor: Optional processor override.

    Returns:
        Loaded `LayoutCorrectorPipeline`.

    Raises:
        OSError: If nested component files are missing.

    Examples:
        >>> LayoutCorrectorPipeline.from_pretrained  # doctest: +ELLIPSIS
        <bound method...
    """
    path = Path(pretrained_model_name_or_path)
    layout_dm = LayoutDMPipeline.from_pretrained(path / "layout_dm")
    corrector = LayoutCorrectorModel.from_pretrained(path / "corrector")
    return cls(layout_dm=layout_dm, corrector=corrector, processor=processor)

normalize_output_type

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

Normalize a public output format string to OutputType.

Source code in models/layout-corrector/src/layout_corrector/pipeline_layout_corrector.py
46
47
48
49
50
51
52
53
def normalize_output_type(output_type: OutputType | str) -> OutputType:
    """Normalize a public output format string to ``OutputType``."""
    if isinstance(output_type, OutputType):
        return output_type
    try:
        return OutputType(output_type)
    except ValueError as exc:
        raise ValueError(f"Unsupported output_type: {output_type}") from exc

sampling

Sampling helpers for Layout-Corrector guided generation.

CorrectorMaskMode

Bases: StrEnum

Supported token remasking modes for Layout-Corrector.

Source code in models/layout-corrector/src/layout_corrector/sampling.py
20
21
22
23
24
class CorrectorMaskMode(StrEnum):
    """Supported token remasking modes for Layout-Corrector."""

    thresh = auto()
    topk = auto()

LayoutCorrectorSamplingConfig dataclass

Sampling options for Layout-Corrector-guided diffusion.

Parameters:

Name Type Description Default
sampling SamplingMode | str

Base LayoutDM sampling strategy.

random
temperature float

Base sampling temperature.

1.0
top_k int

Top-k cutoff for top-k sampling.

5
top_p float

Nucleus cutoff for top-p sampling.

0.9
num_inference_steps int | None

Optional inference timestep count.

None
corrector_steps int

Number of correction passes per selected timestep.

1
corrector_t_list tuple[int, ...]

Explicit timesteps where the corrector is applied.

(10, 20, 30)
corrector_start int

Start timestep for range-based correction.

-1
corrector_end int

End timestep for range-based correction.

-1
corrector_mask_mode CorrectorMaskMode | str

Strategy for selecting tokens to remask.

thresh
corrector_mask_threshold float

Confidence threshold for threshold masking.

0.7
corrector_temperature float

Temperature used for confidence masking.

1.0
use_gumbel_noise bool

Whether to perturb confidence logits.

True
gumbel_temperature float

Temperature for confidence Gumbel noise.

1.0
time_adaptive_temperature bool

Whether to scale noise by timestep ratio.

False

Raises:

Type Description
ValueError

Construction does not raise directly.

Examples:

>>> LayoutCorrectorSamplingConfig(corrector_t_list=(10,)).corrector_t_list
(10,)
Source code in models/layout-corrector/src/layout_corrector/sampling.py
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
@dataclass
class LayoutCorrectorSamplingConfig:
    """Sampling options for Layout-Corrector-guided diffusion.

    Args:
        sampling: Base LayoutDM sampling strategy.
        temperature: Base sampling temperature.
        top_k: Top-k cutoff for top-k sampling.
        top_p: Nucleus cutoff for top-p sampling.
        num_inference_steps: Optional inference timestep count.
        corrector_steps: Number of correction passes per selected timestep.
        corrector_t_list: Explicit timesteps where the corrector is applied.
        corrector_start: Start timestep for range-based correction.
        corrector_end: End timestep for range-based correction.
        corrector_mask_mode: Strategy for selecting tokens to remask.
        corrector_mask_threshold: Confidence threshold for threshold masking.
        corrector_temperature: Temperature used for confidence masking.
        use_gumbel_noise: Whether to perturb confidence logits.
        gumbel_temperature: Temperature for confidence Gumbel noise.
        time_adaptive_temperature: Whether to scale noise by timestep ratio.

    Raises:
        ValueError: Construction does not raise directly.

    Examples:
        >>> LayoutCorrectorSamplingConfig(corrector_t_list=(10,)).corrector_t_list
        (10,)
    """

    sampling: SamplingMode | str = SamplingMode.random
    temperature: float = 1.0
    top_k: int = 5
    top_p: float = 0.9
    num_inference_steps: int | None = None
    corrector_steps: int = 1
    corrector_t_list: tuple[int, ...] = (10, 20, 30)
    corrector_start: int = -1
    corrector_end: int = -1
    corrector_mask_mode: CorrectorMaskMode | str = CorrectorMaskMode.thresh
    corrector_mask_threshold: float = 0.7
    corrector_temperature: float = 1.0
    use_gumbel_noise: bool = True
    gumbel_temperature: float = 1.0
    time_adaptive_temperature: bool = False

    def __post_init__(self) -> None:
        """Normalize public string modes to enum values."""
        self.sampling = normalize_sampling_mode(self.sampling)
        self.corrector_mask_mode = normalize_corrector_mask_mode(
            self.corrector_mask_mode
        )

__post_init__

__post_init__() -> None

Normalize public string modes to enum values.

Source code in models/layout-corrector/src/layout_corrector/sampling.py
86
87
88
89
90
91
def __post_init__(self) -> None:
    """Normalize public string modes to enum values."""
    self.sampling = normalize_sampling_mode(self.sampling)
    self.corrector_mask_mode = normalize_corrector_mask_mode(
        self.corrector_mask_mode
    )

normalize_corrector_mask_mode

normalize_corrector_mask_mode(
    corrector_mask_mode: CorrectorMaskMode | str,
) -> CorrectorMaskMode

Normalize a public remasking mode to CorrectorMaskMode.

Source code in models/layout-corrector/src/layout_corrector/sampling.py
27
28
29
30
31
32
33
34
35
36
37
38
def normalize_corrector_mask_mode(
    corrector_mask_mode: CorrectorMaskMode | str,
) -> CorrectorMaskMode:
    """Normalize a public remasking mode to ``CorrectorMaskMode``."""
    if isinstance(corrector_mask_mode, CorrectorMaskMode):
        return corrector_mask_mode
    try:
        return CorrectorMaskMode(corrector_mask_mode)
    except ValueError as exc:
        raise ValueError(
            f"Unsupported corrector mask mode: {corrector_mask_mode}"
        ) from exc

should_apply_corrector

should_apply_corrector(
    diffusion_index: int,
    config: LayoutCorrectorSamplingConfig,
) -> bool

Return whether the corrector should run at a diffusion timestep.

Parameters:

Name Type Description Default
diffusion_index int

Current diffusion timestep.

required
config LayoutCorrectorSamplingConfig

Corrector sampling options.

required

Returns:

Type Description
bool

True when the timestep matches the explicit list or configured range.

Raises:

Type Description
ValueError

This function does not raise.

Examples:

>>> should_apply_corrector(10, LayoutCorrectorSamplingConfig(corrector_t_list=(10,)))
True
Source code in models/layout-corrector/src/layout_corrector/sampling.py
 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
def should_apply_corrector(
    diffusion_index: int,
    config: LayoutCorrectorSamplingConfig,
) -> bool:
    """Return whether the corrector should run at a diffusion timestep.

    Args:
        diffusion_index: Current diffusion timestep.
        config: Corrector sampling options.

    Returns:
        `True` when the timestep matches the explicit list or configured range.

    Raises:
        ValueError: This function does not raise.

    Examples:
        >>> should_apply_corrector(10, LayoutCorrectorSamplingConfig(corrector_t_list=(10,)))
        True
    """
    if config.corrector_t_list:
        return diffusion_index in set(config.corrector_t_list)
    if config.corrector_start < 0 or config.corrector_end < 0:
        return False
    start, end = sorted((config.corrector_start, config.corrector_end))
    return start <= diffusion_index <= end

add_confidence_gumbel_noise

add_confidence_gumbel_noise(
    confidence_logits: Float[Tensor, "batch tokens"],
    *,
    timestep: Int[Tensor, "batch"],
    mask_ratio: float,
    temperature: float,
    time_adaptive_temperature: bool,
    generator: Generator | None = None,
) -> Float[torch.Tensor, "batch tokens"]

Add Gumbel noise to confidence logits.

Parameters:

Name Type Description Default
confidence_logits Float[Tensor, 'batch tokens']

Rank-2 confidence logits.

required
timestep Int[Tensor, 'batch']

Current timestep tensor.

required
mask_ratio float

Fraction of tokens still masked.

required
temperature float

Base noise temperature.

required
time_adaptive_temperature bool

Whether to scale temperature by mask_ratio.

required
generator Generator | None

Optional PyTorch generator for reproducible noise.

None

Returns:

Type Description
Float[Tensor, 'batch tokens']

Confidence logits after noise injection.

Raises:

Type Description
ValueError

This function does not raise directly.

Examples:

>>> import torch
>>> logits = torch.zeros(1, 2)
>>> add_confidence_gumbel_noise(
...     logits,
...     timestep=torch.tensor([1]),
...     mask_ratio=0.5,
...     temperature=1.0,
...     time_adaptive_temperature=False,
...     generator=torch.Generator().manual_seed(0),
... ).shape
torch.Size([1, 2])
Source code in models/layout-corrector/src/layout_corrector/sampling.py
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
def add_confidence_gumbel_noise(
    confidence_logits: Float[torch.Tensor, "batch tokens"],
    *,
    timestep: Int[torch.Tensor, "batch"],
    mask_ratio: float,
    temperature: float,
    time_adaptive_temperature: bool,
    generator: torch.Generator | None = None,
) -> Float[torch.Tensor, "batch tokens"]:
    """Add Gumbel noise to confidence logits.

    Args:
        confidence_logits: Rank-2 confidence logits.
        timestep: Current timestep tensor.
        mask_ratio: Fraction of tokens still masked.
        temperature: Base noise temperature.
        time_adaptive_temperature: Whether to scale temperature by `mask_ratio`.
        generator: Optional PyTorch generator for reproducible noise.

    Returns:
        Confidence logits after noise injection.

    Raises:
        ValueError: This function does not raise directly.

    Examples:
        >>> import torch
        >>> logits = torch.zeros(1, 2)
        >>> add_confidence_gumbel_noise(
        ...     logits,
        ...     timestep=torch.tensor([1]),
        ...     mask_ratio=0.5,
        ...     temperature=1.0,
        ...     time_adaptive_temperature=False,
        ...     generator=torch.Generator().manual_seed(0),
        ... ).shape
        torch.Size([1, 2])
    """
    scale = torch.full(
        (confidence_logits.shape[0], 1),
        float(temperature),
        device=confidence_logits.device,
        dtype=confidence_logits.dtype,
    )
    if time_adaptive_temperature:
        scale = scale * (1.0 - mask_ratio)
    return confidence_logits + scale * gumbel_noise_like(
        confidence_logits, generator=generator
    )

select_tokens_to_remask

select_tokens_to_remask(
    confidence_logits: Float[Tensor, "batch tokens"],
    *,
    mask_ratio: float,
    mode: CorrectorMaskMode | str,
    threshold: float,
    temperature: float = 1.0,
) -> Bool[torch.Tensor, "batch tokens"]

Select low-confidence tokens that should be masked again.

Parameters:

Name Type Description Default
confidence_logits Float[Tensor, 'batch tokens']

Rank-2 confidence logits shaped (batch, tokens).

required
mask_ratio float

Ratio used to choose top-k remasking count.

required
mode CorrectorMaskMode | str

Selection mode, either "thresh" or "topk".

required
threshold float

Sigmoid confidence threshold for "thresh".

required
temperature float

Temperature applied before thresholding.

1.0

Returns:

Type Description
Bool[Tensor, 'batch tokens']

Boolean mask with True where tokens should be remasked.

Raises:

Type Description
ValueError

If logits are not rank-2 or mode is unsupported.

Examples:

>>> import torch
>>> select_tokens_to_remask(torch.zeros(1, 2), mask_ratio=0.5, mode="topk", threshold=0.7).shape
torch.Size([1, 2])
Source code in models/layout-corrector/src/layout_corrector/sampling.py
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
def select_tokens_to_remask(
    confidence_logits: Float[torch.Tensor, "batch tokens"],
    *,
    mask_ratio: float,
    mode: CorrectorMaskMode | str,
    threshold: float,
    temperature: float = 1.0,
) -> Bool[torch.Tensor, "batch tokens"]:
    """Select low-confidence tokens that should be masked again.

    Args:
        confidence_logits: Rank-2 confidence logits shaped `(batch, tokens)`.
        mask_ratio: Ratio used to choose top-k remasking count.
        mode: Selection mode, either `"thresh"` or `"topk"`.
        threshold: Sigmoid confidence threshold for `"thresh"`.
        temperature: Temperature applied before thresholding.

    Returns:
        Boolean mask with `True` where tokens should be remasked.

    Raises:
        ValueError: If logits are not rank-2 or `mode` is unsupported.

    Examples:
        >>> import torch
        >>> select_tokens_to_remask(torch.zeros(1, 2), mask_ratio=0.5, mode="topk", threshold=0.7).shape
        torch.Size([1, 2])
    """
    if confidence_logits.ndim != 2:
        raise ValueError("confidence_logits must be rank-2")

    normalized_mode = normalize_corrector_mask_mode(mode)
    if normalized_mode is CorrectorMaskMode.thresh:
        confidence = torch.sigmoid(confidence_logits / temperature)
        return confidence < threshold
    if normalized_mode is CorrectorMaskMode.topk:
        num_token = confidence_logits.shape[1]
        k = torch.full(
            (confidence_logits.shape[0],),
            int(mask_ratio * num_token),
            device=confidence_logits.device,
            dtype=torch.long,
        )
        return batch_topk_mask(-confidence_logits, k)
    assert_never(normalized_mode)