Update video refiner rating categories
This commit is contained in:
+247
-43
@@ -26,11 +26,109 @@ LORA_REFINER_TYPE_PROFILES = {
|
||||
"character": {"step": 0.024, "max_offset": 0.20, "min_offset": -0.32, "bad_max_offset": 0.42, "bad_min_offset": -1.30, "culprit_bias": 0.10},
|
||||
}
|
||||
|
||||
RATING_LABELS = [
|
||||
"I like it",
|
||||
"Missing details",
|
||||
"Missing concept",
|
||||
"Missing quality",
|
||||
"I don't like it",
|
||||
]
|
||||
|
||||
RATING_PROFILES = {
|
||||
"I like it": {
|
||||
"key": "like",
|
||||
"level": 5,
|
||||
"legacy_score": 10,
|
||||
"legacy_range": "9-10",
|
||||
"reward": 1.0,
|
||||
"quality_signal": 1.0,
|
||||
"concept_signal": 1.0,
|
||||
"detail_signal": 1.0,
|
||||
"prompt_emphasis": 0.45,
|
||||
},
|
||||
"Missing details": {
|
||||
"key": "missing_details",
|
||||
"level": 4,
|
||||
"legacy_score": 8,
|
||||
"legacy_range": "7-8",
|
||||
"reward": 0.45,
|
||||
"quality_signal": 0.85,
|
||||
"concept_signal": 0.70,
|
||||
"detail_signal": -0.55,
|
||||
"prompt_emphasis": 0.65,
|
||||
},
|
||||
"Missing concept": {
|
||||
"key": "missing_concept",
|
||||
"level": 3,
|
||||
"legacy_score": 6,
|
||||
"legacy_range": "5-6",
|
||||
"reward": -0.35,
|
||||
"quality_signal": 0.65,
|
||||
"concept_signal": -0.90,
|
||||
"detail_signal": -0.70,
|
||||
"prompt_emphasis": 0.95,
|
||||
},
|
||||
"Missing quality": {
|
||||
"key": "missing_quality",
|
||||
"level": 2,
|
||||
"legacy_score": 4,
|
||||
"legacy_range": "3-4",
|
||||
"reward": -0.75,
|
||||
"quality_signal": -0.90,
|
||||
"concept_signal": -0.75,
|
||||
"detail_signal": -0.70,
|
||||
"prompt_emphasis": 0.55,
|
||||
},
|
||||
"I don't like it": {
|
||||
"key": "dislike",
|
||||
"level": 1,
|
||||
"legacy_score": 2,
|
||||
"legacy_range": "1-2",
|
||||
"reward": -1.0,
|
||||
"quality_signal": -1.0,
|
||||
"concept_signal": -1.0,
|
||||
"detail_signal": -1.0,
|
||||
"prompt_emphasis": -0.65,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def _clamp(value, low, high):
|
||||
return max(low, min(high, value))
|
||||
|
||||
|
||||
def normalize_refiner_rating(value):
|
||||
if isinstance(value, str):
|
||||
cleaned = value.strip()
|
||||
if cleaned in RATING_PROFILES:
|
||||
return dict(RATING_PROFILES[cleaned], label=cleaned)
|
||||
try:
|
||||
value = int(float(cleaned))
|
||||
except (TypeError, ValueError):
|
||||
return dict(RATING_PROFILES["Missing concept"], label="Missing concept")
|
||||
|
||||
try:
|
||||
legacy_score = int(value)
|
||||
except (TypeError, ValueError):
|
||||
legacy_score = RATING_PROFILES["Missing concept"]["legacy_score"]
|
||||
|
||||
legacy_score = int(_clamp(legacy_score, 1, 10))
|
||||
if legacy_score >= 9:
|
||||
label = "I like it"
|
||||
elif legacy_score >= 7:
|
||||
label = "Missing details"
|
||||
elif legacy_score >= 5:
|
||||
label = "Missing concept"
|
||||
elif legacy_score >= 3:
|
||||
label = "Missing quality"
|
||||
else:
|
||||
label = "I don't like it"
|
||||
|
||||
profile = dict(RATING_PROFILES[label], label=label)
|
||||
profile["legacy_score"] = legacy_score
|
||||
return profile
|
||||
|
||||
|
||||
PROTECTED_PHRASE_RE = re.compile(r'"([^"]+)"|“([^”]+)”|\\([^\\]+)\\')
|
||||
|
||||
|
||||
@@ -498,14 +596,7 @@ class FunPackVideoRefiner:
|
||||
"required": {
|
||||
"positive_conditioning": ("CONDITIONING",),
|
||||
"mode": (["ltx2", "wan"], {"default": "ltx2", "label": "Tokenizer Mode"}),
|
||||
"rating": ("INT", {
|
||||
"default": 5,
|
||||
"min": 1,
|
||||
"max": 10,
|
||||
"step": 1,
|
||||
"display": "slider",
|
||||
"label": "Rating (1=horrific, 10=masterpiece)"
|
||||
}),
|
||||
"rating": (RATING_LABELS, {"default": "Missing concept", "label": "Rating"}),
|
||||
"refinement_key": ("STRING", {"default": "my_style_v1", "multiline": False}),
|
||||
"scheduler_mode": (["original", "accurate", "aggressive"], {"default": "original"}),
|
||||
},
|
||||
@@ -1317,7 +1408,8 @@ class FunPackVideoRefiner:
|
||||
out[-1] = original[-1]
|
||||
return out
|
||||
|
||||
def _refine_sigma_schedule(self, sigmas, rating: int, global_adaptive: dict, strength_mode: str, seed: int):
|
||||
def _refine_sigma_schedule(self, sigmas, rating: int, global_adaptive: dict, strength_mode: str, seed: int,
|
||||
rating_profile: Optional[dict] = None):
|
||||
if not isinstance(sigmas, torch.Tensor):
|
||||
return torch.FloatTensor([]), "Sigma refinement inactive."
|
||||
|
||||
@@ -1327,7 +1419,9 @@ class FunPackVideoRefiner:
|
||||
|
||||
self._ensure_sigma_state_defaults(global_adaptive)
|
||||
|
||||
reward = (rating - 5.5) / 4.5
|
||||
rating_profile = rating_profile or normalize_refiner_rating(rating)
|
||||
rating_key = rating_profile.get("key", "")
|
||||
reward = float(rating_profile.get("reward", (rating - 5.5) / 4.5))
|
||||
sigma_iterations = int(global_adaptive.get("sigma_iterations", 0))
|
||||
|
||||
profile = np.asarray(global_adaptive.get("sigma_profile", [0.0] * 32), dtype=np.float32)
|
||||
@@ -1374,12 +1468,13 @@ class FunPackVideoRefiner:
|
||||
global_adaptive["sigma_avg_reward_ema"] = sigma_avg_reward_ema
|
||||
global_adaptive["sigma_exploration_base"] = max(
|
||||
0.012,
|
||||
min(0.05, sigma_exploration_base * (0.97 if rating >= 8 else 1.02))
|
||||
min(0.05, sigma_exploration_base * (0.97 if rating_key == "like" else 1.02))
|
||||
)
|
||||
sigma_history = list(global_adaptive.get("sigma_history", []))[-119:]
|
||||
sigma_history.append({
|
||||
"iteration": sigma_iterations + 1,
|
||||
"rating": int(rating),
|
||||
"rating_label": rating_profile.get("label", str(rating)),
|
||||
"reward": round(float(reward), 6),
|
||||
"lr": round(float(sigma_lr), 6),
|
||||
})
|
||||
@@ -1524,7 +1619,8 @@ class FunPackVideoRefiner:
|
||||
except OSError:
|
||||
return False
|
||||
|
||||
def _refine_latent(self, latent, refinement_key, mode, rating, reward, global_adaptive):
|
||||
def _refine_latent(self, latent, refinement_key, mode, rating, reward, global_adaptive,
|
||||
rating_profile: Optional[dict] = None):
|
||||
if isinstance(latent, dict) and not latent_is_plain_video_tensor(latent):
|
||||
self._raise_wrong_latent(latent)
|
||||
|
||||
@@ -1584,7 +1680,16 @@ class FunPackVideoRefiner:
|
||||
latent_state["status"] = "Latent: only zero-valued positions available, passthrough."
|
||||
return refined_latent, latent_state["status"]
|
||||
|
||||
lr = 0.035 if rating >= 7 else 0.055 if rating <= 4 else 0.018
|
||||
rating_profile = rating_profile or normalize_refiner_rating(rating)
|
||||
rating_key = rating_profile.get("key", "")
|
||||
if rating_key == "like":
|
||||
lr = 0.035
|
||||
elif rating_key in {"missing_quality", "dislike"}:
|
||||
lr = 0.055
|
||||
elif rating_key == "missing_concept":
|
||||
lr = 0.030
|
||||
else:
|
||||
lr = 0.018
|
||||
target_delta = (saved_samples - current) * nonzero_mask.to(dtype=current.dtype)
|
||||
update = target_delta * (reward * lr)
|
||||
momentum = 0.82 * momentum + 0.18 * update
|
||||
@@ -1601,6 +1706,7 @@ class FunPackVideoRefiner:
|
||||
|
||||
latent_state["momentum"] = tensor_to_serializable(momentum.detach().cpu())
|
||||
latent_state["last_rating"] = int(rating)
|
||||
latent_state["last_rating_label"] = rating_profile.get("label", str(rating))
|
||||
latent_state["last_reward"] = round(float(reward), 4)
|
||||
latent_state["nonzero_ratio"] = round(float(nonzero_mask.float().mean().item()), 6)
|
||||
latent_state["status"] = (
|
||||
@@ -1690,30 +1796,45 @@ class FunPackVideoRefiner:
|
||||
return min(1.0, best_score), best_labels[:4], best_importance
|
||||
|
||||
def _update_lora_weight_suggestions(self, lora_stack, active, global_adaptive, ordered_concept_ids,
|
||||
concept_clusters, current_concept_labels, rating, reward):
|
||||
concept_clusters, current_concept_labels, rating, reward,
|
||||
rating_profile: Optional[dict] = None):
|
||||
if not isinstance(lora_stack, dict) or not lora_stack.get("loras"):
|
||||
return "LoRA suggestions: no FunPack LoRA stack connected."
|
||||
|
||||
rating_profile = rating_profile or normalize_refiner_rating(rating)
|
||||
rating_key = rating_profile.get("key", "")
|
||||
memory = global_adaptive.setdefault("lora_weight_memory", {})
|
||||
suggestions = {}
|
||||
status_parts = []
|
||||
relation_cache = {}
|
||||
top_concept_relation = 0.0
|
||||
concept_lora_count = 0
|
||||
|
||||
for entry in lora_stack.get("loras", []):
|
||||
lora_type = entry.get("type", "general")
|
||||
profile = LORA_REFINER_TYPE_PROFILES.get(lora_type, LORA_REFINER_TYPE_PROFILES["general"])
|
||||
lora_id, state = self._ensure_lora_memory(memory, entry)
|
||||
lora_id = entry.get("id") or self._lora_state_id(entry.get("name", ""), lora_type)
|
||||
relation, matched_labels, concept_importance = self._score_lora_prompt_relation(
|
||||
entry,
|
||||
ordered_concept_ids,
|
||||
concept_clusters,
|
||||
current_concept_labels,
|
||||
)
|
||||
relation_cache[lora_id] = (relation, matched_labels, concept_importance)
|
||||
if lora_type in {"concept", "character"}:
|
||||
concept_lora_count += 1
|
||||
top_concept_relation = max(top_concept_relation, relation)
|
||||
|
||||
for entry in lora_stack.get("loras", []):
|
||||
lora_type = entry.get("type", "general")
|
||||
profile = LORA_REFINER_TYPE_PROFILES.get(lora_type, LORA_REFINER_TYPE_PROFILES["general"])
|
||||
lora_id, state = self._ensure_lora_memory(memory, entry)
|
||||
relation, matched_labels, concept_importance = relation_cache.get(lora_id, (0.0, [], 1.0))
|
||||
|
||||
state["reward_ema"] = 0.84 * float(state.get("reward_ema", 0.0)) + 0.16 * reward
|
||||
if rating >= 8:
|
||||
if rating_key == "like":
|
||||
state["good_streak"] = int(state.get("good_streak", 0)) + 1
|
||||
state["bad_streak"] = 0
|
||||
elif rating <= 4:
|
||||
elif rating_key in {"missing_quality", "dislike"}:
|
||||
state["bad_streak"] = int(state.get("bad_streak", 0)) + 1
|
||||
state["good_streak"] = 0
|
||||
else:
|
||||
@@ -1724,7 +1845,7 @@ class FunPackVideoRefiner:
|
||||
stable_offset = state.get("stable_offset_ratio")
|
||||
culprit_score = float(state.get("culprit_score", 0.0))
|
||||
culprit_hits = int(state.get("culprit_hits", 0))
|
||||
if stable_offset is not None and rating >= 6:
|
||||
if stable_offset is not None and rating_key in {"like", "missing_details"}:
|
||||
offset = 0.72 * offset + 0.28 * float(stable_offset)
|
||||
|
||||
step = profile["step"] * max(0.15, relation)
|
||||
@@ -1739,7 +1860,15 @@ class FunPackVideoRefiner:
|
||||
concept_match_strength += 0.30 if matched_labels else 0.0
|
||||
concept_match_strength += max(0.0, relation - 0.30) * 1.35
|
||||
|
||||
if rating >= 8:
|
||||
is_primary_concept_lora = (
|
||||
lora_type in {"concept", "character"} and
|
||||
(
|
||||
concept_lora_count == 1 or
|
||||
(top_concept_relation > 0.0 and relation >= max(0.30, top_concept_relation - 1e-6))
|
||||
)
|
||||
)
|
||||
|
||||
if rating_key == "like":
|
||||
value_mult = 0.75 + min(1.4, max(0.5, concept_importance)) * 0.25
|
||||
offset += step * (0.45 + max(0.0, reward)) * value_mult
|
||||
culprit_score *= 0.72
|
||||
@@ -1750,7 +1879,54 @@ class FunPackVideoRefiner:
|
||||
stable_offset = 0.78 * float(stable_offset) + 0.22 * offset
|
||||
state["stable_offset_ratio"] = _clamp(stable_offset, min_offset, max_offset)
|
||||
offset = state["stable_offset_ratio"]
|
||||
elif rating <= 4:
|
||||
elif rating_key == "missing_details":
|
||||
culprit_score *= 0.86
|
||||
culprit_hits = max(0, culprit_hits - 1)
|
||||
if relation >= 0.25 and lora_type in {"concept", "character", "general"}:
|
||||
value_mult = 0.85 + min(1.2, max(0.5, concept_importance)) * 0.20
|
||||
offset += step * (0.30 + relation * 0.45) * value_mult
|
||||
elif relation <= 0.05:
|
||||
offset *= 0.96
|
||||
elif stable_offset is not None:
|
||||
offset = 0.78 * offset + 0.22 * float(stable_offset)
|
||||
elif rating_key == "missing_concept":
|
||||
state["stable_offset_ratio"] = None
|
||||
if is_primary_concept_lora:
|
||||
max_offset = max(max_offset, profile["bad_max_offset"] * 0.82)
|
||||
offset += step * (1.10 + abs(reward) * 1.25) * concept_match_strength
|
||||
culprit_score *= 0.70
|
||||
culprit_hits = max(0, culprit_hits - 1)
|
||||
elif lora_type in {"concept", "character"} and relation > 0.08:
|
||||
culprit_score = _clamp(culprit_score * 0.75 + 0.35 * max(0.25, relation), 0.0, 2.5)
|
||||
culprit_hits = culprit_hits + 1 if culprit_score >= 0.65 else culprit_hits
|
||||
min_offset = min(min_offset, profile["bad_min_offset"] * 0.42)
|
||||
offset -= step * (0.55 + abs(reward)) * max(0.25, relation)
|
||||
elif relation <= 0.05:
|
||||
offset *= 0.96
|
||||
else:
|
||||
offset *= 0.92
|
||||
elif rating_key == "missing_quality":
|
||||
state["stable_offset_ratio"] = None
|
||||
if lora_type == "quality":
|
||||
max_offset = max(max_offset, profile["bad_max_offset"] * 0.70)
|
||||
offset += step * (1.00 + abs(reward) * 0.85) * max(0.45, effective_relation)
|
||||
culprit_score *= 0.76
|
||||
elif is_primary_concept_lora:
|
||||
max_offset = max(max_offset, profile["bad_max_offset"] * 0.55)
|
||||
offset += step * (0.62 + abs(reward) * 0.55) * concept_match_strength
|
||||
culprit_score *= 0.82
|
||||
elif lora_type in {"concept", "character"} and relation > 0.08:
|
||||
culprit_score = _clamp(culprit_score * 0.78 + 0.42 * max(0.25, relation), 0.0, 2.5)
|
||||
culprit_hits = culprit_hits + 1 if culprit_score >= 0.65 else culprit_hits
|
||||
min_offset = min(min_offset, profile["bad_min_offset"] * 0.35)
|
||||
offset -= step * (0.72 + abs(reward)) * max(0.25, relation)
|
||||
else:
|
||||
culprit_score = _clamp(culprit_score * 0.84 + 0.18 * max(0.0, relation), 0.0, 2.5)
|
||||
if relation <= 0.05:
|
||||
offset *= 0.94
|
||||
else:
|
||||
offset -= step * 0.25 * max(0.20, relation)
|
||||
elif rating_key == "dislike":
|
||||
severity = _clamp((5.0 - float(rating)) / 4.0, 0.0, 1.0)
|
||||
culprit_signal = max(0.20, effective_relation) * (0.70 + base_abs * 0.30)
|
||||
if is_concept_lora:
|
||||
@@ -1810,6 +1986,8 @@ class FunPackVideoRefiner:
|
||||
"relation": relation,
|
||||
"matched_concepts": matched_labels,
|
||||
"rating": int(rating),
|
||||
"rating_label": rating_profile.get("label", str(rating)),
|
||||
"rating_range": rating_profile.get("legacy_range", ""),
|
||||
"good_streak": state.get("good_streak", 0),
|
||||
"bad_streak": state.get("bad_streak", 0),
|
||||
"stable": state.get("stable_offset_ratio") is not None,
|
||||
@@ -1827,7 +2005,7 @@ class FunPackVideoRefiner:
|
||||
active["last_lora_stack"] = lora_stack
|
||||
if not status_parts:
|
||||
return "LoRA suggestions: stack empty."
|
||||
return "LoRA suggestions: " + " | ".join(status_parts)
|
||||
return f"LoRA suggestions ({rating_profile.get('label', str(rating))}): " + " | ".join(status_parts)
|
||||
|
||||
# =========================================================================
|
||||
# MAIN REFINE
|
||||
@@ -1843,6 +2021,10 @@ class FunPackVideoRefiner:
|
||||
mode = (mode or "ltx2").lower()
|
||||
if mode not in self._tokenizer_sources:
|
||||
mode = "ltx2"
|
||||
rating_profile = normalize_refiner_rating(rating)
|
||||
rating_label = rating_profile.get("label", str(rating))
|
||||
rating = int(rating_profile.get("legacy_score", 6))
|
||||
reward = float(rating_profile.get("reward", (rating - 5.5) / 4.5))
|
||||
|
||||
if seed != 0:
|
||||
torch.manual_seed(seed)
|
||||
@@ -1921,7 +2103,8 @@ class FunPackVideoRefiner:
|
||||
prompt_key: {
|
||||
"reference_embeds": tensor_to_serializable(raw_positive),
|
||||
"history": [],
|
||||
"last_rating": rating
|
||||
"last_rating": rating,
|
||||
"last_rating_label": rating_label
|
||||
}
|
||||
},
|
||||
"last_prompt_key": prompt_key,
|
||||
@@ -1938,8 +2121,9 @@ class FunPackVideoRefiner:
|
||||
refinement_key,
|
||||
mode,
|
||||
rating,
|
||||
(rating - 5.5) / 4.5,
|
||||
reward,
|
||||
{},
|
||||
rating_profile,
|
||||
)
|
||||
else:
|
||||
fallback_latent, fallback_latent_status = self._latent_refinement_disabled(latent)
|
||||
@@ -1964,8 +2148,9 @@ class FunPackVideoRefiner:
|
||||
refinement_key,
|
||||
mode,
|
||||
rating,
|
||||
(rating - 5.5) / 4.5,
|
||||
reward,
|
||||
{},
|
||||
rating_profile,
|
||||
)
|
||||
else:
|
||||
fallback_latent, fallback_latent_status = self._latent_refinement_disabled(latent)
|
||||
@@ -2027,7 +2212,8 @@ class FunPackVideoRefiner:
|
||||
active = {
|
||||
"reference_embeds": tensor_to_serializable(raw_positive),
|
||||
"history": [],
|
||||
"last_rating": rating
|
||||
"last_rating": rating,
|
||||
"last_rating_label": rating_label
|
||||
}
|
||||
prompt_histories[prompt_key] = active
|
||||
|
||||
@@ -2138,19 +2324,23 @@ class FunPackVideoRefiner:
|
||||
except Exception:
|
||||
similarity = 0.0
|
||||
|
||||
reward = (rating - 5.5) / 4.5
|
||||
last_rating = active.get("last_rating", 5)
|
||||
last_reward = (last_rating - 5.5) / 4.5
|
||||
last_rating_profile = normalize_refiner_rating(active.get("last_rating_label", last_rating))
|
||||
if "last_rating_label" not in active:
|
||||
last_rating_profile = normalize_refiner_rating(last_rating)
|
||||
last_reward = float(last_rating_profile.get("reward", (last_rating - 5.5) / 4.5))
|
||||
rating_shift = abs(rating - last_rating)
|
||||
feedback_memory["rating_change_events"] = list(feedback_memory.get("rating_change_events", []))[-15:]
|
||||
feedback_memory["rating_change_events"].append({
|
||||
"iteration": iter_num,
|
||||
"rating": rating,
|
||||
"rating_label": rating_label,
|
||||
"shift": rating_shift,
|
||||
"prompt_key": prompt_key,
|
||||
})
|
||||
|
||||
word_importance = global_adaptive["word_importance"]
|
||||
prompt_emphasis = float(rating_profile.get("prompt_emphasis", reward))
|
||||
|
||||
lr_scale, confidence, exploration_mult, word_lr_mult = self._get_scheduler_factors(
|
||||
scheduler_mode, rating, reward, similarity, iter_num, total_iters,
|
||||
@@ -2166,7 +2356,7 @@ class FunPackVideoRefiner:
|
||||
wkey = full_word.lower()
|
||||
|
||||
base_lr = 0.22 / (1 + 0.07 * (len(history) ** 0.5))
|
||||
group_delta = reward * base_lr * lr_scale * confidence
|
||||
group_delta = prompt_emphasis * base_lr * lr_scale * confidence
|
||||
if wkey in word_lr_mult:
|
||||
group_delta *= word_lr_mult[wkey]
|
||||
|
||||
@@ -2215,9 +2405,13 @@ class FunPackVideoRefiner:
|
||||
global_adaptive["avg_reward_ema"] = avg_reward_ema
|
||||
|
||||
good_ratio = global_adaptive["good_ratio"]
|
||||
if rating >= 8:
|
||||
rating_key = rating_profile.get("key", "")
|
||||
if rating_key == "like":
|
||||
good_ratio = 0.9 * good_ratio + 0.1 * 1.0
|
||||
expl = max(0.015, expl * 0.96)
|
||||
elif rating_key == "missing_details":
|
||||
good_ratio = 0.9 * good_ratio + 0.1 * 0.55
|
||||
expl = min(0.12, expl * 1.02)
|
||||
else:
|
||||
good_ratio = 0.9 * good_ratio + 0.1 * 0.0
|
||||
expl = min(0.12, expl * 1.08)
|
||||
@@ -2240,23 +2434,25 @@ class FunPackVideoRefiner:
|
||||
prev_modified = torch.zeros_like(old_reference)
|
||||
prev_delta = prev_modified - old_reference
|
||||
multiplier = max(0.05, 1.0 + reward * 1.45)
|
||||
if rating == last_rating and rating >= 8:
|
||||
if rating == last_rating and rating_key == "like":
|
||||
multiplier += 0.35
|
||||
noise = torch.randn_like(old_reference) * (expl * (1.0 - avg_reward_ema * 0.7))
|
||||
new_delta = (prev_delta * multiplier) + noise + (momentum * 0.6)
|
||||
else:
|
||||
good_deltas = []
|
||||
for entry in history:
|
||||
if entry.get("rating", 0) >= 7:
|
||||
mod_data = entry.get("modified_embeds")
|
||||
if mod_data is None:
|
||||
continue
|
||||
try:
|
||||
mod = serializable_to_tensor(mod_data).to(device)
|
||||
if list(mod.shape) == list(old_reference.shape):
|
||||
good_deltas.append(mod - old_reference)
|
||||
except Exception:
|
||||
continue
|
||||
entry_profile = normalize_refiner_rating(entry.get("rating_label", entry.get("rating", 0)))
|
||||
if entry_profile.get("key") not in {"like", "missing_details"}:
|
||||
continue
|
||||
mod_data = entry.get("modified_embeds")
|
||||
if mod_data is None:
|
||||
continue
|
||||
try:
|
||||
mod = serializable_to_tensor(mod_data).to(device)
|
||||
if list(mod.shape) == list(old_reference.shape):
|
||||
good_deltas.append(mod - old_reference)
|
||||
except Exception:
|
||||
continue
|
||||
if good_deltas:
|
||||
new_delta = torch.stack(good_deltas).mean(dim=0) * (0.7 + reward * 0.4)
|
||||
else:
|
||||
@@ -2344,6 +2540,8 @@ class FunPackVideoRefiner:
|
||||
history_entry = {
|
||||
"iteration": iter_num,
|
||||
"rating": rating,
|
||||
"rating_label": rating_label,
|
||||
"rating_range": rating_profile.get("legacy_range", ""),
|
||||
"reward": round(reward, 3),
|
||||
"modified_embeds": tensor_to_serializable(new_positive),
|
||||
"similarity": round(similarity, 4),
|
||||
@@ -2360,6 +2558,7 @@ class FunPackVideoRefiner:
|
||||
|
||||
active["history"] = history
|
||||
active["last_rating"] = rating
|
||||
active["last_rating_label"] = rating_label
|
||||
active["last_positive_prompt"] = positive_prompt
|
||||
data["last_prompt_key"] = prompt_key
|
||||
data["prompt_histories"] = prompt_histories
|
||||
@@ -2371,6 +2570,7 @@ class FunPackVideoRefiner:
|
||||
global_adaptive,
|
||||
sigma_strength,
|
||||
seed,
|
||||
rating_profile,
|
||||
)
|
||||
if latent_output_connected:
|
||||
refined_latent, latent_status = self._refine_latent(
|
||||
@@ -2380,6 +2580,7 @@ class FunPackVideoRefiner:
|
||||
rating,
|
||||
reward,
|
||||
global_adaptive,
|
||||
rating_profile,
|
||||
)
|
||||
else:
|
||||
refined_latent, latent_status = self._latent_refinement_disabled(latent)
|
||||
@@ -2488,6 +2689,7 @@ class FunPackVideoRefiner:
|
||||
current_concept_labels,
|
||||
rating,
|
||||
reward,
|
||||
rating_profile,
|
||||
)
|
||||
|
||||
normalized_reward = max(0.0, min(1.0, (avg_reward_ema + 1.0) / 2.0))
|
||||
@@ -2497,8 +2699,9 @@ class FunPackVideoRefiner:
|
||||
|
||||
training_info = (
|
||||
f"Mode: {mode.upper()} | Scheduler: {scheduler_mode.upper()} | Step: {global_adaptive['current_step']} | "
|
||||
f"Rating: {rating_label} ({rating_profile.get('legacy_range', rating)}) | "
|
||||
f"EMA Reward: {avg_reward_ema:+.3f} | Confidence: {confidence:.2f} | LR Scale: {lr_scale:.3f}\n"
|
||||
f"Exploration: {expl:.3f} | Similarity: {similarity:.4f} | Good Ratio: {good_ratio:.1%}\n"
|
||||
f"Exploration: {expl:.3f} | Similarity: {similarity:.4f} | Good Ratio: {good_ratio:.1%} | Prompt Emphasis: {prompt_emphasis:+.2f}\n"
|
||||
f"**Learning Loss: {learning_loss:.4f}** (lower is better)\n"
|
||||
f"Dominant concept: {dominant_line}\n"
|
||||
f"Concept phrases ({len(concept_clusters)} total): {concept_line}\n"
|
||||
@@ -2520,6 +2723,7 @@ class FunPackVideoRefiner:
|
||||
"total_iteration": global_total_iterations,
|
||||
"learning_loss": round(float(learning_loss), 6),
|
||||
"rating": int(rating),
|
||||
"rating_label": rating_label,
|
||||
"similarity": round(float(similarity), 6),
|
||||
"scheduler_mode": scheduler_mode,
|
||||
"mode": mode,
|
||||
@@ -2572,7 +2776,7 @@ class FunPackVideoRefiner:
|
||||
)
|
||||
|
||||
status = (
|
||||
f"{health} | Mode {mode.upper()} | Rating {rating}/10 {trend} | Iter {iter_num}\n"
|
||||
f"{health} | Mode {mode.upper()} | Rating {rating_label} ({rating_profile.get('legacy_range', rating)}) {trend} | Iter {iter_num}\n"
|
||||
f"Session: {len(prompt_histories)} prompt(s), {global_total_iterations} total update(s), "
|
||||
f"{len(history)} history item(s) on this prompt\n"
|
||||
f"Focus: {dominant_line} | {feedback_state}\n"
|
||||
|
||||
@@ -8,7 +8,15 @@ This node analyzes the positive conditioning produced by your text encoder, trac
|
||||
|
||||
**mode**: Tokenizer mode used for prompt analysis. Use `ltx2` for LTX-style workflows and `wan` for Wan workflows.
|
||||
|
||||
**rating**: Rating for the previously generated result, from 1 to 10, where 1 means "awful" and 10 means "masterpiece".
|
||||
**rating**: Categorical feedback for the previously generated result:
|
||||
|
||||
- `I like it`: The video fully matches the request, or is very close.
|
||||
- `Missing details`: The video is visually solid and the main concept is present, but requested details were ignored or changed.
|
||||
- `Missing concept`: The video is visually solid, but the requested concept and details are absent.
|
||||
- `Missing quality`: The video may be visually pleasant, but anatomy, scene construction, concept, and details are not acceptable.
|
||||
- `I don't like it`: The output is low quality, does not represent the requested concept, and ignores details.
|
||||
|
||||
Older numeric workflows are still understood internally: `9-10` maps to `I like it`, `7-8` to `Missing details`, `5-6` to `Missing concept`, `3-4` to `Missing quality`, and `1-2` to `I don't like it`.
|
||||
|
||||
**refinement_key**: Name of the refinement session. The node stores its learned refinement data under this key so you can continue training the same style later.
|
||||
|
||||
|
||||
@@ -38,11 +38,12 @@ When `per_block` is enabled on an `ltx2` stack, the loader keeps the user-facing
|
||||
|
||||
Connect the `lora_stack` output from `FunPack LoRA Loader` into the optional `lora_stack` input on `FunPack Video Refiner`.
|
||||
|
||||
The refiner compares each LoRA's declared type and filename with the concepts it already extracted from the prompt. After processing the rating, it saves `lora_weight_suggestions` into the same prompt entry in the refiner JSON.
|
||||
The refiner compares each LoRA's declared type and filename with the concepts it already extracted from the prompt. After processing the rating category, it saves `lora_weight_suggestions` into the same prompt entry in the refiner JSON.
|
||||
|
||||
Examples:
|
||||
|
||||
- A `quality` LoRA matching a valuable quality concept can be boosted after good ratings.
|
||||
- A `concept` LoRA matching a bad-rated prompt is treated more aggressively than broad LoRAs, so it can be muted or inverted faster if it keeps distorting that concept.
|
||||
- Repeated bad ratings can mark a LoRA as a likely culprit, push its automatic weight down to `0.0`, and even invert it with a negative weight if it keeps ruining output.
|
||||
- Consistently good ratings can stabilize around a saved offset instead of continually drifting.
|
||||
- `I like it` boosts matching LoRAs gently and can stabilize repeated good offsets.
|
||||
- `Missing details` keeps the main direction mostly positive while nudging related concept, character, and general LoRAs upward.
|
||||
- `Missing concept` boosts the best-matching concept or character LoRA, while reducing weaker competing concept LoRAs that may be crowding it out.
|
||||
- `Missing quality` can boost quality LoRAs and the best concept match, while reducing unrelated or competing concept LoRAs.
|
||||
- `I don't like it` treats matching concept LoRAs more aggressively than broad LoRAs, so repeated failures can mark a LoRA as a likely culprit, push its automatic weight down to `0.0`, or invert it with a negative weight.
|
||||
|
||||
Reference in New Issue
Block a user