def convert_and_compare(
    input_data,
    model_spec,
    expected_results=None,
    atol=1e-4,
    rtol=1e-05,
    backend=("neuralnetwork", "fp32"),
    converter_input_type=None,
    compute_unit=ct.ComputeUnit.CPU_ONLY,
    minimum_deployment_target=None,
    converter=ct.convert,
):
    """
    If expected results is not set, it will by default
    be set to the flattened output of the torch model.

    Inputs:

    - input_data: torch.tensor or list[torch.tensor]
    """
    if isinstance(model_spec, str):
        torch_model = torch.jit.load(model_spec)
    else:
        torch_model = model_spec
    if _HAS_TORCH_EXPORT_API and isinstance(torch_model, ExportedProgram):
        torch_model = torch_model.module()

    if not isinstance(input_data, (list, tuple)):
        input_data = [input_data]

    if expected_results is None:
        torch_input = _copy_input_data(input_data)
        expected_results = torch_model(*torch_input)
    expected_results = flatten_and_detach_torch_results(expected_results)

    PYTEST_CURRENT_TEST = os.environ.get("PYTEST_CURRENT_TEST").split("(call)")[0].strip()
    if PYTEST_CURRENT_TEST in debug_save_mlmodels:
        serialization_path = _create_current_pytest_serialization_path()
        Path(serialization_path).mkdir(parents=True, exist_ok=True)
        flat_inputs = flatten_and_detach_torch_results(input_data)
        np.savez(serialization_path + "ref_inputs.npz", *flat_inputs)
        np.savez(serialization_path + "ref_outputs.npz", *expected_results)

    mlmodel = convert_to_mlmodel(
        model_spec,
        input_data,
        backend=backend,
        converter_input_type=converter_input_type,
        compute_unit=compute_unit,
        minimum_deployment_target=minimum_deployment_target,
        converter=converter,
    )

    coreml_inputs = convert_to_coreml_inputs(mlmodel.input_description, input_data)

    if not _IS_MACOS or (mlmodel.is_package and coremltoolsutils._macos_version() < (12, 0)):
        return model_spec, mlmodel, coreml_inputs, None

    _, dtype = backend
    if mlmodel.compute_unit != ct.ComputeUnit.CPU_ONLY or (dtype == "fp16"):
        atol = max(atol * 100.0, 5e-1)
        rtol = max(rtol * 100.0, 5e-2)

    if not coremltoolsutils._has_custom_layer(mlmodel._spec):
        coreml_preds = mlmodel.predict(coreml_inputs)
        coreml_outputs = mlmodel._spec.description.output
        coreml_results = [coreml_preds[output.name] for output in coreml_outputs]
        for torch_result, coreml_result in zip(expected_results, coreml_results):

            if torch_result.shape == ():
                torch_result = np.array([torch_result])
            np.testing.assert_equal(coreml_result.shape, torch_result.shape)
            np.testing.assert_allclose(coreml_result, torch_result, atol=atol, rtol=rtol)
    return model_spec, mlmodel, coreml_inputs, coreml_preds

    If expected results is not set, it will by default
    be set to the flattened output of the torch model.

    Inputs:

    - input_data: torch.tensor or list[torch.tensor]
    
coremltools/converters/mil/frontend/torch/test/testing_utils.py