diff --git a/conditioning.py b/conditioning.py index 5cf8fbc3..404cc186 100644 --- a/conditioning.py +++ b/conditioning.py @@ -10218,9 +10218,8 @@ class FunPackVideoRefinerV2(FunPackVideoRefiner): _rs_note = { "recorded": "recorded", "no_pending": "NOT recorded — no captured generation was waiting " - "(capture may have been off, or the sampler's " - "h3_repr_steering toggle was off, when that run sampled)", - "disabled": "NOT recorded — capture is paused for this key", + "(the sampler's h3_repr_steering toggle was likely off " + "when that run sampled)", "no_key": "NOT recorded — no refinement key", }.get(_rs_outcome, _rs_outcome) print(f"[FunPackRefiner] H3 representation steering: weight " diff --git a/h3_repr_steering.py b/h3_repr_steering.py index 2cd63335..3b84fadb 100644 --- a/h3_repr_steering.py +++ b/h3_repr_steering.py @@ -116,43 +116,18 @@ def capture(hidden_state, video_mask): def _load(refinement_key): path = state_path(refinement_key) if not os.path.exists(path): - return {"rows": [], "pending": None, "enabled": True} + return {"rows": [], "pending": None} try: data = torch.load(path, map_location="cpu", weights_only=True) except Exception: # noqa: BLE001 - return {"rows": [], "pending": None, "enabled": True} + return {"rows": [], "pending": None} if not isinstance(data, dict): - return {"rows": [], "pending": None, "enabled": True} + return {"rows": [], "pending": None} data.setdefault("rows", []) data.setdefault("pending", None) - data.setdefault("enabled", True) return data -def capture_enabled(refinement_key): - """Whether this key is recording at all -- independent of the sampler's own - h3_repr_steering toggle, which also controls whether the learned direction gets APPLIED. - A user who wants to pause data collection (to test something else without polluting the - log, or because a sweep came back null and they want to think before adding more rows) - still needs the widget on for `block_sweep`/status to mean anything, so the pause lives - here instead of overloading that widget.""" - if not refinement_key: - return True - return bool(_load(refinement_key).get("enabled", True)) - - -def set_capture_enabled(refinement_key, enabled): - if not refinement_key: - return - data = _load(refinement_key) - data["enabled"] = bool(enabled) - try: - _save(refinement_key, data) - except OSError as e: - _log().failed("H3 representation steering", "set capture enabled", e, - "the pause/resume did not persist") - - def _save(refinement_key, data): path = state_path(refinement_key) os.makedirs(os.path.dirname(path), exist_ok=True) @@ -171,8 +146,6 @@ def save_pending(refinement_key, descriptors): if not refinement_key or not descriptors: return data = _load(refinement_key) - if not data.get("enabled", True): - return data["pending"] = {int(b): d.detach().float().cpu() for b, d in descriptors.items()} try: _save(refinement_key, data) @@ -187,17 +160,13 @@ def commit(refinement_key, reward, prompt_hash=None): already-resolved, already-admissibility-filtered reward -- this function trusts it rather than re-deriving a verdict, same as the value functions do with the same number. - -> "recorded" | "no_pending" (nothing generated since the last rating -- or capture was - off when that generation ran, so nothing was ever saved to pair this rating with) | - "disabled" (capture is paused for this key right now) | "no_key". The caller prints this, - not just the reward it computed -- a reward can be correct and still never reach a row if - there was nothing to pair it with, and a log line that only ever reports the reward it - is ABOUT to commit cannot tell that apart from a real commit.""" + -> "recorded" | "no_pending" (nothing generated since the last rating) | "no_key". The + caller prints this, not just the reward it computed -- a reward can be correct and still + never reach a row if there was nothing to pair it with, and a log line that only ever + reports the reward it is ABOUT to commit cannot tell that apart from a real commit.""" if not refinement_key: return "no_key" data = _load(refinement_key) - if not data.get("enabled", True): - return "disabled" pending = data.get("pending") data["pending"] = None if pending is None: diff --git a/movie_editor/frontend/api.js b/movie_editor/frontend/api.js index 87038a3d..544a28a0 100644 --- a/movie_editor/frontend/api.js +++ b/movie_editor/frontend/api.js @@ -200,7 +200,6 @@ // H3 representation steering (Settings ▸ Learning) — per-KEY, unlike the probe above. reinsStatus: (key) => j("GET", API("/h3_repr_steering") + `?key=${encodeURIComponent(key || "default")}`), - reinsSetEnabled: (key, enabled) => j("POST", API("/h3_repr_steering/enabled"), { key: key || "default", enabled: !!enabled }), reinsClear: (key) => j("POST", API("/h3_repr_steering/clear"), { key: key || "default" }), async reinsExport(key) { const k = key || "default"; diff --git a/movie_editor/frontend/settings_window.js b/movie_editor/frontend/settings_window.js index d88856f4..a72cb0c3 100644 --- a/movie_editor/frontend/settings_window.js +++ b/movie_editor/frontend/settings_window.js @@ -408,26 +408,6 @@ return tbl; } - function reinsToggleRow(enabled, onChange) { - const row = el("div", "sw-row"); - const main = el("div", "sw-row-main"); - main.append(el("div", "sw-row-title", "Record ratings for this key")); - main.append(el("div", "sw-row-hint", - "On by default. Independent of the sampler's own toggle — that one controls whether " - + "the learned direction gets APPLIED; this one controls whether it keeps learning at " - + "all. Turn off to pause the log without losing what's captured, or while testing " - + "something else you don't want mixed in.")); - row.append(main); - const lbl = el("label", "chk es-toggle"); - const cb = el("input"); - cb.type = "checkbox"; - cb.checked = !!enabled; - cb.onchange = () => onChange(cb.checked); - lbl.append(cb, el("span", null, "")); - row.append(lbl); - return row; - } - function reinsRows(key) { const box = el("div", "sw-stack"); const paint = () => { @@ -436,21 +416,12 @@ const nLiked = reinsState ? reinsState.n_liked : 0; const nDisliked = reinsState ? reinsState.n_disliked : 0; const ready = !!(reinsState && reinsState.ready); - const enabled = !reinsState || reinsState.enabled !== false; - rows.append(reinsToggleRow(enabled, async (on) => { - reinsError = ""; - try { reinsState = await window.MovieEditorAPI.reinsSetEnabled(key, on); } - catch (e) { reinsError = String(e.message || e); } - paint(); - })); rows.append(infoRow("Rated generations (this key)", `${nLiked} liked / ${nDisliked} disliked`, reinsState ? ready : null)); if (reinsState && !ready) { rows.append(el("div", "sw-hint", - enabled - ? `Needs ${reinsState.min_per_group}+ of each before it steers anything — still ` - + "capturing every generation either way." - : "Recording is off — nothing new is being captured for this key.")); + `Needs ${reinsState.min_per_group}+ of each before it steers anything — still ` + + "capturing every generation either way.")); } rows.append(actionRow("Save this key's REINS data", "Downloads every captured run (all candidate blocks, not just the one that steers) " diff --git a/movie_editor/server.py b/movie_editor/server.py index 8fc37591..c6c15890 100644 --- a/movie_editor/server.py +++ b/movie_editor/server.py @@ -2110,7 +2110,6 @@ if web is not None and PromptServer is not None: "min_per_group": rs.MIN_PER_GROUP, "default_block": rs.DEFAULT_BLOCK, "sweep": {str(b): r for b, r in sweep.items()}, - "enabled": rs.capture_enabled(key), } @routes.get(UI_PREFIX + "/api/h3_repr_steering") @@ -2140,14 +2139,6 @@ if web is not None and PromptServer is not None: body=body, content_type="application/octet-stream", headers={"Content-Disposition": f'attachment; filename="{key}.repr_steer.pt"'}) - @routes.post(UI_PREFIX + "/api/h3_repr_steering/enabled") - async def _repr_steer_set_enabled(req): - body = await req.json() - key = str(body.get("key") or "default").strip() or "default" - _repr_steer_module().set_capture_enabled(key, bool(body.get("enabled"))) - _rs, state = _repr_steer_state(key) - return web.json_response(state) - @routes.post(UI_PREFIX + "/api/h3_repr_steering/clear") async def _repr_steer_clear(req): body = await req.json() diff --git a/tests/test_h3_repr_steering.py b/tests/test_h3_repr_steering.py index 05c62630..079320df 100644 --- a/tests/test_h3_repr_steering.py +++ b/tests/test_h3_repr_steering.py @@ -147,12 +147,6 @@ def test_commit_reports_no_pending_with_nothing_to_pair(): assert rs.commit("k", 1.0) == "no_pending" -def test_commit_reports_disabled_when_capture_is_paused(): - rs.save_pending("k", _pend(torch.tensor([1.0, 0.0]))) - rs.set_capture_enabled("k", False) - assert rs.commit("k", 1.0) == "disabled" - - def test_commit_reports_no_key_for_an_empty_key(): assert rs.commit("", 1.0) == "no_key" @@ -166,36 +160,6 @@ def test_pending_overwrites_not_accumulates(): assert torch.allclose(data["rows"][0]["desc"][rs.DEFAULT_BLOCK], torch.tensor([2.0, 0.0])) -def test_capture_enabled_defaults_true(): - assert rs.capture_enabled("k") is True # no file yet -- still True, not False - - -def test_disabling_capture_stops_save_pending(): - rs.set_capture_enabled("k", False) - rs.save_pending("k", _pend(torch.tensor([1.0, 0.0]))) - rs.commit("k", 1.0) - direction, n_pos, n_neg = rs.direction("k") - assert n_pos == 0 and n_neg == 0 # nothing was ever captured to commit - - -def test_re_enabling_capture_resumes_it(): - rs.set_capture_enabled("k", False) - rs.set_capture_enabled("k", True) - assert rs.capture_enabled("k") is True - rs.save_pending("k", _pend(torch.tensor([1.0, 0.0]))) - rs.commit("k", 1.0) - data = rs._load("k") - assert len(data["rows"]) == 1 - - -def test_disabling_capture_does_not_discard_existing_rows(): - rs.save_pending("k", _pend(torch.tensor([1.0, 0.0]))) - rs.commit("k", 1.0) - rs.set_capture_enabled("k", False) - data = rs._load("k") - assert len(data["rows"]) == 1 - - def test_clear_all_removes_the_state_file(): rs.save_pending("k", _pend(torch.tensor([1.0, 0.0]))) rs.commit("k", 1.0)