Skip to content

Flex dm

Flex-DM masked document modeling package.

FlexDmConfig

Bases: PretrainedConfig

Configuration for a converted Flex-DM MFP model.

Parameters:

Name Type Description Default
dataset_name str

Released dataset name.

'crello'
checkpoint_variant str

Released checkpoint variant name.

'ours-exp-ft'
id2label dict[int | str, str] | None

Public dataset-local label mapping.

None
input_columns dict[str, FlexDmColumnSpec] | None

Heterogeneous model column specs.

None
attribute_groups dict[str, tuple[str, ...] | list[str]] | None

Model feature groups used for infilling.

None
max_seq_length int

Maximum document elements.

50
latent_dim int

Transformer hidden dimension.

256
num_blocks int

Number of DeepSVG-style transformer blocks.

4
block_type str

Released block type. Only deepsvg is implemented.

'deepsvg'
masking_method str

Released masking task selector.

'random'
seq_type str

Released sequence model type. default is the released path.

'default'
arch_type str

Released architecture type. oneshot is the released path.

'oneshot'
context str | None

Optional reference context embedding mode.

None
input_dtype str

Released input ordering mode.

'set'
use_elemwise_noise bool

Whether element-wise noise was enabled.

False
dropout float

Dropout probability.

0.1
layer_norm_epsilon float

LayerNorm epsilon matching Keras defaults.

0.001
l2 float | None

Original L2 setting, stored for provenance.

0.01
original_args dict[str, FlexDmConfigValue] | None

Raw reference args.json values.

None
conversion_report dict[str, FlexDmConfigValue] | None

Checkpoint conversion diagnostics.

None
kwargs str | int | float | bool | None

Extra PretrainedConfig fields.

{}
Source code in models/flex-dm/src/flex_dm/configuration_flex_dm.py
 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
class FlexDmConfig(PretrainedConfig):
    """Configuration for a converted Flex-DM MFP model.

    Args:
        dataset_name: Released dataset name.
        checkpoint_variant: Released checkpoint variant name.
        id2label: Public dataset-local label mapping.
        input_columns: Heterogeneous model column specs.
        attribute_groups: Model feature groups used for infilling.
        max_seq_length: Maximum document elements.
        latent_dim: Transformer hidden dimension.
        num_blocks: Number of DeepSVG-style transformer blocks.
        block_type: Released block type. Only ``deepsvg`` is implemented.
        masking_method: Released masking task selector.
        seq_type: Released sequence model type. ``default`` is the released path.
        arch_type: Released architecture type. ``oneshot`` is the released path.
        context: Optional reference context embedding mode.
        input_dtype: Released input ordering mode.
        use_elemwise_noise: Whether element-wise noise was enabled.
        dropout: Dropout probability.
        layer_norm_epsilon: LayerNorm epsilon matching Keras defaults.
        l2: Original L2 setting, stored for provenance.
        original_args: Raw reference ``args.json`` values.
        conversion_report: Checkpoint conversion diagnostics.
        kwargs: Extra ``PretrainedConfig`` fields.
    """

    model_type = "flex-dm"

    def __init__(
        self,
        dataset_name: str = "crello",
        checkpoint_variant: str = "ours-exp-ft",
        id2label: dict[int | str, str] | None = None,
        input_columns: dict[str, FlexDmColumnSpec] | None = None,
        attribute_groups: dict[str, tuple[str, ...] | list[str]] | None = None,
        max_seq_length: int = 50,
        latent_dim: int = 256,
        num_blocks: int = 4,
        block_type: str = "deepsvg",
        masking_method: str = "random",
        seq_type: str = "default",
        arch_type: str = "oneshot",
        context: str | None = None,
        input_dtype: str = "set",
        use_elemwise_noise: bool = False,
        dropout: float = 0.1,
        layer_norm_epsilon: float = 1e-3,
        l2: float | None = 1e-2,
        original_args: dict[str, FlexDmConfigValue] | None = None,
        conversion_report: dict[str, FlexDmConfigValue] | None = None,
        **kwargs: str | int | float | bool | None,
    ) -> None:
        """Initialize a Flex-DM config."""
        normalized_id2label = _normalize_id2label(id2label)
        kwargs.pop("label2id", None)
        super().__init__(
            id2label=normalized_id2label,
            label2id={label: idx for idx, label in normalized_id2label.items()},
            **kwargs,  # ty: ignore[invalid-argument-type]
        )
        self.dataset_name = dataset_name
        self.checkpoint_variant = checkpoint_variant
        self.input_columns = _normalize_columns(input_columns)
        if attribute_groups is None:
            from .data_specs import attribute_groups_for_dataset

            attribute_groups = dict(attribute_groups_for_dataset(dataset_name))
        groups = attribute_groups

        self.attribute_groups = {key: tuple(value) for key, value in groups.items()}
        self.max_seq_length = max_seq_length
        self.latent_dim = latent_dim
        self.num_blocks = num_blocks
        self.block_type = block_type
        self.masking_method = masking_method
        self.seq_type = seq_type
        self.arch_type = arch_type
        self.context = context
        self.input_dtype = input_dtype

        self.use_elemwise_noise = use_elemwise_noise
        self.dropout = dropout
        self.layer_norm_epsilon = layer_norm_epsilon
        self.l2 = l2
        self.original_args = original_args or {}
        self.conversion_report = conversion_report or {}

    @property
    def max_seq_length_with_length_lookup(self) -> int:
        """Return the max length used by the zero-based length lookup."""
        return self.max_seq_length

    @property
    def valid_sequence_keys(self) -> tuple[str, ...]:
        """Return non-demo sequence fields modeled by Flex-DM."""
        return tuple(
            key for key, column in self.input_columns.items() if column["is_sequence"]
        )

    @property
    def categorical_keys(self) -> tuple[str, ...]:
        """Return sequence fields with categorical heads."""
        return tuple(
            key
            for key, column in self.input_columns.items()
            if column["is_sequence"] and column["type"] == "categorical"
        )

    @property
    def numerical_keys(self) -> tuple[str, ...]:
        """Return sequence fields with numerical heads."""
        return tuple(
            key
            for key, column in self.input_columns.items()
            if column["is_sequence"] and column["type"] == "numerical"
        )

    @property
    def task_names(self) -> tuple[str, ...]:
        """Return task names in sampler order."""
        return ("random", "elem", *self.attribute_groups.keys())

    def mask_token_id_for(self, key: str) -> int:
        """Return the categorical mask token id for ``key``."""
        input_dim = self.input_columns[key]["input_dim"]
        if input_dim is None:
            raise ValueError(f"{key} is not categorical")

        return input_dim

    def unused_token_id_for(self, key: str) -> int:
        """Return the categorical unused token id for ``key``."""
        return self.mask_token_id_for(key) + 1

max_seq_length_with_length_lookup property

max_seq_length_with_length_lookup: int

Return the max length used by the zero-based length lookup.

valid_sequence_keys property

valid_sequence_keys: tuple[str, ...]

Return non-demo sequence fields modeled by Flex-DM.

categorical_keys property

categorical_keys: tuple[str, ...]

Return sequence fields with categorical heads.

numerical_keys property

numerical_keys: tuple[str, ...]

Return sequence fields with numerical heads.

task_names property

task_names: tuple[str, ...]

Return task names in sampler order.

__init__

__init__(
    dataset_name: str = "crello",
    checkpoint_variant: str = "ours-exp-ft",
    id2label: dict[int | str, str] | None = None,
    input_columns: dict[str, FlexDmColumnSpec]
    | None = None,
    attribute_groups: dict[str, tuple[str, ...] | list[str]]
    | None = None,
    max_seq_length: int = 50,
    latent_dim: int = 256,
    num_blocks: int = 4,
    block_type: str = "deepsvg",
    masking_method: str = "random",
    seq_type: str = "default",
    arch_type: str = "oneshot",
    context: str | None = None,
    input_dtype: str = "set",
    use_elemwise_noise: bool = False,
    dropout: float = 0.1,
    layer_norm_epsilon: float = 0.001,
    l2: float | None = 0.01,
    original_args: dict[str, FlexDmConfigValue]
    | None = None,
    conversion_report: dict[str, FlexDmConfigValue]
    | None = None,
    **kwargs: str | int | float | bool | None,
) -> None

Initialize a Flex-DM config.

Source code in models/flex-dm/src/flex_dm/configuration_flex_dm.py
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
def __init__(
    self,
    dataset_name: str = "crello",
    checkpoint_variant: str = "ours-exp-ft",
    id2label: dict[int | str, str] | None = None,
    input_columns: dict[str, FlexDmColumnSpec] | None = None,
    attribute_groups: dict[str, tuple[str, ...] | list[str]] | None = None,
    max_seq_length: int = 50,
    latent_dim: int = 256,
    num_blocks: int = 4,
    block_type: str = "deepsvg",
    masking_method: str = "random",
    seq_type: str = "default",
    arch_type: str = "oneshot",
    context: str | None = None,
    input_dtype: str = "set",
    use_elemwise_noise: bool = False,
    dropout: float = 0.1,
    layer_norm_epsilon: float = 1e-3,
    l2: float | None = 1e-2,
    original_args: dict[str, FlexDmConfigValue] | None = None,
    conversion_report: dict[str, FlexDmConfigValue] | None = None,
    **kwargs: str | int | float | bool | None,
) -> None:
    """Initialize a Flex-DM config."""
    normalized_id2label = _normalize_id2label(id2label)
    kwargs.pop("label2id", None)
    super().__init__(
        id2label=normalized_id2label,
        label2id={label: idx for idx, label in normalized_id2label.items()},
        **kwargs,  # ty: ignore[invalid-argument-type]
    )
    self.dataset_name = dataset_name
    self.checkpoint_variant = checkpoint_variant
    self.input_columns = _normalize_columns(input_columns)
    if attribute_groups is None:
        from .data_specs import attribute_groups_for_dataset

        attribute_groups = dict(attribute_groups_for_dataset(dataset_name))
    groups = attribute_groups

    self.attribute_groups = {key: tuple(value) for key, value in groups.items()}
    self.max_seq_length = max_seq_length
    self.latent_dim = latent_dim
    self.num_blocks = num_blocks
    self.block_type = block_type
    self.masking_method = masking_method
    self.seq_type = seq_type
    self.arch_type = arch_type
    self.context = context
    self.input_dtype = input_dtype

    self.use_elemwise_noise = use_elemwise_noise
    self.dropout = dropout
    self.layer_norm_epsilon = layer_norm_epsilon
    self.l2 = l2
    self.original_args = original_args or {}
    self.conversion_report = conversion_report or {}

mask_token_id_for

mask_token_id_for(key: str) -> int

Return the categorical mask token id for key.

Source code in models/flex-dm/src/flex_dm/configuration_flex_dm.py
209
210
211
212
213
214
215
def mask_token_id_for(self, key: str) -> int:
    """Return the categorical mask token id for ``key``."""
    input_dim = self.input_columns[key]["input_dim"]
    if input_dim is None:
        raise ValueError(f"{key} is not categorical")

    return input_dim

unused_token_id_for

unused_token_id_for(key: str) -> int

Return the categorical unused token id for key.

Source code in models/flex-dm/src/flex_dm/configuration_flex_dm.py
217
218
219
def unused_token_id_for(self, key: str) -> int:
    """Return the categorical unused token id for ``key``."""
    return self.mask_token_id_for(key) + 1

FlexDmForMaskedDocumentModeling

Bases: FlexDmPreTrainedModel

Flex-DM MFP model with a standard Transformers forward method.

Source code in models/flex-dm/src/flex_dm/modeling_flex_dm.py
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
class FlexDmForMaskedDocumentModeling(FlexDmPreTrainedModel):
    """Flex-DM MFP model with a standard Transformers ``forward`` method."""

    def __init__(self, config: FlexDmConfig) -> None:
        """Initialize encoder, transformer blocks, and decoder."""
        super().__init__(config)
        if config.arch_type != "oneshot":
            raise ValueError("Only arch_type='oneshot' is supported")

        if config.block_type != "deepsvg":
            raise ValueError("Only block_type='deepsvg' is supported")

        self.encoder = FlexDmInputEncoder(config)
        self.blocks = nn.ModuleList(
            [FlexDmDeepSvgBlock(config) for _ in range(config.num_blocks)]
        )
        self.decoder = FlexDmDecoder(config)
        self.post_init()

    def forward(
        self,
        *,
        inputs: Mapping[str, Shaped[torch.Tensor, "..."]],
        masks: Mapping[str, Bool[torch.Tensor, "..."]] | None = None,
        labels: Mapping[str, Shaped[torch.Tensor, "..."]] | None = None,
        task_ids: Int[torch.Tensor, "batch"] | None = None,
        output_hidden_states: bool = False,
        return_dict: bool | None = None,
    ) -> (
        FlexDmModelOutput
        | tuple[dict[str, Shaped[torch.Tensor, "..."]], Float[torch.Tensor, ""] | None]
    ):
        """Run a Flex-DM forward pass.

        Args:
            inputs: Per-column model input tensors.
            masks: Optional hidden-field masks for diagnostics.
            labels: Optional per-column reconstruction targets.
            task_ids: Optional task ids.
            output_hidden_states: Whether to include final hidden states.
            return_dict: Whether to return a ``ModelOutput``.

        Returns:
            ``FlexDmModelOutput`` by default.
        """
        hidden_states, seq_mask = self.encoder(inputs, task_ids=task_ids)
        for block in self.blocks:
            hidden_states = block(hidden_states, seq_mask)
        logits = self.decoder(hidden_states)
        loss = self._compute_loss(logits, labels) if labels is not None else None
        output = FlexDmModelOutput(
            logits=logits,
            loss=loss,
            hidden_states=hidden_states if output_hidden_states else None,
            masks=dict(masks) if masks is not None else None,
        )
        if return_dict is False:
            return logits, loss
        return output

    def _compute_loss(
        self,
        logits: Mapping[str, Shaped[torch.Tensor, "..."]],
        labels: Mapping[str, Shaped[torch.Tensor, "..."]],
    ) -> Float[torch.Tensor, ""]:
        losses: list[Float[torch.Tensor, ""]] = []
        for key, target in labels.items():
            if key not in logits:
                continue
            column: FlexDmColumnSpec = self.config.input_columns[key]
            pred = logits[key]
            if column["type"] == "categorical":
                vocab = cast(int, column["input_dim"])
                losses.append(
                    F.cross_entropy(pred.view(-1, vocab), target.long().view(-1))
                )
            else:
                losses.append(F.mse_loss(pred, target.float()))
        if not losses:
            return torch.tensor(0.0, device=next(self.parameters()).device)
        return torch.stack(losses).sum()

__init__

__init__(config: FlexDmConfig) -> None

Initialize encoder, transformer blocks, and decoder.

Source code in models/flex-dm/src/flex_dm/modeling_flex_dm.py
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
def __init__(self, config: FlexDmConfig) -> None:
    """Initialize encoder, transformer blocks, and decoder."""
    super().__init__(config)
    if config.arch_type != "oneshot":
        raise ValueError("Only arch_type='oneshot' is supported")

    if config.block_type != "deepsvg":
        raise ValueError("Only block_type='deepsvg' is supported")

    self.encoder = FlexDmInputEncoder(config)
    self.blocks = nn.ModuleList(
        [FlexDmDeepSvgBlock(config) for _ in range(config.num_blocks)]
    )
    self.decoder = FlexDmDecoder(config)
    self.post_init()

forward

forward(
    *,
    inputs: Mapping[str, Shaped[Tensor, "..."]],
    masks: Mapping[str, Bool[Tensor, "..."]] | None = None,
    labels: Mapping[str, Shaped[Tensor, "..."]]
    | None = None,
    task_ids: Int[Tensor, "batch"] | None = None,
    output_hidden_states: bool = False,
    return_dict: bool | None = None,
) -> (
    FlexDmModelOutput
    | tuple[
        dict[str, Shaped[torch.Tensor, "..."]],
        Float[torch.Tensor, ""] | None,
    ]
)

Run a Flex-DM forward pass.

Parameters:

Name Type Description Default
inputs Mapping[str, Shaped[Tensor, '...']]

Per-column model input tensors.

required
masks Mapping[str, Bool[Tensor, '...']] | None

Optional hidden-field masks for diagnostics.

None
labels Mapping[str, Shaped[Tensor, '...']] | None

Optional per-column reconstruction targets.

None
task_ids Int[Tensor, 'batch'] | None

Optional task ids.

None
output_hidden_states bool

Whether to include final hidden states.

False
return_dict bool | None

Whether to return a ModelOutput.

None

Returns:

Type Description
FlexDmModelOutput | tuple[dict[str, Shaped[Tensor, '...']], Float[Tensor, ''] | None]

FlexDmModelOutput by default.

Source code in models/flex-dm/src/flex_dm/modeling_flex_dm.py
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
def forward(
    self,
    *,
    inputs: Mapping[str, Shaped[torch.Tensor, "..."]],
    masks: Mapping[str, Bool[torch.Tensor, "..."]] | None = None,
    labels: Mapping[str, Shaped[torch.Tensor, "..."]] | None = None,
    task_ids: Int[torch.Tensor, "batch"] | None = None,
    output_hidden_states: bool = False,
    return_dict: bool | None = None,
) -> (
    FlexDmModelOutput
    | tuple[dict[str, Shaped[torch.Tensor, "..."]], Float[torch.Tensor, ""] | None]
):
    """Run a Flex-DM forward pass.

    Args:
        inputs: Per-column model input tensors.
        masks: Optional hidden-field masks for diagnostics.
        labels: Optional per-column reconstruction targets.
        task_ids: Optional task ids.
        output_hidden_states: Whether to include final hidden states.
        return_dict: Whether to return a ``ModelOutput``.

    Returns:
        ``FlexDmModelOutput`` by default.
    """
    hidden_states, seq_mask = self.encoder(inputs, task_ids=task_ids)
    for block in self.blocks:
        hidden_states = block(hidden_states, seq_mask)
    logits = self.decoder(hidden_states)
    loss = self._compute_loss(logits, labels) if labels is not None else None
    output = FlexDmModelOutput(
        logits=logits,
        loss=loss,
        hidden_states=hidden_states if output_hidden_states else None,
        masks=dict(masks) if masks is not None else None,
    )
    if return_dict is False:
        return logits, loss
    return output

FlexDmModelOutput dataclass

Bases: ModelOutput

Output of FlexDmForMaskedDocumentModeling.

Parameters:

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

Per-column logits or numerical predictions.

required
loss Float[Tensor, ''] | None

Optional summed reconstruction loss.

None
hidden_states Float[Tensor, 'batch seq channels'] | None

Optional final hidden states.

None
masks dict[str, Bool[Tensor, '...']] | None

Optional per-column hidden-field masks.

None
Source code in models/flex-dm/src/flex_dm/modeling_flex_dm.py
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
@dataclass
class FlexDmModelOutput(ModelOutput):
    """Output of ``FlexDmForMaskedDocumentModeling``.

    Args:
        logits: Per-column logits or numerical predictions.
        loss: Optional summed reconstruction loss.
        hidden_states: Optional final hidden states.
        masks: Optional per-column hidden-field masks.
    """

    logits: dict[str, Shaped[torch.Tensor, "..."]]
    loss: Float[torch.Tensor, ""] | None = None
    hidden_states: Float[torch.Tensor, "batch seq channels"] | None = None
    masks: dict[str, Bool[torch.Tensor, "..."]] | None = None

    def __post_init__(self) -> None:
        """Keep the logits dictionary as one ModelOutput field."""
        if self.logits is not None:
            self["logits"] = self.logits
        if self.loss is not None:
            self["loss"] = self.loss
        if self.hidden_states is not None:
            self["hidden_states"] = self.hidden_states
        if self.masks is not None:
            self["masks"] = self.masks

__post_init__

__post_init__() -> None

Keep the logits dictionary as one ModelOutput field.

Source code in models/flex-dm/src/flex_dm/modeling_flex_dm.py
35
36
37
38
39
40
41
42
43
44
def __post_init__(self) -> None:
    """Keep the logits dictionary as one ModelOutput field."""
    if self.logits is not None:
        self["logits"] = self.logits
    if self.loss is not None:
        self["loss"] = self.loss
    if self.hidden_states is not None:
        self["hidden_states"] = self.hidden_states
    if self.masks is not None:
        self["masks"] = self.masks

FlexDmPipeline

Bases: LayoutGenerationPipeline

Run Flex-DM completion, refinement, and feature-level content infilling.

Source code in models/flex-dm/src/flex_dm/pipeline_flex_dm.py
 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
class FlexDmPipeline(LayoutGenerationPipeline):
    """Run Flex-DM completion, refinement, and feature-level content infilling."""

    config_class: ClassVar[type[PretrainedConfig]] = FlexDmConfig
    component_specs: ClassVar = model_processor_component_specs(
        model_loader=_load_model_component,
        processor_loader=_load_processor_component,
    )

    config: FlexDmConfig
    model: FlexDmForMaskedDocumentModeling
    processor: FlexDmProcessor

    def __init__(
        self,
        model: FlexDmForMaskedDocumentModeling,
        processor: FlexDmProcessor | None = None,
        config: FlexDmConfig | None = None,
    ) -> None:
        """Initialize model and processor components."""
        super().__init__(config or model.config)
        self.config = config or model.config
        self.model = model
        self.processor = processor or FlexDmProcessor.from_config(self.config)

    @classmethod
    def _from_pretrained_components(
        cls,
        *,
        config: PretrainedConfig,
        components: Mapping[str, FlexDmPipelineComponent | None],
    ) -> "FlexDmPipeline":
        """Build a pipeline from loaded model and processor components."""
        return cls(
            config=cast(FlexDmConfig, config),
            model=cast(FlexDmForMaskedDocumentModeling, components["model"]),
            processor=cast(FlexDmProcessor, components["processor"]),
        )

    @torch.no_grad()
    def __call__(  # ty: ignore[invalid-method-override]
        self,
        *,
        batch_size: int = 1,
        seed: int | None = None,
        generator: torch.Generator | None = None,
        condition_type: ConditionType | str = ConditionType.completion,
        labels: Int[torch.Tensor, "batch elements"]
        | Int[np.ndarray, "batch elements"]
        | Sequence[ArrayLikeInput]
        | None = None,
        bbox: Float[torch.Tensor, "batch elements 4"]
        | Float[np.ndarray, "batch elements 4"]
        | Sequence[ArrayLikeInput]
        | None = None,
        mask: Bool[torch.Tensor, "batch elements"]
        | Bool[np.ndarray, "batch elements"]
        | Sequence[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,
        output_type: Literal["dataclass", "dict"] = "dataclass",
        return_intermediates: bool = False,
        attributes: Mapping[str, FlexDmValue] | None = None,
        content: Mapping[str, FlexDmValue] | None = None,
        feature_group: str | None = None,
        target_indices: Int[torch.Tensor, "..."] | None = None,
        **model_kwargs: FlexDmValue,
    ) -> (
        LayoutGenerationOutput
        | dict[
            str,
            Shaped[torch.Tensor, "..."]
            | dict[int, str]
            | Mapping[str, Shaped[torch.Tensor, "..."]]
            | None,
        ]
    ):
        """Infills masked Flex-DM document fields.

        Args:
            batch_size: Batch size used when synthetic empty inputs are created.
            seed: Common API compatibility argument. Flex-DM's public inference
                path is deterministic and does not currently consume randomness.
            generator: Common API compatibility argument. When supplied, it
                takes precedence over ``seed``; the deterministic Flex-DM
                inference path does not currently consume it.
            condition_type: Canonical condition or local task alias.
            labels: Public element labels.
            bbox: Public element boxes.
            mask: Public valid-element mask.
            num_elements: Optional element counts for synthetic inputs.
            box_format: Input box coordinate format.
            normalized: Whether input boxes are already normalized.
            canvas_size: Pixel canvas size when ``normalized=False``.
            num_inference_steps: Number of iterative decode steps.
            output_type: ``dataclass`` or ``dict``.
            return_intermediates: Whether to include logits and masks.
            attributes: Optional non-core document attributes.
            content: Optional Crello image/text embeddings.
            feature_group: Flex-DM task group such as ``pos`` or ``img``.
            target_indices: Optional element indexes for ``elem`` masking.
            model_kwargs: Reserved model keyword arguments.

        Returns:
            Common layout-generation output.

        Raises:
            NotImplementedError: If the requested canonical condition is not
                supported by released Flex-DM MFP checkpoints.
        """
        _ = model_kwargs
        model_device = next(self.model.parameters()).device
        if generator is None and seed is not None:
            generator = torch.Generator(device=model_device).manual_seed(seed)
        encoded = self.processor(
            condition_type=condition_type,
            labels=labels,
            bbox=bbox,
            mask=mask,
            num_elements=num_elements,
            box_format=box_format,
            normalized=normalized,
            canvas_size=canvas_size,
            attributes=attributes,
            content=content,
            feature_group=feature_group,
            target_indices=target_indices,
            batch_size=batch_size,
        )
        canonical = cast(ConditionType, encoded["condition_type"])
        feature = cast(str | None, encoded["feature_group"])
        self._validate_condition(canonical, feature)
        inputs = {
            key: value.to(model_device)
            for key, value in cast(
                dict[str, Shaped[torch.Tensor, "..."]], encoded["inputs"]
            ).items()
        }
        masks = {
            key: value.to(model_device)
            for key, value in cast(
                dict[str, Bool[torch.Tensor, "..."]], encoded["masks"]
            ).items()
        }
        masked_inputs = self._apply_masks(inputs, masks, generator=generator)
        was_training = self.model.training
        self.model.eval()
        try:
            if num_inference_steps is not None and num_inference_steps > 1:
                outputs = cast(
                    FlexDmModelOutput,
                    iterative_decode(
                        self.model,
                        inputs=masked_inputs,
                        masks=masks,
                        num_iter=num_inference_steps,
                        input_columns=self.config.input_columns,
                        source_inputs=inputs,
                    ),
                )
            else:
                outputs = self.model(
                    inputs=masked_inputs, masks=masks, return_dict=True
                )
        finally:
            self.model.train(was_training)
        return self.processor.post_process_document(
            outputs,
            original_inputs=inputs,
            masks=masks,
            output_type=output_type,
            return_intermediates=return_intermediates,
            refinement_input=inputs if canonical is ConditionType.refinement else None,
        )

    generate = __call__

    def _apply_masks(
        self,
        inputs: Mapping[str, Shaped[torch.Tensor, "..."]],
        masks: Mapping[str, Bool[torch.Tensor, "..."]],
        *,
        generator: torch.Generator | None,
    ) -> dict[str, Shaped[torch.Tensor, "..."]]:
        modified = dict(inputs)
        for key, mask in masks.items():
            if key not in self.config.input_columns:
                continue
            column = self.config.input_columns[key]
            if column["is_sequence"] and mask.ndim == 2 and mask.any():
                modified[key] = apply_token(
                    modified[key],
                    column,
                    mask,
                    "masked",
                    generator=generator,
                )
        return modified

    def _validate_condition(
        self,
        condition_type: ConditionType,
        feature_group: str | None,
    ) -> None:
        if condition_type in {ConditionType.completion, ConditionType.refinement}:
            return
        if condition_type is ConditionType.content_image and feature_group in {
            "img",
            "txt",
        }:
            return
        if condition_type is ConditionType.label:
            raise NotImplementedError(
                "Flex-DM has no standalone label-conditioned mode; use "
                'condition_type="completion", feature_group="type".'
            )

        if condition_type is ConditionType.label_size:
            raise NotImplementedError("Flex-DM does not support label_size generation")

        if condition_type is ConditionType.unconditional:
            raise NotImplementedError(
                "Flex-DM released MFP checkpoints require an input document"
            )

        raise NotImplementedError(
            f"Flex-DM does not support condition_type={condition_type}"
        )

__init__

__init__(
    model: FlexDmForMaskedDocumentModeling,
    processor: FlexDmProcessor | None = None,
    config: FlexDmConfig | None = None,
) -> None

Initialize model and processor components.

Source code in models/flex-dm/src/flex_dm/pipeline_flex_dm.py
81
82
83
84
85
86
87
88
89
90
91
def __init__(
    self,
    model: FlexDmForMaskedDocumentModeling,
    processor: FlexDmProcessor | None = None,
    config: FlexDmConfig | None = None,
) -> None:
    """Initialize model and processor components."""
    super().__init__(config or model.config)
    self.config = config or model.config
    self.model = model
    self.processor = processor or FlexDmProcessor.from_config(self.config)

__call__

__call__(
    *,
    batch_size: int = 1,
    seed: int | None = None,
    generator: Generator | None = None,
    condition_type: ConditionType
    | str = ConditionType.completion,
    labels: Int[Tensor, "batch elements"]
    | Int[ndarray, "batch elements"]
    | Sequence[ArrayLikeInput]
    | None = None,
    bbox: Float[Tensor, "batch elements 4"]
    | Float[ndarray, "batch elements 4"]
    | Sequence[ArrayLikeInput]
    | None = None,
    mask: Bool[Tensor, "batch elements"]
    | Bool[ndarray, "batch elements"]
    | Sequence[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,
    output_type: Literal["dataclass", "dict"] = "dataclass",
    return_intermediates: bool = False,
    attributes: Mapping[str, FlexDmValue] | None = None,
    content: Mapping[str, FlexDmValue] | None = None,
    feature_group: str | None = None,
    target_indices: Int[Tensor, "..."] | None = None,
    **model_kwargs: FlexDmValue,
) -> (
    LayoutGenerationOutput
    | dict[
        str,
        Shaped[torch.Tensor, "..."]
        | dict[int, str]
        | Mapping[str, Shaped[torch.Tensor, "..."]]
        | None,
    ]
)

Infills masked Flex-DM document fields.

Parameters:

Name Type Description Default
batch_size int

Batch size used when synthetic empty inputs are created.

1
seed int | None

Common API compatibility argument. Flex-DM's public inference path is deterministic and does not currently consume randomness.

None
generator Generator | None

Common API compatibility argument. When supplied, it takes precedence over seed; the deterministic Flex-DM inference path does not currently consume it.

None
condition_type ConditionType | str

Canonical condition or local task alias.

completion
labels Int[Tensor, 'batch elements'] | Int[ndarray, 'batch elements'] | Sequence[ArrayLikeInput] | None

Public element labels.

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

Public element boxes.

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

Public valid-element mask.

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

Optional element counts for synthetic inputs.

None
box_format BoxFormat | str

Input box coordinate format.

xywh
normalized bool

Whether input boxes are already normalized.

True
canvas_size tuple[int, int] | None

Pixel canvas size when normalized=False.

None
num_inference_steps int | None

Number of iterative decode steps.

None
output_type Literal['dataclass', 'dict']

dataclass or dict.

'dataclass'
return_intermediates bool

Whether to include logits and masks.

False
attributes Mapping[str, FlexDmValue] | None

Optional non-core document attributes.

None
content Mapping[str, FlexDmValue] | None

Optional Crello image/text embeddings.

None
feature_group str | None

Flex-DM task group such as pos or img.

None
target_indices Int[Tensor, '...'] | None

Optional element indexes for elem masking.

None
model_kwargs FlexDmValue

Reserved model keyword arguments.

{}

Returns:

Type Description
LayoutGenerationOutput | dict[str, Shaped[Tensor, '...'] | dict[int, str] | Mapping[str, Shaped[Tensor, '...']] | None]

Common layout-generation output.

Raises:

Type Description
NotImplementedError

If the requested canonical condition is not supported by released Flex-DM MFP checkpoints.

Source code in models/flex-dm/src/flex_dm/pipeline_flex_dm.py
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
@torch.no_grad()
def __call__(  # ty: ignore[invalid-method-override]
    self,
    *,
    batch_size: int = 1,
    seed: int | None = None,
    generator: torch.Generator | None = None,
    condition_type: ConditionType | str = ConditionType.completion,
    labels: Int[torch.Tensor, "batch elements"]
    | Int[np.ndarray, "batch elements"]
    | Sequence[ArrayLikeInput]
    | None = None,
    bbox: Float[torch.Tensor, "batch elements 4"]
    | Float[np.ndarray, "batch elements 4"]
    | Sequence[ArrayLikeInput]
    | None = None,
    mask: Bool[torch.Tensor, "batch elements"]
    | Bool[np.ndarray, "batch elements"]
    | Sequence[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,
    output_type: Literal["dataclass", "dict"] = "dataclass",
    return_intermediates: bool = False,
    attributes: Mapping[str, FlexDmValue] | None = None,
    content: Mapping[str, FlexDmValue] | None = None,
    feature_group: str | None = None,
    target_indices: Int[torch.Tensor, "..."] | None = None,
    **model_kwargs: FlexDmValue,
) -> (
    LayoutGenerationOutput
    | dict[
        str,
        Shaped[torch.Tensor, "..."]
        | dict[int, str]
        | Mapping[str, Shaped[torch.Tensor, "..."]]
        | None,
    ]
):
    """Infills masked Flex-DM document fields.

    Args:
        batch_size: Batch size used when synthetic empty inputs are created.
        seed: Common API compatibility argument. Flex-DM's public inference
            path is deterministic and does not currently consume randomness.
        generator: Common API compatibility argument. When supplied, it
            takes precedence over ``seed``; the deterministic Flex-DM
            inference path does not currently consume it.
        condition_type: Canonical condition or local task alias.
        labels: Public element labels.
        bbox: Public element boxes.
        mask: Public valid-element mask.
        num_elements: Optional element counts for synthetic inputs.
        box_format: Input box coordinate format.
        normalized: Whether input boxes are already normalized.
        canvas_size: Pixel canvas size when ``normalized=False``.
        num_inference_steps: Number of iterative decode steps.
        output_type: ``dataclass`` or ``dict``.
        return_intermediates: Whether to include logits and masks.
        attributes: Optional non-core document attributes.
        content: Optional Crello image/text embeddings.
        feature_group: Flex-DM task group such as ``pos`` or ``img``.
        target_indices: Optional element indexes for ``elem`` masking.
        model_kwargs: Reserved model keyword arguments.

    Returns:
        Common layout-generation output.

    Raises:
        NotImplementedError: If the requested canonical condition is not
            supported by released Flex-DM MFP checkpoints.
    """
    _ = model_kwargs
    model_device = next(self.model.parameters()).device
    if generator is None and seed is not None:
        generator = torch.Generator(device=model_device).manual_seed(seed)
    encoded = self.processor(
        condition_type=condition_type,
        labels=labels,
        bbox=bbox,
        mask=mask,
        num_elements=num_elements,
        box_format=box_format,
        normalized=normalized,
        canvas_size=canvas_size,
        attributes=attributes,
        content=content,
        feature_group=feature_group,
        target_indices=target_indices,
        batch_size=batch_size,
    )
    canonical = cast(ConditionType, encoded["condition_type"])
    feature = cast(str | None, encoded["feature_group"])
    self._validate_condition(canonical, feature)
    inputs = {
        key: value.to(model_device)
        for key, value in cast(
            dict[str, Shaped[torch.Tensor, "..."]], encoded["inputs"]
        ).items()
    }
    masks = {
        key: value.to(model_device)
        for key, value in cast(
            dict[str, Bool[torch.Tensor, "..."]], encoded["masks"]
        ).items()
    }
    masked_inputs = self._apply_masks(inputs, masks, generator=generator)
    was_training = self.model.training
    self.model.eval()
    try:
        if num_inference_steps is not None and num_inference_steps > 1:
            outputs = cast(
                FlexDmModelOutput,
                iterative_decode(
                    self.model,
                    inputs=masked_inputs,
                    masks=masks,
                    num_iter=num_inference_steps,
                    input_columns=self.config.input_columns,
                    source_inputs=inputs,
                ),
            )
        else:
            outputs = self.model(
                inputs=masked_inputs, masks=masks, return_dict=True
            )
    finally:
        self.model.train(was_training)
    return self.processor.post_process_document(
        outputs,
        original_inputs=inputs,
        masks=masks,
        output_type=output_type,
        return_intermediates=return_intermediates,
        refinement_input=inputs if canonical is ConditionType.refinement else None,
    )

FlexDmProcessor

Bases: ProcessorMixin

Serialize vocabularies and convert public layouts to Flex-DM tensors.

Flex-DM intentionally does not expose a PreTrainedTokenizer because the model consumes a dictionary of heterogeneous categorical and continuous fields rather than one discrete token stream.

Source code in models/flex-dm/src/flex_dm/processing_flex_dm.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
 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
class FlexDmProcessor(ProcessorMixin):
    """Serialize vocabularies and convert public layouts to Flex-DM tensors.

    Flex-DM intentionally does not expose a ``PreTrainedTokenizer`` because the
    model consumes a dictionary of heterogeneous categorical and continuous
    fields rather than one discrete token stream.
    """

    attributes: list[str] = []

    def __init__(
        self,
        *,
        config: FlexDmConfig,
        vocabulary: dict[str, FlexDmValue] | None = None,
        discretizers: dict[str, FlexDmDiscretizerSpec] | None = None,
    ) -> None:
        """Initialize metadata-only processor state."""
        self.config = config
        self.vocabulary = vocabulary or {}
        self.discretizers = discretizers or {
            key: {"min": 0.0, "max": 1.0, "bins": 64} for key in GEOMETRY_KEYS
        }
        if "opacity" in config.input_columns:
            self.discretizers.setdefault("opacity", {"min": 0.0, "max": 1.0, "bins": 8})
        if "color" in config.input_columns:
            self.discretizers.setdefault(
                "color", {"min": 0.0, "max": 255.0, "bins": 16}
            )

    @classmethod
    def from_config(cls, config: FlexDmConfig) -> "FlexDmProcessor":
        """Create a processor from config metadata.

        Args:
            config: Flex-DM configuration.

        Returns:
            Processor with built-in discretizers.
        """
        return cls(config=config)

    def save_pretrained(
        self,
        save_directory: str | PathLike[str],
        push_to_hub: bool = False,
        **kwargs: str | int | float | bool | None,
    ) -> None:
        """Save processor metadata next to a converted checkpoint."""
        _ = (push_to_hub, kwargs)
        root = Path(save_directory)
        root.mkdir(parents=True, exist_ok=True)
        (root / "processor_config.json").write_text(
            json.dumps(
                {
                    "processor_class": self.__class__.__name__,
                    "config": self.config.to_dict(),
                    "vocabulary": self.vocabulary,
                    "discretizers": self.discretizers,
                    "tokenizer_policy_deviation": (
                        "Flex-DM uses ProcessorMixin instead of PreTrainedTokenizer "
                        "because the model consumes heterogeneous dict tensors and "
                        "continuous image/text embeddings."
                    ),
                },
                indent=2,
                sort_keys=True,
            )
        )

    @classmethod
    def from_pretrained(
        cls,
        pretrained_model_name_or_path: str | PathLike[str],
        cache_dir: str | PathLike[str] | None = None,
        force_download: bool = False,
        local_files_only: bool = False,
        token: str | bool | None = None,
        revision: str = "main",
        *,
        subfolder: str | None = None,
        **kwargs: str | int | float | bool | None,
    ) -> "FlexDmProcessor":
        """Load processor metadata from a local converted checkpoint."""
        _ = (cache_dir, force_download, local_files_only, token, revision, kwargs)
        root = Path(pretrained_model_name_or_path)
        if subfolder is not None:
            root = root / subfolder
        data = json.loads((root / "processor_config.json").read_text())
        return cls(
            config=FlexDmConfig.from_dict(data["config"]),
            vocabulary=cast(dict[str, FlexDmValue], data.get("vocabulary", {})),
            discretizers=cast(
                dict[str, FlexDmDiscretizerSpec], data.get("discretizers", {})
            ),
        )

    @classmethod
    def from_vocabulary(
        cls,
        *,
        dataset_name: str,
        vocabulary: dict[str, FlexDmValue],
        checkpoint_variant: str = "ours-exp-ft",
    ) -> "FlexDmProcessor":
        """Build config and processor metadata from vocabulary."""
        id2label = cast(
            dict[int | str, str],
            id2label_from_vocabulary(
                dataset_name, cast(dict[str, FlexDmVocabularyValue], vocabulary)
            ),
        )
        input_columns = build_column_specs(
            dataset_name=dataset_name,
            vocabulary=cast(dict[str, FlexDmVocabularyValue], vocabulary),
        )
        config = FlexDmConfig(
            dataset_name=dataset_name,
            checkpoint_variant=checkpoint_variant,
            id2label=id2label,
            input_columns=input_columns,
        )
        return cls(config=config, vocabulary=vocabulary)

    def __call__(
        self,
        *,
        condition_type: ConditionType | str = ConditionType.completion,
        labels: Int[torch.Tensor, "batch elements"]
        | Int[np.ndarray, "batch elements"]
        | Sequence[ArrayLikeInput]
        | None = None,
        bbox: Float[torch.Tensor, "batch elements 4"]
        | Float[np.ndarray, "batch elements 4"]
        | Sequence[ArrayLikeInput]
        | None = None,
        mask: Bool[torch.Tensor, "batch elements"]
        | Bool[np.ndarray, "batch elements"]
        | Sequence[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,
        attributes: Mapping[str, FlexDmValue] | None = None,
        content: Mapping[str, FlexDmValue] | None = None,
        feature_group: str | None = None,
        target_indices: Int[torch.Tensor, "..."] | None = None,
        batch_size: int = 1,
        return_tensors: Literal["pt"] = "pt",
    ) -> dict[
        str,
        dict[str, Shaped[torch.Tensor, "..."] | Bool[torch.Tensor, "..."]]
        | Shaped[torch.Tensor, "..."]
        | ConditionType
        | str
        | None,
    ]:
        """Convert public layout fields into Flex-DM model tensors."""
        if return_tensors != "pt":
            raise ValueError("FlexDmProcessor only supports return_tensors='pt'")

        if bbox is None or labels is None:
            count = self._num_elements_tensor(num_elements, batch_size)
            max_len = int(count.max().item()) if count.numel() else 0
            bbox_t = torch.zeros((batch_size, max_len, 4), dtype=torch.float32)
            labels_t = torch.zeros((batch_size, max_len), dtype=torch.long)
            mask_t = torch.arange(max_len).unsqueeze(0) < count.unsqueeze(1)
        else:
            bbox_t, labels_t, mask_t = prepare_layout_tensors(
                bbox=bbox,
                labels=labels,
                mask=mask,
                box_format=box_format,
                normalized=normalized,
                canvas_size=canvas_size,
                clamp_converted_normalized=True,
            )
        inputs = self._layout_to_inputs(
            bbox=bbox_t,
            labels=labels_t,
            mask=mask_t,
            attributes=attributes,
            content=content,
        )
        length = mask_t.long().sum(dim=1).clamp(min=1) - 1
        inputs["length"] = length.reshape(-1, 1).long()
        seq_mask = get_seq_mask(inputs["length"].reshape(-1), maxlen=bbox_t.size(1))
        filtered = filter_padding(inputs, self.config.input_columns, seq_mask)
        canonical, normalized_feature = self.normalize_condition_and_feature(
            condition_type,
            feature_group=feature_group,
        )
        masks = build_feature_masks(
            self.config.input_columns,
            seq_mask,
            condition_type=canonical,
            feature_group=normalized_feature,
            target_indices=target_indices,
        )
        return {
            "inputs": filtered,
            "masks": masks,
            "bbox": bbox_t,
            "labels": labels_t,
            "mask": mask_t,
            "condition_type": canonical,
            "feature_group": normalized_feature,
        }

    def normalize_condition_and_feature(
        self,
        condition_type: ConditionType | str,
        *,
        feature_group: str | None = None,
    ) -> tuple[ConditionType, str | None]:
        """Normalize canonical conditions plus local Flex-DM task aliases."""
        aliases = {"random", "elem", "type", "pos", "attr", "img", "txt"}
        if isinstance(condition_type, str) and condition_type in aliases:
            return ConditionType.completion, condition_type
        canonical = normalize_condition_type(condition_type)
        if canonical is ConditionType.content_image and feature_group is None:
            return canonical, "img"
        return canonical, feature_group

    def _num_elements_tensor(
        self,
        num_elements: int | list[int] | Int[torch.Tensor, "batch"] | None,
        batch_size: int,
    ) -> Int[torch.Tensor, "batch"]:
        if num_elements is None:
            return torch.full(
                (batch_size,), min(1, self.config.max_seq_length), dtype=torch.long
            )
        tensor = torch.as_tensor(num_elements, dtype=torch.long)
        if tensor.ndim == 0:
            tensor = tensor.repeat(batch_size)
        return tensor

    def _layout_to_inputs(
        self,
        *,
        bbox: Float[torch.Tensor, "batch elements 4"],
        labels: Int[torch.Tensor, "batch elements"],
        mask: Bool[torch.Tensor, "batch elements"],
        attributes: Mapping[str, FlexDmValue] | None,
        content: Mapping[str, FlexDmValue] | None,
    ) -> dict[str, Shaped[torch.Tensor, "..."]]:
        ltwh = xywh_to_ltwh(bbox).clamp(0.0, 1.0)
        inputs: dict[str, Shaped[torch.Tensor, "..."]] = {}
        for idx, key in enumerate(GEOMETRY_KEYS):
            inputs[key] = self._discretize(key, ltwh[..., idx : idx + 1]).long()
        inputs["type"] = labels.unsqueeze(-1).long()
        attrs = attributes or {}
        cnt = content or {}
        for key, column in self.config.input_columns.items():
            if key in inputs or key == "length":
                continue
            if not column["is_sequence"]:
                inputs[key] = torch.zeros((bbox.size(0), 1), dtype=torch.long)
            else:
                source = cnt.get(key, attrs.get(key))
                inputs[key] = self._coerce_column_value(key, column, source, mask)
        return inputs

    def _coerce_column_value(
        self,
        key: str,
        column: FlexDmColumnSpec,
        value: FlexDmValue,
        mask: Bool[torch.Tensor, "batch elements"],
    ) -> Shaped[torch.Tensor, "batch elements channels"]:
        batch, seq_len = mask.shape
        shape = (batch, seq_len, int(column["shape"][-1]))
        if value is None:
            dtype = torch.float32 if column["type"] == "numerical" else torch.long
            return torch.zeros(shape, dtype=dtype)
        tensor = torch.as_tensor(value)
        if tensor.ndim == 2:
            tensor = tensor.unsqueeze(-1)
        if key in self.discretizers and tensor.dtype.is_floating_point:
            tensor = self._discretize(key, tensor.float())
        return tensor.reshape(shape).to(
            dtype=torch.float32 if column["type"] == "numerical" else torch.long
        )

    def _discretize(
        self, key: str, value: Float[torch.Tensor, "..."]
    ) -> Float[torch.Tensor, "..."]:
        spec = self.discretizers[key]
        scaled = (value - spec["min"]) / (spec["max"] - spec["min"])
        return torch.clamp((scaled * spec["bins"]).floor(), 0, spec["bins"] - 1)

    def _continuize(
        self, key: str, value: Shaped[torch.Tensor, "..."]
    ) -> Float[torch.Tensor, "..."]:
        spec = self.discretizers[key]
        scale = (spec["max"] - spec["min"]) / spec["bins"]
        return value.float() * scale + spec["min"]

    def post_process_document(
        self,
        outputs: FlexDmModelOutput,
        *,
        original_inputs: Mapping[str, Shaped[torch.Tensor, "..."]],
        masks: Mapping[str, Bool[torch.Tensor, "..."]],
        output_type: Literal["dataclass", "dict"] = "dataclass",
        return_intermediates: bool = False,
        refinement_input: Mapping[str, Shaped[torch.Tensor, "..."]] | None = None,
    ) -> (
        LayoutGenerationOutput
        | dict[
            str,
            Shaped[torch.Tensor, "..."]
            | dict[int, str]
            | Mapping[str, Shaped[torch.Tensor, "..."]]
            | None,
        ]
    ):
        """Decode Flex-DM model outputs to the common layout schema."""
        decoded = self._decode_logits(outputs.logits, original_inputs, masks)
        ltwh = torch.cat([decoded[key].float() for key in GEOMETRY_KEYS], dim=-1)
        bbox = ltwh_to_xywh(ltwh).clamp(0.0, 1.0).detach().cpu()
        labels = decoded["type"].squeeze(-1).long().detach().cpu()
        valid_mask = get_seq_mask(
            original_inputs["length"].reshape(-1), maxlen=labels.size(1)
        )
        intermediates = None
        if return_intermediates:
            intermediates = {
                "attributes": {
                    key: value.detach().cpu()
                    for key, value in decoded.items()
                    if key not in (*GEOMETRY_KEYS, "type")
                    and self.config.input_columns[key]["is_sequence"]
                },
                "masks": {key: value.detach().cpu() for key, value in masks.items()},
                "logits": {
                    key: value.detach().cpu() for key, value in outputs.logits.items()
                },
            }
            if refinement_input is not None:
                intermediates["refinement_input"] = {
                    key: value.detach().cpu() for key, value in refinement_input.items()
                }
        result = LayoutGenerationOutput(
            bbox=bbox,
            labels=labels,
            mask=valid_mask.detach().cpu(),
            id2label=cast(dict[int, str], self.config.id2label),
            intermediates=intermediates,
        )
        if output_type == "dict":
            return dict(result)
        if output_type != "dataclass":
            raise ValueError(f"Unsupported output_type: {output_type}")

        return result

    def _decode_logits(
        self,
        logits: Mapping[str, Shaped[torch.Tensor, "..."]],
        original_inputs: Mapping[str, Shaped[torch.Tensor, "..."]],
        masks: Mapping[str, Bool[torch.Tensor, "..."]],
    ) -> dict[str, Shaped[torch.Tensor, "..."]]:
        decoded: dict[str, Shaped[torch.Tensor, "..."]] = {}
        for key, column in self.config.input_columns.items():
            if not column["is_sequence"]:
                continue
            if key in logits:
                pred = (
                    logits[key].argmax(dim=-1)
                    if column["type"] == "categorical"
                    else logits[key]
                )
            else:
                pred = original_inputs[key]
            mask = masks.get(key)
            if mask is not None:
                pred = torch.where(
                    mask.unsqueeze(-1).to(pred.device),
                    pred,
                    original_inputs[key].to(pred.device),
                )
            if key in self.discretizers and column["type"] == "categorical":
                pred = self._continuize(key, pred)
            decoded[key] = pred
        return decoded

__init__

__init__(
    *,
    config: FlexDmConfig,
    vocabulary: dict[str, FlexDmValue] | None = None,
    discretizers: dict[str, FlexDmDiscretizerSpec]
    | None = None,
) -> None

Initialize metadata-only processor state.

Source code in models/flex-dm/src/flex_dm/processing_flex_dm.py
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
def __init__(
    self,
    *,
    config: FlexDmConfig,
    vocabulary: dict[str, FlexDmValue] | None = None,
    discretizers: dict[str, FlexDmDiscretizerSpec] | None = None,
) -> None:
    """Initialize metadata-only processor state."""
    self.config = config
    self.vocabulary = vocabulary or {}
    self.discretizers = discretizers or {
        key: {"min": 0.0, "max": 1.0, "bins": 64} for key in GEOMETRY_KEYS
    }
    if "opacity" in config.input_columns:
        self.discretizers.setdefault("opacity", {"min": 0.0, "max": 1.0, "bins": 8})
    if "color" in config.input_columns:
        self.discretizers.setdefault(
            "color", {"min": 0.0, "max": 255.0, "bins": 16}
        )

from_config classmethod

from_config(config: FlexDmConfig) -> 'FlexDmProcessor'

Create a processor from config metadata.

Parameters:

Name Type Description Default
config FlexDmConfig

Flex-DM configuration.

required

Returns:

Type Description
'FlexDmProcessor'

Processor with built-in discretizers.

Source code in models/flex-dm/src/flex_dm/processing_flex_dm.py
81
82
83
84
85
86
87
88
89
90
91
@classmethod
def from_config(cls, config: FlexDmConfig) -> "FlexDmProcessor":
    """Create a processor from config metadata.

    Args:
        config: Flex-DM configuration.

    Returns:
        Processor with built-in discretizers.
    """
    return cls(config=config)

save_pretrained

save_pretrained(
    save_directory: str | PathLike[str],
    push_to_hub: bool = False,
    **kwargs: str | int | float | bool | None,
) -> None

Save processor metadata next to a converted checkpoint.

Source code in models/flex-dm/src/flex_dm/processing_flex_dm.py
 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
def save_pretrained(
    self,
    save_directory: str | PathLike[str],
    push_to_hub: bool = False,
    **kwargs: str | int | float | bool | None,
) -> None:
    """Save processor metadata next to a converted checkpoint."""
    _ = (push_to_hub, kwargs)
    root = Path(save_directory)
    root.mkdir(parents=True, exist_ok=True)
    (root / "processor_config.json").write_text(
        json.dumps(
            {
                "processor_class": self.__class__.__name__,
                "config": self.config.to_dict(),
                "vocabulary": self.vocabulary,
                "discretizers": self.discretizers,
                "tokenizer_policy_deviation": (
                    "Flex-DM uses ProcessorMixin instead of PreTrainedTokenizer "
                    "because the model consumes heterogeneous dict tensors and "
                    "continuous image/text embeddings."
                ),
            },
            indent=2,
            sort_keys=True,
        )
    )

from_pretrained classmethod

from_pretrained(
    pretrained_model_name_or_path: str | PathLike[str],
    cache_dir: str | PathLike[str] | None = None,
    force_download: bool = False,
    local_files_only: bool = False,
    token: str | bool | None = None,
    revision: str = "main",
    *,
    subfolder: str | None = None,
    **kwargs: str | int | float | bool | None,
) -> "FlexDmProcessor"

Load processor metadata from a local converted checkpoint.

Source code in models/flex-dm/src/flex_dm/processing_flex_dm.py
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
@classmethod
def from_pretrained(
    cls,
    pretrained_model_name_or_path: str | PathLike[str],
    cache_dir: str | PathLike[str] | None = None,
    force_download: bool = False,
    local_files_only: bool = False,
    token: str | bool | None = None,
    revision: str = "main",
    *,
    subfolder: str | None = None,
    **kwargs: str | int | float | bool | None,
) -> "FlexDmProcessor":
    """Load processor metadata from a local converted checkpoint."""
    _ = (cache_dir, force_download, local_files_only, token, revision, kwargs)
    root = Path(pretrained_model_name_or_path)
    if subfolder is not None:
        root = root / subfolder
    data = json.loads((root / "processor_config.json").read_text())
    return cls(
        config=FlexDmConfig.from_dict(data["config"]),
        vocabulary=cast(dict[str, FlexDmValue], data.get("vocabulary", {})),
        discretizers=cast(
            dict[str, FlexDmDiscretizerSpec], data.get("discretizers", {})
        ),
    )

from_vocabulary classmethod

from_vocabulary(
    *,
    dataset_name: str,
    vocabulary: dict[str, FlexDmValue],
    checkpoint_variant: str = "ours-exp-ft",
) -> "FlexDmProcessor"

Build config and processor metadata from vocabulary.

Source code in models/flex-dm/src/flex_dm/processing_flex_dm.py
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
@classmethod
def from_vocabulary(
    cls,
    *,
    dataset_name: str,
    vocabulary: dict[str, FlexDmValue],
    checkpoint_variant: str = "ours-exp-ft",
) -> "FlexDmProcessor":
    """Build config and processor metadata from vocabulary."""
    id2label = cast(
        dict[int | str, str],
        id2label_from_vocabulary(
            dataset_name, cast(dict[str, FlexDmVocabularyValue], vocabulary)
        ),
    )
    input_columns = build_column_specs(
        dataset_name=dataset_name,
        vocabulary=cast(dict[str, FlexDmVocabularyValue], vocabulary),
    )
    config = FlexDmConfig(
        dataset_name=dataset_name,
        checkpoint_variant=checkpoint_variant,
        id2label=id2label,
        input_columns=input_columns,
    )
    return cls(config=config, vocabulary=vocabulary)

__call__

__call__(
    *,
    condition_type: ConditionType
    | str = ConditionType.completion,
    labels: Int[Tensor, "batch elements"]
    | Int[ndarray, "batch elements"]
    | Sequence[ArrayLikeInput]
    | None = None,
    bbox: Float[Tensor, "batch elements 4"]
    | Float[ndarray, "batch elements 4"]
    | Sequence[ArrayLikeInput]
    | None = None,
    mask: Bool[Tensor, "batch elements"]
    | Bool[ndarray, "batch elements"]
    | Sequence[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,
    attributes: Mapping[str, FlexDmValue] | None = None,
    content: Mapping[str, FlexDmValue] | None = None,
    feature_group: str | None = None,
    target_indices: Int[Tensor, "..."] | None = None,
    batch_size: int = 1,
    return_tensors: Literal["pt"] = "pt",
) -> dict[
    str,
    dict[
        str,
        Shaped[torch.Tensor, "..."]
        | Bool[torch.Tensor, "..."],
    ]
    | Shaped[torch.Tensor, "..."]
    | ConditionType
    | str
    | None,
]

Convert public layout fields into Flex-DM model tensors.

Source code in models/flex-dm/src/flex_dm/processing_flex_dm.py
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
def __call__(
    self,
    *,
    condition_type: ConditionType | str = ConditionType.completion,
    labels: Int[torch.Tensor, "batch elements"]
    | Int[np.ndarray, "batch elements"]
    | Sequence[ArrayLikeInput]
    | None = None,
    bbox: Float[torch.Tensor, "batch elements 4"]
    | Float[np.ndarray, "batch elements 4"]
    | Sequence[ArrayLikeInput]
    | None = None,
    mask: Bool[torch.Tensor, "batch elements"]
    | Bool[np.ndarray, "batch elements"]
    | Sequence[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,
    attributes: Mapping[str, FlexDmValue] | None = None,
    content: Mapping[str, FlexDmValue] | None = None,
    feature_group: str | None = None,
    target_indices: Int[torch.Tensor, "..."] | None = None,
    batch_size: int = 1,
    return_tensors: Literal["pt"] = "pt",
) -> dict[
    str,
    dict[str, Shaped[torch.Tensor, "..."] | Bool[torch.Tensor, "..."]]
    | Shaped[torch.Tensor, "..."]
    | ConditionType
    | str
    | None,
]:
    """Convert public layout fields into Flex-DM model tensors."""
    if return_tensors != "pt":
        raise ValueError("FlexDmProcessor only supports return_tensors='pt'")

    if bbox is None or labels is None:
        count = self._num_elements_tensor(num_elements, batch_size)
        max_len = int(count.max().item()) if count.numel() else 0
        bbox_t = torch.zeros((batch_size, max_len, 4), dtype=torch.float32)
        labels_t = torch.zeros((batch_size, max_len), dtype=torch.long)
        mask_t = torch.arange(max_len).unsqueeze(0) < count.unsqueeze(1)
    else:
        bbox_t, labels_t, mask_t = prepare_layout_tensors(
            bbox=bbox,
            labels=labels,
            mask=mask,
            box_format=box_format,
            normalized=normalized,
            canvas_size=canvas_size,
            clamp_converted_normalized=True,
        )
    inputs = self._layout_to_inputs(
        bbox=bbox_t,
        labels=labels_t,
        mask=mask_t,
        attributes=attributes,
        content=content,
    )
    length = mask_t.long().sum(dim=1).clamp(min=1) - 1
    inputs["length"] = length.reshape(-1, 1).long()
    seq_mask = get_seq_mask(inputs["length"].reshape(-1), maxlen=bbox_t.size(1))
    filtered = filter_padding(inputs, self.config.input_columns, seq_mask)
    canonical, normalized_feature = self.normalize_condition_and_feature(
        condition_type,
        feature_group=feature_group,
    )
    masks = build_feature_masks(
        self.config.input_columns,
        seq_mask,
        condition_type=canonical,
        feature_group=normalized_feature,
        target_indices=target_indices,
    )
    return {
        "inputs": filtered,
        "masks": masks,
        "bbox": bbox_t,
        "labels": labels_t,
        "mask": mask_t,
        "condition_type": canonical,
        "feature_group": normalized_feature,
    }

normalize_condition_and_feature

normalize_condition_and_feature(
    condition_type: ConditionType | str,
    *,
    feature_group: str | None = None,
) -> tuple[ConditionType, str | None]

Normalize canonical conditions plus local Flex-DM task aliases.

Source code in models/flex-dm/src/flex_dm/processing_flex_dm.py
261
262
263
264
265
266
267
268
269
270
271
272
273
274
def normalize_condition_and_feature(
    self,
    condition_type: ConditionType | str,
    *,
    feature_group: str | None = None,
) -> tuple[ConditionType, str | None]:
    """Normalize canonical conditions plus local Flex-DM task aliases."""
    aliases = {"random", "elem", "type", "pos", "attr", "img", "txt"}
    if isinstance(condition_type, str) and condition_type in aliases:
        return ConditionType.completion, condition_type
    canonical = normalize_condition_type(condition_type)
    if canonical is ConditionType.content_image and feature_group is None:
        return canonical, "img"
    return canonical, feature_group

post_process_document

post_process_document(
    outputs: FlexDmModelOutput,
    *,
    original_inputs: Mapping[str, Shaped[Tensor, "..."]],
    masks: Mapping[str, Bool[Tensor, "..."]],
    output_type: Literal["dataclass", "dict"] = "dataclass",
    return_intermediates: bool = False,
    refinement_input: Mapping[str, Shaped[Tensor, "..."]]
    | None = None,
) -> (
    LayoutGenerationOutput
    | dict[
        str,
        Shaped[torch.Tensor, "..."]
        | dict[int, str]
        | Mapping[str, Shaped[torch.Tensor, "..."]]
        | None,
    ]
)

Decode Flex-DM model outputs to the common layout schema.

Source code in models/flex-dm/src/flex_dm/processing_flex_dm.py
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
def post_process_document(
    self,
    outputs: FlexDmModelOutput,
    *,
    original_inputs: Mapping[str, Shaped[torch.Tensor, "..."]],
    masks: Mapping[str, Bool[torch.Tensor, "..."]],
    output_type: Literal["dataclass", "dict"] = "dataclass",
    return_intermediates: bool = False,
    refinement_input: Mapping[str, Shaped[torch.Tensor, "..."]] | None = None,
) -> (
    LayoutGenerationOutput
    | dict[
        str,
        Shaped[torch.Tensor, "..."]
        | dict[int, str]
        | Mapping[str, Shaped[torch.Tensor, "..."]]
        | None,
    ]
):
    """Decode Flex-DM model outputs to the common layout schema."""
    decoded = self._decode_logits(outputs.logits, original_inputs, masks)
    ltwh = torch.cat([decoded[key].float() for key in GEOMETRY_KEYS], dim=-1)
    bbox = ltwh_to_xywh(ltwh).clamp(0.0, 1.0).detach().cpu()
    labels = decoded["type"].squeeze(-1).long().detach().cpu()
    valid_mask = get_seq_mask(
        original_inputs["length"].reshape(-1), maxlen=labels.size(1)
    )
    intermediates = None
    if return_intermediates:
        intermediates = {
            "attributes": {
                key: value.detach().cpu()
                for key, value in decoded.items()
                if key not in (*GEOMETRY_KEYS, "type")
                and self.config.input_columns[key]["is_sequence"]
            },
            "masks": {key: value.detach().cpu() for key, value in masks.items()},
            "logits": {
                key: value.detach().cpu() for key, value in outputs.logits.items()
            },
        }
        if refinement_input is not None:
            intermediates["refinement_input"] = {
                key: value.detach().cpu() for key, value in refinement_input.items()
            }
    result = LayoutGenerationOutput(
        bbox=bbox,
        labels=labels,
        mask=valid_mask.detach().cpu(),
        id2label=cast(dict[int, str], self.config.id2label),
        intermediates=intermediates,
    )
    if output_type == "dict":
        return dict(result)
    if output_type != "dataclass":
        raise ValueError(f"Unsupported output_type: {output_type}")

    return result

configuration_flex_dm

Configuration objects for Flex-DM masked document modeling.

FlexDmDatasetName

Bases: StrEnum

Dataset names supported by the Flex-DM MFP checkpoints.

Source code in models/flex-dm/src/flex_dm/configuration_flex_dm.py
22
23
24
25
26
class FlexDmDatasetName(StrEnum):
    """Dataset names supported by the Flex-DM MFP checkpoints."""

    crello = auto()
    rico = auto()

FlexDmColumnType

Bases: StrEnum

Internal column storage type.

Source code in models/flex-dm/src/flex_dm/configuration_flex_dm.py
29
30
31
32
33
class FlexDmColumnType(StrEnum):
    """Internal column storage type."""

    categorical = auto()
    numerical = auto()

FlexDmLossCondition

Bases: TypedDict

Conditional loss filter for conditionally valid fields.

Source code in models/flex-dm/src/flex_dm/configuration_flex_dm.py
36
37
38
39
40
class FlexDmLossCondition(TypedDict):
    """Conditional loss filter for conditionally valid fields."""

    key: str
    mask: tuple[bool, ...]

FlexDmColumnSpec

Bases: TypedDict

Tensor specification for one Flex-DM input/output column.

Source code in models/flex-dm/src/flex_dm/configuration_flex_dm.py
43
44
45
46
47
48
49
50
51
class FlexDmColumnSpec(TypedDict):
    """Tensor specification for one Flex-DM input/output column."""

    type: Literal["categorical", "numerical"]
    input_dim: int | None
    shape: tuple[int, ...]
    is_sequence: bool
    primary_label: int | None
    loss_condition: NotRequired[FlexDmLossCondition | None]

FlexDmConfig

Bases: PretrainedConfig

Configuration for a converted Flex-DM MFP model.

Parameters:

Name Type Description Default
dataset_name str

Released dataset name.

'crello'
checkpoint_variant str

Released checkpoint variant name.

'ours-exp-ft'
id2label dict[int | str, str] | None

Public dataset-local label mapping.

None
input_columns dict[str, FlexDmColumnSpec] | None

Heterogeneous model column specs.

None
attribute_groups dict[str, tuple[str, ...] | list[str]] | None

Model feature groups used for infilling.

None
max_seq_length int

Maximum document elements.

50
latent_dim int

Transformer hidden dimension.

256
num_blocks int

Number of DeepSVG-style transformer blocks.

4
block_type str

Released block type. Only deepsvg is implemented.

'deepsvg'
masking_method str

Released masking task selector.

'random'
seq_type str

Released sequence model type. default is the released path.

'default'
arch_type str

Released architecture type. oneshot is the released path.

'oneshot'
context str | None

Optional reference context embedding mode.

None
input_dtype str

Released input ordering mode.

'set'
use_elemwise_noise bool

Whether element-wise noise was enabled.

False
dropout float

Dropout probability.

0.1
layer_norm_epsilon float

LayerNorm epsilon matching Keras defaults.

0.001
l2 float | None

Original L2 setting, stored for provenance.

0.01
original_args dict[str, FlexDmConfigValue] | None

Raw reference args.json values.

None
conversion_report dict[str, FlexDmConfigValue] | None

Checkpoint conversion diagnostics.

None
kwargs str | int | float | bool | None

Extra PretrainedConfig fields.

{}
Source code in models/flex-dm/src/flex_dm/configuration_flex_dm.py
 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
class FlexDmConfig(PretrainedConfig):
    """Configuration for a converted Flex-DM MFP model.

    Args:
        dataset_name: Released dataset name.
        checkpoint_variant: Released checkpoint variant name.
        id2label: Public dataset-local label mapping.
        input_columns: Heterogeneous model column specs.
        attribute_groups: Model feature groups used for infilling.
        max_seq_length: Maximum document elements.
        latent_dim: Transformer hidden dimension.
        num_blocks: Number of DeepSVG-style transformer blocks.
        block_type: Released block type. Only ``deepsvg`` is implemented.
        masking_method: Released masking task selector.
        seq_type: Released sequence model type. ``default`` is the released path.
        arch_type: Released architecture type. ``oneshot`` is the released path.
        context: Optional reference context embedding mode.
        input_dtype: Released input ordering mode.
        use_elemwise_noise: Whether element-wise noise was enabled.
        dropout: Dropout probability.
        layer_norm_epsilon: LayerNorm epsilon matching Keras defaults.
        l2: Original L2 setting, stored for provenance.
        original_args: Raw reference ``args.json`` values.
        conversion_report: Checkpoint conversion diagnostics.
        kwargs: Extra ``PretrainedConfig`` fields.
    """

    model_type = "flex-dm"

    def __init__(
        self,
        dataset_name: str = "crello",
        checkpoint_variant: str = "ours-exp-ft",
        id2label: dict[int | str, str] | None = None,
        input_columns: dict[str, FlexDmColumnSpec] | None = None,
        attribute_groups: dict[str, tuple[str, ...] | list[str]] | None = None,
        max_seq_length: int = 50,
        latent_dim: int = 256,
        num_blocks: int = 4,
        block_type: str = "deepsvg",
        masking_method: str = "random",
        seq_type: str = "default",
        arch_type: str = "oneshot",
        context: str | None = None,
        input_dtype: str = "set",
        use_elemwise_noise: bool = False,
        dropout: float = 0.1,
        layer_norm_epsilon: float = 1e-3,
        l2: float | None = 1e-2,
        original_args: dict[str, FlexDmConfigValue] | None = None,
        conversion_report: dict[str, FlexDmConfigValue] | None = None,
        **kwargs: str | int | float | bool | None,
    ) -> None:
        """Initialize a Flex-DM config."""
        normalized_id2label = _normalize_id2label(id2label)
        kwargs.pop("label2id", None)
        super().__init__(
            id2label=normalized_id2label,
            label2id={label: idx for idx, label in normalized_id2label.items()},
            **kwargs,  # ty: ignore[invalid-argument-type]
        )
        self.dataset_name = dataset_name
        self.checkpoint_variant = checkpoint_variant
        self.input_columns = _normalize_columns(input_columns)
        if attribute_groups is None:
            from .data_specs import attribute_groups_for_dataset

            attribute_groups = dict(attribute_groups_for_dataset(dataset_name))
        groups = attribute_groups

        self.attribute_groups = {key: tuple(value) for key, value in groups.items()}
        self.max_seq_length = max_seq_length
        self.latent_dim = latent_dim
        self.num_blocks = num_blocks
        self.block_type = block_type
        self.masking_method = masking_method
        self.seq_type = seq_type
        self.arch_type = arch_type
        self.context = context
        self.input_dtype = input_dtype

        self.use_elemwise_noise = use_elemwise_noise
        self.dropout = dropout
        self.layer_norm_epsilon = layer_norm_epsilon
        self.l2 = l2
        self.original_args = original_args or {}
        self.conversion_report = conversion_report or {}

    @property
    def max_seq_length_with_length_lookup(self) -> int:
        """Return the max length used by the zero-based length lookup."""
        return self.max_seq_length

    @property
    def valid_sequence_keys(self) -> tuple[str, ...]:
        """Return non-demo sequence fields modeled by Flex-DM."""
        return tuple(
            key for key, column in self.input_columns.items() if column["is_sequence"]
        )

    @property
    def categorical_keys(self) -> tuple[str, ...]:
        """Return sequence fields with categorical heads."""
        return tuple(
            key
            for key, column in self.input_columns.items()
            if column["is_sequence"] and column["type"] == "categorical"
        )

    @property
    def numerical_keys(self) -> tuple[str, ...]:
        """Return sequence fields with numerical heads."""
        return tuple(
            key
            for key, column in self.input_columns.items()
            if column["is_sequence"] and column["type"] == "numerical"
        )

    @property
    def task_names(self) -> tuple[str, ...]:
        """Return task names in sampler order."""
        return ("random", "elem", *self.attribute_groups.keys())

    def mask_token_id_for(self, key: str) -> int:
        """Return the categorical mask token id for ``key``."""
        input_dim = self.input_columns[key]["input_dim"]
        if input_dim is None:
            raise ValueError(f"{key} is not categorical")

        return input_dim

    def unused_token_id_for(self, key: str) -> int:
        """Return the categorical unused token id for ``key``."""
        return self.mask_token_id_for(key) + 1

max_seq_length_with_length_lookup property

max_seq_length_with_length_lookup: int

Return the max length used by the zero-based length lookup.

valid_sequence_keys property

valid_sequence_keys: tuple[str, ...]

Return non-demo sequence fields modeled by Flex-DM.

categorical_keys property

categorical_keys: tuple[str, ...]

Return sequence fields with categorical heads.

numerical_keys property

numerical_keys: tuple[str, ...]

Return sequence fields with numerical heads.

task_names property

task_names: tuple[str, ...]

Return task names in sampler order.

__init__

__init__(
    dataset_name: str = "crello",
    checkpoint_variant: str = "ours-exp-ft",
    id2label: dict[int | str, str] | None = None,
    input_columns: dict[str, FlexDmColumnSpec]
    | None = None,
    attribute_groups: dict[str, tuple[str, ...] | list[str]]
    | None = None,
    max_seq_length: int = 50,
    latent_dim: int = 256,
    num_blocks: int = 4,
    block_type: str = "deepsvg",
    masking_method: str = "random",
    seq_type: str = "default",
    arch_type: str = "oneshot",
    context: str | None = None,
    input_dtype: str = "set",
    use_elemwise_noise: bool = False,
    dropout: float = 0.1,
    layer_norm_epsilon: float = 0.001,
    l2: float | None = 0.01,
    original_args: dict[str, FlexDmConfigValue]
    | None = None,
    conversion_report: dict[str, FlexDmConfigValue]
    | None = None,
    **kwargs: str | int | float | bool | None,
) -> None

Initialize a Flex-DM config.

Source code in models/flex-dm/src/flex_dm/configuration_flex_dm.py
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
def __init__(
    self,
    dataset_name: str = "crello",
    checkpoint_variant: str = "ours-exp-ft",
    id2label: dict[int | str, str] | None = None,
    input_columns: dict[str, FlexDmColumnSpec] | None = None,
    attribute_groups: dict[str, tuple[str, ...] | list[str]] | None = None,
    max_seq_length: int = 50,
    latent_dim: int = 256,
    num_blocks: int = 4,
    block_type: str = "deepsvg",
    masking_method: str = "random",
    seq_type: str = "default",
    arch_type: str = "oneshot",
    context: str | None = None,
    input_dtype: str = "set",
    use_elemwise_noise: bool = False,
    dropout: float = 0.1,
    layer_norm_epsilon: float = 1e-3,
    l2: float | None = 1e-2,
    original_args: dict[str, FlexDmConfigValue] | None = None,
    conversion_report: dict[str, FlexDmConfigValue] | None = None,
    **kwargs: str | int | float | bool | None,
) -> None:
    """Initialize a Flex-DM config."""
    normalized_id2label = _normalize_id2label(id2label)
    kwargs.pop("label2id", None)
    super().__init__(
        id2label=normalized_id2label,
        label2id={label: idx for idx, label in normalized_id2label.items()},
        **kwargs,  # ty: ignore[invalid-argument-type]
    )
    self.dataset_name = dataset_name
    self.checkpoint_variant = checkpoint_variant
    self.input_columns = _normalize_columns(input_columns)
    if attribute_groups is None:
        from .data_specs import attribute_groups_for_dataset

        attribute_groups = dict(attribute_groups_for_dataset(dataset_name))
    groups = attribute_groups

    self.attribute_groups = {key: tuple(value) for key, value in groups.items()}
    self.max_seq_length = max_seq_length
    self.latent_dim = latent_dim
    self.num_blocks = num_blocks
    self.block_type = block_type
    self.masking_method = masking_method
    self.seq_type = seq_type
    self.arch_type = arch_type
    self.context = context
    self.input_dtype = input_dtype

    self.use_elemwise_noise = use_elemwise_noise
    self.dropout = dropout
    self.layer_norm_epsilon = layer_norm_epsilon
    self.l2 = l2
    self.original_args = original_args or {}
    self.conversion_report = conversion_report or {}

mask_token_id_for

mask_token_id_for(key: str) -> int

Return the categorical mask token id for key.

Source code in models/flex-dm/src/flex_dm/configuration_flex_dm.py
209
210
211
212
213
214
215
def mask_token_id_for(self, key: str) -> int:
    """Return the categorical mask token id for ``key``."""
    input_dim = self.input_columns[key]["input_dim"]
    if input_dim is None:
        raise ValueError(f"{key} is not categorical")

    return input_dim

unused_token_id_for

unused_token_id_for(key: str) -> int

Return the categorical unused token id for key.

Source code in models/flex-dm/src/flex_dm/configuration_flex_dm.py
217
218
219
def unused_token_id_for(self, key: str) -> int:
    """Return the categorical unused token id for ``key``."""
    return self.mask_token_id_for(key) + 1

conversion

Tensor conversion helpers for TensorFlow-to-PyTorch Flex-DM checkpoints.

FlexDmConversionReport dataclass

Summary of a semantic checkpoint conversion.

Source code in models/flex-dm/src/flex_dm/conversion.py
12
13
14
15
16
17
18
19
@dataclass(frozen=True)
class FlexDmConversionReport:
    """Summary of a semantic checkpoint conversion."""

    matched_tensor_count: int
    matched_parameter_count: int
    missing_target_keys: tuple[str, ...]
    unexpected_source_keys: tuple[str, ...]

convert_dense_kernel

convert_dense_kernel(
    tf_kernel: Float[ndarray, "in_features out_features"],
) -> Float[torch.Tensor, "out_features in_features"]

Transpose a TensorFlow Dense kernel into PyTorch Linear layout.

Source code in models/flex-dm/src/flex_dm/conversion.py
22
23
24
25
26
def convert_dense_kernel(
    tf_kernel: Float[np.ndarray, "in_features out_features"],
) -> Float[torch.Tensor, "out_features in_features"]:
    """Transpose a TensorFlow Dense kernel into PyTorch Linear layout."""
    return torch.from_numpy(tf_kernel.T)

convert_dense_bias

convert_dense_bias(
    tf_bias: Float[ndarray, "features"],
) -> Float[torch.Tensor, "features"]

Convert a TensorFlow Dense bias without transposition.

Source code in models/flex-dm/src/flex_dm/conversion.py
29
30
31
32
33
def convert_dense_bias(
    tf_bias: Float[np.ndarray, "features"],
) -> Float[torch.Tensor, "features"]:
    """Convert a TensorFlow Dense bias without transposition."""
    return torch.from_numpy(tf_bias)

convert_embedding

convert_embedding(
    tf_embedding: Float[ndarray, "tokens channels"],
) -> Float[torch.Tensor, "tokens channels"]

Convert a TensorFlow embedding table without transposition.

Source code in models/flex-dm/src/flex_dm/conversion.py
36
37
38
39
40
def convert_embedding(
    tf_embedding: Float[np.ndarray, "tokens channels"],
) -> Float[torch.Tensor, "tokens channels"]:
    """Convert a TensorFlow embedding table without transposition."""
    return torch.from_numpy(tf_embedding)

convert_layer_norm_gamma_beta

convert_layer_norm_gamma_beta(
    gamma: Float[ndarray, "features"],
    beta: Float[ndarray, "features"],
) -> tuple[
    Float[torch.Tensor, "features"],
    Float[torch.Tensor, "features"],
]

Convert TensorFlow LayerNorm gamma/beta to PyTorch weight/bias.

Source code in models/flex-dm/src/flex_dm/conversion.py
43
44
45
46
47
48
def convert_layer_norm_gamma_beta(
    gamma: Float[np.ndarray, "features"],
    beta: Float[np.ndarray, "features"],
) -> tuple[Float[torch.Tensor, "features"], Float[torch.Tensor, "features"]]:
    """Convert TensorFlow LayerNorm gamma/beta to PyTorch weight/bias."""
    return torch.from_numpy(gamma), torch.from_numpy(beta)

map_tensor_by_rule

map_tensor_by_rule(
    source_name: str, value: Shaped[ndarray, "..."]
) -> tuple[str, Shaped[torch.Tensor, "..."]] | None

Map one known vendor variable name to a PyTorch state-dict key.

Parameters:

Name Type Description Default
source_name str

TensorFlow variable name.

required
value Shaped[ndarray, '...']

TensorFlow variable value.

required

Returns:

Type Description
tuple[str, Shaped[Tensor, '...']] | None

Target state-dict key and converted tensor, or None when the source

tuple[str, Shaped[Tensor, '...']] | None

name is not part of the current semantic mapping.

Source code in models/flex-dm/src/flex_dm/conversion.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
 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
def map_tensor_by_rule(
    source_name: str, value: Shaped[np.ndarray, "..."]
) -> tuple[str, Shaped[torch.Tensor, "..."]] | None:
    """Map one known vendor variable name to a PyTorch state-dict key.

    Args:
        source_name: TensorFlow variable name.
        value: TensorFlow variable value.

    Returns:
        Target state-dict key and converted tensor, or ``None`` when the source
        name is not part of the current semantic mapping.
    """
    name = (
        source_name.removesuffix(":0")
        .removesuffix("/.ATTRIBUTES/VARIABLE_VALUE")
        .removesuffix("/VARIABLE_VALUE")
    )
    if name.startswith("optimizer/") or "/.OPTIMIZER_SLOT/" in source_name:
        return None
    if name.startswith("model/encoder/input_layer/"):
        rest = name.removeprefix("model/encoder/input_layer/")
        if rest.endswith("/embeddings"):
            key = rest.removesuffix("/embeddings")
            if key.endswith("_special"):
                field = key.removesuffix("_special")
                return (
                    f"encoder.special_embeddings.field_{field}.weight",
                    convert_embedding(value),
                )
            return f"encoder.input_embeddings.field_{key}.weight", convert_embedding(
                value
            )
        if rest.endswith("/kernel"):
            key = rest.removesuffix("/kernel")
            return (
                f"encoder.input_projections.field_{key}.weight",
                convert_dense_kernel(value),
            )
        if rest.endswith("/bias"):
            key = rest.removesuffix("/bias")
            return (
                f"encoder.input_projections.field_{key}.bias",
                convert_dense_bias(value),
            )
    if name.startswith("model/decoder/decoders/"):
        rest = name.removeprefix("model/decoder/decoders/")
        if rest.endswith("/kernel"):
            key = rest.removesuffix("/kernel")
            return f"decoder.heads.field_{key}.weight", convert_dense_kernel(value)
        if rest.endswith("/bias"):
            key = rest.removesuffix("/bias")
            return f"decoder.heads.field_{key}.bias", convert_dense_bias(value)
    if name.startswith("model/blocks/seq2seq/seq2seq_"):
        rest = name.removeprefix("model/blocks/seq2seq/seq2seq_")
        block_text, layer = rest.split("/", 1)
        block = int(block_text)
        prefixes = {
            "attn/dense_query": f"blocks.{block}.attention.q_proj",
            "attn/dense_key": f"blocks.{block}.attention.k_proj",
            "attn/dense_value": f"blocks.{block}.attention.v_proj",
            "attn/combine_heads": f"blocks.{block}.attention.out_proj",
            "mlp/layer_with_weights-0": f"blocks.{block}.mlp.0",
            "mlp/layer_with_weights-1": f"blocks.{block}.mlp.2",
            "norm1": f"blocks.{block}.norm1",
            "norm2": f"blocks.{block}.norm2",
        }
        for source_prefix, target_prefix in prefixes.items():
            if layer == f"{source_prefix}/kernel":
                return f"{target_prefix}.weight", convert_dense_kernel(value)
            if layer == f"{source_prefix}/bias":
                return f"{target_prefix}.bias", convert_dense_bias(value)
            if layer == f"{source_prefix}/gamma":
                return f"{target_prefix}.weight", torch.from_numpy(value)
            if layer == f"{source_prefix}/beta":
                return f"{target_prefix}.bias", torch.from_numpy(value)
    return None

conversion_report

conversion_report(
    *,
    converted: dict[str, Shaped[Tensor, "..."]],
    target_keys: set[str],
    source_keys: set[str],
    consumed_source_keys: set[str],
) -> FlexDmConversionReport

Build a deterministic conversion summary.

Source code in models/flex-dm/src/flex_dm/conversion.py
130
131
132
133
134
135
136
137
138
139
140
141
142
143
def conversion_report(
    *,
    converted: dict[str, Shaped[torch.Tensor, "..."]],
    target_keys: set[str],
    source_keys: set[str],
    consumed_source_keys: set[str],
) -> FlexDmConversionReport:
    """Build a deterministic conversion summary."""
    return FlexDmConversionReport(
        matched_tensor_count=len(converted),
        matched_parameter_count=sum(tensor.numel() for tensor in converted.values()),
        missing_target_keys=tuple(sorted(target_keys - converted.keys())),
        unexpected_source_keys=tuple(sorted(source_keys - consumed_source_keys)),
    )

data_specs

Built-in Flex-DM dataset schema helpers.

FlexDmBuiltinColumn

Bases: TypedDict

Built-in dataset column metadata.

Source code in models/flex-dm/src/flex_dm/data_specs.py
15
16
17
18
19
20
class FlexDmBuiltinColumn(TypedDict):
    """Built-in dataset column metadata."""

    dtype: str
    shape: tuple[int, ...]
    is_sequence: bool

FlexDmBuiltinSpec

Bases: TypedDict

Built-in dataset schema metadata.

Source code in models/flex-dm/src/flex_dm/data_specs.py
23
24
25
26
27
class FlexDmBuiltinSpec(TypedDict):
    """Built-in dataset schema metadata."""

    name: str
    columns: dict[str, FlexDmBuiltinColumn]

FlexDmFeatureGroup

Bases: StrEnum

Flex-DM feature groups.

Source code in models/flex-dm/src/flex_dm/data_specs.py
33
34
35
36
37
38
39
40
41
42
class FlexDmFeatureGroup(StrEnum):
    """Flex-DM feature groups."""

    random = auto()
    elem = auto()
    type = auto()
    pos = auto()
    attr = auto()
    img = auto()
    txt = auto()

load_builtin_spec

load_builtin_spec(
    dataset_name: FlexDmDatasetName | str,
) -> FlexDmBuiltinSpec

Return a lightweight copy of the Flex-DM column schema.

Parameters:

Name Type Description Default
dataset_name FlexDmDatasetName | str

crello or rico.

required

Returns:

Type Description
FlexDmBuiltinSpec

Dictionary with a columns mapping.

Raises:

Type Description
ValueError

If the dataset name is unsupported.

Examples:

>>> load_builtin_spec("crello")["name"]
'crello'
Source code in models/flex-dm/src/flex_dm/data_specs.py
 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
def load_builtin_spec(dataset_name: FlexDmDatasetName | str) -> FlexDmBuiltinSpec:
    """Return a lightweight copy of the Flex-DM column schema.

    Args:
        dataset_name: ``crello`` or ``rico``.

    Returns:
        Dictionary with a ``columns`` mapping.

    Raises:
        ValueError: If the dataset name is unsupported.

    Examples:
        >>> load_builtin_spec("crello")["name"]
        'crello'
    """
    dataset = _normalize_dataset(dataset_name)
    if dataset is FlexDmDatasetName.crello:
        return {
            "name": "crello",
            "columns": {
                "length": {"dtype": "int64", "shape": (1,), "is_sequence": False},
                "group": {"dtype": "string", "shape": (1,), "is_sequence": False},
                "format": {"dtype": "string", "shape": (1,), "is_sequence": False},
                "canvas_width": {
                    "dtype": "int64",
                    "shape": (1,),
                    "is_sequence": False,
                },
                "canvas_height": {
                    "dtype": "int64",
                    "shape": (1,),
                    "is_sequence": False,
                },
                "category": {
                    "dtype": "string",
                    "shape": (1,),
                    "is_sequence": False,
                },
                "type": {"dtype": "string", "shape": (1,), "is_sequence": True},
                "left": {"dtype": "float32", "shape": (1,), "is_sequence": True},
                "top": {"dtype": "float32", "shape": (1,), "is_sequence": True},
                "width": {"dtype": "float32", "shape": (1,), "is_sequence": True},
                "height": {"dtype": "float32", "shape": (1,), "is_sequence": True},
                "opacity": {"dtype": "float32", "shape": (1,), "is_sequence": True},
                "color": {"dtype": "int64", "shape": (3,), "is_sequence": True},
                "image_embedding": {
                    "dtype": "float32",
                    "shape": (512,),
                    "is_sequence": True,
                },
                "text_embedding": {
                    "dtype": "float32",
                    "shape": (512,),
                    "is_sequence": True,
                },
                "font_family": {
                    "dtype": "string",
                    "shape": (1,),
                    "is_sequence": True,
                },
            },
        }
    return {
        "name": "rico",
        "columns": {
            "length": {"dtype": "int64", "shape": (1,), "is_sequence": False},
            "left": {"dtype": "float32", "shape": (1,), "is_sequence": True},
            "top": {"dtype": "float32", "shape": (1,), "is_sequence": True},
            "width": {"dtype": "float32", "shape": (1,), "is_sequence": True},
            "height": {"dtype": "float32", "shape": (1,), "is_sequence": True},
            "clickable": {"dtype": "int64", "shape": (1,), "is_sequence": True},
            "type": {"dtype": "string", "shape": (1,), "is_sequence": True},
            "icon": {"dtype": "string", "shape": (1,), "is_sequence": True},
            "text_button": {
                "dtype": "string",
                "shape": (1,),
                "is_sequence": True,
            },
        },
    }

attribute_groups_for_dataset

attribute_groups_for_dataset(
    dataset_name: FlexDmDatasetName | str,
) -> dict[str, tuple[str, ...]]

Return attribute groups for a dataset.

Source code in models/flex-dm/src/flex_dm/data_specs.py
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
def attribute_groups_for_dataset(
    dataset_name: FlexDmDatasetName | str,
) -> dict[str, tuple[str, ...]]:
    """Return attribute groups for a dataset."""
    dataset = _normalize_dataset(dataset_name)
    if dataset is FlexDmDatasetName.crello:
        return {
            "type": ("type",),
            "pos": ("left", "top", "width", "height"),
            "attr": ("opacity", "color", "font_family"),
            "img": ("image_embedding",),
            "txt": ("text_embedding",),
        }
    return {
        "type": ("type",),
        "pos": ("left", "top", "width", "height"),
        "attr": ("clickable", "icon", "text_button"),
    }

build_column_specs

build_column_specs(
    *,
    dataset_name: FlexDmDatasetName | str,
    vocabulary: Mapping[str, FlexDmVocabularyValue],
) -> dict[str, FlexDmColumnSpec]

Build Flex-DM model column specs from vocabulary metadata.

Source code in models/flex-dm/src/flex_dm/data_specs.py
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
def build_column_specs(
    *,
    dataset_name: FlexDmDatasetName | str,
    vocabulary: Mapping[str, FlexDmVocabularyValue],
) -> dict[str, FlexDmColumnSpec]:
    """Build Flex-DM model column specs from vocabulary metadata."""
    dataset = _normalize_dataset(dataset_name)
    spec = load_builtin_spec(dataset)
    columns = spec["columns"]
    type_vocabulary = _lookup_vocabulary(
        "type", dataset_name=dataset, vocabulary=vocabulary
    )
    input_columns: dict[str, FlexDmColumnSpec] = {}
    for key, column in columns.items():
        shape = tuple(column.get("shape", (1,)))
        dtype = str(column["dtype"])
        is_sequence = bool(column["is_sequence"])
        is_numerical = key in ("image_embedding", "text_embedding")
        if is_numerical:
            item = cast(
                FlexDmColumnSpec,
                {
                    "type": "numerical",
                    "input_dim": None,
                    "shape": shape,
                    "is_sequence": is_sequence,
                    "primary_label": None,
                },
            )
        else:
            input_dim = (
                50
                if key == "length"
                else _vocabulary_size(key, dataset_name=dataset, vocabulary=vocabulary)
            )
            item = cast(
                FlexDmColumnSpec,
                {
                    "type": "categorical",
                    "input_dim": input_dim,
                    "shape": shape,
                    "is_sequence": is_sequence,
                    "primary_label": 0 if key == "type" else None,
                },
            )
        if dataset is FlexDmDatasetName.crello and key in {
            "color",
            "image_embedding",
            "text_embedding",
            "font_family",
        }:
            allowed = {
                "color": {"textElement", "coloredBackground"},
                "image_embedding": {"svgElement", "imageElement", "maskElement"},
                "text_embedding": {"textElement"},
                "font_family": {"textElement"},
            }[key]
            item["loss_condition"] = {
                "key": "type",
                "mask": tuple(label in allowed for label in type_vocabulary),
            }
        _ = dtype
        input_columns[key] = item
    return input_columns

id2label_from_vocabulary

id2label_from_vocabulary(
    dataset_name: FlexDmDatasetName | str,
    vocabulary: Mapping[str, FlexDmVocabularyValue],
) -> dict[int, str]

Resolve the public type-label mapping from vocabulary data.

Source code in models/flex-dm/src/flex_dm/data_specs.py
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
def id2label_from_vocabulary(
    dataset_name: FlexDmDatasetName | str,
    vocabulary: Mapping[str, FlexDmVocabularyValue],
) -> dict[int, str]:
    """Resolve the public type-label mapping from vocabulary data."""
    dataset = _normalize_dataset(dataset_name)
    raw = vocabulary.get("type")
    if isinstance(raw, Mapping):
        ordered = sorted(raw.items(), key=lambda item: int(cast(int, item[1])))
        return {idx: str(label) for idx, (label, _count) in enumerate(ordered)}
    if isinstance(raw, list | tuple):
        return {idx: str(label) for idx, label in enumerate(raw)}
    if dataset is FlexDmDatasetName.crello:
        return posgen_id2label_for_dataset("crello")
    return laygen_id2label_for_dataset("rico25")

masking

Flex-DM multi-column masking and iterative decoding helpers.

get_seq_mask

get_seq_mask(
    length: Int[Tensor, "..."], *, maxlen: int | None = None
) -> Bool[torch.Tensor, "batch elements"]

Return the zero-based valid-element mask.

Parameters:

Name Type Description Default
length Int[Tensor, '...']

Zero-based document length tensor shaped (batch,) or (batch, 1).

required
maxlen int | None

Optional output width.

None

Returns:

Type Description
Bool[Tensor, 'batch elements']

Boolean mask where True means a valid element.

Examples:

>>> get_seq_mask(torch.tensor([0, 2]), maxlen=4)
tensor([[ True, False, False, False],
        [ True,  True,  True, False]])
Source code in models/flex-dm/src/flex_dm/masking.py
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
def get_seq_mask(
    length: Int[torch.Tensor, "..."], *, maxlen: int | None = None
) -> Bool[torch.Tensor, "batch elements"]:
    """Return the zero-based valid-element mask.

    Args:
        length: Zero-based document length tensor shaped ``(batch,)`` or
            ``(batch, 1)``.
        maxlen: Optional output width.

    Returns:
        Boolean mask where ``True`` means a valid element.

    Examples:
        >>> get_seq_mask(torch.tensor([0, 2]), maxlen=4)
        tensor([[ True, False, False, False],
                [ True,  True,  True, False]])
    """
    length_flat = length.reshape(-1).long()
    width = int(maxlen or (length_flat.max().item() + 1 if length_flat.numel() else 0))
    positions = torch.arange(width, device=length_flat.device)
    return positions.unsqueeze(0) <= length_flat.unsqueeze(1)

get_initial_masks

get_initial_masks(
    input_columns: Mapping[str, FlexDmColumnSpec],
    seq_mask: Bool[Tensor, "batch elements"],
) -> dict[str, Bool[torch.Tensor, "..."]]

Return initial initial masks with no sequence fields hidden.

Source code in models/flex-dm/src/flex_dm/masking.py
51
52
53
54
55
56
57
58
59
60
61
62
63
def get_initial_masks(
    input_columns: Mapping[str, FlexDmColumnSpec],
    seq_mask: Bool[torch.Tensor, "batch elements"],
) -> dict[str, Bool[torch.Tensor, "..."]]:
    """Return initial initial masks with no sequence fields hidden."""
    masks: dict[str, Bool[torch.Tensor, "..."]] = {}
    for key, column in input_columns.items():
        masks[key] = (
            torch.ones(seq_mask.shape[:1], dtype=torch.bool, device=seq_mask.device)
            if not column["is_sequence"]
            else torch.zeros_like(seq_mask, dtype=torch.bool)
        )
    return masks

apply_token

apply_token(
    input_: Shaped[Tensor, "batch elements channels"],
    column: FlexDmColumnSpec,
    mask: Bool[Tensor, "batch elements"],
    token_type: Literal["masked", "unused", "random"],
    *,
    generator: Generator | None = None,
) -> Shaped[torch.Tensor, "batch elements channels"]

Apply a masked, unused, or random model token to selected elements.

Source code in models/flex-dm/src/flex_dm/masking.py
 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
def apply_token(
    input_: Shaped[torch.Tensor, "batch elements channels"],
    column: FlexDmColumnSpec,
    mask: Bool[torch.Tensor, "batch elements"],
    token_type: Literal["masked", "unused", "random"],
    *,
    generator: torch.Generator | None = None,
) -> Shaped[torch.Tensor, "batch elements channels"]:
    """Apply a masked, unused, or random model token to selected elements."""
    mask_expanded = mask.to(device=input_.device).unsqueeze(-1)
    if column["type"] == "categorical":
        input_dim = column["input_dim"]
        if input_dim is None:
            raise ValueError("categorical column requires input_dim")

        if token_type == "masked":
            token = torch.full_like(input_, input_dim)
        elif token_type == "unused":
            token = torch.full_like(input_, input_dim + 1)
        else:
            token = torch.randint(
                input_dim,
                input_.shape,
                device=input_.device,
                dtype=input_.dtype,
                generator=generator,
            )
        return torch.where(mask_expanded, token, input_)
    if token_type == "masked":
        token_f = torch.full_like(input_, MASK_VALUE)
    elif token_type == "unused":
        token_f = torch.full_like(input_, NULL_VALUE)
    else:
        token_f = (
            torch.randn(
                input_.shape,
                device=input_.device,
                dtype=input_.dtype,
                generator=generator,
            )
            * 0.1
        )
    return torch.where(mask_expanded, token_f, input_)

filter_padding

filter_padding(
    inputs: Mapping[str, Shaped[Tensor, "..."]],
    input_columns: Mapping[str, FlexDmColumnSpec],
    mask: Bool[Tensor, "batch elements"],
) -> dict[str, Shaped[torch.Tensor, "..."]]

Replace padded and conditionally invalid fields with model unused tokens.

Source code in models/flex-dm/src/flex_dm/masking.py
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
def filter_padding(
    inputs: Mapping[str, Shaped[torch.Tensor, "..."]],
    input_columns: Mapping[str, FlexDmColumnSpec],
    mask: Bool[torch.Tensor, "batch elements"],
) -> dict[str, Shaped[torch.Tensor, "..."]]:
    """Replace padded and conditionally invalid fields with model unused tokens."""
    modified: dict[str, Shaped[torch.Tensor, "..."]] = {}
    unused_mask = ~mask

    for key, column in input_columns.items():
        input_ = inputs[key]
        if not column["is_sequence"]:
            modified[key] = input_
            continue

        mask_ = unused_mask
        cond = column.get("loss_condition")
        if cond is not None:
            type_values = inputs[cond["key"]].squeeze(-1)
            invalid = torch.zeros_like(unused_mask)
            for idx, flag in enumerate(cond["mask"]):
                if not flag:
                    invalid = invalid | (type_values == idx)
            mask_ = mask_ | invalid

        modified[key] = apply_token(input_, column, mask_, "unused")
    return modified

build_feature_masks

build_feature_masks(
    input_columns: Mapping[str, FlexDmColumnSpec],
    seq_mask: Bool[Tensor, "batch elements"],
    *,
    condition_type: ConditionType,
    feature_group: str | None = None,
    target_indices: Int[Tensor, "..."] | None = None,
) -> dict[str, Bool[torch.Tensor, "..."]]

Create explicit masks for Flex-DM completion/refinement tasks.

Source code in models/flex-dm/src/flex_dm/masking.py
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
def build_feature_masks(
    input_columns: Mapping[str, FlexDmColumnSpec],
    seq_mask: Bool[torch.Tensor, "batch elements"],
    *,
    condition_type: ConditionType,
    feature_group: str | None = None,
    target_indices: Int[torch.Tensor, "..."] | None = None,
) -> dict[str, Bool[torch.Tensor, "..."]]:
    """Create explicit masks for Flex-DM completion/refinement tasks."""
    _ = condition_type
    masks = get_initial_masks(input_columns, seq_mask)
    if feature_group is None or feature_group == "random":
        return masks
    if feature_group == "elem":
        if target_indices is None:
            target_indices = torch.zeros(
                seq_mask.size(0), dtype=torch.long, device=seq_mask.device
            )
        selected = torch.zeros_like(seq_mask)
        selected.scatter_(1, target_indices.reshape(-1, 1), True)
        selected = selected & seq_mask
        for key, column in input_columns.items():
            if column["is_sequence"]:
                masks[key] = selected
        return masks
    group_keys = {
        "type": ("type",),
        "pos": ("left", "top", "width", "height"),
        "attr": ("opacity", "color", "font_family", "clickable", "icon", "text_button"),
        "img": ("image_embedding",),
        "txt": ("text_embedding",),
    }.get(feature_group)
    if group_keys is None:
        raise ValueError(f"Unsupported Flex-DM feature_group: {feature_group}")

    for key in group_keys:
        if key in masks:
            masks[key] = seq_mask.clone()
    return masks

iterative_decode

iterative_decode(
    model: _DecodeModel,
    *,
    inputs: dict[str, Shaped[Tensor, "..."]],
    masks: dict[str, Bool[Tensor, "..."]],
    num_iter: int,
    input_columns: Mapping[str, FlexDmColumnSpec],
    source_inputs: Mapping[str, Shaped[Tensor, "..."]]
    | None = None,
) -> _MutableLogitsOutput

Run a deterministic MaskGIT-like categorical decode loop.

Parameters:

Name Type Description Default
model _DecodeModel

Flex-DM model object with a forward method.

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

Current model inputs.

required
masks dict[str, Bool[Tensor, '...']]

Per-column masks where True means hidden.

required
num_iter int

Number of decode iterations.

required
input_columns Mapping[str, FlexDmColumnSpec]

Model column definitions.

required
source_inputs Mapping[str, Shaped[Tensor, '...']] | None

Unmasked source inputs used for confidence-commit updates.

None

Returns:

Type Description
_MutableLogitsOutput

The final model output.

Source code in models/flex-dm/src/flex_dm/masking.py
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
def iterative_decode(
    model: _DecodeModel,
    *,
    inputs: dict[str, Shaped[torch.Tensor, "..."]],
    masks: dict[str, Bool[torch.Tensor, "..."]],
    num_iter: int,
    input_columns: Mapping[str, FlexDmColumnSpec],
    source_inputs: Mapping[str, Shaped[torch.Tensor, "..."]] | None = None,
) -> _MutableLogitsOutput:
    """Run a deterministic MaskGIT-like categorical decode loop.

    Args:
        model: Flex-DM model object with a ``forward`` method.
        inputs: Current model inputs.
        masks: Per-column masks where ``True`` means hidden.
        num_iter: Number of decode iterations.
        input_columns: Model column definitions.
        source_inputs: Unmasked source inputs used for confidence-commit updates.

    Returns:
        The final model output.
    """
    if num_iter <= 0:
        raise ValueError("num_iter must be positive")

    output = None
    current_inputs = dict(inputs)
    current_masks = dict(masks)
    original_inputs = source_inputs or inputs
    first_key = next(
        key for key, column in input_columns.items() if column["is_sequence"]
    )
    seq_mask = get_seq_mask(
        original_inputs["length"].reshape(-1),
        maxlen=original_inputs[first_key].shape[1],
    )
    filtered_inputs = filter_padding(original_inputs, input_columns, seq_mask)
    categorical_keys = [
        key
        for key, column in input_columns.items()
        if column["is_sequence"] and column["type"] == "categorical"
    ]
    masked_counts = sum(
        current_masks[key].detach().cpu().numpy().astype("int").sum(-1)
        for key in categorical_keys
    )
    updates_per_iter = (masked_counts / num_iter).round().astype("int")
    final_logits: dict[str, Shaped[torch.Tensor, "..."]] | None = None
    for index in range(num_iter):
        output = model(inputs=current_inputs, masks=current_masks, return_dict=True)
        logits = output.logits
        if index == 0:
            final_logits = dict(logits)
        confidence = {
            key: torch.where(
                current_masks[key],
                torch.softmax(logits[key], dim=-1).amax(dim=-1).mean(dim=-1),
                torch.zeros_like(current_masks[key], dtype=logits[key].dtype),
            )
            for key in categorical_keys
            if key in logits
        }
        if confidence:
            confidence_sorted = torch.sort(
                torch.cat([confidence[key] for key in confidence], dim=-1),
                dim=-1,
                descending=True,
            ).values
            threshold = torch.stack(
                [
                    confidence_sorted[row, int(update_count)]
                    for row, update_count in enumerate(updates_per_iter)
                ]
            )
            for key in confidence:
                pred = logits[key].argmax(dim=-1)
                update_field = (confidence[key] >= threshold) & (confidence[key] > 0)
                filtered_inputs[key] = torch.where(
                    update_field.unsqueeze(-1),
                    pred,
                    filtered_inputs[key],
                )
                current_masks[key] = torch.where(
                    current_masks[key] == update_field,
                    torch.zeros_like(current_masks[key]),
                    current_masks[key],
                )
                if index > 0 and final_logits is not None:
                    final_logits[key] = torch.where(
                        update_field[:, :, None, None],
                        logits[key],
                        final_logits[key],
                    )
            for key, column in input_columns.items():
                if column["is_sequence"]:
                    current_inputs[key] = apply_token(
                        filtered_inputs[key],
                        column,
                        current_masks[key],
                        "masked",
                    )
    if output is None:
        raise ValueError("num_iter must be positive")

    if final_logits is not None:
        output_any = output
        for key in ("image_embedding", "text_embedding"):
            if key in output_any.logits:
                final_logits[key] = output_any.logits[key]
        output_any.logits = final_logits
        output_any["logits"] = final_logits
    return output

modeling_flex_dm

PyTorch model classes for Flex-DM masked document modeling.

FlexDmModelOutput dataclass

Bases: ModelOutput

Output of FlexDmForMaskedDocumentModeling.

Parameters:

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

Per-column logits or numerical predictions.

required
loss Float[Tensor, ''] | None

Optional summed reconstruction loss.

None
hidden_states Float[Tensor, 'batch seq channels'] | None

Optional final hidden states.

None
masks dict[str, Bool[Tensor, '...']] | None

Optional per-column hidden-field masks.

None
Source code in models/flex-dm/src/flex_dm/modeling_flex_dm.py
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
@dataclass
class FlexDmModelOutput(ModelOutput):
    """Output of ``FlexDmForMaskedDocumentModeling``.

    Args:
        logits: Per-column logits or numerical predictions.
        loss: Optional summed reconstruction loss.
        hidden_states: Optional final hidden states.
        masks: Optional per-column hidden-field masks.
    """

    logits: dict[str, Shaped[torch.Tensor, "..."]]
    loss: Float[torch.Tensor, ""] | None = None
    hidden_states: Float[torch.Tensor, "batch seq channels"] | None = None
    masks: dict[str, Bool[torch.Tensor, "..."]] | None = None

    def __post_init__(self) -> None:
        """Keep the logits dictionary as one ModelOutput field."""
        if self.logits is not None:
            self["logits"] = self.logits
        if self.loss is not None:
            self["loss"] = self.loss
        if self.hidden_states is not None:
            self["hidden_states"] = self.hidden_states
        if self.masks is not None:
            self["masks"] = self.masks

__post_init__

__post_init__() -> None

Keep the logits dictionary as one ModelOutput field.

Source code in models/flex-dm/src/flex_dm/modeling_flex_dm.py
35
36
37
38
39
40
41
42
43
44
def __post_init__(self) -> None:
    """Keep the logits dictionary as one ModelOutput field."""
    if self.logits is not None:
        self["logits"] = self.logits
    if self.loss is not None:
        self["loss"] = self.loss
    if self.hidden_states is not None:
        self["hidden_states"] = self.hidden_states
    if self.masks is not None:
        self["masks"] = self.masks

FlexDmPreTrainedModel

Bases: PreTrainedModel

Base class for Flex-DM Transformers models.

Source code in models/flex-dm/src/flex_dm/modeling_flex_dm.py
51
52
53
54
55
56
class FlexDmPreTrainedModel(PreTrainedModel):
    """Base class for Flex-DM Transformers models."""

    config_class = FlexDmConfig
    base_model_prefix = "flex_dm"
    supports_gradient_checkpointing = False

FlexDmInputEncoder

Bases: Module

Encode heterogeneous Flex-DM input columns into one hidden sequence.

Source code in models/flex-dm/src/flex_dm/modeling_flex_dm.py
 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
class FlexDmInputEncoder(nn.Module):
    """Encode heterogeneous Flex-DM input columns into one hidden sequence."""

    def __init__(self, config: FlexDmConfig) -> None:
        """Create per-column embeddings and projections."""
        super().__init__()
        self.config = config
        self.input_embeddings = nn.ModuleDict()
        self.input_projections = nn.ModuleDict()
        self.special_embeddings = nn.ModuleDict()
        for key, column in config.input_columns.items():
            if not column["is_sequence"]:
                continue
            if column["type"] == "categorical":
                input_dim = cast(int, column["input_dim"])
                self.input_embeddings[_module_key(key)] = nn.Embedding(
                    input_dim + 2,
                    config.latent_dim,
                )
            else:
                self.input_projections[_module_key(key)] = nn.Linear(
                    int(column["shape"][-1]),
                    config.latent_dim,
                )
                self.special_embeddings[_module_key(key)] = nn.Embedding(
                    2,
                    config.latent_dim,
                )
        self.task_embedding = (
            nn.Embedding(len(config.task_names), config.latent_dim)
            if config.context == "id"
            else None
        )
        self.length_embedding = (
            nn.Embedding(config.max_seq_length + 1, config.latent_dim)
            if config.context == "length"
            else None
        )
        self.position_embedding = (
            nn.Embedding(config.max_seq_length, config.latent_dim)
            if config.input_dtype != "set"
            else None
        )

    def forward(
        self,
        inputs: Mapping[str, Shaped[torch.Tensor, "..."]],
        *,
        task_ids: Int[torch.Tensor, "batch"] | None = None,
    ) -> tuple[
        Float[torch.Tensor, "batch seq channels"],
        Bool[torch.Tensor, "batch seq"],
    ]:
        """Encode model inputs.

        Args:
            inputs: Per-column tensors.
            task_ids: Optional task ids.

        Returns:
            Hidden sequence and valid-element mask.
        """
        first_key = self.config.valid_sequence_keys[0]
        batch, seq_len = inputs[first_key].shape[:2]
        device = inputs[first_key].device
        hidden = torch.zeros(
            batch,
            seq_len,
            self.config.latent_dim,
            device=device,
            dtype=torch.float32,
        )
        for key in self.config.valid_sequence_keys:
            column = self.config.input_columns[key]
            value = inputs[key].to(device)
            if column["type"] == "categorical":
                embedded = self.input_embeddings[_module_key(key)](value.long())
                if embedded.ndim == 4:
                    embedded = embedded.sum(dim=-2)
            else:
                projected = self.input_projections[_module_key(key)](value.float())
                masked = (value == 10.0).all(dim=-1)
                unused = (value == 0.0).all(dim=-1)
                special_ids = torch.zeros_like(masked, dtype=torch.long)
                special_ids = torch.where(
                    unused, torch.ones_like(special_ids), special_ids
                )
                special = self.special_embeddings[_module_key(key)](special_ids)
                embedded = torch.where(
                    (masked | unused).unsqueeze(-1), special, projected
                )
            hidden = hidden + embedded
        if self.position_embedding is not None:
            positions = torch.arange(seq_len, device=device).clamp(
                max=self.config.max_seq_length - 1
            )
            hidden = hidden + self.position_embedding(positions).unsqueeze(0)
        if self.task_embedding is not None and task_ids is not None:
            hidden = hidden + self.task_embedding(task_ids.to(device)).unsqueeze(1)
        if self.length_embedding is not None and "length" in inputs:
            length_ids = (
                inputs["length"]
                .reshape(batch)
                .long()
                .clamp(
                    min=0,
                    max=self.config.max_seq_length,
                )
            )
            hidden = hidden + self.length_embedding(length_ids).unsqueeze(1)
        if "length" in inputs:
            from .masking import get_seq_mask

            seq_mask = get_seq_mask(
                inputs["length"].reshape(batch).long(),
                maxlen=seq_len,
            )
        else:
            seq_mask = torch.ones(batch, seq_len, dtype=torch.bool, device=device)
        return hidden, seq_mask

__init__

__init__(config: FlexDmConfig) -> None

Create per-column embeddings and projections.

Source code in models/flex-dm/src/flex_dm/modeling_flex_dm.py
 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
def __init__(self, config: FlexDmConfig) -> None:
    """Create per-column embeddings and projections."""
    super().__init__()
    self.config = config
    self.input_embeddings = nn.ModuleDict()
    self.input_projections = nn.ModuleDict()
    self.special_embeddings = nn.ModuleDict()
    for key, column in config.input_columns.items():
        if not column["is_sequence"]:
            continue
        if column["type"] == "categorical":
            input_dim = cast(int, column["input_dim"])
            self.input_embeddings[_module_key(key)] = nn.Embedding(
                input_dim + 2,
                config.latent_dim,
            )
        else:
            self.input_projections[_module_key(key)] = nn.Linear(
                int(column["shape"][-1]),
                config.latent_dim,
            )
            self.special_embeddings[_module_key(key)] = nn.Embedding(
                2,
                config.latent_dim,
            )
    self.task_embedding = (
        nn.Embedding(len(config.task_names), config.latent_dim)
        if config.context == "id"
        else None
    )
    self.length_embedding = (
        nn.Embedding(config.max_seq_length + 1, config.latent_dim)
        if config.context == "length"
        else None
    )
    self.position_embedding = (
        nn.Embedding(config.max_seq_length, config.latent_dim)
        if config.input_dtype != "set"
        else None
    )

forward

forward(
    inputs: Mapping[str, Shaped[Tensor, "..."]],
    *,
    task_ids: Int[Tensor, "batch"] | None = None,
) -> tuple[
    Float[torch.Tensor, "batch seq channels"],
    Bool[torch.Tensor, "batch seq"],
]

Encode model inputs.

Parameters:

Name Type Description Default
inputs Mapping[str, Shaped[Tensor, '...']]

Per-column tensors.

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

Optional task ids.

None

Returns:

Type Description
tuple[Float[Tensor, 'batch seq channels'], Bool[Tensor, 'batch seq']]

Hidden sequence and valid-element mask.

Source code in models/flex-dm/src/flex_dm/modeling_flex_dm.py
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
def forward(
    self,
    inputs: Mapping[str, Shaped[torch.Tensor, "..."]],
    *,
    task_ids: Int[torch.Tensor, "batch"] | None = None,
) -> tuple[
    Float[torch.Tensor, "batch seq channels"],
    Bool[torch.Tensor, "batch seq"],
]:
    """Encode model inputs.

    Args:
        inputs: Per-column tensors.
        task_ids: Optional task ids.

    Returns:
        Hidden sequence and valid-element mask.
    """
    first_key = self.config.valid_sequence_keys[0]
    batch, seq_len = inputs[first_key].shape[:2]
    device = inputs[first_key].device
    hidden = torch.zeros(
        batch,
        seq_len,
        self.config.latent_dim,
        device=device,
        dtype=torch.float32,
    )
    for key in self.config.valid_sequence_keys:
        column = self.config.input_columns[key]
        value = inputs[key].to(device)
        if column["type"] == "categorical":
            embedded = self.input_embeddings[_module_key(key)](value.long())
            if embedded.ndim == 4:
                embedded = embedded.sum(dim=-2)
        else:
            projected = self.input_projections[_module_key(key)](value.float())
            masked = (value == 10.0).all(dim=-1)
            unused = (value == 0.0).all(dim=-1)
            special_ids = torch.zeros_like(masked, dtype=torch.long)
            special_ids = torch.where(
                unused, torch.ones_like(special_ids), special_ids
            )
            special = self.special_embeddings[_module_key(key)](special_ids)
            embedded = torch.where(
                (masked | unused).unsqueeze(-1), special, projected
            )
        hidden = hidden + embedded
    if self.position_embedding is not None:
        positions = torch.arange(seq_len, device=device).clamp(
            max=self.config.max_seq_length - 1
        )
        hidden = hidden + self.position_embedding(positions).unsqueeze(0)
    if self.task_embedding is not None and task_ids is not None:
        hidden = hidden + self.task_embedding(task_ids.to(device)).unsqueeze(1)
    if self.length_embedding is not None and "length" in inputs:
        length_ids = (
            inputs["length"]
            .reshape(batch)
            .long()
            .clamp(
                min=0,
                max=self.config.max_seq_length,
            )
        )
        hidden = hidden + self.length_embedding(length_ids).unsqueeze(1)
    if "length" in inputs:
        from .masking import get_seq_mask

        seq_mask = get_seq_mask(
            inputs["length"].reshape(batch).long(),
            maxlen=seq_len,
        )
    else:
        seq_mask = torch.ones(batch, seq_len, dtype=torch.bool, device=device)
    return hidden, seq_mask

FlexDmMultiHeadSelfAttention

Bases: Module

Explicit explicit multi-head self-attention.

Source code in models/flex-dm/src/flex_dm/modeling_flex_dm.py
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
class FlexDmMultiHeadSelfAttention(nn.Module):
    """Explicit explicit multi-head self-attention."""

    def __init__(self, hidden_size: int, num_heads: int = 8) -> None:
        """Create attention projections."""
        super().__init__()
        if hidden_size % num_heads:
            raise ValueError("hidden_size must be divisible by num_heads")

        self.num_heads = num_heads
        self.head_dim = hidden_size // num_heads
        self.q_proj = nn.Linear(hidden_size, hidden_size)
        self.k_proj = nn.Linear(hidden_size, hidden_size)
        self.v_proj = nn.Linear(hidden_size, hidden_size)
        self.out_proj = nn.Linear(hidden_size, hidden_size)

    def _split(
        self, x: Float[torch.Tensor, "batch seq channels"]
    ) -> Float[torch.Tensor, "batch heads seq head_dim"]:
        batch, seq_len, hidden = x.shape
        return x.view(
            batch, seq_len, self.num_heads, hidden // self.num_heads
        ).transpose(1, 2)

    def forward(
        self,
        hidden_states: Float[torch.Tensor, "batch seq channels"],
        attention_mask: Bool[torch.Tensor, "batch seq"],
    ) -> Float[torch.Tensor, "batch seq channels"]:
        """Apply self-attention using an additive ``-1e9`` padding mask."""
        query = self._split(self.q_proj(hidden_states))
        key = self._split(self.k_proj(hidden_states))
        value = self._split(self.v_proj(hidden_states))
        scores = torch.matmul(query, key.transpose(-2, -1)) / (self.head_dim**0.5)
        additive = (~attention_mask).to(scores.device).unsqueeze(1).unsqueeze(2)
        scores = scores.masked_fill(additive, -1e9)
        weights = scores.softmax(dim=-1)
        context = torch.matmul(weights, value).transpose(1, 2).contiguous()
        batch, seq_len = hidden_states.shape[:2]
        context = context.view(batch, seq_len, self.num_heads * self.head_dim)
        return self.out_proj(context)

__init__

__init__(hidden_size: int, num_heads: int = 8) -> None

Create attention projections.

Source code in models/flex-dm/src/flex_dm/modeling_flex_dm.py
184
185
186
187
188
189
190
191
192
193
194
195
def __init__(self, hidden_size: int, num_heads: int = 8) -> None:
    """Create attention projections."""
    super().__init__()
    if hidden_size % num_heads:
        raise ValueError("hidden_size must be divisible by num_heads")

    self.num_heads = num_heads
    self.head_dim = hidden_size // num_heads
    self.q_proj = nn.Linear(hidden_size, hidden_size)
    self.k_proj = nn.Linear(hidden_size, hidden_size)
    self.v_proj = nn.Linear(hidden_size, hidden_size)
    self.out_proj = nn.Linear(hidden_size, hidden_size)

forward

forward(
    hidden_states: Float[Tensor, "batch seq channels"],
    attention_mask: Bool[Tensor, "batch seq"],
) -> Float[torch.Tensor, "batch seq channels"]

Apply self-attention using an additive -1e9 padding mask.

Source code in models/flex-dm/src/flex_dm/modeling_flex_dm.py
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
def forward(
    self,
    hidden_states: Float[torch.Tensor, "batch seq channels"],
    attention_mask: Bool[torch.Tensor, "batch seq"],
) -> Float[torch.Tensor, "batch seq channels"]:
    """Apply self-attention using an additive ``-1e9`` padding mask."""
    query = self._split(self.q_proj(hidden_states))
    key = self._split(self.k_proj(hidden_states))
    value = self._split(self.v_proj(hidden_states))
    scores = torch.matmul(query, key.transpose(-2, -1)) / (self.head_dim**0.5)
    additive = (~attention_mask).to(scores.device).unsqueeze(1).unsqueeze(2)
    scores = scores.masked_fill(additive, -1e9)
    weights = scores.softmax(dim=-1)
    context = torch.matmul(weights, value).transpose(1, 2).contiguous()
    batch, seq_len = hidden_states.shape[:2]
    context = context.view(batch, seq_len, self.num_heads * self.head_dim)
    return self.out_proj(context)

FlexDmDeepSvgBlock

Bases: Module

DeepSVG-style pre-norm transformer block.

Source code in models/flex-dm/src/flex_dm/modeling_flex_dm.py
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
class FlexDmDeepSvgBlock(nn.Module):
    """DeepSVG-style pre-norm transformer block."""

    def __init__(self, config: FlexDmConfig) -> None:
        """Create one transformer block."""
        super().__init__()
        self.norm1 = nn.LayerNorm(config.latent_dim, eps=config.layer_norm_epsilon)
        self.attention = FlexDmMultiHeadSelfAttention(config.latent_dim)
        self.norm2 = nn.LayerNorm(config.latent_dim, eps=config.layer_norm_epsilon)
        self.mlp = nn.Sequential(
            nn.Linear(config.latent_dim, config.latent_dim * 2),
            nn.ReLU(),
            nn.Linear(config.latent_dim * 2, config.latent_dim),
        )
        self.dropout = nn.Dropout(config.dropout)

    def forward(
        self,
        hidden_states: Float[torch.Tensor, "batch seq channels"],
        attention_mask: Bool[torch.Tensor, "batch seq"],
    ) -> Float[torch.Tensor, "batch seq channels"]:
        """Apply pre-norm attention and MLP residuals."""
        hidden_states = hidden_states + self.dropout(
            self.attention(self.norm1(hidden_states), attention_mask)
        )
        return hidden_states + self.dropout(self.mlp(self.norm2(hidden_states)))

__init__

__init__(config: FlexDmConfig) -> None

Create one transformer block.

Source code in models/flex-dm/src/flex_dm/modeling_flex_dm.py
227
228
229
230
231
232
233
234
235
236
237
238
def __init__(self, config: FlexDmConfig) -> None:
    """Create one transformer block."""
    super().__init__()
    self.norm1 = nn.LayerNorm(config.latent_dim, eps=config.layer_norm_epsilon)
    self.attention = FlexDmMultiHeadSelfAttention(config.latent_dim)
    self.norm2 = nn.LayerNorm(config.latent_dim, eps=config.layer_norm_epsilon)
    self.mlp = nn.Sequential(
        nn.Linear(config.latent_dim, config.latent_dim * 2),
        nn.ReLU(),
        nn.Linear(config.latent_dim * 2, config.latent_dim),
    )
    self.dropout = nn.Dropout(config.dropout)

forward

forward(
    hidden_states: Float[Tensor, "batch seq channels"],
    attention_mask: Bool[Tensor, "batch seq"],
) -> Float[torch.Tensor, "batch seq channels"]

Apply pre-norm attention and MLP residuals.

Source code in models/flex-dm/src/flex_dm/modeling_flex_dm.py
240
241
242
243
244
245
246
247
248
249
def forward(
    self,
    hidden_states: Float[torch.Tensor, "batch seq channels"],
    attention_mask: Bool[torch.Tensor, "batch seq"],
) -> Float[torch.Tensor, "batch seq channels"]:
    """Apply pre-norm attention and MLP residuals."""
    hidden_states = hidden_states + self.dropout(
        self.attention(self.norm1(hidden_states), attention_mask)
    )
    return hidden_states + self.dropout(self.mlp(self.norm2(hidden_states)))

FlexDmDecoder

Bases: Module

Decode hidden states into one head per model column.

Source code in models/flex-dm/src/flex_dm/modeling_flex_dm.py
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
class FlexDmDecoder(nn.Module):
    """Decode hidden states into one head per model column."""

    def __init__(self, config: FlexDmConfig) -> None:
        """Create per-column output heads."""
        super().__init__()
        self.config = config
        self.heads = nn.ModuleDict()
        for key in config.valid_sequence_keys:
            column = config.input_columns[key]
            units = int(column["shape"][-1])
            if column["type"] == "categorical":
                units *= cast(int, column["input_dim"])
            self.heads[_module_key(key)] = nn.Linear(config.latent_dim, units)

    def forward(
        self, hidden_states: Float[torch.Tensor, "batch seq channels"]
    ) -> dict[str, Shaped[torch.Tensor, "..."]]:
        """Return per-column logits and predictions."""
        outputs: dict[str, Shaped[torch.Tensor, "..."]] = {}
        for key in self.config.valid_sequence_keys:
            head = self.heads[_module_key(key)]
            column = self.config.input_columns[key]
            raw = head(hidden_states)
            if column["type"] == "categorical":
                shape_dim = int(column["shape"][-1])
                input_dim = cast(int, column["input_dim"])
                outputs[key] = raw.view(*raw.shape[:2], shape_dim, input_dim)
            else:
                outputs[key] = raw.view(*raw.shape[:2], int(column["shape"][-1]))
        return outputs

__init__

__init__(config: FlexDmConfig) -> None

Create per-column output heads.

Source code in models/flex-dm/src/flex_dm/modeling_flex_dm.py
255
256
257
258
259
260
261
262
263
264
265
def __init__(self, config: FlexDmConfig) -> None:
    """Create per-column output heads."""
    super().__init__()
    self.config = config
    self.heads = nn.ModuleDict()
    for key in config.valid_sequence_keys:
        column = config.input_columns[key]
        units = int(column["shape"][-1])
        if column["type"] == "categorical":
            units *= cast(int, column["input_dim"])
        self.heads[_module_key(key)] = nn.Linear(config.latent_dim, units)

forward

forward(
    hidden_states: Float[Tensor, "batch seq channels"],
) -> dict[str, Shaped[torch.Tensor, "..."]]

Return per-column logits and predictions.

Source code in models/flex-dm/src/flex_dm/modeling_flex_dm.py
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
def forward(
    self, hidden_states: Float[torch.Tensor, "batch seq channels"]
) -> dict[str, Shaped[torch.Tensor, "..."]]:
    """Return per-column logits and predictions."""
    outputs: dict[str, Shaped[torch.Tensor, "..."]] = {}
    for key in self.config.valid_sequence_keys:
        head = self.heads[_module_key(key)]
        column = self.config.input_columns[key]
        raw = head(hidden_states)
        if column["type"] == "categorical":
            shape_dim = int(column["shape"][-1])
            input_dim = cast(int, column["input_dim"])
            outputs[key] = raw.view(*raw.shape[:2], shape_dim, input_dim)
        else:
            outputs[key] = raw.view(*raw.shape[:2], int(column["shape"][-1]))
    return outputs

FlexDmForMaskedDocumentModeling

Bases: FlexDmPreTrainedModel

Flex-DM MFP model with a standard Transformers forward method.

Source code in models/flex-dm/src/flex_dm/modeling_flex_dm.py
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
class FlexDmForMaskedDocumentModeling(FlexDmPreTrainedModel):
    """Flex-DM MFP model with a standard Transformers ``forward`` method."""

    def __init__(self, config: FlexDmConfig) -> None:
        """Initialize encoder, transformer blocks, and decoder."""
        super().__init__(config)
        if config.arch_type != "oneshot":
            raise ValueError("Only arch_type='oneshot' is supported")

        if config.block_type != "deepsvg":
            raise ValueError("Only block_type='deepsvg' is supported")

        self.encoder = FlexDmInputEncoder(config)
        self.blocks = nn.ModuleList(
            [FlexDmDeepSvgBlock(config) for _ in range(config.num_blocks)]
        )
        self.decoder = FlexDmDecoder(config)
        self.post_init()

    def forward(
        self,
        *,
        inputs: Mapping[str, Shaped[torch.Tensor, "..."]],
        masks: Mapping[str, Bool[torch.Tensor, "..."]] | None = None,
        labels: Mapping[str, Shaped[torch.Tensor, "..."]] | None = None,
        task_ids: Int[torch.Tensor, "batch"] | None = None,
        output_hidden_states: bool = False,
        return_dict: bool | None = None,
    ) -> (
        FlexDmModelOutput
        | tuple[dict[str, Shaped[torch.Tensor, "..."]], Float[torch.Tensor, ""] | None]
    ):
        """Run a Flex-DM forward pass.

        Args:
            inputs: Per-column model input tensors.
            masks: Optional hidden-field masks for diagnostics.
            labels: Optional per-column reconstruction targets.
            task_ids: Optional task ids.
            output_hidden_states: Whether to include final hidden states.
            return_dict: Whether to return a ``ModelOutput``.

        Returns:
            ``FlexDmModelOutput`` by default.
        """
        hidden_states, seq_mask = self.encoder(inputs, task_ids=task_ids)
        for block in self.blocks:
            hidden_states = block(hidden_states, seq_mask)
        logits = self.decoder(hidden_states)
        loss = self._compute_loss(logits, labels) if labels is not None else None
        output = FlexDmModelOutput(
            logits=logits,
            loss=loss,
            hidden_states=hidden_states if output_hidden_states else None,
            masks=dict(masks) if masks is not None else None,
        )
        if return_dict is False:
            return logits, loss
        return output

    def _compute_loss(
        self,
        logits: Mapping[str, Shaped[torch.Tensor, "..."]],
        labels: Mapping[str, Shaped[torch.Tensor, "..."]],
    ) -> Float[torch.Tensor, ""]:
        losses: list[Float[torch.Tensor, ""]] = []
        for key, target in labels.items():
            if key not in logits:
                continue
            column: FlexDmColumnSpec = self.config.input_columns[key]
            pred = logits[key]
            if column["type"] == "categorical":
                vocab = cast(int, column["input_dim"])
                losses.append(
                    F.cross_entropy(pred.view(-1, vocab), target.long().view(-1))
                )
            else:
                losses.append(F.mse_loss(pred, target.float()))
        if not losses:
            return torch.tensor(0.0, device=next(self.parameters()).device)
        return torch.stack(losses).sum()

__init__

__init__(config: FlexDmConfig) -> None

Initialize encoder, transformer blocks, and decoder.

Source code in models/flex-dm/src/flex_dm/modeling_flex_dm.py
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
def __init__(self, config: FlexDmConfig) -> None:
    """Initialize encoder, transformer blocks, and decoder."""
    super().__init__(config)
    if config.arch_type != "oneshot":
        raise ValueError("Only arch_type='oneshot' is supported")

    if config.block_type != "deepsvg":
        raise ValueError("Only block_type='deepsvg' is supported")

    self.encoder = FlexDmInputEncoder(config)
    self.blocks = nn.ModuleList(
        [FlexDmDeepSvgBlock(config) for _ in range(config.num_blocks)]
    )
    self.decoder = FlexDmDecoder(config)
    self.post_init()

forward

forward(
    *,
    inputs: Mapping[str, Shaped[Tensor, "..."]],
    masks: Mapping[str, Bool[Tensor, "..."]] | None = None,
    labels: Mapping[str, Shaped[Tensor, "..."]]
    | None = None,
    task_ids: Int[Tensor, "batch"] | None = None,
    output_hidden_states: bool = False,
    return_dict: bool | None = None,
) -> (
    FlexDmModelOutput
    | tuple[
        dict[str, Shaped[torch.Tensor, "..."]],
        Float[torch.Tensor, ""] | None,
    ]
)

Run a Flex-DM forward pass.

Parameters:

Name Type Description Default
inputs Mapping[str, Shaped[Tensor, '...']]

Per-column model input tensors.

required
masks Mapping[str, Bool[Tensor, '...']] | None

Optional hidden-field masks for diagnostics.

None
labels Mapping[str, Shaped[Tensor, '...']] | None

Optional per-column reconstruction targets.

None
task_ids Int[Tensor, 'batch'] | None

Optional task ids.

None
output_hidden_states bool

Whether to include final hidden states.

False
return_dict bool | None

Whether to return a ModelOutput.

None

Returns:

Type Description
FlexDmModelOutput | tuple[dict[str, Shaped[Tensor, '...']], Float[Tensor, ''] | None]

FlexDmModelOutput by default.

Source code in models/flex-dm/src/flex_dm/modeling_flex_dm.py
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
def forward(
    self,
    *,
    inputs: Mapping[str, Shaped[torch.Tensor, "..."]],
    masks: Mapping[str, Bool[torch.Tensor, "..."]] | None = None,
    labels: Mapping[str, Shaped[torch.Tensor, "..."]] | None = None,
    task_ids: Int[torch.Tensor, "batch"] | None = None,
    output_hidden_states: bool = False,
    return_dict: bool | None = None,
) -> (
    FlexDmModelOutput
    | tuple[dict[str, Shaped[torch.Tensor, "..."]], Float[torch.Tensor, ""] | None]
):
    """Run a Flex-DM forward pass.

    Args:
        inputs: Per-column model input tensors.
        masks: Optional hidden-field masks for diagnostics.
        labels: Optional per-column reconstruction targets.
        task_ids: Optional task ids.
        output_hidden_states: Whether to include final hidden states.
        return_dict: Whether to return a ``ModelOutput``.

    Returns:
        ``FlexDmModelOutput`` by default.
    """
    hidden_states, seq_mask = self.encoder(inputs, task_ids=task_ids)
    for block in self.blocks:
        hidden_states = block(hidden_states, seq_mask)
    logits = self.decoder(hidden_states)
    loss = self._compute_loss(logits, labels) if labels is not None else None
    output = FlexDmModelOutput(
        logits=logits,
        loss=loss,
        hidden_states=hidden_states if output_hidden_states else None,
        masks=dict(masks) if masks is not None else None,
    )
    if return_dict is False:
        return logits, loss
    return output

pipeline_flex_dm

Transformers-side pipeline for Flex-DM infilling.

FlexDmPipelineComponent

Bases: Protocol

Runtime-checkable loaded pipeline component marker.

Source code in models/flex-dm/src/flex_dm/pipeline_flex_dm.py
27
28
29
@runtime_checkable
class FlexDmPipelineComponent(Protocol):
    """Runtime-checkable loaded pipeline component marker."""

FlexDmPipeline

Bases: LayoutGenerationPipeline

Run Flex-DM completion, refinement, and feature-level content infilling.

Source code in models/flex-dm/src/flex_dm/pipeline_flex_dm.py
 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
class FlexDmPipeline(LayoutGenerationPipeline):
    """Run Flex-DM completion, refinement, and feature-level content infilling."""

    config_class: ClassVar[type[PretrainedConfig]] = FlexDmConfig
    component_specs: ClassVar = model_processor_component_specs(
        model_loader=_load_model_component,
        processor_loader=_load_processor_component,
    )

    config: FlexDmConfig
    model: FlexDmForMaskedDocumentModeling
    processor: FlexDmProcessor

    def __init__(
        self,
        model: FlexDmForMaskedDocumentModeling,
        processor: FlexDmProcessor | None = None,
        config: FlexDmConfig | None = None,
    ) -> None:
        """Initialize model and processor components."""
        super().__init__(config or model.config)
        self.config = config or model.config
        self.model = model
        self.processor = processor or FlexDmProcessor.from_config(self.config)

    @classmethod
    def _from_pretrained_components(
        cls,
        *,
        config: PretrainedConfig,
        components: Mapping[str, FlexDmPipelineComponent | None],
    ) -> "FlexDmPipeline":
        """Build a pipeline from loaded model and processor components."""
        return cls(
            config=cast(FlexDmConfig, config),
            model=cast(FlexDmForMaskedDocumentModeling, components["model"]),
            processor=cast(FlexDmProcessor, components["processor"]),
        )

    @torch.no_grad()
    def __call__(  # ty: ignore[invalid-method-override]
        self,
        *,
        batch_size: int = 1,
        seed: int | None = None,
        generator: torch.Generator | None = None,
        condition_type: ConditionType | str = ConditionType.completion,
        labels: Int[torch.Tensor, "batch elements"]
        | Int[np.ndarray, "batch elements"]
        | Sequence[ArrayLikeInput]
        | None = None,
        bbox: Float[torch.Tensor, "batch elements 4"]
        | Float[np.ndarray, "batch elements 4"]
        | Sequence[ArrayLikeInput]
        | None = None,
        mask: Bool[torch.Tensor, "batch elements"]
        | Bool[np.ndarray, "batch elements"]
        | Sequence[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,
        output_type: Literal["dataclass", "dict"] = "dataclass",
        return_intermediates: bool = False,
        attributes: Mapping[str, FlexDmValue] | None = None,
        content: Mapping[str, FlexDmValue] | None = None,
        feature_group: str | None = None,
        target_indices: Int[torch.Tensor, "..."] | None = None,
        **model_kwargs: FlexDmValue,
    ) -> (
        LayoutGenerationOutput
        | dict[
            str,
            Shaped[torch.Tensor, "..."]
            | dict[int, str]
            | Mapping[str, Shaped[torch.Tensor, "..."]]
            | None,
        ]
    ):
        """Infills masked Flex-DM document fields.

        Args:
            batch_size: Batch size used when synthetic empty inputs are created.
            seed: Common API compatibility argument. Flex-DM's public inference
                path is deterministic and does not currently consume randomness.
            generator: Common API compatibility argument. When supplied, it
                takes precedence over ``seed``; the deterministic Flex-DM
                inference path does not currently consume it.
            condition_type: Canonical condition or local task alias.
            labels: Public element labels.
            bbox: Public element boxes.
            mask: Public valid-element mask.
            num_elements: Optional element counts for synthetic inputs.
            box_format: Input box coordinate format.
            normalized: Whether input boxes are already normalized.
            canvas_size: Pixel canvas size when ``normalized=False``.
            num_inference_steps: Number of iterative decode steps.
            output_type: ``dataclass`` or ``dict``.
            return_intermediates: Whether to include logits and masks.
            attributes: Optional non-core document attributes.
            content: Optional Crello image/text embeddings.
            feature_group: Flex-DM task group such as ``pos`` or ``img``.
            target_indices: Optional element indexes for ``elem`` masking.
            model_kwargs: Reserved model keyword arguments.

        Returns:
            Common layout-generation output.

        Raises:
            NotImplementedError: If the requested canonical condition is not
                supported by released Flex-DM MFP checkpoints.
        """
        _ = model_kwargs
        model_device = next(self.model.parameters()).device
        if generator is None and seed is not None:
            generator = torch.Generator(device=model_device).manual_seed(seed)
        encoded = self.processor(
            condition_type=condition_type,
            labels=labels,
            bbox=bbox,
            mask=mask,
            num_elements=num_elements,
            box_format=box_format,
            normalized=normalized,
            canvas_size=canvas_size,
            attributes=attributes,
            content=content,
            feature_group=feature_group,
            target_indices=target_indices,
            batch_size=batch_size,
        )
        canonical = cast(ConditionType, encoded["condition_type"])
        feature = cast(str | None, encoded["feature_group"])
        self._validate_condition(canonical, feature)
        inputs = {
            key: value.to(model_device)
            for key, value in cast(
                dict[str, Shaped[torch.Tensor, "..."]], encoded["inputs"]
            ).items()
        }
        masks = {
            key: value.to(model_device)
            for key, value in cast(
                dict[str, Bool[torch.Tensor, "..."]], encoded["masks"]
            ).items()
        }
        masked_inputs = self._apply_masks(inputs, masks, generator=generator)
        was_training = self.model.training
        self.model.eval()
        try:
            if num_inference_steps is not None and num_inference_steps > 1:
                outputs = cast(
                    FlexDmModelOutput,
                    iterative_decode(
                        self.model,
                        inputs=masked_inputs,
                        masks=masks,
                        num_iter=num_inference_steps,
                        input_columns=self.config.input_columns,
                        source_inputs=inputs,
                    ),
                )
            else:
                outputs = self.model(
                    inputs=masked_inputs, masks=masks, return_dict=True
                )
        finally:
            self.model.train(was_training)
        return self.processor.post_process_document(
            outputs,
            original_inputs=inputs,
            masks=masks,
            output_type=output_type,
            return_intermediates=return_intermediates,
            refinement_input=inputs if canonical is ConditionType.refinement else None,
        )

    generate = __call__

    def _apply_masks(
        self,
        inputs: Mapping[str, Shaped[torch.Tensor, "..."]],
        masks: Mapping[str, Bool[torch.Tensor, "..."]],
        *,
        generator: torch.Generator | None,
    ) -> dict[str, Shaped[torch.Tensor, "..."]]:
        modified = dict(inputs)
        for key, mask in masks.items():
            if key not in self.config.input_columns:
                continue
            column = self.config.input_columns[key]
            if column["is_sequence"] and mask.ndim == 2 and mask.any():
                modified[key] = apply_token(
                    modified[key],
                    column,
                    mask,
                    "masked",
                    generator=generator,
                )
        return modified

    def _validate_condition(
        self,
        condition_type: ConditionType,
        feature_group: str | None,
    ) -> None:
        if condition_type in {ConditionType.completion, ConditionType.refinement}:
            return
        if condition_type is ConditionType.content_image and feature_group in {
            "img",
            "txt",
        }:
            return
        if condition_type is ConditionType.label:
            raise NotImplementedError(
                "Flex-DM has no standalone label-conditioned mode; use "
                'condition_type="completion", feature_group="type".'
            )

        if condition_type is ConditionType.label_size:
            raise NotImplementedError("Flex-DM does not support label_size generation")

        if condition_type is ConditionType.unconditional:
            raise NotImplementedError(
                "Flex-DM released MFP checkpoints require an input document"
            )

        raise NotImplementedError(
            f"Flex-DM does not support condition_type={condition_type}"
        )

__init__

__init__(
    model: FlexDmForMaskedDocumentModeling,
    processor: FlexDmProcessor | None = None,
    config: FlexDmConfig | None = None,
) -> None

Initialize model and processor components.

Source code in models/flex-dm/src/flex_dm/pipeline_flex_dm.py
81
82
83
84
85
86
87
88
89
90
91
def __init__(
    self,
    model: FlexDmForMaskedDocumentModeling,
    processor: FlexDmProcessor | None = None,
    config: FlexDmConfig | None = None,
) -> None:
    """Initialize model and processor components."""
    super().__init__(config or model.config)
    self.config = config or model.config
    self.model = model
    self.processor = processor or FlexDmProcessor.from_config(self.config)

__call__

__call__(
    *,
    batch_size: int = 1,
    seed: int | None = None,
    generator: Generator | None = None,
    condition_type: ConditionType
    | str = ConditionType.completion,
    labels: Int[Tensor, "batch elements"]
    | Int[ndarray, "batch elements"]
    | Sequence[ArrayLikeInput]
    | None = None,
    bbox: Float[Tensor, "batch elements 4"]
    | Float[ndarray, "batch elements 4"]
    | Sequence[ArrayLikeInput]
    | None = None,
    mask: Bool[Tensor, "batch elements"]
    | Bool[ndarray, "batch elements"]
    | Sequence[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,
    output_type: Literal["dataclass", "dict"] = "dataclass",
    return_intermediates: bool = False,
    attributes: Mapping[str, FlexDmValue] | None = None,
    content: Mapping[str, FlexDmValue] | None = None,
    feature_group: str | None = None,
    target_indices: Int[Tensor, "..."] | None = None,
    **model_kwargs: FlexDmValue,
) -> (
    LayoutGenerationOutput
    | dict[
        str,
        Shaped[torch.Tensor, "..."]
        | dict[int, str]
        | Mapping[str, Shaped[torch.Tensor, "..."]]
        | None,
    ]
)

Infills masked Flex-DM document fields.

Parameters:

Name Type Description Default
batch_size int

Batch size used when synthetic empty inputs are created.

1
seed int | None

Common API compatibility argument. Flex-DM's public inference path is deterministic and does not currently consume randomness.

None
generator Generator | None

Common API compatibility argument. When supplied, it takes precedence over seed; the deterministic Flex-DM inference path does not currently consume it.

None
condition_type ConditionType | str

Canonical condition or local task alias.

completion
labels Int[Tensor, 'batch elements'] | Int[ndarray, 'batch elements'] | Sequence[ArrayLikeInput] | None

Public element labels.

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

Public element boxes.

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

Public valid-element mask.

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

Optional element counts for synthetic inputs.

None
box_format BoxFormat | str

Input box coordinate format.

xywh
normalized bool

Whether input boxes are already normalized.

True
canvas_size tuple[int, int] | None

Pixel canvas size when normalized=False.

None
num_inference_steps int | None

Number of iterative decode steps.

None
output_type Literal['dataclass', 'dict']

dataclass or dict.

'dataclass'
return_intermediates bool

Whether to include logits and masks.

False
attributes Mapping[str, FlexDmValue] | None

Optional non-core document attributes.

None
content Mapping[str, FlexDmValue] | None

Optional Crello image/text embeddings.

None
feature_group str | None

Flex-DM task group such as pos or img.

None
target_indices Int[Tensor, '...'] | None

Optional element indexes for elem masking.

None
model_kwargs FlexDmValue

Reserved model keyword arguments.

{}

Returns:

Type Description
LayoutGenerationOutput | dict[str, Shaped[Tensor, '...'] | dict[int, str] | Mapping[str, Shaped[Tensor, '...']] | None]

Common layout-generation output.

Raises:

Type Description
NotImplementedError

If the requested canonical condition is not supported by released Flex-DM MFP checkpoints.

Source code in models/flex-dm/src/flex_dm/pipeline_flex_dm.py
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
@torch.no_grad()
def __call__(  # ty: ignore[invalid-method-override]
    self,
    *,
    batch_size: int = 1,
    seed: int | None = None,
    generator: torch.Generator | None = None,
    condition_type: ConditionType | str = ConditionType.completion,
    labels: Int[torch.Tensor, "batch elements"]
    | Int[np.ndarray, "batch elements"]
    | Sequence[ArrayLikeInput]
    | None = None,
    bbox: Float[torch.Tensor, "batch elements 4"]
    | Float[np.ndarray, "batch elements 4"]
    | Sequence[ArrayLikeInput]
    | None = None,
    mask: Bool[torch.Tensor, "batch elements"]
    | Bool[np.ndarray, "batch elements"]
    | Sequence[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,
    output_type: Literal["dataclass", "dict"] = "dataclass",
    return_intermediates: bool = False,
    attributes: Mapping[str, FlexDmValue] | None = None,
    content: Mapping[str, FlexDmValue] | None = None,
    feature_group: str | None = None,
    target_indices: Int[torch.Tensor, "..."] | None = None,
    **model_kwargs: FlexDmValue,
) -> (
    LayoutGenerationOutput
    | dict[
        str,
        Shaped[torch.Tensor, "..."]
        | dict[int, str]
        | Mapping[str, Shaped[torch.Tensor, "..."]]
        | None,
    ]
):
    """Infills masked Flex-DM document fields.

    Args:
        batch_size: Batch size used when synthetic empty inputs are created.
        seed: Common API compatibility argument. Flex-DM's public inference
            path is deterministic and does not currently consume randomness.
        generator: Common API compatibility argument. When supplied, it
            takes precedence over ``seed``; the deterministic Flex-DM
            inference path does not currently consume it.
        condition_type: Canonical condition or local task alias.
        labels: Public element labels.
        bbox: Public element boxes.
        mask: Public valid-element mask.
        num_elements: Optional element counts for synthetic inputs.
        box_format: Input box coordinate format.
        normalized: Whether input boxes are already normalized.
        canvas_size: Pixel canvas size when ``normalized=False``.
        num_inference_steps: Number of iterative decode steps.
        output_type: ``dataclass`` or ``dict``.
        return_intermediates: Whether to include logits and masks.
        attributes: Optional non-core document attributes.
        content: Optional Crello image/text embeddings.
        feature_group: Flex-DM task group such as ``pos`` or ``img``.
        target_indices: Optional element indexes for ``elem`` masking.
        model_kwargs: Reserved model keyword arguments.

    Returns:
        Common layout-generation output.

    Raises:
        NotImplementedError: If the requested canonical condition is not
            supported by released Flex-DM MFP checkpoints.
    """
    _ = model_kwargs
    model_device = next(self.model.parameters()).device
    if generator is None and seed is not None:
        generator = torch.Generator(device=model_device).manual_seed(seed)
    encoded = self.processor(
        condition_type=condition_type,
        labels=labels,
        bbox=bbox,
        mask=mask,
        num_elements=num_elements,
        box_format=box_format,
        normalized=normalized,
        canvas_size=canvas_size,
        attributes=attributes,
        content=content,
        feature_group=feature_group,
        target_indices=target_indices,
        batch_size=batch_size,
    )
    canonical = cast(ConditionType, encoded["condition_type"])
    feature = cast(str | None, encoded["feature_group"])
    self._validate_condition(canonical, feature)
    inputs = {
        key: value.to(model_device)
        for key, value in cast(
            dict[str, Shaped[torch.Tensor, "..."]], encoded["inputs"]
        ).items()
    }
    masks = {
        key: value.to(model_device)
        for key, value in cast(
            dict[str, Bool[torch.Tensor, "..."]], encoded["masks"]
        ).items()
    }
    masked_inputs = self._apply_masks(inputs, masks, generator=generator)
    was_training = self.model.training
    self.model.eval()
    try:
        if num_inference_steps is not None and num_inference_steps > 1:
            outputs = cast(
                FlexDmModelOutput,
                iterative_decode(
                    self.model,
                    inputs=masked_inputs,
                    masks=masks,
                    num_iter=num_inference_steps,
                    input_columns=self.config.input_columns,
                    source_inputs=inputs,
                ),
            )
        else:
            outputs = self.model(
                inputs=masked_inputs, masks=masks, return_dict=True
            )
    finally:
        self.model.train(was_training)
    return self.processor.post_process_document(
        outputs,
        original_inputs=inputs,
        masks=masks,
        output_type=output_type,
        return_intermediates=return_intermediates,
        refinement_input=inputs if canonical is ConditionType.refinement else None,
    )

processing_flex_dm

Processor for Flex-DM heterogeneous document fields.

FlexDmDiscretizerSpec

Bases: TypedDict

Linear discretizer metadata for one numeric model field.

Source code in models/flex-dm/src/flex_dm/processing_flex_dm.py
40
41
42
43
44
45
class FlexDmDiscretizerSpec(TypedDict):
    """Linear discretizer metadata for one numeric model field."""

    min: float
    max: float
    bins: int

FlexDmProcessor

Bases: ProcessorMixin

Serialize vocabularies and convert public layouts to Flex-DM tensors.

Flex-DM intentionally does not expose a PreTrainedTokenizer because the model consumes a dictionary of heterogeneous categorical and continuous fields rather than one discrete token stream.

Source code in models/flex-dm/src/flex_dm/processing_flex_dm.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
 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
class FlexDmProcessor(ProcessorMixin):
    """Serialize vocabularies and convert public layouts to Flex-DM tensors.

    Flex-DM intentionally does not expose a ``PreTrainedTokenizer`` because the
    model consumes a dictionary of heterogeneous categorical and continuous
    fields rather than one discrete token stream.
    """

    attributes: list[str] = []

    def __init__(
        self,
        *,
        config: FlexDmConfig,
        vocabulary: dict[str, FlexDmValue] | None = None,
        discretizers: dict[str, FlexDmDiscretizerSpec] | None = None,
    ) -> None:
        """Initialize metadata-only processor state."""
        self.config = config
        self.vocabulary = vocabulary or {}
        self.discretizers = discretizers or {
            key: {"min": 0.0, "max": 1.0, "bins": 64} for key in GEOMETRY_KEYS
        }
        if "opacity" in config.input_columns:
            self.discretizers.setdefault("opacity", {"min": 0.0, "max": 1.0, "bins": 8})
        if "color" in config.input_columns:
            self.discretizers.setdefault(
                "color", {"min": 0.0, "max": 255.0, "bins": 16}
            )

    @classmethod
    def from_config(cls, config: FlexDmConfig) -> "FlexDmProcessor":
        """Create a processor from config metadata.

        Args:
            config: Flex-DM configuration.

        Returns:
            Processor with built-in discretizers.
        """
        return cls(config=config)

    def save_pretrained(
        self,
        save_directory: str | PathLike[str],
        push_to_hub: bool = False,
        **kwargs: str | int | float | bool | None,
    ) -> None:
        """Save processor metadata next to a converted checkpoint."""
        _ = (push_to_hub, kwargs)
        root = Path(save_directory)
        root.mkdir(parents=True, exist_ok=True)
        (root / "processor_config.json").write_text(
            json.dumps(
                {
                    "processor_class": self.__class__.__name__,
                    "config": self.config.to_dict(),
                    "vocabulary": self.vocabulary,
                    "discretizers": self.discretizers,
                    "tokenizer_policy_deviation": (
                        "Flex-DM uses ProcessorMixin instead of PreTrainedTokenizer "
                        "because the model consumes heterogeneous dict tensors and "
                        "continuous image/text embeddings."
                    ),
                },
                indent=2,
                sort_keys=True,
            )
        )

    @classmethod
    def from_pretrained(
        cls,
        pretrained_model_name_or_path: str | PathLike[str],
        cache_dir: str | PathLike[str] | None = None,
        force_download: bool = False,
        local_files_only: bool = False,
        token: str | bool | None = None,
        revision: str = "main",
        *,
        subfolder: str | None = None,
        **kwargs: str | int | float | bool | None,
    ) -> "FlexDmProcessor":
        """Load processor metadata from a local converted checkpoint."""
        _ = (cache_dir, force_download, local_files_only, token, revision, kwargs)
        root = Path(pretrained_model_name_or_path)
        if subfolder is not None:
            root = root / subfolder
        data = json.loads((root / "processor_config.json").read_text())
        return cls(
            config=FlexDmConfig.from_dict(data["config"]),
            vocabulary=cast(dict[str, FlexDmValue], data.get("vocabulary", {})),
            discretizers=cast(
                dict[str, FlexDmDiscretizerSpec], data.get("discretizers", {})
            ),
        )

    @classmethod
    def from_vocabulary(
        cls,
        *,
        dataset_name: str,
        vocabulary: dict[str, FlexDmValue],
        checkpoint_variant: str = "ours-exp-ft",
    ) -> "FlexDmProcessor":
        """Build config and processor metadata from vocabulary."""
        id2label = cast(
            dict[int | str, str],
            id2label_from_vocabulary(
                dataset_name, cast(dict[str, FlexDmVocabularyValue], vocabulary)
            ),
        )
        input_columns = build_column_specs(
            dataset_name=dataset_name,
            vocabulary=cast(dict[str, FlexDmVocabularyValue], vocabulary),
        )
        config = FlexDmConfig(
            dataset_name=dataset_name,
            checkpoint_variant=checkpoint_variant,
            id2label=id2label,
            input_columns=input_columns,
        )
        return cls(config=config, vocabulary=vocabulary)

    def __call__(
        self,
        *,
        condition_type: ConditionType | str = ConditionType.completion,
        labels: Int[torch.Tensor, "batch elements"]
        | Int[np.ndarray, "batch elements"]
        | Sequence[ArrayLikeInput]
        | None = None,
        bbox: Float[torch.Tensor, "batch elements 4"]
        | Float[np.ndarray, "batch elements 4"]
        | Sequence[ArrayLikeInput]
        | None = None,
        mask: Bool[torch.Tensor, "batch elements"]
        | Bool[np.ndarray, "batch elements"]
        | Sequence[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,
        attributes: Mapping[str, FlexDmValue] | None = None,
        content: Mapping[str, FlexDmValue] | None = None,
        feature_group: str | None = None,
        target_indices: Int[torch.Tensor, "..."] | None = None,
        batch_size: int = 1,
        return_tensors: Literal["pt"] = "pt",
    ) -> dict[
        str,
        dict[str, Shaped[torch.Tensor, "..."] | Bool[torch.Tensor, "..."]]
        | Shaped[torch.Tensor, "..."]
        | ConditionType
        | str
        | None,
    ]:
        """Convert public layout fields into Flex-DM model tensors."""
        if return_tensors != "pt":
            raise ValueError("FlexDmProcessor only supports return_tensors='pt'")

        if bbox is None or labels is None:
            count = self._num_elements_tensor(num_elements, batch_size)
            max_len = int(count.max().item()) if count.numel() else 0
            bbox_t = torch.zeros((batch_size, max_len, 4), dtype=torch.float32)
            labels_t = torch.zeros((batch_size, max_len), dtype=torch.long)
            mask_t = torch.arange(max_len).unsqueeze(0) < count.unsqueeze(1)
        else:
            bbox_t, labels_t, mask_t = prepare_layout_tensors(
                bbox=bbox,
                labels=labels,
                mask=mask,
                box_format=box_format,
                normalized=normalized,
                canvas_size=canvas_size,
                clamp_converted_normalized=True,
            )
        inputs = self._layout_to_inputs(
            bbox=bbox_t,
            labels=labels_t,
            mask=mask_t,
            attributes=attributes,
            content=content,
        )
        length = mask_t.long().sum(dim=1).clamp(min=1) - 1
        inputs["length"] = length.reshape(-1, 1).long()
        seq_mask = get_seq_mask(inputs["length"].reshape(-1), maxlen=bbox_t.size(1))
        filtered = filter_padding(inputs, self.config.input_columns, seq_mask)
        canonical, normalized_feature = self.normalize_condition_and_feature(
            condition_type,
            feature_group=feature_group,
        )
        masks = build_feature_masks(
            self.config.input_columns,
            seq_mask,
            condition_type=canonical,
            feature_group=normalized_feature,
            target_indices=target_indices,
        )
        return {
            "inputs": filtered,
            "masks": masks,
            "bbox": bbox_t,
            "labels": labels_t,
            "mask": mask_t,
            "condition_type": canonical,
            "feature_group": normalized_feature,
        }

    def normalize_condition_and_feature(
        self,
        condition_type: ConditionType | str,
        *,
        feature_group: str | None = None,
    ) -> tuple[ConditionType, str | None]:
        """Normalize canonical conditions plus local Flex-DM task aliases."""
        aliases = {"random", "elem", "type", "pos", "attr", "img", "txt"}
        if isinstance(condition_type, str) and condition_type in aliases:
            return ConditionType.completion, condition_type
        canonical = normalize_condition_type(condition_type)
        if canonical is ConditionType.content_image and feature_group is None:
            return canonical, "img"
        return canonical, feature_group

    def _num_elements_tensor(
        self,
        num_elements: int | list[int] | Int[torch.Tensor, "batch"] | None,
        batch_size: int,
    ) -> Int[torch.Tensor, "batch"]:
        if num_elements is None:
            return torch.full(
                (batch_size,), min(1, self.config.max_seq_length), dtype=torch.long
            )
        tensor = torch.as_tensor(num_elements, dtype=torch.long)
        if tensor.ndim == 0:
            tensor = tensor.repeat(batch_size)
        return tensor

    def _layout_to_inputs(
        self,
        *,
        bbox: Float[torch.Tensor, "batch elements 4"],
        labels: Int[torch.Tensor, "batch elements"],
        mask: Bool[torch.Tensor, "batch elements"],
        attributes: Mapping[str, FlexDmValue] | None,
        content: Mapping[str, FlexDmValue] | None,
    ) -> dict[str, Shaped[torch.Tensor, "..."]]:
        ltwh = xywh_to_ltwh(bbox).clamp(0.0, 1.0)
        inputs: dict[str, Shaped[torch.Tensor, "..."]] = {}
        for idx, key in enumerate(GEOMETRY_KEYS):
            inputs[key] = self._discretize(key, ltwh[..., idx : idx + 1]).long()
        inputs["type"] = labels.unsqueeze(-1).long()
        attrs = attributes or {}
        cnt = content or {}
        for key, column in self.config.input_columns.items():
            if key in inputs or key == "length":
                continue
            if not column["is_sequence"]:
                inputs[key] = torch.zeros((bbox.size(0), 1), dtype=torch.long)
            else:
                source = cnt.get(key, attrs.get(key))
                inputs[key] = self._coerce_column_value(key, column, source, mask)
        return inputs

    def _coerce_column_value(
        self,
        key: str,
        column: FlexDmColumnSpec,
        value: FlexDmValue,
        mask: Bool[torch.Tensor, "batch elements"],
    ) -> Shaped[torch.Tensor, "batch elements channels"]:
        batch, seq_len = mask.shape
        shape = (batch, seq_len, int(column["shape"][-1]))
        if value is None:
            dtype = torch.float32 if column["type"] == "numerical" else torch.long
            return torch.zeros(shape, dtype=dtype)
        tensor = torch.as_tensor(value)
        if tensor.ndim == 2:
            tensor = tensor.unsqueeze(-1)
        if key in self.discretizers and tensor.dtype.is_floating_point:
            tensor = self._discretize(key, tensor.float())
        return tensor.reshape(shape).to(
            dtype=torch.float32 if column["type"] == "numerical" else torch.long
        )

    def _discretize(
        self, key: str, value: Float[torch.Tensor, "..."]
    ) -> Float[torch.Tensor, "..."]:
        spec = self.discretizers[key]
        scaled = (value - spec["min"]) / (spec["max"] - spec["min"])
        return torch.clamp((scaled * spec["bins"]).floor(), 0, spec["bins"] - 1)

    def _continuize(
        self, key: str, value: Shaped[torch.Tensor, "..."]
    ) -> Float[torch.Tensor, "..."]:
        spec = self.discretizers[key]
        scale = (spec["max"] - spec["min"]) / spec["bins"]
        return value.float() * scale + spec["min"]

    def post_process_document(
        self,
        outputs: FlexDmModelOutput,
        *,
        original_inputs: Mapping[str, Shaped[torch.Tensor, "..."]],
        masks: Mapping[str, Bool[torch.Tensor, "..."]],
        output_type: Literal["dataclass", "dict"] = "dataclass",
        return_intermediates: bool = False,
        refinement_input: Mapping[str, Shaped[torch.Tensor, "..."]] | None = None,
    ) -> (
        LayoutGenerationOutput
        | dict[
            str,
            Shaped[torch.Tensor, "..."]
            | dict[int, str]
            | Mapping[str, Shaped[torch.Tensor, "..."]]
            | None,
        ]
    ):
        """Decode Flex-DM model outputs to the common layout schema."""
        decoded = self._decode_logits(outputs.logits, original_inputs, masks)
        ltwh = torch.cat([decoded[key].float() for key in GEOMETRY_KEYS], dim=-1)
        bbox = ltwh_to_xywh(ltwh).clamp(0.0, 1.0).detach().cpu()
        labels = decoded["type"].squeeze(-1).long().detach().cpu()
        valid_mask = get_seq_mask(
            original_inputs["length"].reshape(-1), maxlen=labels.size(1)
        )
        intermediates = None
        if return_intermediates:
            intermediates = {
                "attributes": {
                    key: value.detach().cpu()
                    for key, value in decoded.items()
                    if key not in (*GEOMETRY_KEYS, "type")
                    and self.config.input_columns[key]["is_sequence"]
                },
                "masks": {key: value.detach().cpu() for key, value in masks.items()},
                "logits": {
                    key: value.detach().cpu() for key, value in outputs.logits.items()
                },
            }
            if refinement_input is not None:
                intermediates["refinement_input"] = {
                    key: value.detach().cpu() for key, value in refinement_input.items()
                }
        result = LayoutGenerationOutput(
            bbox=bbox,
            labels=labels,
            mask=valid_mask.detach().cpu(),
            id2label=cast(dict[int, str], self.config.id2label),
            intermediates=intermediates,
        )
        if output_type == "dict":
            return dict(result)
        if output_type != "dataclass":
            raise ValueError(f"Unsupported output_type: {output_type}")

        return result

    def _decode_logits(
        self,
        logits: Mapping[str, Shaped[torch.Tensor, "..."]],
        original_inputs: Mapping[str, Shaped[torch.Tensor, "..."]],
        masks: Mapping[str, Bool[torch.Tensor, "..."]],
    ) -> dict[str, Shaped[torch.Tensor, "..."]]:
        decoded: dict[str, Shaped[torch.Tensor, "..."]] = {}
        for key, column in self.config.input_columns.items():
            if not column["is_sequence"]:
                continue
            if key in logits:
                pred = (
                    logits[key].argmax(dim=-1)
                    if column["type"] == "categorical"
                    else logits[key]
                )
            else:
                pred = original_inputs[key]
            mask = masks.get(key)
            if mask is not None:
                pred = torch.where(
                    mask.unsqueeze(-1).to(pred.device),
                    pred,
                    original_inputs[key].to(pred.device),
                )
            if key in self.discretizers and column["type"] == "categorical":
                pred = self._continuize(key, pred)
            decoded[key] = pred
        return decoded

__init__

__init__(
    *,
    config: FlexDmConfig,
    vocabulary: dict[str, FlexDmValue] | None = None,
    discretizers: dict[str, FlexDmDiscretizerSpec]
    | None = None,
) -> None

Initialize metadata-only processor state.

Source code in models/flex-dm/src/flex_dm/processing_flex_dm.py
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
def __init__(
    self,
    *,
    config: FlexDmConfig,
    vocabulary: dict[str, FlexDmValue] | None = None,
    discretizers: dict[str, FlexDmDiscretizerSpec] | None = None,
) -> None:
    """Initialize metadata-only processor state."""
    self.config = config
    self.vocabulary = vocabulary or {}
    self.discretizers = discretizers or {
        key: {"min": 0.0, "max": 1.0, "bins": 64} for key in GEOMETRY_KEYS
    }
    if "opacity" in config.input_columns:
        self.discretizers.setdefault("opacity", {"min": 0.0, "max": 1.0, "bins": 8})
    if "color" in config.input_columns:
        self.discretizers.setdefault(
            "color", {"min": 0.0, "max": 255.0, "bins": 16}
        )

from_config classmethod

from_config(config: FlexDmConfig) -> 'FlexDmProcessor'

Create a processor from config metadata.

Parameters:

Name Type Description Default
config FlexDmConfig

Flex-DM configuration.

required

Returns:

Type Description
'FlexDmProcessor'

Processor with built-in discretizers.

Source code in models/flex-dm/src/flex_dm/processing_flex_dm.py
81
82
83
84
85
86
87
88
89
90
91
@classmethod
def from_config(cls, config: FlexDmConfig) -> "FlexDmProcessor":
    """Create a processor from config metadata.

    Args:
        config: Flex-DM configuration.

    Returns:
        Processor with built-in discretizers.
    """
    return cls(config=config)

save_pretrained

save_pretrained(
    save_directory: str | PathLike[str],
    push_to_hub: bool = False,
    **kwargs: str | int | float | bool | None,
) -> None

Save processor metadata next to a converted checkpoint.

Source code in models/flex-dm/src/flex_dm/processing_flex_dm.py
 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
def save_pretrained(
    self,
    save_directory: str | PathLike[str],
    push_to_hub: bool = False,
    **kwargs: str | int | float | bool | None,
) -> None:
    """Save processor metadata next to a converted checkpoint."""
    _ = (push_to_hub, kwargs)
    root = Path(save_directory)
    root.mkdir(parents=True, exist_ok=True)
    (root / "processor_config.json").write_text(
        json.dumps(
            {
                "processor_class": self.__class__.__name__,
                "config": self.config.to_dict(),
                "vocabulary": self.vocabulary,
                "discretizers": self.discretizers,
                "tokenizer_policy_deviation": (
                    "Flex-DM uses ProcessorMixin instead of PreTrainedTokenizer "
                    "because the model consumes heterogeneous dict tensors and "
                    "continuous image/text embeddings."
                ),
            },
            indent=2,
            sort_keys=True,
        )
    )

from_pretrained classmethod

from_pretrained(
    pretrained_model_name_or_path: str | PathLike[str],
    cache_dir: str | PathLike[str] | None = None,
    force_download: bool = False,
    local_files_only: bool = False,
    token: str | bool | None = None,
    revision: str = "main",
    *,
    subfolder: str | None = None,
    **kwargs: str | int | float | bool | None,
) -> "FlexDmProcessor"

Load processor metadata from a local converted checkpoint.

Source code in models/flex-dm/src/flex_dm/processing_flex_dm.py
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
@classmethod
def from_pretrained(
    cls,
    pretrained_model_name_or_path: str | PathLike[str],
    cache_dir: str | PathLike[str] | None = None,
    force_download: bool = False,
    local_files_only: bool = False,
    token: str | bool | None = None,
    revision: str = "main",
    *,
    subfolder: str | None = None,
    **kwargs: str | int | float | bool | None,
) -> "FlexDmProcessor":
    """Load processor metadata from a local converted checkpoint."""
    _ = (cache_dir, force_download, local_files_only, token, revision, kwargs)
    root = Path(pretrained_model_name_or_path)
    if subfolder is not None:
        root = root / subfolder
    data = json.loads((root / "processor_config.json").read_text())
    return cls(
        config=FlexDmConfig.from_dict(data["config"]),
        vocabulary=cast(dict[str, FlexDmValue], data.get("vocabulary", {})),
        discretizers=cast(
            dict[str, FlexDmDiscretizerSpec], data.get("discretizers", {})
        ),
    )

from_vocabulary classmethod

from_vocabulary(
    *,
    dataset_name: str,
    vocabulary: dict[str, FlexDmValue],
    checkpoint_variant: str = "ours-exp-ft",
) -> "FlexDmProcessor"

Build config and processor metadata from vocabulary.

Source code in models/flex-dm/src/flex_dm/processing_flex_dm.py
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
@classmethod
def from_vocabulary(
    cls,
    *,
    dataset_name: str,
    vocabulary: dict[str, FlexDmValue],
    checkpoint_variant: str = "ours-exp-ft",
) -> "FlexDmProcessor":
    """Build config and processor metadata from vocabulary."""
    id2label = cast(
        dict[int | str, str],
        id2label_from_vocabulary(
            dataset_name, cast(dict[str, FlexDmVocabularyValue], vocabulary)
        ),
    )
    input_columns = build_column_specs(
        dataset_name=dataset_name,
        vocabulary=cast(dict[str, FlexDmVocabularyValue], vocabulary),
    )
    config = FlexDmConfig(
        dataset_name=dataset_name,
        checkpoint_variant=checkpoint_variant,
        id2label=id2label,
        input_columns=input_columns,
    )
    return cls(config=config, vocabulary=vocabulary)

__call__

__call__(
    *,
    condition_type: ConditionType
    | str = ConditionType.completion,
    labels: Int[Tensor, "batch elements"]
    | Int[ndarray, "batch elements"]
    | Sequence[ArrayLikeInput]
    | None = None,
    bbox: Float[Tensor, "batch elements 4"]
    | Float[ndarray, "batch elements 4"]
    | Sequence[ArrayLikeInput]
    | None = None,
    mask: Bool[Tensor, "batch elements"]
    | Bool[ndarray, "batch elements"]
    | Sequence[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,
    attributes: Mapping[str, FlexDmValue] | None = None,
    content: Mapping[str, FlexDmValue] | None = None,
    feature_group: str | None = None,
    target_indices: Int[Tensor, "..."] | None = None,
    batch_size: int = 1,
    return_tensors: Literal["pt"] = "pt",
) -> dict[
    str,
    dict[
        str,
        Shaped[torch.Tensor, "..."]
        | Bool[torch.Tensor, "..."],
    ]
    | Shaped[torch.Tensor, "..."]
    | ConditionType
    | str
    | None,
]

Convert public layout fields into Flex-DM model tensors.

Source code in models/flex-dm/src/flex_dm/processing_flex_dm.py
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
def __call__(
    self,
    *,
    condition_type: ConditionType | str = ConditionType.completion,
    labels: Int[torch.Tensor, "batch elements"]
    | Int[np.ndarray, "batch elements"]
    | Sequence[ArrayLikeInput]
    | None = None,
    bbox: Float[torch.Tensor, "batch elements 4"]
    | Float[np.ndarray, "batch elements 4"]
    | Sequence[ArrayLikeInput]
    | None = None,
    mask: Bool[torch.Tensor, "batch elements"]
    | Bool[np.ndarray, "batch elements"]
    | Sequence[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,
    attributes: Mapping[str, FlexDmValue] | None = None,
    content: Mapping[str, FlexDmValue] | None = None,
    feature_group: str | None = None,
    target_indices: Int[torch.Tensor, "..."] | None = None,
    batch_size: int = 1,
    return_tensors: Literal["pt"] = "pt",
) -> dict[
    str,
    dict[str, Shaped[torch.Tensor, "..."] | Bool[torch.Tensor, "..."]]
    | Shaped[torch.Tensor, "..."]
    | ConditionType
    | str
    | None,
]:
    """Convert public layout fields into Flex-DM model tensors."""
    if return_tensors != "pt":
        raise ValueError("FlexDmProcessor only supports return_tensors='pt'")

    if bbox is None or labels is None:
        count = self._num_elements_tensor(num_elements, batch_size)
        max_len = int(count.max().item()) if count.numel() else 0
        bbox_t = torch.zeros((batch_size, max_len, 4), dtype=torch.float32)
        labels_t = torch.zeros((batch_size, max_len), dtype=torch.long)
        mask_t = torch.arange(max_len).unsqueeze(0) < count.unsqueeze(1)
    else:
        bbox_t, labels_t, mask_t = prepare_layout_tensors(
            bbox=bbox,
            labels=labels,
            mask=mask,
            box_format=box_format,
            normalized=normalized,
            canvas_size=canvas_size,
            clamp_converted_normalized=True,
        )
    inputs = self._layout_to_inputs(
        bbox=bbox_t,
        labels=labels_t,
        mask=mask_t,
        attributes=attributes,
        content=content,
    )
    length = mask_t.long().sum(dim=1).clamp(min=1) - 1
    inputs["length"] = length.reshape(-1, 1).long()
    seq_mask = get_seq_mask(inputs["length"].reshape(-1), maxlen=bbox_t.size(1))
    filtered = filter_padding(inputs, self.config.input_columns, seq_mask)
    canonical, normalized_feature = self.normalize_condition_and_feature(
        condition_type,
        feature_group=feature_group,
    )
    masks = build_feature_masks(
        self.config.input_columns,
        seq_mask,
        condition_type=canonical,
        feature_group=normalized_feature,
        target_indices=target_indices,
    )
    return {
        "inputs": filtered,
        "masks": masks,
        "bbox": bbox_t,
        "labels": labels_t,
        "mask": mask_t,
        "condition_type": canonical,
        "feature_group": normalized_feature,
    }

normalize_condition_and_feature

normalize_condition_and_feature(
    condition_type: ConditionType | str,
    *,
    feature_group: str | None = None,
) -> tuple[ConditionType, str | None]

Normalize canonical conditions plus local Flex-DM task aliases.

Source code in models/flex-dm/src/flex_dm/processing_flex_dm.py
261
262
263
264
265
266
267
268
269
270
271
272
273
274
def normalize_condition_and_feature(
    self,
    condition_type: ConditionType | str,
    *,
    feature_group: str | None = None,
) -> tuple[ConditionType, str | None]:
    """Normalize canonical conditions plus local Flex-DM task aliases."""
    aliases = {"random", "elem", "type", "pos", "attr", "img", "txt"}
    if isinstance(condition_type, str) and condition_type in aliases:
        return ConditionType.completion, condition_type
    canonical = normalize_condition_type(condition_type)
    if canonical is ConditionType.content_image and feature_group is None:
        return canonical, "img"
    return canonical, feature_group

post_process_document

post_process_document(
    outputs: FlexDmModelOutput,
    *,
    original_inputs: Mapping[str, Shaped[Tensor, "..."]],
    masks: Mapping[str, Bool[Tensor, "..."]],
    output_type: Literal["dataclass", "dict"] = "dataclass",
    return_intermediates: bool = False,
    refinement_input: Mapping[str, Shaped[Tensor, "..."]]
    | None = None,
) -> (
    LayoutGenerationOutput
    | dict[
        str,
        Shaped[torch.Tensor, "..."]
        | dict[int, str]
        | Mapping[str, Shaped[torch.Tensor, "..."]]
        | None,
    ]
)

Decode Flex-DM model outputs to the common layout schema.

Source code in models/flex-dm/src/flex_dm/processing_flex_dm.py
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
def post_process_document(
    self,
    outputs: FlexDmModelOutput,
    *,
    original_inputs: Mapping[str, Shaped[torch.Tensor, "..."]],
    masks: Mapping[str, Bool[torch.Tensor, "..."]],
    output_type: Literal["dataclass", "dict"] = "dataclass",
    return_intermediates: bool = False,
    refinement_input: Mapping[str, Shaped[torch.Tensor, "..."]] | None = None,
) -> (
    LayoutGenerationOutput
    | dict[
        str,
        Shaped[torch.Tensor, "..."]
        | dict[int, str]
        | Mapping[str, Shaped[torch.Tensor, "..."]]
        | None,
    ]
):
    """Decode Flex-DM model outputs to the common layout schema."""
    decoded = self._decode_logits(outputs.logits, original_inputs, masks)
    ltwh = torch.cat([decoded[key].float() for key in GEOMETRY_KEYS], dim=-1)
    bbox = ltwh_to_xywh(ltwh).clamp(0.0, 1.0).detach().cpu()
    labels = decoded["type"].squeeze(-1).long().detach().cpu()
    valid_mask = get_seq_mask(
        original_inputs["length"].reshape(-1), maxlen=labels.size(1)
    )
    intermediates = None
    if return_intermediates:
        intermediates = {
            "attributes": {
                key: value.detach().cpu()
                for key, value in decoded.items()
                if key not in (*GEOMETRY_KEYS, "type")
                and self.config.input_columns[key]["is_sequence"]
            },
            "masks": {key: value.detach().cpu() for key, value in masks.items()},
            "logits": {
                key: value.detach().cpu() for key, value in outputs.logits.items()
            },
        }
        if refinement_input is not None:
            intermediates["refinement_input"] = {
                key: value.detach().cpu() for key, value in refinement_input.items()
            }
    result = LayoutGenerationOutput(
        bbox=bbox,
        labels=labels,
        mask=valid_mask.detach().cpu(),
        id2label=cast(dict[int, str], self.config.id2label),
        intermediates=intermediates,
    )
    if output_type == "dict":
        return dict(result)
    if output_type != "dataclass":
        raise ValueError(f"Unsupported output_type: {output_type}")

    return result

testing

Testing helpers for Flex-DM package tests.

tiny_config

tiny_config() -> FlexDmConfig

Return a small Flex-DM config for CPU tests.

Source code in models/flex-dm/src/flex_dm/testing.py
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
def tiny_config() -> FlexDmConfig:
    """Return a small Flex-DM config for CPU tests."""
    input_columns = build_column_specs(dataset_name="crello", vocabulary={})
    for key, column in input_columns.items():
        if (
            column["is_sequence"]
            and column["type"] == "categorical"
            and key not in {"left", "top", "width", "height"}
        ):
            column["input_dim"] = min(int(column["input_dim"] or 4), 4)
        if key in {"image_embedding", "text_embedding"}:
            column["shape"] = (4,)
    return FlexDmConfig(
        dataset_name="crello",
        id2label={0: "coloredBackground", 1: "imageElement", 2: "textElement"},
        input_columns=input_columns,
        max_seq_length=3,
        latent_dim=16,
        num_blocks=1,
        dropout=0.0,
    )

tiny_pipeline

tiny_pipeline() -> FlexDmPipeline

Return a small random-weight pipeline.

Source code in models/flex-dm/src/flex_dm/testing.py
35
36
37
38
39
40
41
def tiny_pipeline() -> FlexDmPipeline:
    """Return a small random-weight pipeline."""
    config = tiny_config()
    return FlexDmPipeline(
        model=FlexDmForMaskedDocumentModeling(config),
        processor=FlexDmProcessor.from_config(config),
    )

tf_checkpoint

Optional TensorFlow checkpoint inspection helpers for Flex-DM.

list_tf_checkpoint_variables

list_tf_checkpoint_variables(
    checkpoint_prefix: str | Path,
) -> list[tuple[str, tuple[int, ...]]]

List TensorFlow checkpoint variable names and shapes.

Parameters:

Name Type Description Default
checkpoint_prefix str | Path

Path to best.ckpt or another TF checkpoint prefix.

required

Returns:

Type Description
list[tuple[str, tuple[int, ...]]]

Sorted (name, shape) pairs.

Raises:

Type Description
ImportError

If TensorFlow is not installed.

Source code in models/flex-dm/src/flex_dm/tf_checkpoint.py
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
def list_tf_checkpoint_variables(
    checkpoint_prefix: str | Path,
) -> list[tuple[str, tuple[int, ...]]]:
    """List TensorFlow checkpoint variable names and shapes.

    Args:
        checkpoint_prefix: Path to ``best.ckpt`` or another TF checkpoint prefix.

    Returns:
        Sorted ``(name, shape)`` pairs.

    Raises:
        ImportError: If TensorFlow is not installed.
    """
    tf = _load_tensorflow()
    variables = tf.train.list_variables(str(checkpoint_prefix))
    return [(name, tuple(int(dim) for dim in shape)) for name, shape in variables]

load_tf_checkpoint_variables

load_tf_checkpoint_variables(
    checkpoint_prefix: str | Path,
) -> dict[str, Shaped[np.ndarray, "..."]]

Load all TensorFlow checkpoint variables into NumPy arrays.

Source code in models/flex-dm/src/flex_dm/tf_checkpoint.py
60
61
62
63
64
65
66
67
68
def load_tf_checkpoint_variables(
    checkpoint_prefix: str | Path,
) -> dict[str, Shaped[np.ndarray, "..."]]:
    """Load all TensorFlow checkpoint variables into NumPy arrays."""
    tf = _load_tensorflow()
    return {
        name: np.asarray(tf.train.load_variable(str(checkpoint_prefix), name))
        for name, _shape in tf.train.list_variables(str(checkpoint_prefix))
    }

tensorflow_version

tensorflow_version() -> str

Return the TensorFlow version available in the active environment.

Source code in models/flex-dm/src/flex_dm/tf_checkpoint.py
71
72
73
74
75
76
77
def tensorflow_version() -> str:
    """Return the TensorFlow version available in the active environment."""
    try:
        tf = import_module("tensorflow")
    except ImportError:
        return "not-installed"
    return str(tf.__version__)