minimax-h3 i2i

Signed-off-by: Vladimir Mandic <mandic00@live.com>
This commit is contained in:
Vladimir Mandic
2026-08-13 11:23:36 +02:00
parent 10c2343d9a
commit 0ddd0f7091
6 changed files with 36 additions and 17 deletions
+12 -3
View File
@@ -1,6 +1,13 @@
# Change Log for SD.Next
## Update for 2026-08-11
## TODO
- video API: video, text2image, image2image
- MiniMax-H3
- LTX-2.5
- Group offloading in 16gb
## Update for 2026-08-13
- **Detailer**: Pretty much *detailer.next* :)
Detailer detection models were traditionally *YOLO* models, but now we can also use:
@@ -18,10 +25,11 @@
- [SDNQ](https://github.com/Disty0/sdnq) is now a separate package and no longer part of sdnext repo
installed and used internally by sd.next, but also supported by diffusers natively
- **Server**
- update handlers for all authenticated workflows
- nunchaku-lite support for `torch==2.13`
- update handlers for all authenticated workflows
- update handlers for all hf-based progress bars
- log long torch autotune operations
- utilize torch.accelerator
- utilize `torch.accelerator` where available
- add `SD_DIFFUSERS_DEBUG` and `SD_TRANSFORMERS_DEBUG` env variables to trace diffusers and transformers internal operations
- **Removed**
- remove DirectML support
@@ -33,6 +41,7 @@
- improve handling of hf auth
- improve pipeline detection for non-cached models
- cleanup alt offload codepaths
- hf progress bars
## Update for 2026-08-07
+1 -1
View File
@@ -378,5 +378,5 @@ def worker(
sd_models.apply_balanced_offload(shared.sd_model)
stream.output_queue.push(('end', None))
t1 = time.time()
log.info(f'Processed: frames={total_generated_frames} fps={total_generated_frames/(t1-t0):.2f} its={(shared.state.sampling_step)/(t1-t0):.2f} time={t1-t0:.2f} timers={timer.process.dct()} memory={memstats.memory_stats()}')
log.info(f'Processed: frames={total_generated_frames} fps={total_generated_frames/(t1-t0):.2f} its={(shared.state.sampling_step)/(t1-t0):.3f} time={t1-t0:.2f} timers={timer.process.dct()} memory={memstats.memory_stats()}')
shared.state.end(videojob)
+1 -1
View File
@@ -670,7 +670,7 @@ def run_ltx(task_id,
memory = shared.mem_mon.summary()
total_time = max(t_end - t0, 1e-6)
fps = f'{num_frames/total_time:.2f}'
its = f'{(steps)/total_time:.2f}'
its = f'{(steps)/total_time:.3f}'
shared.state.end(videojob)
progress.finish_task(task_id)
+5 -5
View File
@@ -29,12 +29,12 @@ def install_state_hook(pipe):
runner_log.addFilter(InterruptLogFilter())
def set_phase(phase: str, module: torch.nn.Module | None = None):
# every stage runs inside one pipeline call, so the forward hooks are the only place the current stage is visible; state.begin clears the label per job
# every stage runs inside one pipeline call, so the forward hooks are the only place the current stage is visible
if getattr(pipe, 'sdnext_phase', None) != phase:
pipe.sdnext_phase = phase
jobid = getattr(pipe, 'sdnext_phaseid', None)
shared.state.end(jobid)
pipe.sdnext_phaseid = shared.state.begin(phase)
jobid = getattr(pipe, 'sdnext_phaseid', None) # previous jobid if any
shared.state.end(jobid) # clear the previous job if exists
pipe.sdnext_phaseid = shared.state.begin(phase) # start a new job for the current phase
log.debug(f'Pipeline: phase={phase} cls={pipe.__class__.__name__} module={module.__class__.__name__ if module is not None else None}')
def _pre_transformer_hook(module, args): # pylint: disable=unused-argument
@@ -179,7 +179,7 @@ def load_modular_pipe(repo_cls, repo: str, workflow: str | None = None, revision
preloaded = preload_components(pipe, workflow, load_config=load_config)
if preloaded:
pipe.update_components(**preloaded) # registered before the rest, which load_components then skips
log.debug(f'Load modular: preloaded={list(preloaded)}')
log.debug(f'Load modular: cls={pipe.__class__.__name__} preloaded={list(preloaded)}')
pipe.load_components(
workflow=workflow,
dtype=devices.dtype,
+1 -1
View File
@@ -590,7 +590,7 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
p.ops = list(set(p.ops))
if not p.disable_extra_networks:
log.info(f'Processed: images={len(output_images)} its={(p.steps * len(output_images)) / (t1 - t0):.2f} ops={p.ops}')
log.info(f'Processed: images={len(output_images)} its={(p.steps * len(output_images)) / (t1 - t0):.3f} ops={p.ops}')
print_stats()
if shared.cmd_opts.lowvram or shared.cmd_opts.medvram:
+16 -6
View File
@@ -19,8 +19,8 @@ debug_log = log.trace if debug_enabled else lambda *args, **kwargs: None
disable_pbar = os.environ.get('SD_DISABLE_PBAR', None) is not None
def task_modular_kwargs(p, model): # pylint: disable=unused-argument
# model_cls = model.__class__.__name__
def task_modular_kwargs(p, model):
model_cls = model.__class__.__name__
task_args = {}
p.ops.append('modular')
@@ -34,6 +34,15 @@ def task_modular_kwargs(p, model): # pylint: disable=unused-argument
if mask_image is not None:
task_args['mask_image'] = mask_image
if model_cls in ['MiniMaxH3ModularPipeline'] and task_args.get('image', None) is not None:
if len(task_args.get('image', [])) > 2:
task_args['normalized_references'] = task_args['image']
task_args.pop('image', None) # remove image, only use normalized_references
elif len(task_args.get('image', [])) > 1:
task_args['last_image'] = task_args['image'][1]
if len(task_args.get('image', [])) > 0:
task_args['image'] = task_args['image'][0]
if debug_enabled:
debug_log(f'Process task specific args: {task_args}')
return task_args
@@ -170,13 +179,15 @@ def task_specific_kwargs(p, model):
def get_params(model):
possible = []
if hasattr(model, 'blocks') and hasattr(model.blocks, 'inputs'): # modular pipeline
possible = [input_param.name for input_param in model.blocks.inputs]
return possible + ['output'] # __call__ param selecting which state values to return, not a block input
possible += ['output'] # __call__ param selecting which state values to return, not a block input
else:
signature = inspect.signature(type(model).__call__, follow_wrapped=True)
possible = list(signature.parameters)
return possible
possible = [p for p in possible if p not in ['self', 'kwargs', None]]
return possible
def get_defaults(model, kwargs):
@@ -241,8 +252,7 @@ def set_pipeline_args(p, model, prompts:list, negative_prompts:list, prompts_2:l
possible = get_params(model)
if debug_enabled:
debug_log(f'Process pipeline possible: {possible}')
log.debug(f'Pipeline: cls={cls} possible={possible}')
steps = kwargs.get("num_inference_steps", None) or len(getattr(p, 'timesteps', ['1']))
clip_skip = kwargs.pop("clip_skip", 1)