Skip to content

Rename modelopt_recipes/huggingface to model_type with backward-compat alias - #2328

Draft
shengliangxu wants to merge 3 commits into
mainfrom
shengliangx/recipe-models
Draft

Rename modelopt_recipes/huggingface to model_type with backward-compat alias#2328
shengliangxu wants to merge 3 commits into
mainfrom
shengliangx/recipe-models

Conversation

@shengliangxu

Copy link
Copy Markdown
Collaborator

What does this PR do?

Type of change: Refactor + deprecation (recipe-library restructure, backward compatible), plus an unrelated transformers-compat test fix.

Rename the architecture-specific recipe tier modelopt_recipes/huggingface/ to
modelopt_recipes/model_type/, making explicit that it holds recipes shared across
every checkpoint of a Hugging Face model_type
— as opposed to the checkpoint-mirror
models/<org>/<model_id>/ tier. The old huggingface/ path keeps working as a
deprecated backward-compat alias (a source-tree symlink plus a loader alias), so no
saved --recipe path breaks.

  • Loader alias (modelopt/recipe/loader.py): generalized so saved
    --recipe huggingface/<model_type>/... paths rewrite to model_type/..., alongside
    the existing huggingface/models/... -> models/... rewrite (checked first as the more
    specific prefix). This keeps old paths resolving for pip-installed wheels, where the
    source-tree symlinks don't survive.
  • Internal $imports: rewritten from huggingface/... -> model_type/... inside the
    shipped recipes so they resolve without the symlink — mandatory for wheels, since
    $import resolution goes through config_loader (no alias there).
  • Packaging (pyproject.toml, MANIFEST.in): extended the symlink-exclusion globs
    so the recursive **/*.yaml package-data glob doesn't double-ship recipes through the
    huggingface -> model_type and model_type/models -> ../models symlinks.
  • Docs / examples / skills / tests: migrated all internal references to the canonical
    model_type/; huggingface/ remains only in the deprecated-alias tests and explanatory
    notes.
  • Unrelated fix (2nd commit): tests/unit/torch/export/test_quant_aware_conversion.py
    failed on transformers>=5.9, which dropped base_model_prefix from
    WeightTransform.__slots__ (the scoped-rule tests assigned it on the now-slotted
    object). Production _scope_prefixes already reads it via getattr(..., None) and
    degrades correctly, so there is no runtime change — the tests now set it through a
    helper that suppresses AttributeError across the supported transformers range.

Usage

# New canonical path
python examples/hf_ptq/hf_ptq.py --model <ckpt> \
    --recipe model_type/qwen3_vl/ptq/fp8_vision-kv_none

# Old path still works (deprecated backward-compat alias)
python examples/hf_ptq/hf_ptq.py --model <ckpt> \
    --recipe huggingface/qwen3_vl/ptq/fp8_vision-kv_none
from modelopt.recipe import load_recipe

load_recipe("model_type/vit/ptq/fp8")    # canonical
load_recipe("huggingface/vit/ptq/fp8")   # deprecated alias, resolves to the same recipe

Testing

  • tests/unit/recipe/336 passed, including the new
    test_load_recipe_huggingface_arch_backward_compat_alias and the updated
    structural/doc tests (test_recipe_docs.py).
  • tests/unit/torch/export/test_quant_aware_conversion.py16 passed (was 4 failed
    on transformers 5.9.0).
  • Built an sdist and a wheel and inspected both manifests: each recipe ships exactly
    once (27 model_type/, 11 models/, 153 total) with zero huggingface/ or
    model_type/models/ duplicates and no build error on the symlinks.
  • Simulated a wheel install (symlink-free extracted tree) and confirmed
    huggingface/<arch>/..., model_type/..., and huggingface/models/... all resolve via
    the loader alias — including a recipe that pulls internal $imports.

Before your PR is "Ready for review"

  • Is this change backward compatible?: ✅ — old huggingface/... recipe paths keep resolving via the symlink + loader alias.
  • If you copied code from any other sources or added a new PIP dependency, did you follow guidance in CONTRIBUTING.md: N/A
  • Did you write any new necessary tests?: ✅ — backward-compat alias test added; structural/doc tests updated to the new layout.
  • Did you update Changelog?: ✅ — Deprecations entry under 0.48.0. (The transformers-compat test fix is not changelog-worthy.)
  • Did you get Claude approval on this PR?: ❌ — not yet.

Additional Information

The model_type/models -> ../models symlink is kept purely as a backward-compat alias for
old huggingface/models/<org>/<model_id>/... paths; model_type/ is otherwise
architecture-only. If we ever want it strictly architecture-only, that symlink can be
dropped later without breaking anything, since the loader rewrites huggingface/models/...
straight to the top-level models/ tier.

…t alias

Rename the architecture-specific recipe tier from modelopt_recipes/huggingface/
to modelopt_recipes/model_type/ to make clear it holds recipes shared across
every checkpoint of a Hugging Face model_type. The old huggingface/ path is
retained only as a deprecated backward-compatibility alias.

- Loader: generalize the recipe-path alias in modelopt/recipe/loader.py so saved
  --recipe huggingface/<model_type>/... paths rewrite to model_type/..., next to
  the existing huggingface/models/... -> models/... rewrite (checked first as the
  more specific prefix). This keeps old paths working for pip-installed wheels,
  where the source-tree symlinks don't survive.
- Recipes: rewrite internal $import references under model_type/ from
  huggingface/... to model_type/... so recipes load without the symlink (required
  for wheels).
- Packaging: extend the exclude-package-data globs and MANIFEST.in prunes to
  cover the huggingface -> model_type and model_type/models -> ../models symlinks
  so each recipe ships exactly once.
- Docs/examples/skills/tests: migrate all internal references to the canonical
  model_type/ path; huggingface/ remains only in the backward-compat alias tests
  and explanatory notes.
- Add a Deprecations changelog entry and a test covering the
  huggingface/<model_type>/ -> model_type/ alias.

Verified: tests/unit/recipe passes (336); built sdist and wheel ship each recipe
once with no huggingface/ or model_type/models/ duplicates; a simulated wheel
install (no symlinks) resolves huggingface/..., model_type/..., and
huggingface/models/... via the loader alias.

Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
transformers>=5.9 dropped base_model_prefix from WeightTransform's __slots__
(scoped matching now keys off scope_prefix alone), so the scoped-rule tests in
tests/unit/torch/export/test_quant_aware_conversion.py raised AttributeError
when assigning transform.base_model_prefix on the now-slotted object.

Production _scope_prefixes already reads the attribute via getattr(..., None)
and degrades correctly when it is absent (the base-prefixed candidate collapses
to the scope_prefix-only one), so there is no runtime behavior change. Set
base_model_prefix through a helper that suppresses AttributeError so the tests
run across the whole supported transformers range (>=4.57,<5.15), and clarify
the version dependence in the _scope_prefixes docstring.

Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
@copy-pr-bot

copy-pr-bot Bot commented Sep 3, 2026

Copy link
Copy Markdown

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

@coderabbitai

coderabbitai Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor
PR Preview Action v1.8.1

QR code for preview link

🚀 View preview at
https://NVIDIA.github.io/Model-Optimizer/pr-preview/pr-2328/

Built to branch gh-pages at 2026-09-03 22:14 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

@codecov

codecov Bot commented Sep 3, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 88.46154% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 79.29%. Comparing base (bfd52b3) to head (e5e5ce7).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
modelopt/torch/opt/config_loader.py 80.00% 3 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main    #2328   +/-   ##
=======================================
  Coverage   79.28%   79.29%           
=======================================
  Files         527      527           
  Lines       61482    61491    +9     
=======================================
+ Hits        48748    48758   +10     
+ Misses      12734    12733    -1     
Flag Coverage Δ
unit 55.88% <88.46%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

…ocal trees

Address PR review: the huggingface/ -> model_type/ backward-compat alias only
lived in load_recipe(), leaving two gaps.

- $import resolution goes through config_loader._resolve_config_path, not the
  recipe-path alias, so a custom recipe importing a shipped snippet by its old
  huggingface/... path would fail from a wheel (where the symlink is gone). Move
  the prefix rewrite into a shared _alias_builtin_recipe_prefix helper in
  config_loader and apply it to the built-in $import candidates too.

- The loader rewrote huggingface/ for the filesystem fallback as well, so a
  user's own local huggingface/... recipe tree could no longer load by its
  natural relative name. Built-in candidates now use the alias; the filesystem
  fallback probes the path exactly as given first, then the aliased form.

Also alias model_type/models/ -> models/ (the model_type/models symlink is
source-only and pruned from wheels) so that path resolves identically from a
checkout and an installed wheel.

Adds tests for the $import alias, the local-huggingface no-shadow case, and the
model_type/models alias; verified in a symlink-free extracted-wheel tree.

Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant