Skip to content

Commit 02aa707

Browse files
authored
Allow using references with MiniMax-H3 Fun Union and fix prefetch race condition (#16020)
1 parent 3216c62 commit 02aa707

2 files changed

Lines changed: 16 additions & 9 deletions

File tree

comfy/ldm/minimax/controlnet.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,6 @@ def __init__(self, control_in_dim=49, injection_layers=(0, 10, 20, 30, 40), hidd
4242
for i in range(len(self.injection_layers))])
4343

4444
def init_stream(self, h, control_latent, layout, t_emb):
45-
if any(kind not in ("text", "audio", "video") for _, _, kind in layout.segments):
46-
raise ValueError("MiniMax H3 Fun ControlNet does not support keyframe or reference conditioning")
4745
adaln_in = self.control_blocks[0].adaln_proj.linear.in_features
4846
if t_emb.shape[-1] != adaln_in:
4947
raise RuntimeError(
@@ -59,8 +57,13 @@ def init_stream(self, h, control_latent, layout, t_emb):
5957
elif target_rows.shape[1] > patch_dim:
6058
raise ValueError("MiniMax H3 control input has {} columns but the model patch expects {}".format(target_rows.shape[1], patch_dim))
6159

60+
# keyframe/reference conditioning rows get a zero control row
61+
img_update = layout.img_update.to(h.device)
62+
rows = torch.zeros(img_update.shape[0], patch_dim, dtype=torch.float32, device=h.device)
63+
rows[img_update] = target_rows
64+
6265
c = h.clone()
63-
c[layout.img_pos.to(h.device)] = self.control_proj_in(target_rows).to(h.dtype)
66+
c[layout.img_pos.to(h.device)] = self.control_proj_in(rows).to(h.dtype)
6467
return self.control_blocks[0].before_proj(c).add_(h)
6568

6669
def step(self, index, c, t_emb, mod_segments, rope_freqs, transformer_options):

comfy_extras/nodes_minimax_h3.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,7 @@ def __init__(self, model_patch, vae, control_video, mask, source_video, strength
414414
self.control_latent = None
415415
self.control_latent_shape = None
416416
self.control_stream = None
417+
self.pristine_stream = None
417418
self.active = False
418419

419420
def _fit_frames(self, frames, frame_count, width, height):
@@ -472,26 +473,28 @@ def diffusion_model_wrapper(self, executor, x, timestep, context, transformer_op
472473
self.active = self.sigma_end <= sigma <= self.sigma_start
473474
self.control_stream = None
474475
if self.active:
475-
payload = kwargs.get("minimax_payload") or {}
476-
if payload.get("keyframes") or payload.get("refs"):
477-
raise ValueError("MiniMax H3 Fun ControlNet does not support keyframe or reference conditioning")
478476
self.prepare_control_latent(x[0].shape)
479477
try:
480478
return executor(x, timestep, context, transformer_options, **kwargs)
481479
finally:
482480
self.control_stream = None
481+
self.pristine_stream = None
483482

484483
def before_block(self, block_index, args):
485484
if not self.active or block_index != self.model_patch.model.injection_layers[0]:
486485
return
487-
self.control_latent = self.control_latent.to(args["img"].device)
488-
self.control_stream = self.model_patch.model.init_stream(
489-
args["img"], self.control_latent, args["layout"], args["t_emb"])
486+
# stash only: control weight loads here would clobber the base block's freshly staged weights
487+
self.pristine_stream = args["img"].clone()
490488

491489
def after_block(self, block_index, args, out):
492490
if not self.active:
493491
return out
494492
control_index = self.model_patch.model.injection_layers.index(block_index)
493+
if control_index == 0:
494+
self.control_latent = self.control_latent.to(out["img"].device)
495+
self.control_stream = self.model_patch.model.init_stream(
496+
self.pristine_stream, self.control_latent, args["layout"], args["t_emb"])
497+
self.pristine_stream = None
495498
self.control_stream, skip = self.model_patch.model.step(
496499
control_index, self.control_stream, args["t_emb"], args["mod_segments"], args["rope_freqs"],
497500
transformer_options=args["transformer_options"])
@@ -510,6 +513,7 @@ def cleanup(self):
510513
self.control_latent = None
511514
self.control_latent_shape = None
512515
self.control_stream = None
516+
self.pristine_stream = None
513517
self.active = False
514518

515519
def models(self):

0 commit comments

Comments
 (0)