def parse_steps(model: onnx.ModelProto, config: list[dict]):
    """Parse the config and return a dictionary of step name and its parameters.

    ## Config examples:
    1. if there io_map is missing, the config could be simplified as:
        ```
        [
            {
                "ReverseAxis": {
                    "axis": 2,
                    "dim_value": 3,
                    "name": "BGR_to_RGB"
                }
            },
            {
                "Normalize": {
                    "normalization_values": [[0.485, 0.229],[0.456,0.224], [0.406,0.225]],
                    "layout": "CHW"
                }
            }
        ]
        ```

    2. if there is io_map, the config looks like:
        ```
        {
            "Resize": {
                "params": {
                    "resize_to": [
                        {
                            "type": "__model_input__",
                            "input_index": 0,
                            "dim_index": -1
                        },
                        {
                            "type": "__model_output__",
                            "output_index": 0,
                            "dim_index": -2
                        }
                    ]
                },
                "io_map": [["ConvertImageToBGR",0,0]]
            }
        }
        ```
    ## Config schema:

    1. simple form:
         ```
         {"step_name": {"param_name": param_value}}
         ```

    2. full form:
        ```
        {
            "step_name": {
                "params": {"param_name": param_value},
                "io_map": [[step_name, input_index, output_index]]
            }
        }
        ```

       The detailed io_map definition and usage is
       https://github.com/microsoft/onnxruntime-extensions/blob/main/onnxruntime_extensions/tools/Example%20usage%20of%20the%20PrePostProcessor.md#iomapentry-usage

       Please note the io_map is optional, if it is missing, the config is simplified as the simple form.

    3. Customized parameter type for parameter value:
        ```
        {
            "SentencePieceTokenizer": {
                "tokenizer_param": {
                    "type": "TokenizerParam",
                    "params": {
                        "vocab_or_file": "test_data/sentencepiece/test_model.model"
                    }
                }
            }
        }
        ```
       In this example, the type will be looked in the imported modules. So, please remember to import it before
       looking up the type. The params dictionary is the parameters for the type class.

    4. model input and output placeholder.
       The PrePostPipeline will add some operators into the onnx graph. Sometimes, we need specify the model input or
       output pins for the steps definition. For example, we need use w_in and h_in (input model shape dimension) in
       Resize steps in superresolution. For this purpose, the following two placeholder type is introduced:
       a), `__model_input__`: the input model shape dimension. The input_index is the input index of the model.
            ```
            {
                "type": "__model_input__",
                "input_index": 0,
                "dim_index": -1
            }
            ```
        b), `__model_output__`: the output model shape dimension. The output_index is the output index of the model.
            ```
            {
                "type": "__model_output__",
                "output_index": 0,
                "dim_index": -2
            }
            ```
        When these config is parsed, they will be converted to using the ModelProto shape information.

    5. For list value, they will be treated to tuple in the function. User could explicitly specify the type as list if
       the default tuple behavior is not expected. Instead of using `"param_name": param_value`, user could use the
       following form by using `type` and `value`:
            ```
            "explicit_list": {
                "type": "list",
                "value": [
                    1,
                    2,
                    3
                ]
            }
            ```
    6. the full example of the config is here:
        TODO: add the file link demonstration here.

    """
    step_configs = []
    for step_config in config:
        step_config_result = parse_step_config(model, step_config)
        step_configs.append(step_config_result[0])
    return step_configs
Parse the config and return a dictionary of step name and its parameters.

    ## Config examples:
    1. if there io_map is missing, the config could be simplified as:
        ```
        [
            {
                "ReverseAxis": {
                    "axis": 2,
                    "dim_value": 3,
                    "name": "BGR_to_RGB"
                }
            },
            {
                "Normalize": {
                    "normalization_values": [[0.485, 0.229],[0.456,0.224], [0.406,0.225]],
                    "layout": "CHW"
                }
            }
        ]
        ```

    2. if there is io_map, the config looks like:
        ```
        {
            "Resize": {
                "params": {
                    "resize_to": [
                        {
                            "type": "__model_input__",
                            "input_index": 0,
                            "dim_index": -1
                        },
                        {
                            "type": "__model_output__",
                            "output_index": 0,
                            "dim_index": -2
                        }
                    ]
                },
                "io_map": [["ConvertImageToBGR",0,0]]
            }
        }
        ```
    ## Config schema:

    1. simple form:
         ```
         {"step_name": {"param_name": param_value}}
         ```

    2. full form:
        ```
        {
            "step_name": {
                "params": {"param_name": param_value},
                "io_map": [[step_name, input_index, output_index]]
            }
        }
        ```

       The detailed io_map definition and usage is
       https://github.com/microsoft/onnxruntime-extensions/blob/main/onnxruntime_extensions/tools/Example%20usage%20of%20the%20PrePostProcessor.md#iomapentry-usage

       Please note the io_map is optional, if it is missing, the config is simplified as the simple form.

    3. Customized parameter type for parameter value:
        ```
        {
            "SentencePieceTokenizer": {
                "tokenizer_param": {
                    "type": "TokenizerParam",
                    "params": {
                        "vocab_or_file": "test_data/sentencepiece/test_model.model"
                    }
                }
            }
        }
        ```
       In this example, the type will be looked in the imported modules. So, please remember to import it before
       looking up the type. The params dictionary is the parameters for the type class.

    4. model input and output placeholder.
       The PrePostPipeline will add some operators into the onnx graph. Sometimes, we need specify the model input or
       output pins for the steps definition. For example, we need use w_in and h_in (input model shape dimension) in
       Resize steps in superresolution. For this purpose, the following two placeholder type is introduced:
       a), `__model_input__`: the input model shape dimension. The input_index is the input index of the model.
            ```
            {
                "type": "__model_input__",
                "input_index": 0,
                "dim_index": -1
            }
            ```
        b), `__model_output__`: the output model shape dimension. The output_index is the output index of the model.
            ```
            {
                "type": "__model_output__",
                "output_index": 0,
                "dim_index": -2
            }
            ```
        When these config is parsed, they will be converted to using the ModelProto shape information.

    5. For list value, they will be treated to tuple in the function. User could explicitly specify the type as list if
       the default tuple behavior is not expected. Instead of using `"param_name": param_value`, user could use the
       following form by using `type` and `value`:
            ```
            "explicit_list": {
                "type": "list",
                "value": [
                    1,
                    2,
                    3
                ]
            }
            ```
    6. the full example of the config is here:
        TODO: add the file link demonstration here.

    
olive/passes/onnx/pipeline/step_utils.py