# Copyright 2026 The HuggingFace Team. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from huggingface_hub.dataclasses import strict from transformers.configuration_utils import PreTrainedConfig from transformers.models.auto import CONFIG_MAPPING, AutoConfig from transformers.utils import auto_docstring from .configuration_lfm3 import Lfm3Config from .configuration_lfm3_vl import Lfm3VlVisionConfig def _config_class(model_type): # the LFM3 configs ship with the checkpoint instead of the transformers registry remote = {"lfm3": Lfm3Config, "lfm3_vl_vision": Lfm3VlVisionConfig, "lfm3_omni_encoder": Lfm3OmniEncoderConfig} return remote.get(model_type) or CONFIG_MAPPING[model_type] # `dtype` is dropped so that the top-level dtype governs every component of a legacy export _LEGACY_SUBCONFIG_DROPPED_KEYS = ( "architectures", "transformers_version", "is_causal", "auto_map", "_name_or_path", "dtype", ) def _subconfig_dict(values: dict, default_model_type: str) -> dict: values = {key: value for key, value in values.items() if key not in _LEGACY_SUBCONFIG_DROPPED_KEYS} values.setdefault("model_type", default_model_type) return values @auto_docstring(checkpoint="LiquidAI/LFM3-Omni-2B-Preview") @strict class Lfm3OmniEncoderConfig(PreTrainedConfig): r""" text_config (`Lfm2Config` or `dict`, *optional*): The configuration of the LFM2 model run over the downsampled spectrogram. Defaults to the 17-layer, 768-wide model of LFM3-Audio. num_mel_bins (`int`, *optional*, defaults to 128): The number of mel bins of the input features. conv_channels (`int`, *optional*, defaults to 256): The number of channels of the downsampling convolutions. hidden_size (`int`, *optional*, defaults to 768): The width of the encoder output, equal to `text_config.hidden_size`. sliding_window (`int`, *optional*, defaults to 32): The number of past frames each frame attends to, itself included. initializer_range (`float`, *optional*, defaults to 0.02): The standard deviation of the truncated normal initializer of the convolutions. """ model_type = "lfm3_omni_encoder" sub_configs = {"text_config": AutoConfig} text_config: dict | PreTrainedConfig | None = None num_mel_bins: int = 128 conv_channels: int = 256 hidden_size: int = 768 sliding_window: int = 32 initializer_range: float = 0.02 def __post_init__(self, **kwargs): if isinstance(self.text_config, dict): # the encoder consumes embeddings only: no end-of-sequence id in its two-token vocabulary self.text_config = {"eos_token_id": None, **_subconfig_dict(self.text_config, "lfm2")} self.text_config = _config_class(self.text_config["model_type"])(**self.text_config) elif self.text_config is None: self.text_config = _config_class("lfm2")( vocab_size=2, hidden_size=self.hidden_size, intermediate_size=2560, num_hidden_layers=17, num_attention_heads=8, num_key_value_heads=4, layer_types=(["conv", "conv", "full_attention"] * 5) + ["full_attention", "full_attention"], conv_L_cache=3, rope_parameters={"rope_type": "default", "rope_theta": 1_000_000.0}, pad_token_id=0, bos_token_id=1, eos_token_id=None, ) super().__post_init__(**kwargs) @auto_docstring(checkpoint="LiquidAI/LFM3-Omni-2B-Preview") @strict class Lfm3OmniConfig(PreTrainedConfig): r""" This is the configuration class to store the configuration of a [`Lfm3OmniForConditionalGeneration`]. text_config (`Lfm3Config` or `dict`, *optional*): The configuration of the LFM3 language model. audio_encoder_config (`Lfm3OmniEncoderConfig` or `dict`, *optional*): The configuration of the speech encoder. depth_config (`Lfm3Config` or `dict`, *optional*): The configuration of the depth decoder, a bidirectional LFM3 model over the codebook axis of one speech frame. Defaults to the 3-layer, 1024-wide model of LFM3-Audio. num_codebooks (`int`, *optional*, defaults to 12): The number of codebooks per speech frame. codebook_size (`int`, *optional*, defaults to 2017): The size of each codebook, the codec's codes plus the end-of-audio code. audio_eos_code (`int`, *optional*, defaults to 2016): The end-of-audio code. A frame holding it in every codebook ends a speech segment. maskgit_schedule (`list[int]`, *optional*, defaults to `[4, 4, 4]`): The number of codebooks revealed by each pass of the depth decoder when sampling a frame. interleaved_n_text (`int`, *optional*, defaults to 6): The number of text tokens per block of the interleaved generation mode. interleaved_n_audio (`int`, *optional*, defaults to 12): The number of speech frames per block of the interleaved generation mode. audio_token_id (`int`, *optional*, defaults to 125031): The id of the placeholder token standing for one encoded input speech frame. audio_out_token_id (`int`, *optional*, defaults to 125032): The id of the placeholder token standing for one output speech frame. audio_start_token_id (`int`, *optional*, defaults to 125012): The id of `<|audio_start|>`, which switches generation to speech until an end-of-audio frame. text_end_token_id (`int`, *optional*, defaults to 125014): The id of `<|text_end|>`, which ends the text of an interleaved answer. mixed_start_token_id (`int`, *optional*, defaults to 125015): The id of `<|mixed_start|>`, which switches generation to interleaved text and speech. tie_word_embeddings (`bool`, *optional*, defaults to `True`): Whether to tie the language model head to the input embeddings. text_loss_weight (`float`, *optional*, defaults to 1.0): The weight of the text loss in the training loss. audio_loss_weight (`float`, *optional*, defaults to 1.0): The weight of the speech loss in the training loss. initializer_range (`float`, *optional*, defaults to 0.02): The standard deviation of the truncated normal initializer of the projector and depth decoder. vision_config (`Lfm3VlVisionConfig` or `dict`, *optional*): The configuration of the image encoder. video_token_id (`int`, *optional*, defaults to 125029): The id of the placeholder token standing for one encoded video patch group. image_token_id (`int`, *optional*, defaults to 125030): The placeholder for one projected image token. projector_hidden_size (`int`, *optional*, defaults to 4096): The intermediate dimension of the image projector. projector_hidden_act (`str`, *optional*, defaults to `"gelu"`): The image projector activation. projector_bias (`bool`, *optional*, defaults to `True`): Whether the image projector linear layers have biases. projector_layer_norm_eps (`float`, *optional*, defaults to 1e-06): The epsilon of the image projector layer normalization. downsample_factor (`int`, *optional*, defaults to 2): The side length of each image patch block merged into one language token. """ model_type = "lfm3_omni" sub_configs = { "text_config": AutoConfig, "audio_encoder_config": Lfm3OmniEncoderConfig, "depth_config": AutoConfig, "vision_config": AutoConfig, } text_config: dict | PreTrainedConfig | None = None audio_encoder_config: dict | PreTrainedConfig | None = None depth_config: dict | PreTrainedConfig | None = None num_codebooks: int = 12 codebook_size: int = 2017 audio_eos_code: int = 2016 maskgit_schedule: list[int] | None = None interleaved_n_text: int = 6 interleaved_n_audio: int = 12 audio_token_id: int = 125_031 audio_out_token_id: int = 125_032 audio_start_token_id: int = 125_012 text_end_token_id: int = 125_014 mixed_start_token_id: int = 125_015 tie_word_embeddings: bool = True text_loss_weight: float = 1.0 audio_loss_weight: float = 1.0 initializer_range: float = 0.02 # the ids `generate` and `transcribe_live` index the text logits with _token_id_fields = ( "audio_token_id", "audio_out_token_id", "audio_start_token_id", "text_end_token_id", "mixed_start_token_id", ) vision_config: dict | PreTrainedConfig | None = None image_token_id: int = 125_030 video_token_id: int = 125_029 projector_hidden_size: int = 4096 projector_hidden_act: str = "gelu" projector_bias: bool = True projector_layer_norm_eps: float = 1e-6 downsample_factor: int = 2 def __post_init__(self, **kwargs): if isinstance(self.vision_config, dict): self.vision_config = _config_class("lfm3_vl_vision")(**self.vision_config) elif self.vision_config is None: self.vision_config = _config_class("lfm3_vl_vision")() if "lfm" in kwargs or "format_version" in kwargs: raise ValueError( "LFM3-Omni reads the canonical checkpoint layout only; training exports (`lfm` / `format_version`) " "are not supported, load a canonical Hugging Face checkpoint." ) if isinstance(self.text_config, dict): self.text_config = _subconfig_dict(self.text_config, "lfm3") self.text_config = _config_class(self.text_config["model_type"])(**self.text_config) elif self.text_config is None: self.text_config = _config_class("lfm3")() self.validate_vision_fields() if isinstance(self.audio_encoder_config, dict): self.audio_encoder_config = self.sub_configs["audio_encoder_config"](**self.audio_encoder_config) elif self.audio_encoder_config is None: self.audio_encoder_config = self.sub_configs["audio_encoder_config"]() if isinstance(self.depth_config, dict): # the depth decoder consumes embeddings only; its token ids are placeholders self.depth_config = { "pad_token_id": None, "bos_token_id": None, "eos_token_id": None, **_subconfig_dict(self.depth_config, "lfm3"), } self.depth_config = _config_class(self.depth_config["model_type"])(**self.depth_config) elif self.depth_config is None: self.depth_config = _config_class("lfm3")( vocab_size=1, pad_token_id=None, hidden_size=1024, intermediate_size=2816, num_hidden_layers=3, num_attention_heads=32, num_key_value_heads=8, head_dim=32, max_position_embeddings=self.num_codebooks, layer_types=["full_attention"] * 3, rope_parameters={ "full_attention": {"rope_type": "default", "rope_theta": 1_000_000.0, "partial_rotary_factor": 1.0} }, sliding_window=None, use_sandwich_norm=False, use_cache=False, bos_token_id=None, eos_token_id=None, ) steps = kwargs.pop("maskgit_steps", 3) if self.maskgit_schedule is None: if not 1 <= steps <= self.num_codebooks: raise ValueError( f"maskgit_steps must be between 1 and num_codebooks={self.num_codebooks}, got {steps}" ) self.maskgit_schedule = [self.num_codebooks // steps] * steps self.maskgit_schedule[-1] += self.num_codebooks - sum(self.maskgit_schedule) self.maskgit_schedule = list(self.maskgit_schedule) self._validate_speech_fields() super().__post_init__(**kwargs) def validate_speech_fields(self): """Part of `@strict`-powered validation, so `validate()` and `save_pretrained` refuse later edits too.""" self._validate_speech_fields() def _validate_speech_fields(self): if min(self.maskgit_schedule, default=0) < 1 or sum(self.maskgit_schedule) != self.num_codebooks: raise ValueError( f"maskgit_schedule {self.maskgit_schedule} must be positive counts summing to " f"num_codebooks={self.num_codebooks}" ) # the end-of-audio code indexes every codebook; a code outside them could never be sampled or embedded if not 0 <= self.audio_eos_code < self.codebook_size: raise ValueError( f"audio_eos_code={self.audio_eos_code} must lie in [0, codebook_size={self.codebook_size})" ) if self.interleaved_n_text < 1 or self.interleaved_n_audio < 1: raise ValueError("interleaved_n_text and interleaved_n_audio must be positive") vocab_size = self.text_config.vocab_size for name in self._token_id_fields: if not 0 <= getattr(self, name) < vocab_size: raise ValueError(f"{name}={getattr(self, name)} must lie in [0, text_config.vocab_size={vocab_size})") def validate_vision_fields(self): """Part of `@strict`-powered validation, so `validate()` and `save_pretrained` refuse later edits too.""" if self.downsample_factor != self.vision_config.spatial_merge_size: raise ValueError("downsample_factor must match vision_config.spatial_merge_size") # an `inputs_embeds` forward embeds both placeholder ids to find them vocab_size = self.text_config.vocab_size for name in ("image_token_id", "video_token_id"): if not 0 <= getattr(self, name) < vocab_size: raise ValueError(f"{name}={getattr(self, name)} must lie in [0, text_config.vocab_size={vocab_size})") __all__ = ["Lfm3OmniConfig", "Lfm3OmniEncoderConfig"]