mirror of
https://github.com/vladmandic/automatic
synced 2026-09-20 01:31:13 +02:00
fix(ltx,processing): address pr #4819 review
review feedback from vladmandic on commit 80fde086f.
- run_ltx: drop the inline random.seed() / randrange resolve and use
processing.fix_seed(p) right after the StableDiffusionProcessingVideo
construction. p.seed carries the resolved int across every stage
(latent_pass, both upsample paths, refine, post-refine vae_decode).
matches the existing fix_seed(p) call sites in img2img.py:30,
video_run.py:101, xyz_grid.py:266 and 8 others.
- process_decode: add AudioFrameList(list) subclass and attach_audio
helper to carry output.audio onto the returned frame list. mirrors
the existing output.bytes early-return contract: samples.audio
survives downstream so process_images_inner can collect it via the
Processed.audio kwarg.
- drop the p.audio_capture transit in process_diffusers and the
fallback read in process_images_inner. p is input params, not
output state.
This commit is contained in:
@@ -170,15 +170,6 @@ def run_ltx(task_id,
|
||||
yield from abort(f'Video: cls={shared.sd_model.__class__.__name__} selected model is not LTX', ok=True)
|
||||
return
|
||||
|
||||
# get_generator(-1) reseeds globally per call, so every stage would otherwise
|
||||
# roll an uncorrelated seed. Resolve once and thread the int through.
|
||||
import random
|
||||
if seed is None or int(seed) < 0:
|
||||
random.seed()
|
||||
resolved_seed = int(random.randrange(4294967294))
|
||||
else:
|
||||
resolved_seed = int(seed)
|
||||
|
||||
# Lightricks TI2VidTwoStagesPipeline: Stage 1 at half-res, 2x upsample, Stage 2 refine at target.
|
||||
# Auto-couple when the user picks Refine but not Upsample. Both Dev and Distilled refine paths
|
||||
# expect upsampled latents; same-res refine on Distilled produces oversaturation. Condition
|
||||
@@ -262,7 +253,7 @@ def run_ltx(task_id,
|
||||
prompt=prompt,
|
||||
negative_prompt=negative,
|
||||
styles=styles,
|
||||
seed=resolved_seed,
|
||||
seed=int(seed) if seed is not None else -1,
|
||||
sampler_name=sampler_name,
|
||||
sampler_shift=float(sampler_shift),
|
||||
steps=int(steps),
|
||||
@@ -275,6 +266,7 @@ def run_ltx(task_id,
|
||||
vae_type='Default',
|
||||
vae_tile_frames=16,
|
||||
)
|
||||
processing.fix_seed(p)
|
||||
p.scripts = None
|
||||
p.script_args = None
|
||||
p.do_not_save_grid = True
|
||||
@@ -362,7 +354,7 @@ def run_ltx(task_id,
|
||||
mp4_fps=mp4_fps,
|
||||
conditions=conditions,
|
||||
image_cond_noise_scale=image_cond_noise_scale if caps.supports_image_cond_noise_scale else None,
|
||||
seed=resolved_seed,
|
||||
seed=p.seed,
|
||||
image=p.task_args.get('image'),
|
||||
)
|
||||
else:
|
||||
@@ -414,7 +406,7 @@ def run_ltx(task_id,
|
||||
up_args = {
|
||||
'width': final_w,
|
||||
'height': final_h,
|
||||
'generator': get_generator(resolved_seed),
|
||||
'generator': get_generator(p.seed),
|
||||
'output_type': 'latent',
|
||||
}
|
||||
if latents.ndim == 4:
|
||||
@@ -435,7 +427,7 @@ def run_ltx(task_id,
|
||||
'height': final_h,
|
||||
'num_frames': get_frames(frames),
|
||||
'latents_normalized': False,
|
||||
'generator': get_generator(resolved_seed),
|
||||
'generator': get_generator(p.seed),
|
||||
'output_type': 'latent',
|
||||
}
|
||||
if latents.ndim == 4:
|
||||
@@ -470,7 +462,7 @@ def run_ltx(task_id,
|
||||
'height': final_h,
|
||||
'num_frames': get_frames(frames),
|
||||
'num_inference_steps': steps,
|
||||
'generator': get_generator(resolved_seed),
|
||||
'generator': get_generator(p.seed),
|
||||
'callback_on_step_end': diffusers_callback,
|
||||
'output_type': 'pil',
|
||||
}
|
||||
@@ -573,7 +565,7 @@ def run_ltx(task_id,
|
||||
try:
|
||||
if torch.is_tensor(latents):
|
||||
# 0.9.x returns raw latents with output_type='latent'; 2.x pre-denormalizes.
|
||||
frames_out = vae_decode(latents, decode_timestep if caps.supports_decode_timestep else 0.0, resolved_seed, denormalize=caps.family == '0.9')
|
||||
frames_out = vae_decode(latents, decode_timestep if caps.supports_decode_timestep else 0.0, p.seed, denormalize=caps.family == '0.9')
|
||||
else:
|
||||
frames_out = latents
|
||||
except AssertionError as e:
|
||||
|
||||
@@ -528,7 +528,7 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
|
||||
output_images.append(batch_image)
|
||||
infotexts.append(batch_infotext)
|
||||
|
||||
audio = getattr(samples, 'audio', None) or getattr(p, 'audio_capture', None)
|
||||
audio = getattr(samples, 'audio', None)
|
||||
|
||||
if shared.cmd_opts.lowvram:
|
||||
devices.torch_gc(force=True, reason='lowvram')
|
||||
|
||||
@@ -452,17 +452,32 @@ def process_refine(p: processing.StableDiffusionProcessing, output):
|
||||
return output
|
||||
|
||||
|
||||
class AudioFrameList(list):
|
||||
"""list subclass with an audio attribute. Plain lists can't hold attributes,
|
||||
so process_decode uses this when the pipeline output includes audio."""
|
||||
audio = None
|
||||
|
||||
|
||||
def attach_audio(results, audio):
|
||||
if audio is None:
|
||||
return results
|
||||
wrapped = AudioFrameList(results if isinstance(results, list) else list(results))
|
||||
wrapped.audio = audio
|
||||
return wrapped
|
||||
|
||||
|
||||
def process_decode(p: processing.StableDiffusionProcessing, output):
|
||||
shared.sd_model = sd_models.apply_balanced_offload(shared.sd_model, exclude=['vae'])
|
||||
if output is not None:
|
||||
if hasattr(output, 'bytes') and output.bytes is not None:
|
||||
log.debug(f'Generated: bytes={len(output.bytes)}')
|
||||
return output
|
||||
audio = getattr(output, 'audio', None)
|
||||
if not hasattr(output, 'images') and hasattr(output, 'frames'):
|
||||
log.debug(f'Generated: frames={len(output.frames[0])}')
|
||||
output.images = output.frames[0]
|
||||
if output.images is not None and len(output.images) > 0 and isinstance(output.images[0], Image.Image):
|
||||
return output.images
|
||||
return attach_audio(output.images, audio)
|
||||
model = shared.sd_model if not is_refiner_enabled(p) else shared.sd_refiner
|
||||
if not hasattr(model, 'vae'):
|
||||
if hasattr(model, 'pipe') and hasattr(model.pipe, 'vae'):
|
||||
@@ -506,8 +521,9 @@ def process_decode(p: processing.StableDiffusionProcessing, output):
|
||||
results = []
|
||||
else:
|
||||
log.warning('Processing: no results')
|
||||
audio = None
|
||||
results = []
|
||||
return results
|
||||
return attach_audio(results, audio)
|
||||
|
||||
|
||||
def update_pipeline(sd_model, p: processing.StableDiffusionProcessing):
|
||||
@@ -628,10 +644,6 @@ def process_diffusers(p: processing.StableDiffusionProcessing):
|
||||
timer.process.add('lora', lora_common.timer.total)
|
||||
lora_common.timer.clear(complete=True)
|
||||
|
||||
# process_decode flattens video output to a frame list and drops the audio attribute;
|
||||
# stash it on `p` so video pipelines can recover it after process_images returns.
|
||||
if output is not None and getattr(output, 'audio', None) is not None:
|
||||
p.audio_capture = output.audio
|
||||
results = process_decode(p, output)
|
||||
timer.process.record('decode')
|
||||
|
||||
|
||||
Reference in New Issue
Block a user