mirror of
https://github.com/vladmandic/automatic
synced 2026-09-20 01:31:13 +02:00
ltx-conditioned prototype
Signed-off-by: Vladimir Mandic <mandic00@live.com>
This commit is contained in:
+5
-5
@@ -1,8 +1,8 @@
|
||||
# Change Log for SD.Next
|
||||
|
||||
## Update for 2025-07-07
|
||||
## Update for 2025-07-09
|
||||
|
||||
### Highlights for 2025-07-08
|
||||
### Highlights for 2025-07-09
|
||||
|
||||
In this release we finally break with legacy with the removal of the original [A1111](https://github.com/AUTOMATIC1111/stable-diffusion-webui/) codebase which has not been maintained for a while now
|
||||
This plus major cleanup of codebase and external dependencies resulted in ~53k LoC (*lines-of-code*) reduction and spread over [~680 files](https://github.com/vladmandic/sdnext/pull/4017)!
|
||||
@@ -11,9 +11,9 @@ We also switched project license to [Apache-2.0](https://github.com/vladmandic/s
|
||||
|
||||
Feature highlights include:
|
||||
- **ModernUI** layout redesign which should make it more user friendly and easier to navigate
|
||||
- Redesigned **Video** interface with
|
||||
- Redesigned **Video** interface with native **FramePack** support
|
||||
- New background replacement and relightning methods using **Latent Bridge Matching** and new **PixelArt** processing filter
|
||||
- New LLM/VLM models available for captioning and prompt enhance
|
||||
- New **LLM/VLM** models available for captioning and prompt enhance
|
||||
- Compute improvements
|
||||
|
||||
And (as always) many bugfixes and improvements to existing features!
|
||||
@@ -23,7 +23,7 @@ Although upgrades and existing installations are tested and should work fine!
|
||||
|
||||
[ReadMe](https://github.com/vladmandic/automatic/blob/master/README.md) | [ChangeLog](https://github.com/vladmandic/automatic/blob/master/CHANGELOG.md) | [Docs](https://vladmandic.github.io/sdnext-docs/) | [WiKi](https://github.com/vladmandic/automatic/wiki) | [Discord](https://discord.com/invite/sd-next-federal-batch-inspectors-1101998836328697867)
|
||||
|
||||
### Details for 2025-07-08
|
||||
### Details for 2025-07-09
|
||||
|
||||
- **License**
|
||||
- SD.Next [license](https://github.com/vladmandic/sdnext/blob/dev/LICENSE.txt) switched from **aGPL-v3.0** to **Apache-v2.0**
|
||||
|
||||
@@ -505,7 +505,10 @@ function setupExtraNetworksForTab(tabname) {
|
||||
if (window.opts.extra_networks_card_cover === 'sidebar') en.style.width = 0;
|
||||
gradioApp().getElementById(`${tabname}_settings`).parentNode.style.width = 'unset';
|
||||
}
|
||||
if (tabname === 'video') gradioApp().getElementById('framepack_settings').parentNode.style.width = gradioApp().getElementById(`${tabname}_settings`).parentNode.style.width;
|
||||
if (tabname === 'video') {
|
||||
gradioApp().getElementById('framepack_settings').parentNode.style.width = gradioApp().getElementById(`${tabname}_settings`).parentNode.style.width;
|
||||
gradioApp().getElementById('ltx_settings').parentNode.style.width = gradioApp().getElementById(`${tabname}_settings`).parentNode.style.width;
|
||||
}
|
||||
}
|
||||
});
|
||||
intersectionObserver.observe(en); // monitor visibility
|
||||
|
||||
@@ -273,6 +273,15 @@ function submit_framepack(...args) {
|
||||
return args;
|
||||
}
|
||||
|
||||
function submit_ltx(...args) {
|
||||
const id = randomId();
|
||||
log('submitFramepack', id);
|
||||
requestProgress(id, null, null);
|
||||
window.submit_state = '';
|
||||
args[0] = id;
|
||||
return args;
|
||||
}
|
||||
|
||||
function submit_video_wrapper(...args) {
|
||||
const modernEl = gradioApp().querySelector('.video_output.fade-in');
|
||||
let id = modernEl ? modernEl.id : args[0];
|
||||
@@ -280,6 +289,7 @@ function submit_video_wrapper(...args) {
|
||||
log('submitVideoWrapper', id);
|
||||
const btn = gradioApp().getElementById(`${id}_generate_btn`);
|
||||
if (btn) btn.click();
|
||||
else console.log('submit_video_wrapper: no button found', id);
|
||||
}
|
||||
|
||||
function submit_postprocessing(...args) {
|
||||
|
||||
@@ -0,0 +1,214 @@
|
||||
"""
|
||||
- condition upload image
|
||||
- condition upload video
|
||||
- condition video get frames
|
||||
- custom sampler
|
||||
- new way of generate video
|
||||
- modernui
|
||||
- lora loader
|
||||
"""
|
||||
import os
|
||||
import time
|
||||
import threading
|
||||
import diffusers
|
||||
from modules import shared, sd_models, errors, timer, memstats, progress
|
||||
from modules.processing_callbacks import diffusers_callback
|
||||
from modules.ltx.ltx_util import get_bucket, get_frames, load_model, load_upsample, get_conditions, get_generator, get_prompts, vae_decode
|
||||
|
||||
|
||||
debug = shared.log.trace if os.environ.get('SD_VIDEO_DEBUG', None) is not None else lambda *args, **kwargs: None
|
||||
engine, model = 'LTX Video', 'LTXVideo 0.9.7 13B'
|
||||
upsample_repo_id = "a-r-r-o-w/LTX-Video-0.9.7-Latent-Spatial-Upsampler-diffusers"
|
||||
upsample_pipe = None
|
||||
queue_lock = threading.Lock()
|
||||
|
||||
|
||||
def run_ltx(task_id,
|
||||
_ui_state,
|
||||
prompt:str,
|
||||
negative:str,
|
||||
styles:list[str],
|
||||
width:int,
|
||||
height:int,
|
||||
frames:int,
|
||||
steps:int,
|
||||
sampler_index:int,
|
||||
seed:int,
|
||||
upsample_enable:bool,
|
||||
upsample_ratio:float,
|
||||
refine_enable:bool,
|
||||
refine_strength:float,
|
||||
condition_image_strength:float,
|
||||
condition_video_strength:float,
|
||||
condition_video_frames:int,
|
||||
condition_image,
|
||||
condition_video,
|
||||
decode_timestep:float,
|
||||
image_cond_noise_scale:float,
|
||||
_overrides,
|
||||
):
|
||||
|
||||
def abort(e, ok:bool=False):
|
||||
if ok:
|
||||
shared.log.info(e)
|
||||
else:
|
||||
shared.log.error(f'Video: cls={shared.sd_model.__class__.__name__} op=base {e}')
|
||||
errors.display(e, 'LTX')
|
||||
shared.state.end()
|
||||
progress.finish_task(task_id)
|
||||
yield None, f'LTX Error: {str(e)}'
|
||||
|
||||
progress.add_task_to_queue(task_id)
|
||||
with queue_lock:
|
||||
progress.start_task(task_id)
|
||||
memstats.reset_stats()
|
||||
timer.process.reset()
|
||||
yield None, 'LTX: Loading...'
|
||||
load_model(engine, model)
|
||||
|
||||
shared.state.begin('Video', task_id=task_id)
|
||||
shared.state.job_count = 1
|
||||
|
||||
conditions = get_conditions(
|
||||
condition_image,
|
||||
condition_image_strength,
|
||||
condition_video,
|
||||
condition_video_strength,
|
||||
condition_video_frames,
|
||||
)
|
||||
|
||||
prompt, negative, networks = get_prompts(prompt, negative, styles)
|
||||
shared.log.debug(f'Video: cls={shared.sd_model.__class__.__name__} op=init prompt="{prompt}" negative="{negative}" styles={styles} networks={networks}')
|
||||
|
||||
t0 = time.time()
|
||||
shared.sd_model = sd_models.apply_balanced_offload(shared.sd_model)
|
||||
t1 = time.time()
|
||||
base_args = {
|
||||
"prompt": prompt,
|
||||
"negative_prompt": negative,
|
||||
"width": get_bucket(width),
|
||||
"height": get_bucket(height),
|
||||
"num_frames": get_frames(frames),
|
||||
"num_inference_steps": steps,
|
||||
"image_cond_noise_scale": image_cond_noise_scale,
|
||||
"generator": get_generator(seed),
|
||||
"callback_on_step_end": diffusers_callback,
|
||||
"output_type": "latent",
|
||||
}
|
||||
if len(conditions) > 0:
|
||||
base_args["conditions"] = conditions
|
||||
shared.log.debug(f'Video: cls={shared.sd_model.__class__.__name__} op=base {base_args}')
|
||||
yield None, 'LTX: Generate in progress...'
|
||||
try:
|
||||
latents = shared.sd_model(**base_args).frames[0]
|
||||
except AssertionError as e:
|
||||
yield from abort(e, ok=True)
|
||||
return
|
||||
except Exception as e:
|
||||
yield from abort(e, ok=False)
|
||||
return
|
||||
t2 = time.time()
|
||||
shared.sd_model = sd_models.apply_balanced_offload(shared.sd_model)
|
||||
t3 = time.time()
|
||||
timer.process.add('offload', t1 - t0)
|
||||
timer.process.add('base', t2 - t1)
|
||||
timer.process.add('offload', t3 - t2)
|
||||
# diffusers.LTXConditionPipeline
|
||||
|
||||
if upsample_enable:
|
||||
t4 = time.time()
|
||||
shared.state.begin('Upsample')
|
||||
global upsample_pipe
|
||||
upsample_pipe = load_upsample(upsample_pipe, upsample_repo_id)
|
||||
upsample_pipe = sd_models.apply_balanced_offload(upsample_pipe)
|
||||
upscale_args = {
|
||||
"width": get_bucket(upsample_ratio * width),
|
||||
"height": get_bucket(upsample_ratio * height),
|
||||
"generator": get_generator(seed),
|
||||
"output_type": "latent",
|
||||
}
|
||||
if latents.ndim == 4:
|
||||
latents = latents.unsqueeze(0) # add batch dimension
|
||||
shared.log.debug(f'Video: cls={shared.sd_model.__class__.__name__} op=upsample latents={latents.shape} {upscale_args}')
|
||||
yield None, 'LTX: Upsample in progress...'
|
||||
try:
|
||||
upsampled_latents = upsample_pipe(latents=latents, **upscale_args).frames[0]
|
||||
except AssertionError as e:
|
||||
yield from abort(e, ok=True)
|
||||
return
|
||||
except Exception as e:
|
||||
yield from abort(e, ok=False)
|
||||
return
|
||||
latents = upsampled_latents
|
||||
t5 = time.time()
|
||||
upsample_pipe = sd_models.apply_balanced_offload(upsample_pipe)
|
||||
t6 = time.time()
|
||||
timer.process.add('upsample', t5 - t4)
|
||||
timer.process.add('offload', t6 - t5)
|
||||
shared.state.end()
|
||||
|
||||
if refine_enable:
|
||||
t7 = time.time()
|
||||
shared.state.begin('Refine')
|
||||
shared.sd_model = sd_models.apply_balanced_offload(shared.sd_model)
|
||||
refine_args = {
|
||||
"prompt": prompt,
|
||||
"negative_prompt": negative,
|
||||
"width": get_bucket(upsample_ratio * width),
|
||||
"height": get_bucket(upsample_ratio * height),
|
||||
"num_frames": get_frames(frames),
|
||||
"denoise_strength": refine_strength,
|
||||
"num_inference_steps": steps,
|
||||
"image_cond_noise_scale": image_cond_noise_scale,
|
||||
"generator": get_generator(seed),
|
||||
"callback_on_step_end": diffusers_callback,
|
||||
"output_type": "latent",
|
||||
}
|
||||
if len(conditions) > 0:
|
||||
refine_args["conditions"] = conditions
|
||||
if latents.ndim == 4:
|
||||
latents = latents.unsqueeze(0) # add batch dimension
|
||||
shared.log.debug(f'Video: cls={shared.sd_model.__class__.__name__} op=refine latents={latents.shape} {refine_args}')
|
||||
yield None, 'LTX: Refine in progress...'
|
||||
try:
|
||||
refined_latents = shared.sd_model(latents=latents, **refine_args).frames[0]
|
||||
except AssertionError as e:
|
||||
yield from abort(e, ok=True)
|
||||
return
|
||||
except Exception as e:
|
||||
yield from abort(e, ok=False)
|
||||
return
|
||||
latents = refined_latents
|
||||
t8 = time.time()
|
||||
shared.sd_model = sd_models.apply_balanced_offload(shared.sd_model)
|
||||
t9 = time.time()
|
||||
timer.process.add('refine', t8 - t7)
|
||||
timer.process.add('offload', t9 - t8)
|
||||
shared.state.end()
|
||||
|
||||
yield None, 'LTX: VAE decode in progress...'
|
||||
try:
|
||||
frames = vae_decode(latents, decode_timestep, seed)
|
||||
except AssertionError as e:
|
||||
yield from abort(e, ok=True)
|
||||
return
|
||||
except Exception as e:
|
||||
yield from abort(e, ok=False)
|
||||
return
|
||||
t10 = time.time()
|
||||
shared.sd_model = sd_models.apply_balanced_offload(shared.sd_model)
|
||||
t11 = time.time()
|
||||
timer.process.add('offload', t11 - t10)
|
||||
shared.state.end()
|
||||
progress.finish_task(task_id)
|
||||
|
||||
t_end = time.time()
|
||||
num_frames = len(frames)
|
||||
resolution = f'{frames[0].width}x{frames[0].height}' if num_frames > 0 else None
|
||||
summary = timer.process.summary(min_time=0.25, total=False).replace('=', ' ')
|
||||
memory = shared.mem_mon.summary()
|
||||
fps = f'{num_frames/(t_end-t0):.2f}'
|
||||
its = f'{(steps)/(t_end-t0):.2f}'
|
||||
|
||||
shared.log.info(f'Processed: frames={num_frames} fps={fps} its={its} resolution={resolution} time={t_end-t0:.2f} timers={timer.process.dct()} memory={memstats.memory_stats()}')
|
||||
yield frames, f'LTX: Generation completed | Frames {len(frames)} | Resolution {resolution} | f/s {fps} | it/s {its} '+ f"<div class='performance'><p>{summary} {memory}</p></div>"
|
||||
@@ -0,0 +1,79 @@
|
||||
import os
|
||||
import gradio as gr
|
||||
from modules import shared, sd_models, ui_sections, ui_symbols
|
||||
from modules.ui_components import ToolButton
|
||||
from modules.ltx import ltx_process
|
||||
|
||||
|
||||
debug = shared.log.trace if os.environ.get('SD_VIDEO_DEBUG', None) is not None else lambda *args, **kwargs: None
|
||||
|
||||
|
||||
def create_ui(prompt, negative, styles, overrides):
|
||||
with gr.Row():
|
||||
with gr.Column(variant='compact', elem_id="ltx_settings", elem_classes=['settings-column'], scale=1):
|
||||
with gr.Row():
|
||||
generate = gr.Button('Generate', elem_id="ltx_generate_btn", variant='primary', visible=False)
|
||||
with gr.Accordion(open=True, label="Size", elem_id='ltx_generate_accordion'):
|
||||
with gr.Row():
|
||||
width, height = ui_sections.create_resolution_inputs('ltx', default_width=704, default_height=512)
|
||||
with gr.Row():
|
||||
frames = gr.Slider(label='Frames', minimum=1, maximum=513, step=1, value=17, elem_id="ltx_frames")
|
||||
seed = gr.Number(label='Initial seed', value=-1, elem_id="ltx_seed", container=True)
|
||||
random_seed = ToolButton(ui_symbols.random, elem_id="ltx_random_seed")
|
||||
with gr.Accordion(open=False, label="Condition", elem_id='ltx_condition_accordion'):
|
||||
with gr.Tabs():
|
||||
with gr.Tab('Image', id='ltx_condition_image_tab'):
|
||||
condition_image_strength = gr.Slider(label='Condition strength', minimum=0.1, maximum=1.0, step=0.05, value=0.8, elem_id="ltx_condition_image_strength")
|
||||
condition_image = gr.Image(label='Image', type='filepath', elem_id="ltx_condition_image", visible=False)
|
||||
with gr.Tab('Video', id='ltx_condition_video_tab'):
|
||||
condition_video_strength = gr.Slider(label='Condition strength', minimum=0.1, maximum=1.0, step=0.05, value=0.8, elem_id="ltx_condition_video_strength")
|
||||
condition_video_frames = gr.Slider(label='Condition frames', minimum=1, maximum=1024, step=1, value=15, elem_id="ltx_condition_video_frames")
|
||||
condition_video = gr.Video(label='Video', type='filepath', elem_id="ltx_condition_video", visible=False)
|
||||
with gr.Accordion(open=False, label="Upsample", elem_id='ltx_upsample_accordion'):
|
||||
upsample_enable = gr.Checkbox(label='Enable upsampling', value=False, elem_id="ltx_upsample_enable")
|
||||
upsample_ratio = gr.Slider(label='Upsample ratio', minimum=1.0, maximum=4.0, step=0.1, value=2.0, elem_id="ltx_upsample_ratio", interactive=False)
|
||||
with gr.Accordion(open=False, label="Refine", elem_id='ltx_refine_accordion'):
|
||||
refine_enable = gr.Checkbox(label='Enable refinement', value=False, elem_id="ltx_refine_enable")
|
||||
refine_strength = gr.Slider(label='Refine strength', minimum=0.1, maximum=1.0, step=0.05, value=0.4, elem_id="ltx_refine_strength")
|
||||
with gr.Accordion(open=False, label="Advanced", elem_id='ltx_parameters_accordion'):
|
||||
steps, sampler_index = ui_sections.create_sampler_and_steps_selection(None, "ltx", default_steps=50)
|
||||
with gr.Row():
|
||||
decode_timestep = gr.Slider(label='Decode timestep', minimum=0.01, maximum=1.0, step=0.01, value=0.05, elem_id="ltx_decode_timestep")
|
||||
image_cond_noise_scale = gr.Slider(label='Noise scale', minimum=0.01, maximum=1.0, step=0.01, value=0.025, elem_id="ltx_image_cond_noise_scale")
|
||||
|
||||
with gr.Column(elem_id='ltx-output-column', scale=2) as _column_output:
|
||||
with gr.Row():
|
||||
# video = gr.Video(label="Output", show_label=False, elem_id='ltx_output_video', elem_classes=['control-image'], height=512, autoplay=False)
|
||||
video = gr.Gallery(value=[], label="Output", show_label=False, elem_id='ltx_output_video', elem_classes=['control-image'], height=512)
|
||||
with gr.Row():
|
||||
text = gr.HTML('', elem_id='ltx_generation_info', show_label=False)
|
||||
|
||||
random_seed.click(fn=lambda: -1, show_progress=False, inputs=[], outputs=[seed])
|
||||
task_id = gr.Textbox(visible=False, value='')
|
||||
ui_state = gr.Textbox(visible=False, value='')
|
||||
state_inputs = [task_id, ui_state]
|
||||
|
||||
video_inputs = [
|
||||
prompt, negative, styles,
|
||||
width, height, frames,
|
||||
steps, sampler_index, seed,
|
||||
upsample_enable, upsample_ratio,
|
||||
refine_enable, refine_strength,
|
||||
condition_image_strength, condition_video_strength, condition_video_frames,
|
||||
condition_image, condition_video,
|
||||
decode_timestep, image_cond_noise_scale,
|
||||
overrides,
|
||||
]
|
||||
video_outputs = [
|
||||
video,
|
||||
text,
|
||||
]
|
||||
|
||||
video_dict = dict(
|
||||
fn=ltx_process.run_ltx,
|
||||
_js="submit_ltx",
|
||||
inputs=state_inputs + video_inputs,
|
||||
outputs=video_outputs,
|
||||
show_progress=False,
|
||||
)
|
||||
generate.click(**video_dict)
|
||||
@@ -0,0 +1,100 @@
|
||||
import time
|
||||
import torch
|
||||
from modules import devices, shared, sd_models, timer, extra_networks
|
||||
|
||||
|
||||
def get_bucket(size: int):
|
||||
return int(size) - (int(size) % shared.sd_model.vae_temporal_compression_ratio)
|
||||
|
||||
|
||||
def get_frames(frames: int):
|
||||
return int(8 * (int(frames) // 8)) + 1
|
||||
|
||||
|
||||
def load_model(engine: str, model: str):
|
||||
t0 = time.time()
|
||||
from modules.video_models import models_def, video_load
|
||||
selected: models_def.Model = [m for m in models_def.models[engine] if m.name == model][0]
|
||||
shared.log.info(f'Video load: cls={selected.repo_cls.__name__} repo="{selected.repo}"')
|
||||
video_load.load_model(selected)
|
||||
t1 = time.time()
|
||||
shared.sd_model = sd_models.apply_balanced_offload(shared.sd_model)
|
||||
t2 = time.time()
|
||||
timer.process.add('load', t1 - t0)
|
||||
timer.process.add('offload', t2 - t1)
|
||||
|
||||
|
||||
def load_upsample(upsample_pipe, upsample_repo_id):
|
||||
if upsample_pipe is None:
|
||||
t0 = time.time()
|
||||
shared.state.begin('Load')
|
||||
from diffusers.pipelines.ltx.pipeline_ltx_latent_upsample import LTXLatentUpsamplePipeline
|
||||
shared.log.info(f'Video load: cls={LTXLatentUpsamplePipeline.__class__.__name__} repo="{upsample_repo_id}"')
|
||||
upsample_pipe = LTXLatentUpsamplePipeline.from_pretrained(
|
||||
upsample_repo_id,
|
||||
vae=shared.sd_model.vae,
|
||||
cache_dir=shared.opts.hfcache_dir,
|
||||
torch_dtype=devices.dtype,
|
||||
)
|
||||
shared.state.end()
|
||||
t1 = time.time()
|
||||
timer.process.add('load', t1 - t0)
|
||||
return upsample_pipe
|
||||
|
||||
|
||||
def get_conditions(condition_image, condition_image_strength, condition_video, condition_video_strength, condition_video_frames):
|
||||
def get_video_frames(fn: str):
|
||||
pass
|
||||
|
||||
conditions = []
|
||||
if condition_image is not None:
|
||||
from diffusers.pipelines.ltx.pipeline_ltx_condition import LTXImageCondition
|
||||
conditions.append(LTXImageCondition(image=condition_image, strength=condition_image_strength))
|
||||
if condition_video is not None:
|
||||
from diffusers.pipelines.ltx.pipeline_ltx_condition import LTXVideoCondition
|
||||
condition_frames = get_video_frames(condition_video, num_frames=condition_video_frames)
|
||||
conditions.append(LTXVideoCondition(video=condition_frames, frame_index=0, strength=condition_video_strength))
|
||||
return conditions
|
||||
|
||||
|
||||
def get_prompts(prompt, negative, styles):
|
||||
prompt = shared.prompt_styles.apply_styles_to_prompt(prompt, styles)
|
||||
negative = shared.prompt_styles.apply_negative_styles_to_prompt(negative, styles)
|
||||
prompts, networks = extra_networks.parse_prompts([prompt])
|
||||
prompt = prompts[0] if len(prompts) > 0 else prompt
|
||||
return prompt, negative, networks
|
||||
|
||||
|
||||
def get_generator(seed):
|
||||
import random
|
||||
if seed is None or seed < 0:
|
||||
random.seed()
|
||||
seed = int(random.randrange(4294967294))
|
||||
return torch.Generator().manual_seed(seed)
|
||||
|
||||
|
||||
def vae_decode(latents, decode_timestep, seed):
|
||||
t0 = time.time()
|
||||
shared.state.begin('VAE')
|
||||
shared.log.debug(f'Video: cls={shared.sd_model.vae.__class__.__name__} op=vae latents={latents.shape} timestep={decode_timestep}')
|
||||
from diffusers.utils.torch_utils import randn_tensor
|
||||
latents = shared.sd_model._denormalize_latents(
|
||||
latents,
|
||||
shared.sd_model.vae.latents_mean,
|
||||
shared.sd_model.vae.latents_std,
|
||||
shared.sd_model.vae.config.scaling_factor
|
||||
)
|
||||
latents = latents.to(device=devices.device, dtype=devices.dtype)
|
||||
if not shared.sd_model.vae.config.timestep_conditioning:
|
||||
timestep = None
|
||||
else:
|
||||
noise = randn_tensor(latents.shape, generator=get_generator(seed), device=devices.device, dtype=devices.dtype)
|
||||
timestep = torch.tensor([decode_timestep], device=devices.device, dtype=latents.dtype)
|
||||
noise_scale = torch.tensor([decode_timestep], device=devices.device, dtype=devices.dtype)[:, None, None, None, None]
|
||||
latents = (1 - noise_scale) * latents + noise_scale * noise
|
||||
frames = shared.sd_model.vae.decode(latents, timestep, return_dict=False)[0]
|
||||
frames = shared.sd_model.video_processor.postprocess_video(frames, output_type='pil')
|
||||
shared.state.end()
|
||||
t1 = time.time()
|
||||
timer.process.add('vae', t1 - t0)
|
||||
return frames[0]
|
||||
@@ -55,11 +55,11 @@ def diffusers_callback(pipe, step: int = 0, timestep: int = 0, kwargs: dict = {}
|
||||
t0 = time.time()
|
||||
if devices.backend == "zluda":
|
||||
torch.cuda.synchronize(devices.device)
|
||||
if p is None:
|
||||
return kwargs
|
||||
latents = kwargs.get('latents', None)
|
||||
if debug:
|
||||
debug_callback(f'Callback: step={step} timestep={timestep} latents={latents.shape if latents is not None else None} kwargs={list(kwargs)}')
|
||||
if shared.state.sampling_steps == 0 and getattr(pipe, 'num_timesteps', 0) > 0:
|
||||
shared.state.sampling_steps = pipe.num_timesteps
|
||||
shared.state.step()
|
||||
if shared.state.interrupted or shared.state.skipped:
|
||||
raise AssertionError('Interrupted...')
|
||||
@@ -73,6 +73,8 @@ def diffusers_callback(pipe, step: int = 0, timestep: int = 0, kwargs: dict = {}
|
||||
return kwargs
|
||||
elif shared.opts.nan_skip:
|
||||
assert not torch.isnan(latents[..., 0, 0]).all(), f'NaN detected at step {step}: Skipping...'
|
||||
if p is None:
|
||||
return kwargs
|
||||
if len(getattr(p, 'ip_adapter_names', [])) > 0 and p.ip_adapter_names[0] != 'None':
|
||||
ip_adapter_scales = list(p.ip_adapter_scales)
|
||||
ip_adapter_starts = list(p.ip_adapter_starts)
|
||||
|
||||
@@ -200,12 +200,12 @@ def create_correction_inputs(tab):
|
||||
return hdr_mode, hdr_brightness, hdr_color, hdr_sharpen, hdr_clamp, hdr_boundary, hdr_threshold, hdr_maximize, hdr_max_center, hdr_max_boundry, hdr_color_picker, hdr_tint_ratio
|
||||
|
||||
|
||||
def create_sampler_and_steps_selection(choices, tabname):
|
||||
def create_sampler_and_steps_selection(choices, tabname, default_steps:int=20):
|
||||
if choices is None:
|
||||
sd_samplers.set_samplers()
|
||||
choices = [x for x in sd_samplers.samplers if not x.name == 'Same as primary']
|
||||
with gr.Row(elem_classes=['flex-break']):
|
||||
steps = gr.Slider(minimum=1, maximum=100, step=1, label="Steps", elem_id=f"{tabname}_steps", value=20)
|
||||
steps = gr.Slider(minimum=1, maximum=100, step=1, label="Steps", elem_id=f"{tabname}_steps", value=default_steps)
|
||||
sampler_index = gr.Dropdown(label='Sampling method', elem_id=f"{tabname}_sampling", choices=[x.name for x in choices], value='Default', type="index")
|
||||
return steps, sampler_index
|
||||
|
||||
|
||||
+6
-1
@@ -27,12 +27,15 @@ def create_ui():
|
||||
with gr.Row(elem_id="video_interface", equal_height=False):
|
||||
with gr.Tabs(elem_classes=['video-tabs'], elem_id='video-tabs'):
|
||||
overrides = ui_common.create_override_inputs('video')
|
||||
with gr.Tab('Video', id='video-tab') as video_tab:
|
||||
with gr.Tab('Generic', id='video-tab') as video_tab:
|
||||
from modules.video_models import video_ui
|
||||
video_ui.create_ui(prompt, negative, styles, overrides)
|
||||
with gr.Tab('FramePack', id='framepack-tab') as framepack_tab:
|
||||
from modules.framepack import framepack_ui
|
||||
framepack_ui.create_ui(prompt, negative, styles, overrides)
|
||||
with gr.Tab('LTX', id='ltx-tab') as ltx_tab:
|
||||
from modules.ltx import ltx_ui
|
||||
ltx_ui.create_ui(prompt, negative, styles, overrides)
|
||||
|
||||
paste_fields = [
|
||||
(prompt, "Prompt"), # cannot add more fields as they are not defined yet
|
||||
@@ -44,6 +47,8 @@ def create_ui():
|
||||
current_tab = gr.Textbox(visible=False, value='video')
|
||||
video_tab.select(fn=lambda: 'video', inputs=[], outputs=[current_tab])
|
||||
framepack_tab.select(fn=lambda: 'framepack', inputs=[], outputs=[current_tab])
|
||||
ltx_tab.select(fn=lambda: 'ltx', inputs=[], outputs=[current_tab])
|
||||
|
||||
generate_btn.click(fn=None, _js='submit_video_wrapper', inputs=[current_tab], outputs=[])
|
||||
|
||||
# from framepack_api import create_api # pylint: disable=wrong-import-order
|
||||
|
||||
@@ -71,6 +71,12 @@ models = {
|
||||
],
|
||||
'LTX Video': [
|
||||
Model(name='None'),
|
||||
Model(name='LTXVideo 0.9.7 13B',
|
||||
url='https://huggingface.co/Lightricks/LTX-Video-0.9.7-dev',
|
||||
repo='a-r-r-o-w/LTX-Video-0.9.7-diffusers',
|
||||
repo_cls=diffusers.LTXConditionPipeline,
|
||||
te_cls=transformers.T5EncoderModel,
|
||||
dit_cls=diffusers.LTXVideoTransformer3DModel),
|
||||
Model(name='LTXVideo 0.9.6 2B T2V',
|
||||
url='https://huggingface.co/Lightricks/LTX-Video',
|
||||
repo='Lightricks/LTX-Video',
|
||||
|
||||
@@ -10,6 +10,7 @@ debug = shared.log.trace if os.environ.get('SD_VIDEO_DEBUG', None) is not None e
|
||||
|
||||
|
||||
def load_model(selected: models_def.Model):
|
||||
shared.state.begin('Load')
|
||||
if selected is None:
|
||||
return ''
|
||||
global loaded_model # pylint: disable=global-statement
|
||||
@@ -83,14 +84,20 @@ def load_model(selected: models_def.Model):
|
||||
shared.sd_model.vae.orig_encode = shared.sd_model.vae.encode
|
||||
shared.sd_model.vae.encode = video_vae.hijack_vae_encode
|
||||
if selected.te_hijack and hasattr(shared.sd_model, 'encode_prompt'):
|
||||
shared.sd_model.orig_encode_prompt = shared.sd_model.encode_prompt
|
||||
# shared.sd_model.orig_encode_prompt = shared.sd_model.encode_prompt
|
||||
sd_hijack_te.init_hijack(shared.sd_model)
|
||||
if selected.image_hijack and hasattr(shared.sd_model, 'encode_image'):
|
||||
shared.sd_model.orig_encode_image = shared.sd_model.encode_image
|
||||
shared.sd_model.encode_image = video_utils.hijack_encode_image
|
||||
if hasattr(shared.sd_model.vae, 'enable_slicing'):
|
||||
shared.sd_model.vae.enable_slicing()
|
||||
if hasattr(shared.sd_model.vae, 'enable_tiling'):
|
||||
shared.sd_model.vae.enable_tiling()
|
||||
if hasattr(shared.sd_model, "set_progress_bar_config"):
|
||||
shared.sd_model.set_progress_bar_config(bar_format='Progress {rate_fmt}{postfix} {bar} {percentage:3.0f}% {n_fmt}/{total_fmt} {elapsed} {remaining} ' + '\x1b[38;5;71m', ncols=80, colour='#327fba')
|
||||
|
||||
loaded_model = selected.name
|
||||
msg = f'Video load: cls={shared.sd_model.__class__.__name__} model="{selected.name}" time={t1-t0:.2f}'
|
||||
shared.log.info(msg)
|
||||
shared.state.end()
|
||||
return msg
|
||||
|
||||
Reference in New Issue
Block a user