def merge_decoders(
    decoder: Union[ModelProto, Path, str],
    decoder_with_past: Union[ModelProto, Path, str],
    save_path: Optional[Union[Path, str]] = None,
    graph_name: str = "merged",
    strict: bool = True,
    save_as_external_data: bool = True,
    all_tensors_to_one_file: bool = True,
    check_model: bool = True,
) -> ModelProto:
    """Input decoder ONNX model and decoder with past ONNX model are merged into one ONNX model with if logic.

    Args:
        decoder (`Union[Path, str]`):
            Decoder ONNX model.
        decoder_with_past (`Union[Path, str]`):
            Decoder with past ONNX model.
        save_path (`Union[str, Path]`):
            The path to save merged ONNX model.
        graph_name (`str`, defaults to `"merged"`):
            Name of the parent graph (graph of the control flow node).
        strict (`bool`, defaults to `True`):
            When set, the decoder and decoder_with_past are expected to have strictly the same number of outputs.
            When False, the decoder is allowed to have more outputs that decoder_with_past, in which case constant
            outputs are added to match the number of outputs.
        save_as_external_data (`bool`):
            Serializes tensor data to separate files instead of directly in the ONNX file. Large models (>2GB)
            may be forced to save external data regardless of the value of this parameter.
        all_tensors_to_one_file (`bool`):
            Effective only if save_as_external_data is True. If true, save all tensors to one external file
            specified by 'external_data_name'. If false, save each tensor to a file named with the tensor name.
        check_model (`bool`):
            Check model after merging.

    """
    if isinstance(decoder, (str, Path)):
        decoder = onnx.load(Path(decoder).as_posix())

    if isinstance(decoder_with_past, (str, Path)):
        decoder_with_past = onnx.load(Path(decoder_with_past).as_posix())

    decoder_opset: int = _get_onnx_opset(decoder)
    decoder_with_past_opset: int = _get_onnx_opset(decoder_with_past)
    if decoder_opset != decoder_with_past_opset:
        raise ValueError(
            f"Decoder's opset is {decoder_opset}, but decoder with past's opset is {decoder_with_past_opset}. "
            "Make sure having the same opset before merging."
        )

    all_inputs: list[ValueInfoProto] = _get_all_inputs([decoder, decoder_with_past])

    # Replace the axis name `sequence_length` of the attention_mask input by `attention_mask_sequence_length`.
    # This is because the merged model `input_ids` and `attention_mask` inputs may not always have the same length
    # on the 2nd axis. In the first pass, `input_ids` and `attention_mask` are indeed of the same length, but in
    # later pass `input_ids` is of length 1 while `attention_mask` is of length `past_sequence_length + 1`
    for inp in all_inputs:
        if inp.name == "attention_mask":
            if inp.type.tensor_type.shape.dim[1].dim_param != "sequence_length":
                raise ValueError("Expected attention_mask second axis to be dynamic and named `sequence_length`.")

            inp.type.tensor_type.shape.dim[1].dim_param = "attention_mask_sequence_length"

    _unify_onnx_outputs(decoder, decoder_with_past, strict=strict)
    deduplicated_initializers: list[TensorProto] = _deduplicated_cross_model_initializers(
        [decoder, decoder_with_past], suffix=graph_name
    )

    # Make subgraphs
    no_past_branch: GraphProto = _convert_graph_to_subgraph(decoder.graph, "no_past")
    with_past_branch: GraphProto = _convert_graph_to_subgraph(decoder_with_past.graph, "with_past")

    # Merge subgraphs
    merged_graph: GraphProto = _merge_graphs_with_if_operator(
        all_inputs, deduplicated_initializers, no_past_branch, with_past_branch, graph_name
    )

    # Preserve imports from the decoder without/with past ONNX
    opset_imports: list[OperatorSetIdProto] = []
    opset_domains: set[str] = set()
    for opset_import in list(decoder.opset_import) + list(decoder_with_past.opset_import):
        if opset_import.domain not in opset_domains:
            opset_imports.append(opset_import)
            opset_domains.add(opset_import.domain)

    merged_model: ModelProto = onnx.helper.make_model(merged_graph, opset_imports=opset_imports)

    if save_path:
        save_path = Path(save_path).as_posix()
        onnx.save(
            merged_model,
            save_path,
            save_as_external_data=save_as_external_data,
            all_tensors_to_one_file=all_tensors_to_one_file,
            location=os.path.basename(save_path) + ".data",
        )

        if check_model:
            try:
                onnx.checker.check_model(save_path)
            except Exception as e:
                if "No Op registered for" in str(e):
                    pass
                else:
                    raise

    return merged_model
Input decoder ONNX model and decoder with past ONNX model are merged into one ONNX model with if logic.

    Args:
        decoder (`Union[Path, str]`):
            Decoder ONNX model.
        decoder_with_past (`Union[Path, str]`):
            Decoder with past ONNX model.
        save_path (`Union[str, Path]`):
            The path to save merged ONNX model.
        graph_name (`str`, defaults to `"merged"`):
            Name of the parent graph (graph of the control flow node).
        strict (`bool`, defaults to `True`):
            When set, the decoder and decoder_with_past are expected to have strictly the same number of outputs.
            When False, the decoder is allowed to have more outputs that decoder_with_past, in which case constant
            outputs are added to match the number of outputs.
        save_as_external_data (`bool`):
            Serializes tensor data to separate files instead of directly in the ONNX file. Large models (>2GB)
            may be forced to save external data regardless of the value of this parameter.
        all_tensors_to_one_file (`bool`):
            Effective only if save_as_external_data is True. If true, save all tensors to one external file
            specified by 'external_data_name'. If false, save each tensor to a file named with the tensor name.
        check_model (`bool`):
            Check model after merging.

    
olive/passes/onnx/merge_decoders.py