From ad9e171e4fc46edbd3f4cbe1fb28b4dda06cb5a0 Mon Sep 17 00:00:00 2001 From: digital-garbage <133010426+digital-garbage@users.noreply.github.com> Date: Wed, 3 Jun 2026 00:18:16 +0300 Subject: [PATCH] Batch Training: distinct per-variant seeds in the SINGLE-scene path too (real cause of identical videos) The live log showed the single-scene path: 'packed 3 variant conditioning(s)' with ACTUAL scene_seeds identical across all 3 (all inherited the base entry's funpack_scene_seed). My earlier seed fix only covered the multi-scene duplication path. When a prompt resolves to one scene (common), _v2_build_batch_variants reused the base scene seed for every variant -> identical noise -> identical videos (only tiny diffs from VF ascent). Fix: _v2_pack_batch now assigns a fresh, well-spread per-variant scene seed (gen-seeded RNG, reproducible, per-scene offset) to the packed entries in BOTH paths, after building them. Verified in venv: single-scene 3 variants -> 3 distinct seeds. Co-Authored-By: Claude Opus 4.8 --- conditioning.py | 50 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/conditioning.py b/conditioning.py index 8add82c4..74be29df 100644 --- a/conditioning.py +++ b/conditioning.py @@ -12256,31 +12256,47 @@ class FunPackVideoRefinerV2(FunPackVideoRefiner): n = max(1, int(n or 1)) if n <= 1 or not output_conditioning: return output_conditioning + # Build the N variant entries. Single-scene output -> _v2_build_batch_variants (re-resolves + # shortcuts per variant). Multi-scene (transition split) -> duplicate the whole scene-set + # per variant. Each variant tags ALL its scene entries with the same index. if len(output_conditioning) == 1: - return self._v2_build_batch_variants( + packed = self._v2_build_batch_variants( raw_prompt, n, seed, clip, encode_cache, source_image, base_entry=output_conditioning[0], base_prompt=base_prompt, global_state=global_state, learning_profile=learning_profile, repair_feedback=repair_feedback, intent_family_slot=intent_family_slot, vf=vf, concept_dir=concept_dir, concept_strength=concept_strength, current_final_texts=current_final_texts) - # Each variant needs DISTINCT noise, but multi-scene entries carry a per-scene - # 'funpack_scene_seed' that the sampler honors over its own seed — so duplicating the set - # verbatim makes every variant identical. Override the scene seeds per variant with a - # seeded RNG (reproducible per gen, well-spread across variants), so the N chains differ. + else: + packed = [] + for i in range(n): + for entry in output_conditioning: + cond = entry[0] + meta = entry[1] if len(entry) > 1 and isinstance(entry[1], dict) else {} + m = dict(meta) + m["funpack_batch_variant"] = i + packed.append((cond, m)) + # CRITICAL: each scene entry carries a 'funpack_scene_seed' the Chain Sampler honors OVER + # its own seed. Variants inherit the base entry's scene seed, so without this every variant + # uses identical noise (the single-scene bug seen in the wild). Assign a fresh, well-spread + # seed PER VARIANT (seeded by the gen seed -> reproducible), with a per-scene offset, so the + # N chains have genuinely different noise. Applies to BOTH single- and multi-scene paths. rng = random.Random(int(seed) & 0xffffffffffffffff) - packed = [] - for i in range(n): - variant_seed = rng.randint(1, 0xffffffffffffffff) - for sidx, entry in enumerate(output_conditioning): - cond = entry[0] - meta = entry[1] if len(entry) > 1 and isinstance(entry[1], dict) else {} - m = dict(meta) - m["funpack_batch_variant"] = i - m["funpack_scene_seed"] = (variant_seed + sidx) & 0xffffffffffffffff - packed.append((cond, m)) - print(f"[FunPackVideoRefinerV2] Batch Training: packed {n} x {len(output_conditioning)}-scene " - f"set = {len(packed)} entries with variant markers + distinct per-variant seeds.") + variant_seed = {} + scene_idx = {} + for entry in packed: + m = entry[1] + if not isinstance(m, dict): + continue + vi = int(m.get("funpack_batch_variant", 0)) + if vi not in variant_seed: + variant_seed[vi] = rng.randint(1, 0xffffffffffffffff) + scene_idx[vi] = 0 + m["funpack_scene_seed"] = (variant_seed[vi] + scene_idx[vi]) & 0xffffffffffffffff + scene_idx[vi] += 1 + print(f"[FunPackVideoRefinerV2] Batch Training: packed {n} variant(s) over " + f"{len(output_conditioning)} scene(s) = {len(packed)} entries; per-variant seeds = " + f"{[variant_seed[k] for k in sorted(variant_seed)]}") return packed def _v2_build_batch_variants(self, raw_prompt, n, seed, clip, encode_cache, source_image,