Test character slot seed determinism
This commit is contained in:
@@ -228,6 +228,12 @@ Common trap: `row_number` participates in `seed_config.axis_rng`. If two
|
|||||||
workflows have the same seeds but different `row_number`, they are not expected
|
workflows have the same seeds but different `row_number`, they are not expected
|
||||||
to match.
|
to match.
|
||||||
|
|
||||||
|
Character `slot_seed` is more specific than the `person` axis. A fixed
|
||||||
|
`slot_seed` owns that slot's random age/body/appearance/hair choices, so
|
||||||
|
rerolling `person_seed` will not drift that character. Leave `slot_seed=-1`
|
||||||
|
when the slot should follow `person_seed` or the global seed like the fallback
|
||||||
|
cast generator.
|
||||||
|
|
||||||
Each generated row stores `generation_trace.seed_axes` in `metadata_json`.
|
Each generated row stores `generation_trace.seed_axes` in `metadata_json`.
|
||||||
Use it to verify whether an axis followed the main seed or a configured seed,
|
Use it to verify whether an axis followed the main seed or a configured seed,
|
||||||
and to compare the exact per-axis RNG seed used for the row.
|
and to compare the exact per-axis RNG seed used for the row.
|
||||||
|
|||||||
@@ -7458,6 +7458,70 @@ def smoke_seed_config_policy() -> None:
|
|||||||
deterministic_b = _prompt_row(**deterministic_kwargs)
|
deterministic_b = _prompt_row(**deterministic_kwargs)
|
||||||
_expect(deterministic_a == deterministic_b, "locked seed config should reproduce identical prompt row output")
|
_expect(deterministic_a == deterministic_b, "locked seed config should reproduce identical prompt row output")
|
||||||
|
|
||||||
|
slot_descriptor_keys = ("age_band", "body_phrase", "skin", "hair", "eyes", "figure")
|
||||||
|
|
||||||
|
def slot_seed_cast(slot_seed: int) -> str:
|
||||||
|
return pb.build_character_slot_json(
|
||||||
|
subject_type="woman",
|
||||||
|
label="A",
|
||||||
|
slot_seed=slot_seed,
|
||||||
|
age="random",
|
||||||
|
ethnicity="random",
|
||||||
|
figure="random",
|
||||||
|
body="random",
|
||||||
|
hair_color="random",
|
||||||
|
hair_length="random",
|
||||||
|
hair_style="random",
|
||||||
|
descriptor_detail="full",
|
||||||
|
)["character_cast"]
|
||||||
|
|
||||||
|
def slot_seed_row(character_cast: str, reroll_seed: int) -> dict[str, Any]:
|
||||||
|
return _prompt_row(
|
||||||
|
name=f"seed_config_policy_slot_seed_{reroll_seed}",
|
||||||
|
category="Casual clothes",
|
||||||
|
subcategory="Casual clothes / Streetwear",
|
||||||
|
seed=41001,
|
||||||
|
seed_config=pb.build_seed_lock_config_json(
|
||||||
|
base_seed=41001,
|
||||||
|
reroll_axis="person",
|
||||||
|
reroll_seed=reroll_seed,
|
||||||
|
),
|
||||||
|
character_cast=character_cast,
|
||||||
|
women_count=1,
|
||||||
|
men_count=0,
|
||||||
|
)
|
||||||
|
|
||||||
|
seeded_slot_cast = slot_seed_cast(50123)
|
||||||
|
seeded_slot_a = slot_seed_row(seeded_slot_cast, 60001)
|
||||||
|
seeded_slot_b = slot_seed_row(seeded_slot_cast, 60002)
|
||||||
|
_expect(
|
||||||
|
tuple(seeded_slot_a.get(key) for key in slot_descriptor_keys)
|
||||||
|
== tuple(seeded_slot_b.get(key) for key in slot_descriptor_keys),
|
||||||
|
"slot_seed should keep random character-slot descriptors stable across person-axis rerolls",
|
||||||
|
)
|
||||||
|
seeded_trace_a = seeded_slot_a.get("generation_trace") if isinstance(seeded_slot_a.get("generation_trace"), dict) else {}
|
||||||
|
seeded_trace_b = seeded_slot_b.get("generation_trace") if isinstance(seeded_slot_b.get("generation_trace"), dict) else {}
|
||||||
|
_expect(
|
||||||
|
seeded_trace_a.get("seed_axes", {}).get("person", {}).get("seed")
|
||||||
|
!= seeded_trace_b.get("seed_axes", {}).get("person", {}).get("seed"),
|
||||||
|
"slot_seed regression check should actually reroll the person axis",
|
||||||
|
)
|
||||||
|
seeded_krea_a = krea_formatter.format_krea2_prompt("", metadata_json=_json(seeded_slot_a), target="single")
|
||||||
|
seeded_krea_b = krea_formatter.format_krea2_prompt("", metadata_json=_json(seeded_slot_b), target="single")
|
||||||
|
_expect(
|
||||||
|
seeded_krea_a.get("krea_prompt") == seeded_krea_b.get("krea_prompt"),
|
||||||
|
"slot_seed should keep final Krea prompt stable across person-axis rerolls",
|
||||||
|
)
|
||||||
|
|
||||||
|
unseeded_slot_cast = slot_seed_cast(-1)
|
||||||
|
unseeded_slot_a = slot_seed_row(unseeded_slot_cast, 60001)
|
||||||
|
unseeded_slot_b = slot_seed_row(unseeded_slot_cast, 60002)
|
||||||
|
_expect(
|
||||||
|
tuple(unseeded_slot_a.get(key) for key in slot_descriptor_keys)
|
||||||
|
!= tuple(unseeded_slot_b.get(key) for key in slot_descriptor_keys),
|
||||||
|
"unseeded random character slot should still follow person-axis rerolls",
|
||||||
|
)
|
||||||
|
|
||||||
pose_changed = False
|
pose_changed = False
|
||||||
for reroll_seed in range(deterministic_seed + 1, deterministic_seed + 10):
|
for reroll_seed in range(deterministic_seed + 1, deterministic_seed + 10):
|
||||||
pose_reroll = _prompt_row(
|
pose_reroll = _prompt_row(
|
||||||
|
|||||||
Reference in New Issue
Block a user