Repository: Lightning-AI/torchmetrics

Issue:
Error importing torchmetrics
## 🐛 Bug

When `transformers.models.auto` is imported somewhere before `torchmetrics`, the following error is raised: `ValueError: transformers.models.auto.__spec__ is None`.

I believe this is caused by how transformers lazyly [adds this module to `sys.modules`](https://github.com/huggingface/transformers/blob/master/src/transformers/models/auto/__init__.py#L251) combined to how torchmetrics checks for it's availability with [_module_available](https://github.com/PyTorchLightning/metrics/blob/master/torchmetrics/utilities/imports.py#L25).

This causes [find_spec](https://github.com/python/cpython/blob/main/Lib/importlib/util.py#L73) to raise an uncatched ValueError, introduced in https://github.com/PyTorchLightning/metrics/pull/739 with `_TRANSFORMERS_AUTO_AVAILABLE = _module_available("transformers.models.auto")`

### To Reproduce

Steps to reproduce the behavior:

1. `pip install transformers`
2. `pip install torchmetrics`
3. `python -c "from transformers.models import auto; from torchmetrics import Metric"`

```
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "envs/test-spec/lib/python3.7/site-packages/torchmetrics/__init__.py", line 14, in <module>
    from torchmetrics import functional  # noqa: E402
  File "envs/test-spec/lib/python3.7/site-packages/torchmetrics/functional/__init__.py", line 14, in <module>
    from torchmetrics.functional.audio.pit import permutation_invariant_training, pit, pit_permutate
  File "envs/test-spec/lib/python3.7/site-packages/torchmetrics/functional/audio/__init__.py", line 14, in <module>
    from torchmetrics.functional.audio.pit import permutation_invariant_training, pit, pit_permutate  # noqa: F401
  File "envs/test-spec/lib/python3.7/site-packages/torchmetrics/functional/audio/pit.py", line 24, in <module>
    from torchmetrics.utilities.imports import _SCIPY_AVAILABLE
  File "envs/test-spec/lib/python3.7/site-packages/torchmetrics/utilities/imports.py", line 92, in <module>
    _TRANSFORMERS_AUTO_AVAILABLE = _module_available("transformers.models.auto")
  File "envs/test-spec/lib/python3.7/site-packages/torchmetrics/utilities/imports.py", line 36, in _module_available
    return find_spec(module_path) is not None
  File "envs/test-spec/lib/python3.7/importlib/util.py", line 117, in find_spec
    raise ValueError('{}.__spec__ is None'.format(name))
ValueError: transformers.models.auto.__spec__ is None
```

### Expected behavior

No exception being raised. 

### Environment

- PyTorch Version (e.g., 1.0): 1.10.1'
- OS (e.g., Linux): MacOS
- How you installed PyTorch (`conda`, `pip`, source): pip
- Python version: 3.7, 3.8, 3.9, 3.10


Discussion:
Hi! thanks for your contribution!, great first issue!
that is interesting, I can replicate it and it is about this combination in a single python call, in contrast, if I call them separately everything works fine:
```bash
python -c "from transformers.models import auto"
python -c "from torchmetrics import Metric"
```

Resolving patch:
diff --git a/torchmetrics/utilities/imports.py b/torchmetrics/utilities/imports.py
--- a/torchmetrics/utilities/imports.py
+++ b/torchmetrics/utilities/imports.py
@@ -22,18 +22,16 @@
 from pkg_resources import DistributionNotFound, get_distribution
 
 
-def _module_available(module_path: str) -> bool:
-    """Check if a path is available in your environment.
+def _package_available(package_name: str) -> bool:
+    """Check if a package is available in your environment.
 
-    >>> _module_available('os')
+    >>> _package_available('os')
     True
-    >>> _module_available('os.bla')
-    False
-    >>> _module_available('bla.bla')
+    >>> _package_available('bla')
     False
     """
     try:
-        return find_spec(module_path) is not None
+        return find_spec(package_name) is not None
     except AttributeError:
         # Python 3.6
         return False
@@ -42,6 +40,30 @@ def _module_available(module_path: str) -> bool:
         return False
 
 
+def _module_available(module_path: str) -> bool:
+    """Check if a module path is available in your environment.
+
+    >>> _module_available('os')
+    True
+    >>> _module_available('os.bla')
+    False
+    >>> _module_available('bla.bla')
+    False
+    """
+    module_names = module_path.split(".")
+    if not _package_available(module_names[0]):
+        return False
+    try:
+        module = import_module(module_names[0])
+    except ImportError:
+        return False
+    for name in module_names[1:]:
+        if not hasattr(module, name):
+            return False
+        module = getattr(module, name)
+    return True
+
+
 def _compare_version(package: str, op: Callable, version: str) -> Optional[bool]:
     """Compare package version with some requirements.
 
@@ -76,22 +98,22 @@ def _compare_version(package: str, op: Callable, version: str) -> Optional[bool]
 _TORCH_GREATER_EQUAL_1_7: Optional[bool] = _compare_version("torch", operator.ge, "1.7.0")
 _TORCH_GREATER_EQUAL_1_8: Optional[bool] = _compare_version("torch", operator.ge, "1.8.0")
 
-_LIGHTNING_AVAILABLE: bool = _module_available("pytorch_lightning")
-_JIWER_AVAILABLE: bool = _module_available("jiwer")
-_NLTK_AVAILABLE: bool = _module_available("nltk")
-_ROUGE_SCORE_AVAILABLE: bool = _module_available("rouge_score")
-_BERTSCORE_AVAILABLE: bool = _module_available("bert_score")
-_SCIPY_AVAILABLE: bool = _module_available("scipy")
-_TORCH_FIDELITY_AVAILABLE: bool = _module_available("torch_fidelity")
-_LPIPS_AVAILABLE: bool = _module_available("lpips")
-_PYCOCOTOOLS_AVAILABLE: bool = _module_available("pycocotools")
-_TORCHVISION_AVAILABLE: bool = _module_available("torchvision")
+_LIGHTNING_AVAILABLE: bool = _package_available("pytorch_lightning")
+_JIWER_AVAILABLE: bool = _package_available("jiwer")
+_NLTK_AVAILABLE: bool = _package_available("nltk")
+_ROUGE_SCORE_AVAILABLE: bool = _package_available("rouge_score")
+_BERTSCORE_AVAILABLE: bool = _package_available("bert_score")
+_SCIPY_AVAILABLE: bool = _package_available("scipy")
+_TORCH_FIDELITY_AVAILABLE: bool = _package_available("torch_fidelity")
+_LPIPS_AVAILABLE: bool = _package_available("lpips")
+_PYCOCOTOOLS_AVAILABLE: bool = _package_available("pycocotools")
+_TORCHVISION_AVAILABLE: bool = _package_available("torchvision")
 _TORCHVISION_GREATER_EQUAL_0_8: Optional[bool] = _compare_version("torchvision", operator.ge, "0.8.0")
-_TQDM_AVAILABLE: bool = _module_available("tqdm")
-_TRANSFORMERS_AVAILABLE: bool = _module_available("transformers")
+_TQDM_AVAILABLE: bool = _package_available("tqdm")
+_TRANSFORMERS_AVAILABLE: bool = _package_available("transformers")
 _TRANSFORMERS_AUTO_AVAILABLE = _module_available("transformers.models.auto")
-_PESQ_AVAILABLE: bool = _module_available("pesq")
-_SACREBLEU_AVAILABLE: bool = _module_available("sacrebleu")
-_REGEX_AVAILABLE: bool = _module_available("regex")
-_PYSTOI_AVAILABLE: bool = _module_available("pystoi")
-_FAST_BSS_EVAL_AVAILABLE: bool = _module_available("fast_bss_eval")
+_PESQ_AVAILABLE: bool = _package_available("pesq")
+_SACREBLEU_AVAILABLE: bool = _package_available("sacrebleu")
+_REGEX_AVAILABLE: bool = _package_available("regex")
+_PYSTOI_AVAILABLE: bool = _package_available("pystoi")
+_FAST_BSS_EVAL_AVAILABLE: bool = _package_available("fast_bss_eval")


Test patch: