Version franΓ§aise | English
Audience: this document is written for an AI assistant (LLM) asked to understand, debug, or adapt this project to another machine. Read it fully before editing code. It contains the architecture, the dependency map, the complete history of problems already solved, and the non-regression rules.
- What: a Windows desktop app that batch-upscales images with the ByteDance SeedVR2-3B one-step diffusion super-resolution model.
- Official-code policy: the app wraps the official inference scripts
(repo
ByteDance-Seed/SeedVR, cloned asSeedVR/next toapp.py). It does not reimplement the pipeline. Only checkpoint loading is extended (safetensors FP16/FP8, GGUF), plus Windows compatibility shims. - Stack: Python 3.11β3.14 (3.12 safest), torch (CUDA builds, cu130 index;
cu128 fallback for pre-580 drivers β note cu128 stopped at torch 2.11),
Gradio UI, threaded batch engine. Comments and user-facing logs are in
French; the Gradio UI is bilingual FR/EN (hot-switch via
i18n.py). - Reference hardware (validated): RTX 2000 Ada 16 GB, sm_89, bf16 OK, Windows 11, 32 GB RAM. Whole pipeline runs (GGUF Q8_0, Γ4, 288 px tiles).
- No CPU/demo mode by design: without a CUDA GPU the app refuses to run and prints a repair diagnostic (see Β§6.6). Don't reintroduce silent fallbacks.
app.py GUI + CLI entry point; sets PYTORCH_CUDA_ALLOC_CONF
(=expandable_segments:True) BEFORE any torch import.
check_install.py Standalone diagnostics (Python, deps, GPU, repo, models).
install.bat / run_app.bat Windows bootstrap (English console output).
requirements.txt App-level deps β comments MUST start with '#' (a ';'
prefix is parsed as a pip environment marker -> #bug-1).
config/settings.json User settings (git-ignored; auto-migrated by Settings.__post_init__).
models/ User weights (git-ignored). SeedVR/ official repo clone (git-ignored).
seedvr2_upscaler/
βββ constants.py Paths, extensions, HF download presets, SEEDVR2_REPO env var name.
βββ models.py Typed dataclasses/enums: JobConfig, ModelInfo, ModelKind,
β OutputFormat/ConflictPolicy (from_label is FR/EN/canonical tolerant),
β Precision, TilingConfig, RunnerState, BatchStats, ImageOutcome.
βββ settings.py JSON persistence. __post_init__ migrates legacy French radio
β labels β canonical values, drops removed 'demo' backend,
β clamps language to fr/en. ADD NEW FIELDS HERE with defaults.
βββ i18n.py FR/EN string tables (same keys in both β unit-tested) + tr().
βββ registry.py scan_models/classify_model (kind+quant from filename),
β AuxAssets (VAE/pos/neg), ensure_aux_assets (auto-download
β from HF ByteDance-Seed/SeedVR2-3B), download_file (hf_hub_download).
βββ naming.py apply_suffix (off by default), resolve_output_path
β (overwrite/skip/rename `name (1).ext`, in-batch reservation set).
βββ images.py load_image (EXIF transpose, ICC, exif bytes, RGBA split),
β save_image (PNG/JPEG/WebP, quality, EXIF+ICC restore,
β piexif for PNG), split_alpha/merge_alpha.
βββ tiling.py compute_tiles (overlap grid), stitch (feather blending),
β needs_tiling (output > 4 Mpx auto).
βββ gpu_check.py detect_gpu() β GpuStatus (driver via nvidia-smi, torch build,
β cuda_available, bf16), cause_key() for the bilingual UI banner,
β French long-form help for logs/CLI. Never raises.
βββ backend/
β βββ base.py UpscaleBackend ABC + BackendOptions; generic upscale():
β β alpha split, ceil_div(Β·,16) rounding, tile loop with
β β tile_cb(i,n) UI callback, stitch. MAX_TILE_OUT_SIDE = 1152
β β caps OUTPUT tile side (training regime) β see #bug-9.
β βββ official.py The heart. Wraps projects.video_diffusion_sr.infer.
β β VideoDiffusionInfer + configs_3b/main.yaml. See Β§3.
β βββ gguf_loader.py GGUF β state_dict via official `gguf` package; dequantizes
β β Q*-types on CPU to target dtype, renames llama-style keys
β β to the DiT checkpoint schema. ~6.5 GB RAM spike at load.
β βββ flash_fallback.py Injects fake `flash_attn` module (flash_attn_varlen_func)
β β backed by torch SDPA. Uses ModuleSpec (importlib needs
β β __spec__/__path__) β see #bug-7. Real package wins if present.
β βββ apex_fallback.py Same trick for apex: FusedLayerNormβnn.LayerNorm,
β FusedRMSNormβnn.RMSNorm (state_dict compatible) β #bug-5.
βββ worker.py BatchRunner thread + EventBus (log/progress/preview/state/
β tile/finished). Pause/resume/cancel Events, ETA (5-image
β moving average), resume file `.seedvr2_resume.json` (config
β fingerprint), OOMβauto-tiling retry, parallel saves (2),
β append-mode log.txt, report.txt, disk-space preflight,
β Windows sleep inhibition (SetThreadExecutionState) and
β end-of-batch beep. Loads the model ONCE per batch.
βββ gui_gradio.py Gradio Blocks. 0.5 s Timer drains the EventBus. All widget
texts via i18n registry (hot language switch, no reload).
Radio widgets carry canonical values (label, value) tuples.
GPU banner built from cause_key() for the current language.
tests/selftest.py 21 unit tests, no GPU needed: naming, registry, tiling,
I/O, settings (+migration), i18n parity, batch engine with
an injected CPU fake backend (BatchRunner(backend_factory=β¦)).
docs/LLM_GUIDE*.md This file.
An image is treated as a 1-frame video by the official scripts.
Load (load() β _load_pipeline()):
gpu_checkdiagnostics first; abort with repair instructions if no CUDA.torch.backends.cudnn.benchmark = True(constant tile shapes β conv autotune).- Install flash/apex shims proactively (Windows), then
_with_autorepairwraps every step: on ModuleNotFoundError, pip-installs the known package (_PYPI_NAMESmap) into the current interpreter, once per module. - Load
configs_3b/main.yamlviacommon.config.load_configwith CWD temporarily switched to the repo root (config uses relative paths). _init_distributed_best_effort: the repo's@log_runtimedecorator callsdist.barrier()unconditionally, so a real single-process gloo group is created (Windows has no NCCL). Shims are the last resort.- dtype: bf16 if
torch.cuda.is_bf16_supported()else fp16. - Assets:
ensure_aux_assets(VAE + pos/neg text embeddings, HF auto-download). - DiT weights: official
.pthβrunner.configure_dit_model(...)verbatim; safetensors/GGUF β_build_dit_from_state: meta-device construction (mirrors the official branch),load_state_dict(strict=False, assign=True), then_materialize_buffers(see #bug-8),.to(device, dtype). - VAE:
configure_vae_model()then_tune_vae_memory_limitoverrides the officialconv_max_mem: 0.5 GiBwithmin(7.0, max(1.0, free*0.5)) GiBβ the 0.5 GiB default micro-slices decoding (17 s/tile measured) β #bug-10. - Diffusion: cfg 1.0, rescale 0, timesteps steps = 1,
configure_diffusion(). - Optional
color_fix.wavelet_reconstructionif the file exists in the repo.
Inference per region (_upscale_region_impl), mirroring
projects/inference_seedvr2_3b.py image branch:
TF.to_tensor β [T=1,C,H,W] β NaResize(resolution=β(out_hΒ·out_w), area, downsample_only=False) β clamp01 β DivisibleCrop(16,16) β Normalize(0.5,0.5) β Rearrange t c h w β c t h w β vae_encode([cond]) β _generation_step
(randn_like noises, per-tile set_seed(seed, same_across_ranks=True) with
fallback to manual_seed, cond_noise_scale=0.0, get_condition(task='sr'),
texts_pos/neg from cached device tensors, runner.inference(..., dit_offload=low_vram) under inference_mode+bf16 autocast) β output
branch exactly as official: video[:, None] when video.ndim == 3 (means
[C,H,W], time axis lost) β using video[None] silently transposes C/T β 1-channel
image ("not enough image data") β #bug-9. Then clamp [-1,1]β[0,255] uint8 RGB.
VRAM swap identical to the official script when low_vram (ditβcpu, vaeβcuda);
auto-disabled when VRAM β₯ 14 GB, auto-enabled below 10 GB (_tune_low_vram).
App venv (requirements.txt + install.bat): gradio, Pillow, numpy,
safetensors, gguf, huggingface_hub, einops, omegaconf (+ optional piexif for
EXIF-in-PNG). Plus torch/torchvision from the cu130 index (pip install torch torchvision --index-url https://download.pytorch.org/whl/cu130;
Python 3.10-3.14 wheels, NVIDIA driver >= 580; cu128 stays as fallback for
older drivers, torch <= 2.11).
Official repo deps (curated, not its requirements.txt β it pins
torch==2.3.0 which would break modern Pythons and downgrade CUDA torch):
diffusers>=0.29, transformers>=4.38, rotary-embedding-torch>=0.5,
opencv-python, mediapy. apex and flash-attn are replaced by shims.
Python β₯ 3.14 β torch CUDA wheels may not exist yet (No matching distribution found for torch) β recreate venv with py -3.12.
| Missing piece | Shim | Why equivalent here |
|---|---|---|
| NCCL (no Windows build) | real gloo 1-proc group (init_process_group, tcp://127.0.0.1:29512) |
only dist.barrier()/rank getters are exercised; world_size=1 |
| flash-attn | SDPA flash_attn_varlen_func (F.scaled_dot_product_attention per segment of cu_seqlens) |
DiT v2 calls it without causal/window_size β SDPA is mathematically identical (validated <1e-5 fp32 vs naive attention, uniform+variable lengths) |
apex fusedln/fusedrms (used by configs_3b norms) |
nn.LayerNorm / nn.RMSNorm (eps forwarded, elementwise affine, same parameter names β state_dict compatible) |
fused kernels are numerics-identical, only faster |
Both shims build real types.ModuleType with ModuleSpec + loader, and
__path__=[] for packages, otherwise importlib/pkgutil break (#bug-7).
If the real package exists, it is used untouched.
- gradio never installs; pip dies with
InvalidMarkerβ requirements.txt comment lines started with;β parsed as environment markers. Fix:#-prefixed comments only. No matching distribution for torchon a CUDA index β user's Python too new for that index's wheels. Fix: install.bat preferspy -3.12/py -3.11, chain cu130 β cu128 β PyPI.ModuleNotFoundError: rotary_embedding_torchat first load β repo deps absent. Fix: curated unpinned install + runtime_with_autorepair(one auto pip attempt per module, then a clear error with the exact command).- flash-attn cannot compile on Windows β SDPA shim (Β§5).
- apex required by configs_3b (
fusedln,fusedrms,norm: fusedrms,txt_in_norm: fusedln) β nn.LayerNorm/RMSNorm shim (Β§5). ValueError: Default process group has not been initializedβ officiallog_runtimedecorator barriers unconditionally;init_torchhardcodes NCCL. Fix: env RANK/LOCAL_RANK/WORLD_SIZE + real gloo group (Β§5).ValueError: flash_attn.__spec__ is Noneβ fake modules lacked importlib metadata. Fix: ModuleSpec-based module factory in both shims.- Bare
AssertionError()after weight load βrotary-embedding-torch0.9.x registers extra non-persistent buffers (cached_freqs8192Γ42,freqs), while the officialmeta_non_persistent_buffer_init_fnonly materializes buffers named dummy then asserts. Fix:_materialize_buffersrecomposes RoPEfreqsexactly (1/ΞΈ^(2i/d), freqs_for='lang', ΞΈ=10000; verified 0.00 vs a fresh module), zeros for cached/dummy placeholders. - "not enough image data" after 7 min of correct inference + silent
1-channel output β my code used
video[None]instead of officialvideo[:, None]; ndim==3 β [C,H,W]. Transposed silently. Fix + regression tests on both ndim branches. Lesson: copy the official indexation character for character. - 4031 s/image β three stacked causes: (a)
low_vramswap active on a 16 GB card β auto thresholds (Β§3); (b) tiles larger than the training regime (~1 Mpx) β attention cost quadratic β clamp OUTPUT tile side to 1152 px (MAX_TILE_OUT_SIDE, logged); (c) VAEconv_max_mem: 0.5 GiBβ micro-sliced decode β_tune_vae_memory_limit. After fixes: seconds/tile. - "GPU not detected" after a reboot, and silent quality degradation β
the app silently fell back to a CPU demo backend. Fix: demo backend
removed entirely;
gpu_check.detect_gpu()diagnostics everywhere (bat line, GUI banner, load-time error, check_install.py) with the three classic causes (dead driver / CPU-only torch build / no reboot after driver update) and exact repair commands. - Gradio drag&drop confusion β dropped folders land in the OS temp dir
β outputs appeared to "vanish" into
β¦\Temp\gradio\β¦\upscaled. The UI label warns; advise explicit output paths. Also: the preview is a β€768 px thumbnail β a user once mistook it for a "shrunken" output; the log prints true dimensions (inputΓβ¦ β outputΓβ¦) for every image.
- Env vars:
SEEDVR2_REPO(repo path override),PYTORCH_CUDA_ALLOC_CONF(set by app.py, don't unset). - Settings file
config/settings.json: plain JSON; unknown keys ignored; canonical radio values (x2/x4/x8/custom,keep/png/jpg/webp,overwrite/skip/rename,auto/bf16/fp16,auto/official,fr/en). Legacy French labels auto-migrate (Settings.post_init). - Key constants (
constants.py/base.py):DIVISOR=16,TILING_AUTO_THRESHOLD_MPX=4.0,MAX_TILE_OUT_SIDE=1152,_ETA_WINDOW=5, gloo port 29512.
Add a GUI option end-to-end (checklist β missing one place breaks silently):
- field in
Settings(+ validation in__post_init__if enum-like); - add key to
_persist_settingskeys list and tosetting_inputsand the_on_startunpack tuple β same order everywhere; - field in
JobConfig; wire into the job in_on_start; - consume in
worker.py/backend; - add i18n keys to BOTH tables of
i18n.py(unit test enforces parity); - register the widget with
reg(comp, label=("s","my.key"), β¦); - add/extend a unit test; run
python tests/selftest.py.
Add a language: add a third table in i18n.py with exactly the same keys;
SUPPORTED_LANGUAGES entry; nothing else.
Add a weight format: extend registry.classify_model; teach
official._read_state_dict to produce a DiT-schema state_dict; the rest is
generic.
Never do: reimplement pipeline math silently (wrap the official code and cite it); change filename-preservation defaults; leak per-tile seeding (seed+index per tile = reproducibility); swallow exceptions (logs carry full tracebacks by design); add a CPU/demo fallback (project policy).
python -m compileall -q app.py check_install.py seedvr2_upscaler tests
python tests/selftest.py # 21 tests, all must pass, no GPU needed
python -m seedvr2_upscaler.gpu_check --summary
python check_install.py
# Headless GUI smoke: build_app(tmp models dir) must construct ~70 components,
# and _on_language_change(session, "en") must return one update per registered
# widget (see tests history / docs).| Symptom | File |
|---|---|
| Wrong output names/suffixes | naming.py, worker._process_one |
| Tiles visible seams | tiling.stitch (overlap/feather) |
| Slow per-image time | log Γ©tapes β line; official._tune_vae_memory_limit, base.MAX_TILE_OUT_SIDE, _tune_low_vram |
| OOM | BackendOptions.tiling, low_vram, alloc env var |
| Import errors from SeedVR repo | _with_autorepair, _PYPI_NAMES, shims |
| Language not applied | widget not in reg(...) registry or missing i18n key (test catches) |
| Settings lost/old label | settings.__post_init__ migrations |
| EXIF dropped | images.save_image (+ piexif installed?) |
| GPU vanished after reboot | gpu_check (run python check_install.py) |