Spaces:
Running
Running
Upload Quasar_axrvi_ranker.py
Browse files- Quasar_axrvi_ranker.py +95 -1
Quasar_axrvi_ranker.py
CHANGED
|
@@ -9847,6 +9847,69 @@ class HFSyncLayer:
|
|
| 9847 |
# SECTION 18b β RANKER CHECKPOINT MANAGER
|
| 9848 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 9849 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9850 |
class RankerCheckpointManager:
|
| 9851 |
"""
|
| 9852 |
Bridge-facing checkpoint controller for QuasarAXRVIBridge.
|
|
@@ -10103,6 +10166,18 @@ class RankerCheckpointManager:
|
|
| 10103 |
current_num_assets = bridge.axrvi_net.num_assets if bridge.axrvi_net is not None else -1
|
| 10104 |
_model_compatible = True
|
| 10105 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10106 |
if ckpt_num_assets != -1 and ckpt_num_assets != current_num_assets:
|
| 10107 |
ckpt_assets = ckpt.get("asset_symbols", "unknown")
|
| 10108 |
logger.warning(
|
|
@@ -10131,7 +10206,26 @@ class RankerCheckpointManager:
|
|
| 10131 |
tr = bridge.trainer
|
| 10132 |
if _model_compatible:
|
| 10133 |
if "optimizer" in ckpt:
|
| 10134 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10135 |
if "scheduler" in ckpt:
|
| 10136 |
tr.scheduler.load_state_dict(ckpt["scheduler"])
|
| 10137 |
else:
|
|
|
|
| 9847 |
# SECTION 18b β RANKER CHECKPOINT MANAGER
|
| 9848 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 9849 |
|
| 9850 |
+
def _sanitize_optimizer_state_by_shape(optimizer, opt_state: dict) -> dict:
|
| 9851 |
+
"""
|
| 9852 |
+
Drop any per-parameter Adam state (exp_avg / exp_avg_sq / etc.) whose
|
| 9853 |
+
stored tensor shape no longer matches the corresponding *live* param
|
| 9854 |
+
in `optimizer`.
|
| 9855 |
+
|
| 9856 |
+
Why this exists: relying on a saved 'num_assets' checkpoint field (or
|
| 9857 |
+
any other metadata flag) to detect a stale-optimizer situation is
|
| 9858 |
+
fragile β older checkpoints may not have that field at all, and even
|
| 9859 |
+
when shapes match at model-load time (e.g. a lazily-created submodule
|
| 9860 |
+
like FABLECLCU wasn't in the checkpoint dict yet, so it's just a
|
| 9861 |
+
"missing key" rather than a raise), the *optimizer* checkpoint can
|
| 9862 |
+
still hold a state entry at that same param slot sized for the old N.
|
| 9863 |
+
That mismatch only surfaces later, deep inside adamw()'s
|
| 9864 |
+
`exp_avg.lerp_(grad, ...)`, once the lazily-created param gets
|
| 9865 |
+
attached to the optimizer's existing (stale-shaped) state β by which
|
| 9866 |
+
point it's a hard crash on every training step rather than a clean,
|
| 9867 |
+
loggable restore-time skip.
|
| 9868 |
+
|
| 9869 |
+
Comparing shapes directly against the live optimizer's params is
|
| 9870 |
+
metadata-agnostic: it catches the mismatch regardless of why it
|
| 9871 |
+
happened, and only ever discards the specific entries that are
|
| 9872 |
+
actually incompatible β every other trained parameter's momentum
|
| 9873 |
+
keeps flowing through untouched.
|
| 9874 |
+
"""
|
| 9875 |
+
if not opt_state or "state" not in opt_state:
|
| 9876 |
+
return opt_state
|
| 9877 |
+
|
| 9878 |
+
# Flatten in the same order load_state_dict expects: params in the
|
| 9879 |
+
# order they appear across param_groups, which is how the integer
|
| 9880 |
+
# keys in opt_state['state'] are indexed.
|
| 9881 |
+
live_params = [p for group in optimizer.param_groups for p in group["params"]]
|
| 9882 |
+
|
| 9883 |
+
state = opt_state["state"]
|
| 9884 |
+
dropped = []
|
| 9885 |
+
for idx in list(state.keys()):
|
| 9886 |
+
if idx >= len(live_params):
|
| 9887 |
+
# Optimizer has fewer params now than the checkpoint did
|
| 9888 |
+
# (e.g. a whole layer removed) β nothing to compare against.
|
| 9889 |
+
dropped.append(idx)
|
| 9890 |
+
del state[idx]
|
| 9891 |
+
continue
|
| 9892 |
+
live_shape = tuple(live_params[idx].shape)
|
| 9893 |
+
entry = state[idx]
|
| 9894 |
+
mismatched = any(
|
| 9895 |
+
hasattr(v, "shape") and tuple(v.shape) != live_shape
|
| 9896 |
+
for v in entry.values()
|
| 9897 |
+
if hasattr(v, "shape") and v.dim() > 0 # skip scalar 'step' counters
|
| 9898 |
+
)
|
| 9899 |
+
if mismatched:
|
| 9900 |
+
dropped.append(idx)
|
| 9901 |
+
del state[idx]
|
| 9902 |
+
|
| 9903 |
+
if dropped:
|
| 9904 |
+
logger.warning(
|
| 9905 |
+
f"[OptimizerRestore] Dropped {len(dropped)} stale optimizer state "
|
| 9906 |
+
f"entr{'y' if len(dropped) == 1 else 'ies'} with shape mismatches "
|
| 9907 |
+
f"against the current model (fresh Adam state will be used for "
|
| 9908 |
+
f"those params; every other param's momentum is preserved)."
|
| 9909 |
+
)
|
| 9910 |
+
return opt_state
|
| 9911 |
+
|
| 9912 |
+
|
| 9913 |
class RankerCheckpointManager:
|
| 9914 |
"""
|
| 9915 |
Bridge-facing checkpoint controller for QuasarAXRVIBridge.
|
|
|
|
| 10166 |
current_num_assets = bridge.axrvi_net.num_assets if bridge.axrvi_net is not None else -1
|
| 10167 |
_model_compatible = True
|
| 10168 |
|
| 10169 |
+
# NOTE: older checkpoints (e.g. ones restored from HF before
|
| 10170 |
+
# 'num_assets' was added to the save dict) don't carry this field,
|
| 10171 |
+
# so this check can silently miss a real mismatch and report
|
| 10172 |
+
# "compatible". That's fine here β axrvi_net.load_state_dict()
|
| 10173 |
+
# below is strict=False and a shape-mismatched tensor at a shared
|
| 10174 |
+
# key would raise immediately regardless of that flag, so it's
|
| 10175 |
+
# safe either way. The optimizer side is *not* self-protecting the
|
| 10176 |
+
# same way (stale state can attach to a lazily-created param
|
| 10177 |
+
# later without erroring at load time), which is why it gets its
|
| 10178 |
+
# own metadata-independent shape check below via
|
| 10179 |
+
# _sanitize_optimizer_state_by_shape() rather than trusting this
|
| 10180 |
+
# flag alone.
|
| 10181 |
if ckpt_num_assets != -1 and ckpt_num_assets != current_num_assets:
|
| 10182 |
ckpt_assets = ckpt.get("asset_symbols", "unknown")
|
| 10183 |
logger.warning(
|
|
|
|
| 10206 |
tr = bridge.trainer
|
| 10207 |
if _model_compatible:
|
| 10208 |
if "optimizer" in ckpt:
|
| 10209 |
+
# FIX 5: don't trust `_model_compatible` alone β it's
|
| 10210 |
+
# derived from a 'num_assets' checkpoint field that
|
| 10211 |
+
# older checkpoints (like ones restored from HF before
|
| 10212 |
+
# this field existed) simply don't have, silently
|
| 10213 |
+
# defaulting to "compatible". Validate optimizer state
|
| 10214 |
+
# against live param shapes directly as a second,
|
| 10215 |
+
# metadata-independent line of defense β see
|
| 10216 |
+
# _sanitize_optimizer_state_by_shape() for why this
|
| 10217 |
+
# can't be caught at axrvi_net.load_state_dict() time.
|
| 10218 |
+
try:
|
| 10219 |
+
safe_opt_state = _sanitize_optimizer_state_by_shape(
|
| 10220 |
+
tr.optimizer, ckpt["optimizer"]
|
| 10221 |
+
)
|
| 10222 |
+
tr.optimizer.load_state_dict(safe_opt_state)
|
| 10223 |
+
except Exception as e:
|
| 10224 |
+
logger.warning(
|
| 10225 |
+
f"[Restore] β οΈ Optimizer state restore failed "
|
| 10226 |
+
f"({e}) β continuing with fresh optimizer state "
|
| 10227 |
+
f"rather than crashing the restore."
|
| 10228 |
+
)
|
| 10229 |
if "scheduler" in ckpt:
|
| 10230 |
tr.scheduler.load_state_dict(ckpt["scheduler"])
|
| 10231 |
else:
|