[Download] Resolve the revision once at the beginning of from_pretrained - #14340
[Download] Resolve the revision once at the beginning of from_pretrained#14340Wauplin wants to merge 2 commits into
Conversation
Use `huggingface_hub.resolve_revision` (new in huggingface_hub 1.26.0) at the top of the loading entrypoints so that every file fetched afterwards is pinned to the same commit and can be served from the cache without re-resolving the revision on each call. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
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. |
|
CI status: everything green except Hub tests for models, schedulers, and pipelines, which fails on Green: |
Follow-up on
huggingface_hubv1.26.0, which shippedHfApi.resolve_revision/ResolvedRevision.What
Loading a model or a pipeline fetches several files from the same repo one by one (
model_index.json,config.json, the weight index, each checkpoint shard, custom code, ...). Each of those calls resolvesrevision="main"into a commit hash on its own — one HTTP request per file, and no guarantee that two calls land on the same commit if the repo is updated in between.This PR resolves the revision once, at the beginning of the loading methods, and passes the resulting
ResolvedRevisiondown. Since it is astrsubclass whose string value stays the user-facing revision ("main"), nothing else had to change: error messages keep sayingmain, and the download helpers (hf_hub_download,snapshot_download,get_cached_repo_tree) pick up.resolvedtransparently.Where
A single
_resolve_revisionhelper inutils/hub_utils.py, called from:DiffusionPipeline.from_pretrainedandDiffusionPipeline.downloadModelMixin.from_pretrainedAutoPipelineForText2Image/Image2Image/Inpainting/Text2Audio.from_pretrainedModularPipeline.from_pretrainedandModularPipelineBlocks.from_pretrainedDeliberately left out, since they fetch a single file from the repo and resolving would only add a request:
ConfigMixin.load_config/SchedulerMixin.from_pretrained,_fetch_state_dict(LoRA),from_single_file, textual inversion, and the DDUF path.load_ip_adapteris also left out because a singlerevisionthere can span several repos.The helper is best-effort by design: local folders are returned untouched, and if the Hub can't answer (repo/revision not found, offline with an empty cache, invalid repo id) the original
revisionis returned so the download that follows raises its usual, diffusers-flavored error instead of aRevisionResolutionErrorleaking from the top offrom_pretrained.Measurements
HTTP calls (telemetry excluded), counted by wrapping
httpx.Client.send:DiffusionPipeline.from_pretrained(tiny-stable-diffusion-torch)ModelMixin.from_pretrained(single-file unet)ModelMixin.from_pretrained(2-shard transformer)The win is on reuse; a cold single-file load pays one extra
repo_info. The commit-consistency guarantee applies in all cases.Also in this PR
huggingface_hubto1.26.0(from1.23.0) insetup.pyanddependency_versions_table.py.test_kwargs_local_files_onlywrote<sha>hugintorefs/main; that value is now read back byresolve_revisionand passed around as a commit hash, so it has to stay a syntactically valid one.test_local_files_only_with_sharded_checkpointraisedHfHubHTTPError(response=mock.Mock());resolve_revisionreadserror.response.status_codeto tell a Hub outage from a definitive answer, so the mock now carries the real response.Possible follow-up
Now that
revisionis always resolved beforeload_config, thecommit_hashplumbing inModelMixin.from_pretrained(load_config(return_commit_hash=True)→_get_model_file(revision=revision or commit_hash)) is redundant. Left alone here sincereturn_commit_hashis public API.Testing
Ran locally against
huggingface_hub==1.26.0:tests/pipelines/test_pipelines.py— 53 passed, 33 skipped, 10 xpassedtests/pipelines/test_pipelines_auto.py— 19 passed, 3 skippedtests/pipelines/test_pipeline_utils.py,tests/others/,tests/lora/test_lora_loader_utils.py— pass (tests/others/test_cli_commands.py::test_toplevel_help_lists_all_commandsfails onmaintoo)tests/models/test_modeling_common.py— 12 passed, 5 skippedtests/modular_pipelines/test_modular_pipelines_custom_blocks.py,test_components_manager.py,test_conditional_pipeline_blocks.py— 47 passed, 6 skipped🤖 Generated with Claude Code