Emit progress_total events from PreTrainedModel.from_pretrained()#1609
Emit progress_total events from PreTrainedModel.from_pretrained()#1609JacobiusMakes wants to merge 4 commits intohuggingface:mainfrom
Conversation
Closes huggingface#1052. When a progress_callback is provided, gather file metadata (sizes) upfront via HEAD/Range requests before downloads begin. This lets consumers build a single aggregate progress bar across all model files, matching the behavior already present in the pipeline() API. The implementation reuses the existing get_model_files() and get_file_metadata() utilities and follows the same wrapping pattern used in pipelines.js, emitting progress_total events that include per-file and overall loaded/total byte counts. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
I ran into the exact same ptoblem too yesterday :D |
nico-martin
left a comment
There was a problem hiding this comment.
Thanks for this PR, I like the direction. I noticed two issues while testing that I think we should fix before merging:
- Total progress will always stay below 100%
config.jsonis loaded first.- Then the total-progress tracker is built and includes
config.jsonin the total bytes. - But that file is already finished, so its loaded bytes are never added to the new tracker.
So in practice, the final progress_total can get stuck under 100% even when all downloads are done.
- Duplicate
progress_totalevents when usingpipeline()
pipeline()already emits aggregatedprogress_total.- This PR also emits
progress_totalfrom model loading. - In
pipeline(), both streams are forwarded/emitted, so clients receive both.
So users can see about 2x progress_total events for model download.
|
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. |
Fixes two issues raised in code review: 1. config.json is fetched by AutoConfig.from_pretrained() before the progress tracker is initialized. Pre-mark it as fully loaded in files_loading so total progress reaches 100%. 2. pipeline() already wraps the callback with progress_total events. When from_pretrained() wrapped it again, users got duplicate events. Fix: mark wrapped callbacks with _progress_total_wrapped flag. from_pretrained() checks the flag and skips wrapping if already set. pipeline()'s wrapper now also sets this flag. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Thanks for the thorough review! Both issues fixed in e28ce2c: 1) config.json progress stuck below 100% — config.json is now pre-marked as fully loaded in 2) Duplicate progress_total with pipeline() — Wrapped callbacks now carry a |
|
There is still a problem with the prod build: https://github.com/huggingface/transformers.js/actions/runs/23668078336/job/69010757045?pr=1609 |
|
thanks for the PR! I think a better way to handle this is with a wrapper function class instance which can detect if we need to wrap the object using an |
|
merged via #1615 |
Summary
Closes #1052.
When users call
PreTrainedModel.from_pretrained()directly (rather than throughpipeline()), they currently have no way to know the total size of all model files before downloads begin. This makes it impossible to render a single aggregate progress bar.This PR adds the same
progress_totalevent infrastructure that already exists inpipeline()toPreTrainedModel.from_pretrained():get_model_files()andget_file_metadata()utilitiesprogress_callbackto emitprogress_totalevents on eachprogressupdate, containing aggregateloaded/totalbyte counts plus a per-file breakdown infilespipelines.js(lines 139-178)Example usage
Test plan
prettierformatting passestests/utils/hub.test.js— all passtests/utils/model_registry.test.js— all passnode -c) passesprogress_totalevents fire correctlyChanges
packages/transformers/src/models/modeling_utils.js— Added ~60 lines toPreTrainedModel.from_pretrained()that gather file metadata upfront and wrap the progress callback to emitprogress_totalevents.🤖 Generated with Claude Code