Skip to content

feat(working-memory): reserve FLUX.2 denoise working memory from measured lines - #9927

Draft
Pfannkuchensack wants to merge 36 commits into
invoke-ai:mainfrom
Pfannkuchensack:feat/working-memory-flux2-denoise
Draft

Pfannkuchensack wants to merge 36 commits into
invoke-ai:mainfrom
Pfannkuchensack:feat/working-memory-flux2-denoise

Conversation

@Pfannkuchensack

@Pfannkuchensack Pfannkuchensack commented Oct 18, 2026 •

Copy link
Copy Markdown
Member

Stacked on #9919 (and through it #9910, #9899, #9898, #9897, #9894). Until those merge, the diff also shows their commits. This PR's own change is 4ba43cda56.

Summary

The FLUX.2 denoise reserved a hand-set 0.42 MiB per attended token, scaled linearly by transformer width, plus a fixed 1 GiB, on every platform. Fresh-process measurements on an RTX 4090 and an RX 9060 XT show this reserves too much. The denoise now runs through the working-memory estimator framework with one measured line per width.

FLUX.2 Klein 9B (width 4096), bf16 1024² 2048² 2048² + one 2024 px reference
Before (every platform) 2959 MiB 8120 MiB 14894 MiB
RTX 4090, native allocator 1788 6556 12814
RTX 4090, cudaMallocAsync 1186 4320 8434
RX 9060 XT, expandable segments (Windows) 1333 4169 7891
RX 9060 XT, native (Windows) 2005 6747 12970
Unmeasured: XPU, MPS, CPU, Linux ROCm, other allocators at least the previous values

Estimator

  • denoise.flux2 prices a fitted line per width: Klein 4B 3072, Klein 9B 4096, [dev] 6144. The size is the attended tokens (image + reference + caption) × batch. Batch and reference images lie on the line.
  • Regional bias, the SDPA score matrix, LoRA patches, the dequantization copy and the fp8 cast transient are analytic terms.
  • The node passes model_on_device(working_memory=…). User calibration stays VAE-only.

Measurement

  • New scripts/calibrate_flux2_denoise_working_memory.py. Its old denoise section is removed, and so is the old script's VAE section.
  • The fresh-process plumbing shared with the Z-Image script moves to scripts/working_memory/fresh_points.py: the point records, the server runtime, the child protocol and the driver. The cold-and-warm rule moves to invokeai/backend/working_memory/measurement.py.
  • The fit-eligibility rule is one helper (fit.off_line_reasons).

Related Issues / Discussions

QA Instructions

Measured points

  • 144 fresh-process points ship in working_memory/data/denoise.json:
    • RTX 4090 (torch 2.13+cu130), native and cudaMallocAsync;
    • RX 9060 XT (torch 2.13+rocm10.0, Windows, AOTriton fused), expandable and native.
  • Grid: random-init transformer, 2 blocks per stream, at each width, bf16:
    • 512–2048 px with a 512-token caption, plus 77-token captions;
    • 1 and 3 references, batch 2;
    • a large-token grid up to 33025 tokens (2048 px + one 2024 px reference).
  • Each point sits at 1.05–1.26× its estimate. Two 77-token caption points sit at 1.42× and 1.40× on the native allocators and are listed exceptions: caption tokens cost less than image tokens, and the line has to cover the 512-caption points.
  • 4 vs 2 blocks: equal on the RTX 4090; +5–7 % on the RX 9060 XT.
  • Forced math kernel: 8.74 bytes per score element against the 17 charged.

In-server check with real models, through the calibrate route. Real-model demand divided by the 2-block point at the same tokens:

Card Model Ratio
RTX 4090, native Klein 4B fp8 0.96–0.99
RTX 4090, native Klein 9B fp8 0.96–0.97
RX 9060 XT, expandable Klein 4B bf16 0.81–0.95
RX 9060 XT, expandable Klein 9B fp8, after its fp8 cast term 0.71–0.77

A/B, family E2E tool, interleaved before → after → before, 1 warm-up + 3 measured, Klein 4B and Klein 9B at 1024²–2048²:

  • RTX 4090, Klein 9B at 2048²: the transformer goes from 84 % to 94 % resident, and the time from 38.5–39.1 s to 37.5–38.0 s. Other cases are unchanged within run-to-run spread.
  • RX 9060 XT: unchanged within the spread, transformer 100 % resident in both. A constant 288 MiB shared-memory reading appears equally before and after.

Tests

  • uv run --no-sync pytest -n 4 over the working-memory, calibration-service, FLUX.2/Z-Image/VAE invocation, builder, calibration-script, fresh_points and run_app environment suites: 3805 passed.
  • Ruff is clean. VAE and Z-Image data, fits and reservations are byte-identical to the base.
  • Mutation checks, each caught: estimator terms against the frozen legacy formula, the legacy flag, the moved cold-and-warm rule.

Review

Resolved findings

  • The calibration scripts duplicated about 120 lines of plumbing; it is now shared.
  • The fit-eligibility rule was copied per estimator; it is now one helper.
  • The old FLUX.2 script kept a stale VAE section and stale text; both are removed.
  • The docs called 33025 tokens the node's maximum. The node caps neither side, so they now say "measured to 33025 tokens, extrapolated linearly beyond".
  • An old 28068-token check row is retired: its shape is unreachable (several references are resized to 1024 px each), it was measured on a superseded torch build, and that range is now measured directly.

Remaining limits

  • Linux ROCm native stays on the previous values (unmeasured).
  • The RX 9060 XT [dev] lines are measured only to 1440 px and without three references.
  • Above 33025 tokens (4096 px, or more references) the lines extrapolate linearly.

Compatibility / Rollout

  • No persisted state. No API change.
  • scripts/calibrate_flux2_working_memory.py keeps only its dispatch and SDPA checks.

Checklist

  • The PR has a short but descriptive title, suitable for a changelog
  • Meaningful regression coverage added / updated where needed; obsolete tests/code removed
  • Persisted-state and API changes include required migrations / compatibility validation
  • Relevant performance/efficiency opportunities considered; material claims have evidence
  • Material review findings resolved and relevant checks rerun
  • Documentation added / updated (if applicable)
  • Updated What's New copy (if doing a release after this PR)

View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.

Runs each installed model family through a launched scratch server and compares PSNR, time and driver-level VRAM against accepted references.
Graphs come from the frontend builders via an offline graph export; the generate submission plan is shared with the workbench.
VAE estimators return a WorkingMemoryEstimate built from fitted and analytic terms; model_on_device accepts it as working_memory=.
The AutoencoderKL coefficients and their measured points move to backend/working_memory/data, checked by a data test; reservations are unchanged.
A probe records each estimated model_on_device window's device-level demand inside a calibration scope; results go to a per-device-class store under databases/working_memory.
Admin endpoints start, inspect, reset and export runs; the reserved queue origin is refused for ordinary enqueues.
VAE estimators price a measured slope and base per conv backend, allocator and dtype instead of scaling one bf16 constant by element size; CogView4 gets its own lines.
SD/SDXL nodes and their estimate share one run-dtype rule; on ROCm Windows an SDXL fp32 1024² decode reserves 6.2 instead of 14.6 GB and the UNet stays resident.
A lower second reading at a measured size no longer tilts a fitted line, and points that include cast weight growth no longer fit one; two shipped lines move by under 1 %.
…n fact

Environment ids now include windows, linux or other, so calibrations from different operating systems are kept apart; the OS build string moves to soft fact os_build.
… runs

start --calibrate submits each case through the calibration endpoint and saves the store export per server lifetime; scripts/working_memory/build_shipped.py turns exports into probe points and refits.
Probe points bound estimates from below only, and the builder refuses data that the shared bound rule rejects.
# Conflicts:
#	docs/src/content/docs/development/Architecture/model-manager.mdx
…anager

Adds a working-memory section to the model detail: plan, calibrate, stop and reset per GPU, with the measured, built-in and calibrated estimate per size.
User fits from finished calibration attempts price VAE decodes within their measured range (+10 % + 256 MiB on the fitted part) and never below built-in values above it.
New plan and summary routes; summary reports lines shared with other models and returns 404 for unknown models.
…calibration

Judges allocator fragmentation per calibration attempt with one rule shared with the shipped-data builder, and moves other models off the GPU before a measured calibration lock.
User fits use the shipped 5 % margin; the plan sizes cases from the capacity the cache will grant, including memory the driver keeps after earlier runs.
The table marks uncounted sizes with their reason and explains each value column.
# Conflicts:
#	invokeai/backend/util/vae_working_memory.py
#	tests/app/invocations/test_flux2_working_memory.py
# Conflicts:
#	invokeai/backend/util/vae_working_memory.py
Main added useNsfwChecker and useWatermark to the generation project settings; exported calibration and E2E graphs run without both, as the defaults do.
…ser-calibration

# Conflicts:
#	invokeai/frontend/webv2/performance/browser-baseline.json
#	invokeai/frontend/webv2/scripts/mock-backend-fixtures.test.mjs
#	invokeai/frontend/webv2/scripts/mock-backend.mjs
…e baseline

Raises otherRawBytes to the measured 215114 B on every route; the 3791 B growth are the Model Manager working-memory strings.
…f the model page

The section starts collapsed and shows the GPU with the calibration state, or the run progress, in its header; the plan loads on first open.
The mock prices sizes above the measured range with the larger of the user line and built-in, as the server does.
…sured lines

Prices the Z-Image denoise through an EstimatorSpec whose per-token lines are fitted from fresh-process measurements on CUDA and ROCm, with an fp8 cast term and the legacy constants as the floor where nothing was measured.
Fitted lines can now run over tokens; the builder takes measured point files, and calibration scripts share the server runtime and the probe's measurement window.
# Conflicts:
#	docs/src/content/docs/development/Architecture/model-manager.mdx
#	invokeai/backend/model_manager/load/load_base.py
# Conflicts:
#	docs/src/content/docs/development/Architecture/model-manager.mdx
#	invokeai/backend/util/vae_working_memory.py
#	invokeai/backend/working_memory/coefficients.py
#	invokeai/backend/working_memory/data/vae.json
#	invokeai/backend/working_memory/platform.py
#	scripts/calibrate_flux2_working_memory.py
#	tests/app/invocations/test_flux2_working_memory.py
#	tests/app/invocations/test_vae_working_memory_backend.py
#	tests/app/invocations/test_z_image_tiled_decode.py
#	tests/backend/util/test_rocm_sdpa_head_dim_guard.py
#	tests/backend/working_memory/test_shipped_coefficients.py
…ured lines

Prices the FLUX.2 denoise through an EstimatorSpec with one measured line per transformer width, fitted from fresh-process points up to 33025 attended tokens on CUDA and ROCm, with the legacy constants as the floor where nothing was measured.
Calibration scripts share their fresh-process plumbing and the cold-and-warm rule.
@github-actions github-actions Bot added api python PRs that change python files invocations PRs that change invocations backend PRs that change backend files services PRs that change app services frontend-deps PRs that change frontend dependencies frontend PRs that change frontend files python-tests PRs that change python tests docs PRs that change docs labels Oct 18, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api backend PRs that change backend files docs PRs that change docs frontend PRs that change frontend files frontend-deps PRs that change frontend dependencies invocations PRs that change invocations python PRs that change python files python-tests PRs that change python tests services PRs that change app services

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant