Expose callback for download progress
Author: tristanMatthias
Pull request: no

### Feature request

When using `AutoTokenizer` and `AutoModelForCausalLM`, I would like be able to pass a callback function (or some other solution) that will allow me to report on the status of the download if it's not cached.

```
AutoTokenizer.from_pretrained(
  model_name,
  download_progress_callback=lambda perc: print(f"Downloading tokenizer: {perc}%")
)
AutoModelForCausalLM.from_pretrained(
  model_name,
  download_progress_callback=lambda perc: print(f"Downloading model: {perc}%")
)
```

Ideally this would be the **total** download progress (achievable with the `file_metadata` flag of `HfApi.model_info`).

### Motivation

I am building a UI wrapper around hugging face models, and would like to enable a "on click" install for any model. The issue is it can take quite some time to download, and the UI is left spinning sometimes for hours. I would like to provide more feedback to the end user on the status (plus maybe some time estimations eventually)

### Your contribution

Happy to contribute in any way, however I'll need to be pointed in the right direction. I've taken a peruse through the `huggingface_hub` repo, as well as this one, but am a little unsure of how to approach this. In particular, I'm unsure how a model determines _which specific_ files to download from the hub.

Comments:
This looks like a feature that would need to be implemented in `huggingface_hub` first, then we would use it here and pass along the proper argument.

cc @Wauplin and @LysandreJik 

Hey @tristanMatthias :wave: This is a tricky feature request as I don't want to complexify too much the current API/implementation of the underlying methods to download files. It is quite unknown but in `snapshot_download` there is a [`tqdm_class: Optional[tqdm]`](https://huggingface.co/docs/huggingface_hub/v0.13.3/en/package_reference/file_download#huggingface_hub.snapshot_download.tqdm_class) parameter that can be passed. Instead of providing a callback, you overwrite completely the progress bar that is used. The passed class must inherit from `tqdm.auto.tqdm` or at least mimic its behavior. 

What we can do in `huggingface_hub` is to add this parameter to `hf_hub_download` as well. Then `transformers` would have to adapt its API. What do you think about it? If it fits your need, I can point you the code that needs to be updated in `hfh`.

This issue has been automatically marked as stale because it has not had recent activity. If you think this still needs to be addressed please comment on this thread.

Please note that issues that do not follow the [contributing guidelines](https://github.com/huggingface/transformers/blob/main/CONTRIBUTING.md) are likely to be ignored.

@Wauplin 

Hey! I'm looking for a similar callback for loading progress straight from the file, which should be easier since loading is likely handled directly in transformers. Can you point me to the right place? I can't seem to find where loading happens (for Llama)

Hi @Ednaordinary, I'm not sure to understand what the progress would be for. Do you want to display a progress when reading a file that is on the disk? 

Usually, `transformers` checks if a file is already in the cache using [`_get_cache_file_to_return`](https://github.com/huggingface/transformers/blob/87be06ca77166e6a6215eee5a990ab9f07238a18/src/transformers/utils/hub.py#L149)


Thanks! I think this is what I need. I'm looking for the function that creates the tqdm progress bar when loading the model files, specifically, but this should also work since it's called to get each individual file

Hi @Wauplin!

I've been playing around with the optional ```tqdm_class``` parameter to ```snapshot_download```. From the behavior (and digging through the code a bit), it seems that this parameter will allow me to be notified when upon completion of each file that is downloaded.. is that right? 

In other words, it currently can't be used to, say, provide an overall % completion (number of bytes downloaded / total size of all files in requested HF repo) -- right? I very well could have missed something..

I have the same exact motivation as @tristanMatthias, where I'd like to somehow connect ```snapshot_download``` to a UI progress bar to reduce user stress.

Thanks!



> it seems that this parameter will allow me to be notified when upon completion of each file that is downloaded.. is that right?

This is correct yes.

> In other words, it currently can't be used to, say, provide an overall % completion (number of bytes downloaded / total size of all files in requested HF repo) -- right?

Correct yes.

For now we have:
- a progress bar to track number of files to download, regardless of their size => this is where `tqdm_class` is used
- a progress bar per file to track downloaded bytes => only displayed when file has not been downloaded yet. Not possible to pass a custom progress bar for this in current implementation.

The problem with having a global progress bar to track bytes to download across all files is that it would require to check the file size and caching status of every file before trying to download the first one. We would also have to synchronize the global progress bar in all downloading thread. This would add quite some complexity / overhead to the logic.

> > it seems that this parameter will allow me to be notified when upon completion of each file that is downloaded.. is that right?
> 
> This is correct yes.
> 
> > In other words, it currently can't be used to, say, provide an overall % completion (number of bytes downloaded / total size of all files in requested HF repo) -- right?
> 
> Correct yes.
> 
> For now we have:
> 
> * a progress bar to track number of files to download, regardless of their size => this is where `tqdm_class` is used
> * a progress bar per file to track downloaded bytes => only displayed when file has not been downloaded yet. Not possible to pass a custom progress bar for this in current implementation.
> 
> The problem with having a global progress bar to track bytes to download across all files is that it would require to check the file size and caching status of every file before trying to download the first one. We would also have to synchronize the global progress bar in all downloading thread. This would add quite some complexity / overhead to the logic.

Thanks for the reply!

Makes sense -- I can understand why you wouldn't want to add that kind of complexity to the internals of snapshot_download. I found some examples that use ```HfFileSystem, hf_hub_url``` to get list of repo files / URLs. With this, I can just download the needed repo files via requests module, and keep track of / update *overall* %.

Regards!

Glad to know you've found a workaround for your use case! Feel free to share a snippet for the community if you have something sharable. Might help some other users in the future 🤗