v2.2.0: clean up ROCM SamplerCustomAdvanced interface

- Remove optimize_for_video (auto-detects 5D video latents)
- Remove precision_mode (was a no-op)
- compatibility_mode moved to advanced=True toggle
- Node now matches stock interface exactly (5 inputs) with only
  an advanced debug toggle added
- Video workflow auto-detected from latent shape (5D, T > 1)
- Architecture logging explicitly shows GPU family on ROCm
- Benchmark node also cleaned up (no extra params)
This commit is contained in:
iGavroche
2026-06-13 11:10:56 -04:00
parent b3b82e1cb8
commit f779d67adf
2 changed files with 33 additions and 52 deletions
+8 -7
View File
@@ -39,9 +39,7 @@ This is the standard pattern for LTX Video, LTX 2.3 AV, and many other advanced
| `sampler` | SAMPLER | Yes | e.g. KSamplerSelect |
| `sigmas` | SIGMAS | Yes | e.g. BasicScheduler |
| `latent_image` | LATENT | Yes | e.g. LTXVConcatAVLatent |
| `optimize_for_video` | BOOLEAN | No (default: False) | Disables previews when latent is 5D with T > 1 |
| `precision_mode` | COMBO | No (default: auto) | `auto`, `fp32`, `bf16` — ROCm precision hint |
| `compatibility_mode` | BOOLEAN | No (default: False) | When True, skips all ROCm optimizations (pure stock behavior) |
| `compatibility_mode` | BOOLEAN | No (advanced) | Skip all ROCm optimizations, use pure stock behavior |
## Outputs
@@ -57,18 +55,21 @@ This is the standard pattern for LTX Video, LTX 2.3 AV, and many other advanced
1. Delete the stock `SamplerCustomAdvanced` node
2. Add `ROCM SamplerCustomAdvanced` from `ROCm Ninodes/Sampling`
3. Wire the same connections (noise, guider, sampler, sigmas, latent_image)
4. Optionally configure `optimize_for_video`, `precision_mode`, or `compatibility_mode`
5. Run — the console will show per-step progress, model detection, and completion
4. Run — the console will show GPU architecture, model detection, and per-step progress
### LTX 2.3 / LTX Video Workflows
For LTX-based workflows (like `LTX2.3-Director-App-Mariah.json`), the `latent_image` input typically comes from `LTXVConcatAVLatent`. ROCMSamplerCustomAdvanced detects the flow-matching model type (128ch latent, memory factor 5.5x) and applies appropriate memory management before and after sampling.
For LTX-based workflows (like `LTX2.3-Director-App-Mariah.json`), the `latent_image` input typically comes from `LTXVConcatAVLatent`. ROCMSamplerCustomAdvanced detects the flow-matching model type (128ch latent, memory factor 5.5x) and applies appropriate memory management before and after sampling. Video (5D latent with T > 1) is auto-detected — previews are disabled for multi-frame latents to reduce overhead.
### When to Use `compatibility_mode`
Enable it via the node's advanced properties panel if you suspect the ROCm optimizations are causing issues. This returns the exact stock behavior for debugging.
## Benchmark Node
`ROCMSamplerCustomAdvancedBenchmark` (`ROCm Ninodes/Sampling > ROCm SamplerCustomAdvanced Benchmark`) runs both the stock and ROCm-optimized sampler in sequence on identical inputs and outputs a comparison string.
**Inputs:** Same as SamplerCustomAdvanced.
**Inputs:** Same as SamplerCustomAdvanced (no extra params).
**Outputs:**
- `LATENT` — result from the ROCm-optimized run
+25 -45
View File
@@ -449,8 +449,8 @@ class ROCMSamplerCustomAdvanced(io.ComfyNode):
Key enhancements over stock SamplerCustomAdvanced:
- Auto-detects AMD GPU architecture and applies optimal backend settings
- Emergency memory defrag for high-memory models (128ch latents)
- Optional BF16 precision hint for supported AMD GPUs
- Enhanced callback with ETA, per-step timing, and video-workflow optimization
- Enhanced callback with ETA and per-step timing
- Video workflow auto-detection (5D latent → no previews)
- Gentle post-sample memory cleanup
"""
@@ -458,7 +458,7 @@ class ROCMSamplerCustomAdvanced(io.ComfyNode):
def define_schema(cls):
return io.Schema(
node_id="ROCMSamplerCustomAdvanced",
display_name="ROCM SamplerCustomAdvanced",
display_name="ROCm SamplerCustomAdvanced",
category="ROCm Ninodes/Sampling",
description="Drop-in replacement for SamplerCustomAdvanced with ROCm memory management, backend tuning, and detailed progress tracking. Particularly beneficial for high-memory models like LTX Video (128ch latent).",
inputs=[
@@ -467,13 +467,8 @@ class ROCMSamplerCustomAdvanced(io.ComfyNode):
io.Sampler.Input("sampler"),
io.Sigmas.Input("sigmas"),
io.Latent.Input("latent_image"),
io.Boolean.Input("optimize_for_video", optional=True, default=False,
tooltip="Disable previews for multi-frame latents (video workflows)"),
io.Combo.Input("precision_mode", optional=True, default="auto",
options=["auto", "fp32", "bf16"],
tooltip="ROCm precision hint (no-op on CUDA/CPU)"),
io.Boolean.Input("compatibility_mode", optional=True, default=False,
tooltip="Force pure stock behavior, no ROCm optimizations"),
io.Boolean.Input("compatibility_mode", optional=True, default=False, advanced=True,
tooltip="Skip all ROCm optimizations, force pure stock behavior"),
],
outputs=[
io.Latent.Output(display_name="output"),
@@ -483,31 +478,28 @@ class ROCMSamplerCustomAdvanced(io.ComfyNode):
@classmethod
def execute(cls, noise, guider, sampler, sigmas, latent_image,
optimize_for_video=False, precision_mode="auto", compatibility_mode=False) -> io.NodeOutput:
# ── Detect architecture and model type ──────────────────────────
compatibility_mode=False) -> io.NodeOutput:
model = guider.model_patcher
# ── ROCm setup (skipped in compatibility_mode) ──────────────────
if not compatibility_mode:
arch_info = detect_architecture()
model_info = detect_model_sampling_type(model)
apply_rocm_backend_settings(arch_info)
is_rocm = bool(getattr(torch.version, 'hip', None))
if is_rocm:
print(f"🚀 ROCm detected on {arch_info['family']} "
f"({arch_info.get('arch_name', 'unknown')}) "
f"— applying backend tuning", flush=True)
if model_info["has_high_memory"]:
print(f"💾 High-memory model detected (factor: {model_info['memory_usage_factor']}) — cleaning up")
print(f"💾 High-memory model (factor: {model_info['memory_usage_factor']}x, "
f"{model_info['latent_channels']}ch latent) — defragging VRAM", flush=True)
emergency_memory_cleanup()
if model_info["model_type"] == "flow":
print(f"🌊 Flow-matching model detected ({model_info['latent_channels']}ch latent)")
elif model_info["is_pixel_space"]:
print(f"📷 Pixel-space model detected — no VAE decode needed downstream")
is_rocm = bool(getattr(torch.version, 'hip', None))
if is_rocm and torch.cuda.is_available() and precision_mode == "bf16":
try:
if getattr(torch.cuda, 'is_bf16_supported', lambda: False)():
pass
except Exception:
pass
print(f"🌊 Flow-matching model ({model_info['latent_channels']}ch)", flush=True)
# ── Stock SamplerCustomAdvanced logic ──────────────────────────
latent = latent_image
@@ -527,14 +519,12 @@ class ROCMSamplerCustomAdvanced(io.ComfyNode):
x0_output = {}
total_steps = sigmas.shape[-1] - 1
# ── Video optimization ──────────────────────────────────────────
is_video_workflow = False
if not compatibility_mode and optimize_for_video and latent_image_tensor.ndim == 5 and latent_image_tensor.shape[2] > 1:
is_video_workflow = True
# ── Auto-detect video (5D latent with T > 1) ──────────────────────
is_video = latent_image_tensor.ndim == 5 and latent_image_tensor.shape[2] > 1
# ── Create previewer once (like stock prepare_callback) ──────
# ── Create previewer once (like stock prepare_callback) ──────────
previewer = None
if not is_video_workflow:
if not is_video:
try:
previewer = latent_preview.get_previewer(
guider.model_patcher.load_device,
@@ -556,7 +546,6 @@ class ROCMSamplerCustomAdvanced(io.ComfyNode):
progress_pct = ((step + 1) / total_steps) * 100
pct_key = (int(progress_pct) // 10) * 10
# ── Update progress bar with preview (throttled) ────────
if current_time - last_update_time[0] >= 0.3 or step == total_steps - 1:
preview_bytes = None
if previewer and step % 5 == 0:
@@ -570,11 +559,9 @@ class ROCMSamplerCustomAdvanced(io.ComfyNode):
pass
last_update_time[0] = current_time
# ── Console timing at 10% milestones only ──────────────
if step == 0 or step == total_steps - 1 or pct_key not in reported_milestones:
reported_milestones.add(pct_key)
elapsed = current_time - start_time
wf_type = "Video" if is_video_workflow else "Image"
if step == 0:
print(f"📊 ROCm CustomAdvanced: Starting {total_steps} steps...", flush=True)
else:
@@ -587,11 +574,11 @@ class ROCMSamplerCustomAdvanced(io.ComfyNode):
f"({avg:.2f}s/step)", flush=True)
callback = enhanced_callback
disable_pbar = is_video_workflow
disable_pbar = is_video
# ── Sampling ────────────────────────────────────────────────────
print(f"🚀 ROCm SamplerCustomAdvanced: {total_steps} steps"
f"{' (video mode)' if is_video_workflow else ''}", flush=True)
f"{' (video mode)' if is_video else ''}", flush=True)
samples = guider.sample(
noise.generate_noise(latent), latent_image_tensor, sampler, sigmas,
denoise_mask=noise_mask, callback=callback, disable_pbar=disable_pbar,
@@ -649,10 +636,6 @@ class ROCMSamplerCustomAdvancedBenchmark:
"sampler": ("SAMPLER",),
"sigmas": ("SIGMAS",),
"latent_image": ("LATENT",),
},
"optional": {
"optimize_for_video": ("BOOLEAN", {"default": False}),
"precision_mode": (["auto", "fp32", "bf16"], {"default": "auto"}),
}
}
@@ -662,8 +645,7 @@ class ROCMSamplerCustomAdvancedBenchmark:
CATEGORY = "ROCm Ninodes/Sampling"
DESCRIPTION = "Compare stock vs ROCm-optimized custom sampler performance"
def run(self, noise, guider, sampler, sigmas, latent_image,
optimize_for_video=False, precision_mode="auto"):
def run(self, noise, guider, sampler, sigmas, latent_image):
import time as time_module
import gc
@@ -713,9 +695,7 @@ class ROCMSamplerCustomAdvancedBenchmark:
if model_info["has_high_memory"]:
emergency_memory_cleanup()
is_video_workflow = False
if optimize_for_video and latent_image_tensor.ndim == 5 and latent_image_tensor.shape[2] > 1:
is_video_workflow = True
is_video = latent_image_tensor.ndim == 5 and latent_image_tensor.shape[2] > 1
mem_before_rocm = torch.cuda.memory_allocated(0) if torch.cuda.is_available() else 0
@@ -739,7 +719,7 @@ class ROCMSamplerCustomAdvancedBenchmark:
rocm_samples = guider.sample(
noise.generate_noise(latent), latent_image_tensor, sampler, sigmas,
denoise_mask=noise_mask, callback=rocm_callback,
disable_pbar=is_video_workflow, seed=noise.seed
disable_pbar=is_video, seed=noise.seed
)
rocm_samples = rocm_samples.to(comfy.model_management.intermediate_device())
t3 = time_module.time()