Skip to content
Closed
20 changes: 20 additions & 0 deletions optimum/exporters/onnx/model_configs.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
NormalizedTimeSeriesForecastingConfig,
NormalizedVisionConfig,
PerceiverDummyInputGenerator,
TimesFMDummyInputGenerator,
VitPoseDummyInputGenerator,
is_diffusers_available,
is_diffusers_version,
Expand Down Expand Up @@ -2641,6 +2642,25 @@ class EncoderDecoderOnnxConfig(EncoderDecoderBaseOnnxConfig):
DEFAULT_ONNX_OPSET = 14 # uses SDPA in Transformers, hence opset>=14.


class TimesFMOnnxConfig(OnnxConfig):
NORMALIZED_CONFIG_CLASS = NormalizedTimeSeriesForecastingConfig
MIN_TRANSFORMERS_VERSION = version.parse("4.52.0")
DUMMY_INPUT_GENERATOR_CLASSES = (TimesFMDummyInputGenerator,)
DEFAULT_ONNX_OPSET = 14 # uses SDPA in Transformers, needs opset>=14

@property
def inputs(self) -> Dict[str, Dict[int, str]]:
return {"past_values": {0: "batch_size", 1: "sequence_length"}}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

an issue is remaining before we can merge : it seems that the resulting onnx graph doesn't considered the batch_size as dynamic (won't accept one different than the one given during export) likely coming from :

https://github.com/huggingface/transformers/blob/79d4bc761d9da7a125b65a3b8c09441608d05436/src/transformers/models/timesfm/modeling_timesfm.py#L791

@kashif any chance we can add the modification directly in the transformers modeling ? otherwise we need to patch the model before export

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

checking but i believe so

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, that does look to be the source of the loss of dynamic shapes. torch.onnx.export doesn't play well with python list operations, so we'd need to refactor it to use tensor operations, if possible.


@property
def outputs(self) -> Dict[str, Dict[int, str]]:
return {
"last_hidden_state": {0: "batch_size"},
"mean_predictions": {0: "batch_size"},
"full_predictions": {0: "batch_size"},
}


class PatchTSTOnnxConfig(OnnxConfig):
NORMALIZED_CONFIG_CLASS = NormalizedTimeSeriesForecastingConfig
DUMMY_INPUT_GENERATOR_CLASSES = (DummyPatchTSTInputGenerator,)
Expand Down
5 changes: 5 additions & 0 deletions optimum/exporters/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ class TasksManager:
("pt", "visual-bert", "question-answering"): ("transformers", "VisualBertForQuestionAnswering"),
# VisionEncoderDecoderModel is not registered in AutoModelForDocumentQuestionAnswering
("pt", "vision-encoder-decoder", "document-question-answering"): ("transformers", "VisionEncoderDecoderModel"),
("pt", "timesfm", "time-series-forecasting"): ("transformers", "TimesFmModelForPrediction"),
("pt", "vitpose", "keypoint-detection"): ("transformers", "VitPoseForPoseEstimation"),
}

Expand Down Expand Up @@ -996,6 +997,10 @@ class TasksManager:
"text-classification",
onnx="Qwen2OnnxConfig",
),
"timesfm": supported_tasks_mapping(
"time-series-forecasting",
onnx="TimesFMOnnxConfig",
),
"llama": supported_tasks_mapping(
"feature-extraction",
"feature-extraction-with-past",
Expand Down
1 change: 1 addition & 0 deletions optimum/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
MistralDummyPastKeyValuesGenerator,
MultiQueryPastKeyValuesGenerator,
PerceiverDummyInputGenerator,
TimesFMDummyInputGenerator,
VitPoseDummyInputGenerator,
)
from .modeling_utils import recurse_getattr, recurse_setattr
Expand Down
25 changes: 25 additions & 0 deletions optimum/utils/input_generators.py
Original file line number Diff line number Diff line change
Expand Up @@ -1658,3 +1658,28 @@ class PerceiverDummyInputGenerator(DummyVisionStaticInputGenerator):

class VitPoseDummyInputGenerator(DummyVisionStaticInputGenerator):
pass


class TimesFMDummyInputGenerator(DummyInputGenerator):
SUPPORTED_INPUT_NAMES = ("past_values",)

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

def generate(self, input_name: str, framework: str = "pt", int_dtype: str = "int64", float_dtype: str = "fp32"):
return self.random_float_tensor(
shape=[self.batch_size, self.context_length],
min_value=-1,
max_value=1,
framework=framework,
dtype=float_dtype,
)
1 change: 1 addition & 0 deletions tests/exporters/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@
"swin2sr": "hf-internal-testing/tiny-random-Swin2SRModel",
"t5": "hf-internal-testing/tiny-random-t5",
"table-transformer": "hf-internal-testing/tiny-random-TableTransformerModel",
"timesfm": "huggingface/timesfm-tourism-monthly",
"vit": "hf-internal-testing/tiny-random-vit",
"vit-mae": "hf-internal-testing/tiny-random-ViTMAEModel",
"vit-msn": "hf-internal-testing/tiny-random-ViTMSNForImageClassification",
Expand Down