Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/source/openvino/models.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ Here is the list of the supported architectures :
- EXAONE 4
- Falcon
- Falcon-Mamba
- Falcon-H1
- FlauBERT
- GLM-4
- GLM-Edge
Expand Down
71 changes: 71 additions & 0 deletions optimum/exporters/openvino/input_generators.py
Original file line number Diff line number Diff line change
Expand Up @@ -1699,6 +1699,77 @@ def generate(self, input_name: str, framework: str = "pt", int_dtype: str = "int
return past_key_values


class FalconH1DummyPastKeyValuesGenerator(DummyPastKeyValuesGenerator):
"""
Generates dummy cache_params inputs for FalconH1 architectures.

FalconH1 is a fully-parallel hybrid architecture: every decoder layer contains
both a Mamba2 mixer (conv + ssm states) and a self-attention block (key + value
cache). Therefore the number of mamba layers and the number of attention layers
are both equal to ``num_hidden_layers``.
"""

SUPPORTED_INPUT_NAMES = ("cache_params",)

def __init__(
self,
task: str,
normalized_config,
batch_size: int = DEFAULT_DUMMY_SHAPES["batch_size"],
sequence_length: int = DEFAULT_DUMMY_SHAPES["sequence_length"],
**kwargs,
):
super().__init__(
task=task,
normalized_config=normalized_config,
batch_size=batch_size,
sequence_length=sequence_length,
**kwargs,
)

config = normalized_config.config
self.intermediate_size = (
config.mamba_d_ssm
if getattr(config, "mamba_d_ssm", None) is not None
else int(config.mamba_expand * config.hidden_size)
)
self.conv_kernel_size = config.mamba_d_conv
self.mamba_d_state = config.mamba_d_state
self.n_mamba_heads = config.mamba_n_heads
self.mamba_ngroups = config.mamba_n_groups
self.mamba_headdim = config.mamba_d_head
self.head_dim = getattr(config, "head_dim", config.hidden_size // config.num_attention_heads)
self.num_key_value_heads = config.num_key_value_heads
# every layer is hybrid: both mamba and attention states exist per layer
self.num_mamba_layers = config.num_hidden_layers
self.num_attention_layers = config.num_hidden_layers
# past attention cache starts empty (sequence_length == 0), states are appended during decode
self.sequence_length = 0

def generate(self, input_name: str, framework: str = "pt", int_dtype: str = "int64", float_dtype: str = "fp32"):
past_key_values = []
for i in range(self.num_mamba_layers):
conv_state_shape = (
self.batch_size,
self.intermediate_size + 2 * self.mamba_ngroups * self.mamba_d_state,
self.conv_kernel_size,
)
conv_state = self.random_float_tensor(conv_state_shape, framework=framework, dtype=float_dtype)
past_key_values.append(conv_state)
ssm_state_shape = (self.batch_size, self.n_mamba_heads, self.mamba_headdim, self.mamba_d_state)
ssm_state = self.random_float_tensor(ssm_state_shape, framework=framework, dtype=float_dtype)
past_key_values.append(ssm_state)

for i in range(self.num_attention_layers):
kv_shape = (self.batch_size, self.num_key_value_heads, self.sequence_length, self.head_dim)
k = self.random_float_tensor(kv_shape, framework=framework, dtype=float_dtype)
v = self.random_float_tensor(kv_shape, framework=framework, dtype=float_dtype)
past_key_values.append(k)
past_key_values.append(v)

return past_key_values


class Lfm2DummyPastKeyValuesGenerator(DummyPastKeyValuesGenerator):
"""
Generates dummy past_key_values inputs for Lfm2 architectures.
Expand Down
51 changes: 51 additions & 0 deletions optimum/exporters/openvino/model_configs.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
LTX2TransformerDummyInputGenerator,
LTX2VaeDummyInputGenerator,
LTX2VocoderDummyInputGenerator,
FalconH1DummyPastKeyValuesGenerator,
LTXTransformerDummyInputGenerator,
LTXVaeDummyInputGenerator,
MambaCacheDummyInputGenerator,
Expand All @@ -108,6 +109,7 @@
DBRXModelPatcher,
DeciLMModelPatcher,
DeepseekPatcher,
FalconH1ModelPatcher,
FalconModelPatcher,
FluxTransformerModelPatcher,
FunASRModelPatcher,
Expand Down Expand Up @@ -5712,6 +5714,55 @@ def inputs(self) -> Dict[str, Dict[int, str]]:
return common_inputs


@register_in_tasks_manager(
"falcon_h1", *["text-generation", "text-generation-with-past"], library_name="transformers"
)
class FalconH1OpenVINOConfig(MambaOpenVINOConfig):
# FalconH1 is a fully-parallel hybrid: every decoder layer contains both a Mamba2 mixer
# (conv + ssm states) and a self-attention block (key + value cache).
DUMMY_INPUT_GENERATOR_CLASSES = (DummyTextInputGenerator, FalconH1DummyPastKeyValuesGenerator)
DUMMY_PKV_GENERATOR_CLASS = FalconH1DummyPastKeyValuesGenerator
NORMALIZED_CONFIG_CLASS = NormalizedTextConfig
MIN_TRANSFORMERS_VERSION = "4.53.0"
_MODEL_PATCHER = FalconH1ModelPatcher

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
_warn_potential_accuracy_issue_ov_2026_1("falcon_h1")

def add_past_key_values(self, inputs_or_outputs: Dict[str, Dict[int, str]], direction: str):
if direction not in ["inputs", "outputs"]:
raise ValueError(f'direction must either be "inputs" or "outputs", but {direction} was given')

if direction == "inputs":
decoder_sequence_name = "past_sequence_length"
cache_name_prefix = "cache_params.past"
else:
decoder_sequence_name = "past_sequence_length + sequence_length"
cache_name_prefix = "cache_params.present"

num_hidden_layers = self._normalized_config.num_layers
for i in range(num_hidden_layers):
# [batch_size, conv_dim, conv_kernel_size]
inputs_or_outputs[f"{cache_name_prefix}.conv.{i}"] = {0: "batch_size"}
# [batch_size, mamba_n_heads, mamba_d_head, mamba_d_state]
inputs_or_outputs[f"{cache_name_prefix}.ssm.{i}"] = {0: "batch_size"}

for i in range(num_hidden_layers):
inputs_or_outputs[f"{cache_name_prefix}.key.{i}"] = {0: "batch_size", 2: decoder_sequence_name}
inputs_or_outputs[f"{cache_name_prefix}.value.{i}"] = {0: "batch_size", 2: decoder_sequence_name}

@property
def inputs(self) -> Dict[str, Dict[int, str]]:
common_inputs = {
"input_ids": {0: "batch_size", 1: "sequence_length"},
"attention_mask": {0: "batch_size", 1: "sequence_length"},
}
if self.use_past_in_inputs:
self.add_past_key_values(common_inputs, direction="inputs")
return common_inputs


@register_in_tasks_manager("audio-spectrogram-transformer", *["feature-extraction", "audio-classification"])
class ASTOpenVINOConfig(OpenVINOConfig):
NORMALIZED_CONFIG_CLASS = NormalizedConfig.with_args(
Expand Down
Loading
Loading