Repository: speechbrain/speechbrain

Issue:
[Bug]: `foreign_class` not working with auth token
### Describe the bug

Hello,
I am trying to load a custom encoder from a private HuggingFace model with `foreign_class` but am faced with the following issues.
1. It seems `use_auth_token` is not properly passed here:
https://github.com/speechbrain/speechbrain/blob/64c8fa951bdade7e28c81b37452331c61af7b548/speechbrain/pretrained/interfaces.py#L91-L92
That is because `use_auth_token` is the sixth parameter in `fetch` and as such should be called like:
   ```
   fetch(hparams_file, source, savedir, use_auth_token=use_auth_token)
   ```
   By changing that I was able to download the custom encoder.py and hyperparams.yaml

2. Authentication fails again while trying to fetch the model checkpoints during `collect_files` of the Pretrainer:
https://github.com/speechbrain/speechbrain/blob/64c8fa951bdade7e28c81b37452331c61af7b548/speechbrain/utils/parameter_transfer.py#L202-L204
Where there seems to be no option to pass the auth token. 


### Expected behaviour

Passing the HuggingFace access token in `foreign_class(..., use_auth_token={token})` should authenticate and download the required files.

### To Reproduce

_No response_

### Versions

speechbrain==0.5.13

### Relevant log output

_No response_

### Additional context

_No response_


Discussion:

Resolving patch:
diff --git a/speechbrain/pretrained/interfaces.py b/speechbrain/pretrained/interfaces.py
--- a/speechbrain/pretrained/interfaces.py
+++ b/speechbrain/pretrained/interfaces.py
@@ -7,6 +7,7 @@
  * Mirco Ravanelli 2020
  * Titouan Parcollet 2021
  * Abdel Heba 2021
+ * Andreas Nautsch 2022
 """
 import logging
 import hashlib
@@ -41,6 +42,7 @@ def foreign_class(
     overrides={},
     savedir=None,
     use_auth_token=False,
+    download_only=False,
     **kwargs,
 ):
     """Fetch and load an interface from an outside source
@@ -80,6 +82,8 @@ def foreign_class(
     use_auth_token : bool (default: False)
         If true Hugginface's auth_token will be used to load private models from the HuggingFace Hub,
         default is False because majority of models are public.
+    download_only : bool (default: False)
+        If true, class and instance creation is skipped.
 
     Returns
     -------
@@ -88,8 +92,24 @@ def foreign_class(
     """
     if savedir is None:
         savedir = f"./pretrained_models/{classname}-{hashlib.md5(source.encode('UTF-8', errors='replace')).hexdigest()}"
-    hparams_local_path = fetch(hparams_file, source, savedir, use_auth_token)
-    pymodule_local_path = fetch(pymodule_file, source, savedir, use_auth_token)
+    hparams_local_path = fetch(
+        filename=hparams_file,
+        source=source,
+        savedir=savedir,
+        overwrite=False,
+        save_filename=None,
+        use_auth_token=use_auth_token,
+        revision=None,
+    )
+    pymodule_local_path = fetch(
+        filename=pymodule_file,
+        source=source,
+        savedir=savedir,
+        overwrite=False,
+        save_filename=None,
+        use_auth_token=use_auth_token,
+        revision=None,
+    )
     sys.path.append(str(pymodule_local_path.parent))
 
     # Load the modules:
@@ -102,13 +122,14 @@ def foreign_class(
     # For distributed setups, have this here:
     run_on_main(pretrainer.collect_files, kwargs={"default_source": source})
     # Load on the CPU. Later the params can be moved elsewhere by specifying
-    # run_opts={"device": ...}
-    pretrainer.load_collected(device="cpu")
+    if not download_only:
+        # run_opts={"device": ...}
+        pretrainer.load_collected(device="cpu")
 
-    # Import class and create instance
-    module = import_from_path(pymodule_local_path)
-    cls = getattr(module, classname)
-    return cls(modules=hparams["modules"], hparams=hparams, **kwargs)
+        # Import class and create instance
+        module = import_from_path(pymodule_local_path)
+        cls = getattr(module, classname)
+        return cls(modules=hparams["modules"], hparams=hparams, **kwargs)
 
 
 class Pretrained(torch.nn.Module):
@@ -288,6 +309,7 @@ def from_hparams(
         savedir=None,
         use_auth_token=False,
         revision=None,
+        download_only=False,
         **kwargs,
     ):
         """Fetch and load based from outside source based on HyperPyYAML file
@@ -335,16 +357,30 @@ def from_hparams(
             The model revision corresponding to the HuggingFace Hub model revision.
             This is particularly useful if you wish to pin your code to a particular
             version of a model hosted at HuggingFace.
+        download_only : bool (default: False)
+            If true, class and instance creation is skipped.
         """
         if savedir is None:
             clsname = cls.__name__
             savedir = f"./pretrained_models/{clsname}-{hashlib.md5(source.encode('UTF-8', errors='replace')).hexdigest()}"
         hparams_local_path = fetch(
-            hparams_file, source, savedir, use_auth_token, revision
+            filename=hparams_file,
+            source=source,
+            savedir=savedir,
+            overwrite=False,
+            save_filename=None,
+            use_auth_token=use_auth_token,
+            revision=revision,
         )
         try:
             pymodule_local_path = fetch(
-                pymodule_file, source, savedir, use_auth_token, revision
+                filename=pymodule_file,
+                source=source,
+                savedir=savedir,
+                overwrite=False,
+                save_filename=None,
+                use_auth_token=use_auth_token,
+                revision=revision,
             )
             sys.path.append(str(pymodule_local_path.parent))
         except ValueError:
@@ -367,11 +403,12 @@ def from_hparams(
         # For distributed setups, have this here:
         run_on_main(pretrainer.collect_files, kwargs={"default_source": source})
         # Load on the CPU. Later the params can be moved elsewhere by specifying
-        # run_opts={"device": ...}
-        pretrainer.load_collected(device="cpu")
+        if not download_only:
+            # run_opts={"device": ...}
+            pretrainer.load_collected(device="cpu")
 
-        # Now return the system
-        return cls(hparams["modules"], hparams, **kwargs)
+            # Now return the system
+            return cls(hparams["modules"], hparams, **kwargs)
 
 
 class EndToEndSLU(Pretrained):
diff --git a/speechbrain/utils/parameter_transfer.py b/speechbrain/utils/parameter_transfer.py
--- a/speechbrain/utils/parameter_transfer.py
+++ b/speechbrain/utils/parameter_transfer.py
@@ -200,7 +200,13 @@ def collect_files(self, default_source=None):
                     "and no default_source given!"
                 )
             path = fetch(
-                filename, source, self.collect_in, save_filename=save_filename
+                filename=filename,
+                source=source,
+                savedir=self.collect_in,
+                overwrite=False,
+                save_filename=save_filename,
+                use_auth_token=False,
+                revision=None,
             )
             loadable_paths[name] = path
         return loadable_paths


Test patch: