Skip to content

feat(phyai): refactor quantization methods.#42

Merged
chenghuaWang merged 1 commit into
MEmbodied:mainfrom
chenghuaWang:dev/chenghua
Jul 6, 2026
Merged

feat(phyai): refactor quantization methods.#42
chenghuaWang merged 1 commit into
MEmbodied:mainfrom
chenghuaWang:dev/chenghua

Conversation

@chenghuaWang

@chenghuaWang chenghuaWang commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • New Features

    • Added quantization support for model loading, including automatic detection of supported checkpoint formats and per-layer quantization selection.
    • Enabled quantized model setup across several entry points, with graceful fallback to default precision when no quantization config is present.
    • Added a new Chinese “text humanizer” skill for rewriting AI-like writing into more natural prose.
  • Documentation

    • Added new English and Chinese documentation for quantization overview, configuration, and internals.

@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ab3209db-d76d-4fc4-aaa2-fa5731e8adf5

📥 Commits

Reviewing files that changed from the base of the PR and between 1644b93 and e3c51f8.

⛔ Files ignored due to path filters (2)
  • docs/images/quantization/layered-design.svg is excluded by !**/*.svg
  • docs/images/quantization/resolve-example.svg is excluded by !**/*.svg
📒 Files selected for processing (30)
  • .claude/skills/humanizer-zh/SKILL.md
  • .claude/skills/humanizer-zh/cite.md
  • .claude/skills/humanizer/SKILL.md
  • .claude/skills/humanizer/cite.md
  • .gitignore
  • CLAUDE.md
  • docs/docs.json
  • docs/quantization/configuration.mdx
  • docs/quantization/internals.mdx
  • docs/quantization/overview.mdx
  • docs/zh/quantization/configuration.mdx
  • docs/zh/quantization/internals.mdx
  • docs/zh/quantization/overview.mdx
  • phyai/src/phyai/layers/linear/layers.py
  • phyai/src/phyai/layers/quant/active.py
  • phyai/src/phyai/layers/quant/importers/__init__.py
  • phyai/src/phyai/layers/quant/importers/base.py
  • phyai/src/phyai/layers/quant/importers/compressed_tensors.py
  • phyai/src/phyai/layers/quant/importers/fp8.py
  • phyai/src/phyai/layers/quant/importers/modelopt.py
  • phyai/src/phyai/layers/quant/importers/registry.py
  • phyai/src/phyai/layers/quant/materialize.py
  • phyai/src/phyai/layers/quant/plan.py
  • phyai/src/phyai/layers/quant/scheme.py
  • phyai/src/phyai/models/cosmos3/main_cosmos3.py
  • phyai/src/phyai/models/cosmos3/main_cosmos3_policy.py
  • phyai/src/phyai/models/cosmos3/main_cosmos3_policy_wn.py
  • phyai/src/phyai/models/cosmos3/main_cosmos3_wn.py
  • phyai/src/phyai/models/pi0/main_pi0.py
  • phyai/src/phyai/models/pi05/main_pi05.py

📝 Walkthrough

Walkthrough

This PR adds a semantic-to-physical quantization system for PhyAI, including QuantScheme/TensorQuant types, QuantPlan rule matching, a materialize lowering function, three config importers (fp8, compressed-tensors, ModelOpt), an active-plan context, Linear layer wiring, and model entrypoint integration for Cosmos3/PI0/PI05, plus English/Chinese documentation. It separately adds two unrelated Claude "humanizer" skill definitions, a CLAUDE.md convention, and a .gitignore entry.

Changes

Quantization System

Layer / File(s) Summary
Semantic model
phyai/.../layers/quant/scheme.py
Defines QDType, TensorQuant, and QuantScheme frozen dataclasses representing pure quantization semantics.
Plan and materialize
phyai/.../layers/quant/plan.py, phyai/.../layers/quant/materialize.py
Implements Matcher/Rule/QuantPlan.resolve() and materialize(scheme, sm) to produce physical WeightSpec objects.
Config importers and registry
phyai/.../layers/quant/importers/*
Adds ConfigSources/QuantImporter protocol, Fp8Importer, CompressedTensorsImporter, ModelOptImporter, DEFAULT_IMPORTERS, select_importer, build_quant_plan.
Active plan context
phyai/.../layers/quant/active.py
Adds get_active_plan, use_quant_plan, and load_quant_plan for checkpoint-driven quant plan resolution via a ContextVar.
Linear layer wiring
phyai/.../layers/linear/layers.py
Adds scheme parameter across LinearBase and variants; resolves spec via explicit spec, scheme materialization, active plan, or Bf16Spec fallback.
Model entrypoint integration
phyai/.../models/cosmos3/*.py, phyai/.../models/pi0/main_pi0.py, phyai/.../models/pi05/main_pi05.py
Wraps model/transformer construction in use_quant_plan(load_quant_plan(...)) for Cosmos3, PI0, and PI05 entrypoints.
Documentation
docs/quantization/*, docs/zh/quantization/*, docs/docs.json
Adds English/Chinese overview, configuration, and internals docs, and registers new navigation groups.

Estimated code review effort: 4 (Complex) | ~60 minutes

Humanizer Skill Definitions and Misc Config

Layer / File(s) Summary
English humanizer skill
.claude/skills/humanizer/SKILL.md, .claude/skills/humanizer/cite.md
Adds a text-editing skill removing AI writing patterns across content, language, style, and communication categories, with examples and citation.
Chinese humanizer-zh skill
.claude/skills/humanizer-zh/SKILL.md, .claude/skills/humanizer-zh/cite.md
Adds a parallel Chinese-language skill with equivalent pattern rules, scoring rubric, checklist, and citation.
Config updates
CLAUDE.md, .gitignore
Adds a convention bullet referencing the humanizer skills and ignores docs/compose/.

Estimated code review effort: 2 (Simple) | ~15 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Entry as ModelEntry.setup
  participant Active as load_quant_plan
  participant Plan as QuantPlan
  participant Linear as LinearBase
  participant Materialize as materialize

  Entry->>Active: load_quant_plan(checkpoint_dir)
  Active->>Plan: build_quant_plan(ConfigSources)
  Entry->>Linear: construct model inside use_quant_plan(plan)
  Linear->>Plan: resolve(prefix, module_cls)
  Plan-->>Linear: QuantScheme or None
  Linear->>Materialize: materialize(scheme, sm)
  Materialize-->>Linear: WeightSpec
Loading

Possibly related PRs

  • MEmbodied/phyai#26: Updates the same Cosmos3 entrypoints' setup() with quantization-plan wiring, overlapping with prior Cosmos3 plugin/entrypoint additions.
  • MEmbodied/phyai#34: Modifies PI0Entry.setup in main_pi0.py, overlapping with the PI0 engine/plugin entry setup flow added earlier.
  • MEmbodied/phyai#37: Adds quant-plan context to the same Cosmos3 multi-GPU/TP-CFG entrypoint files touched here.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a comprehensive quantization subsystem for PhyAI, featuring a layered design that separates semantic quantization decisions (QuantScheme) from physical memory layouts and kernel selections (WeightSpec). It adds automatic quantization plan loading from checkpoints (supporting HF fp8, compressed-tensors, and NVIDIA ModelOpt formats), integrates this loading into model setup entry points, and adds extensive documentation in both English and Chinese. The review feedback highlights several robustness improvements to prevent runtime errors, such as handling None values for the SM architecture in CPU environments, and safely parsing JSON configurations where expected lists might be strings or top-level elements might not be dictionaries.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

if w.dtype is QDType.FP8_E4M3:
return Fp8Spec(granularity=w.granularity, block_shape=w.block_shape)
if w.dtype is QDType.NVFP4:
layout = "128x4" if sm >= _NVFP4_128X4_MIN_SM else "linear"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

If sm_arch() returns None (e.g., on non-CUDA or CPU-only test environments), sm will be None. Comparing None >= 100 will raise a TypeError. We should handle None gracefully by defaulting sm to 0 or checking if it is not None.

Suggested change
layout = "128x4" if sm >= _NVFP4_128X4_MIN_SM else "linear"
layout = "128x4" if (sm or 0) >= _NVFP4_128X4_MIN_SM else "linear"

Comment on lines +34 to +35
ignored = cfg.get("ignored_layers") or cfg.get("modules_to_not_convert") or []
rules = tuple(Rule(Matcher("name", name), None) for name in ignored)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If ignored_layers or modules_to_not_convert is configured as a single string instead of a list of strings (e.g., "lm_head"), iterating over ignored will iterate over its characters (e.g., "l", "m", etc.), creating incorrect rules. We should check if ignored is a string and wrap it in a list to prevent this.

Suggested change
ignored = cfg.get("ignored_layers") or cfg.get("modules_to_not_convert") or []
rules = tuple(Rule(Matcher("name", name), None) for name in ignored)
ignored = cfg.get("ignored_layers") or cfg.get("modules_to_not_convert") or []
if isinstance(ignored, str):
ignored = [ignored]
rules = tuple(Rule(Matcher("name", name), None) for name in ignored)

Comment on lines +56 to +57
excluded = block.get("exclude_modules") or block.get("ignore") or []
rules = tuple(Rule(Matcher("name", name), None) for name in excluded)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If exclude_modules or ignore is configured as a single string instead of a list of strings, iterating over excluded will iterate over its characters, creating incorrect rules. We should check if excluded is a string and wrap it in a list.

Suggested change
excluded = block.get("exclude_modules") or block.get("ignore") or []
rules = tuple(Rule(Matcher("name", name), None) for name in excluded)
excluded = block.get("exclude_modules") or block.get("ignore") or []
if isinstance(excluded, str):
excluded = [excluded]
rules = tuple(Rule(Matcher("name", name), None) for name in excluded)

Comment on lines +70 to +71
for name in cfg.get("ignore") or []:
rules.append(Rule(_target_matcher(name), None))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If ignore is configured as a single string instead of a list of strings, iterating over it will iterate over its characters. We should check if it is a string and wrap it in a list.

Suggested change
for name in cfg.get("ignore") or []:
rules.append(Rule(_target_matcher(name), None))
ignore = cfg.get("ignore") or []
if isinstance(ignore, str):
ignore = [ignore]
for name in ignore:
rules.append(Rule(_target_matcher(name), None))

Comment on lines +77 to +78
for target in group.get("targets") or []:
rules.append(Rule(_target_matcher(target), scheme))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If targets is configured as a single string instead of a list of strings, iterating over it will iterate over its characters, creating incorrect rules. We should check if targets is a string and wrap it in a list.

Suggested change
for target in group.get("targets") or []:
rules.append(Rule(_target_matcher(target), scheme))
targets = group.get("targets") or []
if isinstance(targets, str):
targets = [targets]
for target in targets:
rules.append(Rule(_target_matcher(target), scheme))

Comment on lines +66 to +68
hf_quant_config = raw.get("quantization_config") or raw.get(
"compression_config"
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If config.json contains a non-dictionary top-level element (e.g., a list or a string), calling raw.get will raise an AttributeError. We should check if raw is a dictionary before calling .get().

Suggested change
hf_quant_config = raw.get("quantization_config") or raw.get(
"compression_config"
)
if isinstance(raw, dict):
hf_quant_config = raw.get("quantization_config") or raw.get(
"compression_config"
)

Comment on lines +72 to +76
standalone = None
standalone_path = folder / "hf_quant_config.json"
if standalone_path.is_file():
with standalone_path.open("r", encoding="utf-8") as f:
standalone = json.load(f)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If hf_quant_config.json contains a non-dictionary top-level element, standalone will not be a dictionary, and calling src.standalone.get in _quant_block will raise an AttributeError. We should check if the loaded JSON is a dictionary before assigning it to standalone.

Suggested change
standalone = None
standalone_path = folder / "hf_quant_config.json"
if standalone_path.is_file():
with standalone_path.open("r", encoding="utf-8") as f:
standalone = json.load(f)
standalone = None
standalone_path = folder / "hf_quant_config.json"
if standalone_path.is_file():
with standalone_path.open("r", encoding="utf-8") as f:
raw_standalone = json.load(f)
if isinstance(raw_standalone, dict):
standalone = raw_standalone

@chenghuaWang chenghuaWang merged commit ac1a230 into MEmbodied:main Jul 6, 2026
1 of 2 checks passed
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