revert: remove the REINS capture-pause toggle entirely
Misread "disable that .pt tracking" as "stop recording ratings" -- the actual ask was about console noise, already handled by removing the block-sweep print. This toggle instead silently stopped every rating from being recorded while it was on, confirmed live: a real key sat at "0 liked / 0 disliked" through multiple ratings with no visible error, and the "committing weight" log line looked correct the whole time (fixed separately, but the toggle itself should never have existed). Removed cleanly rather than patched: capture_enabled/set_capture_enabled, the enabled gate in save_pending/commit, the /enabled route, the API client method, and the Settings toggle row. save_pending and commit now behave exactly as they did before this was ever added -- every rating is recorded, unconditionally.
This commit is contained in:
+2
-3
@@ -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 "
|
||||
|
||||
+7
-38
@@ -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:
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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) "
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user