Merge diffusion-train-precision: grad norm chart + review fixes

# Conflicts:
#	studio/backend/core/training/diffusion_dit_trainer.py
#	studio/backend/core/training/diffusion_lora_trainer.py
#	studio/backend/core/training/diffusion_training_service.py
#	studio/backend/models/training.py
#	studio/frontend/src/features/images/api.ts
#	studio/frontend/src/features/images/train/diffusion-charts.tsx
#	studio/frontend/src/features/images/train/diffusion-train-panel.tsx
This commit is contained in:
Daniel Han 2026-07-04 04:37:58 +00:00
commit a346a0eb20
5 changed files with 18 additions and 5 deletions

View file

@ -181,6 +181,11 @@ def install_compile_safe_patches() -> int:
for cls, new_fn in _specs():
if cls is None:
continue
# torch < 2.4 has no F.rms_norm: leave diffusers' original RMSNorm.forward in
# place rather than installing a patch whose fast path would AttributeError.
if cls is _RMSNorm and not hasattr(F, "rms_norm"):
logger.info("eager-patch: skipping RMSNorm (this torch has no F.rms_norm)")
continue
# Capture the live original BEFORE patching so the RMSNorm fast path can fall back
# to it for the uncommon (NPU / bias / fp32-weight / tuple-dim) cases.
if cls is _RMSNorm:

View file

@ -482,9 +482,10 @@ def discover_image_caption_pairs(
if sidecar.is_file():
caption = sidecar.read_text(encoding = "utf-8").strip()
break
# 2. metadata row keyed by file name (basename or the name as written).
# 2. metadata row keyed by file name (basename or the relative path; as_posix so a
# Windows backslash path still matches the jsonl's forward-slash keys).
if caption is None:
caption = meta_caption.get(img.name) or meta_caption.get(str(img.relative_to(root)))
caption = meta_caption.get(img.name) or meta_caption.get(img.relative_to(root).as_posix())
# 3. dreambooth instance prompt.
if caption is None and instance_prompt:
caption = instance_prompt

View file

@ -1549,7 +1549,15 @@ def _image_record(
caption = None
break
if caption is None:
# Basename first, then the relative path as written in the jsonl (as_posix so a
# Windows backslash path still matches forward-slash keys) -- the same lookup
# order discover_image_caption_pairs uses.
meta = meta_captions.get(image_path.name)
if meta is None:
try:
meta = meta_captions.get(image_path.relative_to(folder).as_posix())
except ValueError:
meta = None
if meta is not None:
caption = meta
source = "metadata"

View file

@ -481,7 +481,7 @@ function AdvancedSelect({
return (
<div className="flex flex-col gap-1">
<div className="flex items-center justify-between gap-2">
<span className="flex items-center gap-1 text-xs font-medium text-muted-foreground">
<span className="flex shrink-0 items-center gap-1 whitespace-nowrap text-xs font-medium text-muted-foreground">
{label}
{hint && <InfoHint>{hint}</InfoHint>}
</span>
@ -1872,7 +1872,7 @@ export function ImagesPage({ active = true }: { active?: boolean }) {
{!status?.loaded || status.model_kind === "gguf" ? (
<AdvancedSelect
label="GGUF compute"
desc="Off runs the GGUF as-is. INT8/FP8/FP4 dequantise the transformer onto low-precision tensor cores for a faster step, at the cost of a larger download and more VRAM."
desc="Off runs the GGUF as-is. INT8/FP8/FP4 instead download the base model's bf16 transformer and quantise it directly onto low-precision tensor cores (the GGUF is not requantised): a faster step, at the cost of a larger download and more VRAM."
hint="Optional speed-up for GGUF models. Off runs the GGUF as-is. FP8/INT8/FP4 instead load the FULL base model and quantise its transformer onto low-precision tensor cores: faster per step, but a larger download and more VRAM, and it falls back to the GGUF if it can't fit. Needs CUDA."
value={transformerQuant}
onValueChange={(v) => setTransformerQuant(v as typeof transformerQuant)}

View file

@ -106,7 +106,6 @@ export function DiffusionCharts({
() => buildYDomain(gradData.map((p) => p.displayGradNorm)),
[gradData],
);
const avgRaw =
lossItems.length > 0
? +(lossItems.reduce((s, p) => s + p.loss, 0) / lossItems.length).toFixed(4)