align snapshot_download to respect hfh latest version#14118
Conversation
|
The PEFT tests succeed on this branch, thanks a lot. (reminder to myself: testing with |
|
The docs for this PR live here. All of your documentation changes will be reflected on that endpoint. The docs are available until 30 days after the last update. |
BenjaminBossan
left a comment
There was a problem hiding this comment.
I can't comment on the logic of the fix, but it resolves the PEFT errors. Thanks.
| lambda image_url_or_path: load_image(image_url_or_path) | ||
| if urlparse(image_url_or_path).scheme | ||
| else Image.open(image_url_or_path).convert("RGB") | ||
| lambda image_url_or_path: ( |
There was a problem hiding this comment.
Changes seem to be unrelated.
|
A question: Is there going to be a patch release with this fix? If not, I need to prepare a fix on PEFT to exempt the failing tests until Diffusers 0.40 is released. |
|
It's a breaking change from hfh and not diffusers. So, maybe you will need to wait till the next release. |
Due to a recent change in huggingface-hub, loading Diffusers pipelines in offline mode can fail. Since the PEFT caching mechanism works by setting offline mode, several PEFT tests are affected by this. There is a fix on the way in Diffusers, but there won't be a patch release: huggingface/diffusers#14118 Therefore, we skip these tests for now. Once Diffusers 0.40.0 releases, the tests will run again, but we can also remove the skipping logic completely.
Wauplin
left a comment
There was a problem hiding this comment.
This PR feels correct 👍 (sorry for the delay reviewing it)
Though for a broader context I still do not understand why the allow_pattern/ignore_pattern arguments are different depending on the Hub availability
It's a breaking change from hfh and not diffusers. So, maybe you will need to wait till the next release.
It's not considered as a breaking change on hfh-side so it won't be fixed in next releases no
| config_file = hf_hub_download( | ||
| pretrained_model_name, | ||
| cls.config_name, | ||
| cache_dir=cache_dir, | ||
| revision=revision, | ||
| token=token, | ||
| local_files_only=True, | ||
| ) | ||
| return Path(config_file).parent |
There was a problem hiding this comment.
hacky but "works" though you don't benefit from the new "raise if incomplete snapshot"-feature i.e. if a previous download failed mid-way it won't be caught here, meaning a separate error will be raised downstream (likely when trying to load the model) - and the base exception will have been lost in the process
Wauplin
left a comment
There was a problem hiding this comment.
(sorry just wanted to "comment" instead of "approve" -not well versed with diffusers internals- but the summary is the same^^)
I took this to mean that it will have to wait until the next Diffusers (minor) release, which will contain this fix, as there won't be a Diffusers patch release for this. |
Next release of Diffusers. I am not sure why it's not considered a breaking change on HFH side because it clearly broke things in Diffusers as we can see. From what I understand, the behaviour of the underlying HFH-side functions also changed. Maybe I am missing something. |
Mostly because it's considered as bug fix (I know it's mostly semantic^^)
did it broke things only in the tests or in real life? I feel like if we are now raising an error for an incomplete download it's better than having diffusers raise because a file is not found in a local snapshot that was supposed to contain it |
Instead of returning the cached snapshot folder without validation when offline, compute the same allow/ignore patterns as the online path (sourcing the file listing from the cached snapshot instead of model_info) and let snapshot_download validate the cached snapshot against them, so an interrupted download surfaces hfh's IncompleteSnapshotError instead of failing later at model load time. Also revert the _get_checkpoint_shard_files divergence: its patterns were already identical in both modes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
huggingface_hub>=1.22.0 reports a missing cached shard via IncompleteSnapshotError (repo-relative path) before diffusers' own cached-folder check (absolute path) runs, so assert on the shard's filename, which both messages contain. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
| try: | ||
| config_file = hf_hub_download( | ||
| pretrained_model_name, | ||
| cls.config_name, | ||
| cache_dir=cache_dir, | ||
| revision=revision, | ||
| token=token, | ||
| local_files_only=True, | ||
| ) | ||
| except LocalEntryNotFoundError: | ||
| config_file = None | ||
|
|
||
| if config_file is not None: | ||
| snapshot_folder = Path(config_file).parent | ||
| if local_files_only: | ||
| filenames = { | ||
| f.relative_to(snapshot_folder).as_posix() for f in snapshot_folder.rglob("*") if f.is_file() | ||
| } |
There was a problem hiding this comment.
requesting to download a single file to then use Path(...).parent is IMO a hacky way of getting the snapshot_folder. (hence why it needs 7 lines of explanation in comments)
to avoid that I've opened huggingface/huggingface_hub#4500 to expose the snapshot_folder in the error in case of IncompleteSnapshotError. I think this is the most explicit way to do things. In diffusers the code will look like this:
try:
snapshot_path = snapshot_download(...)
except IncompleteSnapshotError as error:
incomplete_snapshot_path = error.snapshot_pathmaking it explicit for anyone reading the code that the folder is incomplete and that we knowingly ignored it
(even though, once again, I do think the best way to tackle this is to provide the correct allow_pattern/ignore_pattern filters in the first place. I still don't understand why it's not the solution we are trying to have in this PR. If there is a rational behind not trying to fix the root cause I genuinely believe it should at the very least be mentioned/documented somewhere)
There was a problem hiding this comment.
Thanks for offering further thoughts. Post-mortem:
The reason we can't write the patterns down without any file listing: they're data-dependent. allow_patterns are largely concrete filenames chosen by variant_compatible_siblings (variant / sharded / safetensors-vs-bin resolution), and _get_ignore_patterns picks formats based on what actually exists in the repo.
For the online path, that listing comes from model_info().siblings. For the offline path, the only faithful source is the cached snapshot itself, which holds exactly what the same computation downloaded when online — so both modes compute the same patterns. We also test it here:
diffusers/tests/pipelines/test_pipelines.py
Line 508 in e92e259
More precisely, the offline path falls through into the same pattern-computation code as online, fed with a filenames' set that came from the cache instead of model_info().siblings. Before this PR, the offline path skipped all of this (patterns stayed None).
Regarding hf_hub_download(config_file), the online branch makes the identical call because model_index.json's content dictates the computation (component folders, _ignore_files, custom pipeline):
diffusers/src/diffusers/pipelines/pipeline_utils.py
Lines 1655 to 1664 in e92e259
(All of that is used for computing the patterns)
For the offline path, we are also reusing its parent as the snapshot dir, matching the pre-existing snapshot_folder = Path(config_file).parent on main.
huggingface/huggingface_hub#4500 is cool, thanks! snapshot_path on the error does locate the folder correctly. But the error only fires from snapshot_download.We need the folder before calling snapshot_download (its listing is the input to the pattern computation). Using it would mean a deliberate no-patterns call that fails on every offline diffusers load just to catch the error.
Maybe there's a way to refactor this but that's for another PR.
There was a problem hiding this comment.
Thanks for the detailed response! That makes sense then. So if I understand correctly what's missing before-hand is the list of files in the repo when in offline mode, right? Luckily we now have this information in cache -hence why we are able to tell if a folder is incomplete-. We could definitely add a method to retrieve that cached list to that you can:
- make a repo info call to get
repo.siblings - if that fails, get
repo.siblingsfrom the cache (requires a method fromhuggingface_hub) - and then compute the allow/ignore patterns from the list of files, no matter if you are in online or offline mode
Would that be interesting for you?
Using it would mean a deliberate no-patterns call that fails on every offline diffusers load just to catch the error.
Yes that's what I had in mind. I feel that it's less hacky than a deliberate hf_hub_download call on the index file, just to do a Path(index file).parent afterwards.
There was a problem hiding this comment.
opened huggingface/huggingface_hub#4513 to add a get_cached_repo_tree method useful when repo.siblings or list_repo_tree fails (in offline mode). A priori, this is the cleanest way to determine the patterns down the line (with variants, etc.) without raising an error and without skipping the "incomplete folder check". Should be shipped today or tomorrow with the rest.
What does this PR do?
Fixes #14117
@BenjaminBossan does this work for you?