Skip to content

feat: ONNX model optimization pipeline (Phase 2)#2

Merged
VjayRam merged 5 commits into
masterfrom
feat/classifier
Jun 26, 2026
Merged

feat: ONNX model optimization pipeline (Phase 2)#2
VjayRam merged 5 commits into
masterfrom
feat/classifier

Conversation

@VjayRam

@VjayRam VjayRam commented Jun 26, 2026

Copy link
Copy Markdown
Owner

Summary

  • Implements the full 3-stage ONNX optimization pipeline: FP32 export → O2 graph optimization → dynamic INT8 quantization
  • Each pipeline run gets a UUID, with model artifacts and logs written to separate directory trees (models/<run-id>/, logs/optimizer/<run-id>/)
  • Migrated to optimum 2.x APIs (main_export for export, ORT's quantize_dynamic directly for quantization) after discovering breaking changes in the Optimum 2.x release
  • Added project README and updated CLAUDE.md with the target production folder structure

Changes

File What
pipelines/optimizer/export.py main_export from optimum.exporters.onnx — correct API for optimum 2.x
pipelines/optimizer/optimize.py O2 graph optimization via ORTOptimizer; fuses Attention, SkipLayerNormalization, GeLU
pipelines/optimizer/quantize.py Dynamic INT8 via quantize_dynamic with DefaultTensorType extra option to handle Microsoft-domain custom ops introduced by O2
pipelines/optimizer/pipeline.py Orchestrator with UUID run IDs, separated artifact/log paths, structured log fields, report.json per run
pipelines/optimizer/explanation.md Component-level explanation of every design decision including the API migration and the O2/quantization compatibility issue
pipelines/evaluation/ Placeholder files for benchmark and validate stages (Phase 2 follow-up)
README.md Project overview, build phase status, pipeline usage, tech stack
CLAUDE.md Target production folder structure (pipelines/ organized by deployment boundary)
.gitignore Added logs/

Verified

  • Full pipeline ran end-to-end against VijayRam1812/content-classifier-roberta
  • FP32: 476 MB → O2: 476 MB → INT8: 120 MB (75% size reduction)
  • report.json written correctly with run ID, stage durations, and artifact paths

Notes

Two optimum 2.x compatibility issues discovered and fixed:

  1. opset parameter removed from ORTModelForSequenceClassification.from_pretrained — switched to main_export
  2. O2 graph fusion introduces com.microsoft domain ops (Attention, SkipLayerNormalization) that break ORT's quantizer type inference — fixed by dropping to quantize_dynamic with extra_options={"DefaultTensorType": onnx.TensorProto.FLOAT} since QuantizationConfig does not expose this escape hatch

🤖 Generated with Claude Code

VjayRam and others added 4 commits June 25, 2026 19:15
Captures the deployment-boundary-first layout (pipelines/ vs services/)
so future phases refactor toward it rather than away from it.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ORT compatibility issues with O2-optimized custom ops.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hi @VjayRam! 👋

Your private repo does not have access to Sourcery.

Please upgrade to continue using Sourcery ✨

@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@VjayRam, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 58 minutes and 54 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Free

Run ID: 8a418335-dc02-4b1f-a50a-47a899f1ef06

📥 Commits

Reviewing files that changed from the base of the PR and between d340b4e and 2cc2be0.

📒 Files selected for processing (13)
  • .gitignore
  • CLAUDE.md
  • README.md
  • pipelines/__init__.py
  • pipelines/evaluation/__init__.py
  • pipelines/evaluation/benchmark.py
  • pipelines/evaluation/validate.py
  • pipelines/optimizer/__init__.py
  • pipelines/optimizer/explanation.md
  • pipelines/optimizer/export.py
  • pipelines/optimizer/optimize.py
  • pipelines/optimizer/pipeline.py
  • pipelines/optimizer/quantize.py

Note

🎁 Summarized by CodeRabbit Free

Your organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Pro by visiting https://app.coderabbit.ai/login.

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

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@VjayRam
VjayRam merged commit db1f77f into master Jun 26, 2026
5 checks passed
VjayRam added a commit that referenced this pull request Jul 3, 2026
Ran dev-start.sh end-to-end against a real k3d cluster and exercised it
under real load for the first time this session — surfaced three bugs
none of the unit tests, terraform validate, or standalone smoke tests
could have caught:

1. services/classifier/model.py: reverted padding="max_length" (#8's
   earlier "fix"). Every batch was tokenizing to the full 512 tokens
   regardless of actual input length — reproduced live, this OOM-killed
   the classifier pod (1Gi limit) twice under realistic load. The
   "latency doesn't depend on batch content" benefit isn't worth crashing
   the service; verified the revert holds memory flat (~324Mi) through a
   300-trace sustained load test with zero restarts.

2. services/classifier/main.py: fixed #43's registration-skip check.
   download_model() always caches a MinIO-backed model under a local
   directory (/tmp/sentinel-model-cache/...), so _classifier.model_path
   is *always* an absolute local path — checking model_path.startswith("/")
   to detect "non-portable local fallback" therefore skipped registration
   for the common MinIO-backed case too. Every classification write then
   violated classifications_model_version_fkey, since the model_version
   never existed in model_registry. Now uses `model_dir is not None` (only
   None for a genuine local-only fallback) and registers the original
   MinIO path from the registry lookup, not the local cache path.

3. services/stream-processor/main.py: _pg_write only caught
   OperationalError (connection lost) for its reconnect logic. A
   ForeignKeyViolation from bug #2 above is a different failure mode —
   the connection stays alive but its transaction is aborted, so every
   subsequent command fails with InFailedSqlTransaction until rolled
   back. Without a rollback, the long-lived connection stayed permanently
   broken after the first such error — reproduced live, this stalled all
   PostgreSQL writes indefinitely even after bug #2 was fixed and
   redeployed, until this rollback was added.

Verified end-to-end after all three fixes: dev-start.sh completes with
zero errors, Kafka survives a real pod restart with identical topic/
consumer-group state before and after, and a fresh simulate-traces.py run
shows classifications/flagged_content counts increasing correctly with
zero duplicates and zero consumer lag.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.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