async def find_failing_modules(
        self,
        inputs: Tuple[torch.tensor],
        compare_outputs: CompareOutputs,
        source_module_keys: Optional[List[TorchScriptModuleInfo.Key]] = None,
    ) -> List[TorchScriptModuleMappingInfo]:
        """
        Asynchronously finds failing operations in the converted model.

        This method compares the outputs of the source PyTorch model with the
        converted Core ML model to identify operations that produce different results.

        Parameters
        ----------
        inputs : Tuple[torch.tensor]
            Input data for the models.

        compare_outputs : CompareOutputs
            Function to compare outputs between models.

        source_module_keys : Optional[List[TorchScriptModuleInfo.Key]]
            Specific module keys to check. Defaults to None (checks all modules).

        Returns
        -------
        List[TorchModuleMLModelMappingInfo]
            A list of failing modules.

        Examples
        --------
        .. sourcecode:: python

            class Model(torch.nn.Module):
                def forward(self, x, y):
                    return x + y


            model = Model()
            input1 = torch.full((1, 10), 1, dtype=torch.float)
            input2 = torch.full((1, 10), 2, dtype=torch.float)
            example_inputs = (input1, input2)
            comparator = (
                coremltools.models.ml_program.experimental.torch.TorchScriptMLModelComparator(
                    model=model,
                    example_inputs=example_inputs,
                    inputs=[
                        coremltools.TensorType(name="x", shape=inputs[0].shape, dtype=np.float32),
                        coremltools.TensorType(name="y", shape=inputs[1].shape, dtype=np.float32),
                    ],
                    minimum_deployment_target=coremltools.target.iOS16,
                    compute_units=coremltools.ComputeUnit.ALL,
                )
            )


            def compare_outputs(module, reference_output, target_output):
                return np.allclose(reference_output, target_output, atol=0.01)


            modules = await comparator.find_failing_modules(
                inputs=example_inputs, compare_outputs=compare_outputs
            )
        """

        statuses = {}

        if source_module_keys is None:
            source_module_keys = [self._source_root_module.source.key]

        source_module_outputs = self._source_model_inspector.inspect(
            inputs=inputs,
            module_info_keys=[key for key in self._module_map_infos],
        )

        target_inputs = {}
        for name, input in zip(self._target_model_input_names, inputs):
            target_inputs[name] = input.detach().cpu().numpy()

        source_outputs = {}
        for key, output in source_module_outputs:
            if isinstance(output, (list, tuple)):
                source_outputs[key] = output
            else:
                source_outputs[key] = [output]

        module_map_infos = []
        for module_key in source_module_keys:
            module_map_info = self._module_map_infos.get(module_key, None)
            if module_map_info is None:
                raise ValueError(
                    f"Module key '{module_key}' not found in the module map. "
                    f"Available keys are: {list(self._module_map_infos.keys())}"
                )

            module_map_infos.append(module_map_info)

        result = []
        with tqdm.tqdm(
            total=len(self._module_map_infos), desc="\033[1mAnalyzing modules...\033[0m"
        ) as pbar:
            for module_map_info in module_map_infos:
                values = await self._find_failing_modules(
                    source_outputs=source_outputs,
                    module_map_info=module_map_info,
                    inputs=target_inputs,
                    compare_outputs=compare_outputs,
                    statuses=statuses,
                    pbar=pbar,
                )

                result.extend(values)

        self._source_outputs = {}
        self._target_outputs = {}

        return result

        Asynchronously finds failing operations in the converted model.

        This method compares the outputs of the source PyTorch model with the
        converted Core ML model to identify operations that produce different results.

        Parameters
        ----------
        inputs : Tuple[torch.tensor]
            Input data for the models.

        compare_outputs : CompareOutputs
            Function to compare outputs between models.

        source_module_keys : Optional[List[TorchScriptModuleInfo.Key]]
            Specific module keys to check. Defaults to None (checks all modules).

        Returns
        -------
        List[TorchModuleMLModelMappingInfo]
            A list of failing modules.

        Examples
        --------
        .. sourcecode:: python

            class Model(torch.nn.Module):
                def forward(self, x, y):
                    return x + y


            model = Model()
            input1 = torch.full((1, 10), 1, dtype=torch.float)
            input2 = torch.full((1, 10), 2, dtype=torch.float)
            example_inputs = (input1, input2)
            comparator = (
                coremltools.models.ml_program.experimental.torch.TorchScriptMLModelComparator(
                    model=model,
                    example_inputs=example_inputs,
                    inputs=[
                        coremltools.TensorType(name="x", shape=inputs[0].shape, dtype=np.float32),
                        coremltools.TensorType(name="y", shape=inputs[1].shape, dtype=np.float32),
                    ],
                    minimum_deployment_target=coremltools.target.iOS16,
                    compute_units=coremltools.ComputeUnit.ALL,
                )
            )


            def compare_outputs(module, reference_output, target_output):
                return np.allclose(reference_output, target_output, atol=0.01)


            modules = await comparator.find_failing_modules(
                inputs=example_inputs, compare_outputs=compare_outputs
            )
        
coremltools/models/ml_program/experimental/torch/debugging_utils.py