mirror of
https://github.com/wassname/jsteer.git
synced 2026-09-09 11:25:03 +08:00
fit: tqdm progress bar + first-prompt trace + summary; config configures loguru on import
- Jacobian.fit wraps prompts in tqdm (jlens has no bar; safe since fit only enumerate/len's them), logs the full first prompt (special tokens on, SHOULD line) and a done-summary -- token-efficient-logging style, both tqdm intervals set - config.py sets up loguru on import (compact single-char icons, routed through tqdm.write so bars survive), so every script/notebook importing config gets it - notebooks drop their manual logger setup and import config in cell 1 Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
This commit is contained in:
@@ -9,6 +9,17 @@ template -- see chat_corpus for why.
|
||||
from pathlib import Path
|
||||
|
||||
import torch
|
||||
from loguru import logger
|
||||
from tqdm.auto import tqdm
|
||||
|
||||
# Configure loguru once, on import, so every script/notebook that imports config
|
||||
# gets the same compact format. Routed through tqdm.write so log lines don't
|
||||
# break a live progress bar (e.g. the fit bar).
|
||||
logger.remove()
|
||||
logger.add(lambda m: tqdm.write(m, end=""), colorize=True,
|
||||
format="<level>{level.icon}</level> {message}", level="INFO")
|
||||
for _lvl, _icon in (("INFO", "I"), ("WARNING", "W"), ("ERROR", "E"), ("DEBUG", "D")):
|
||||
logger.level(_lvl, icon=_icon)
|
||||
|
||||
ROOT = Path(__file__).resolve().parent
|
||||
ART = ROOT / "artifacts"
|
||||
|
||||
+17
-2
@@ -151,10 +151,25 @@ class Jacobian:
|
||||
makes the fit resumable (atomic writes)."""
|
||||
lm = from_hf(model, tok, compile=compile)
|
||||
source_layers = _resolve_layers(layers, lm.n_layers)
|
||||
lens = _jlens_fit(lm, prompts, source_layers=source_layers,
|
||||
|
||||
# Full trace of the first fit prompt as jlens sees it (special tokens on).
|
||||
# SHOULD: a chat fit opens with the template's <|im_start|>user and ends at
|
||||
# the assistant/<think> start; plain text means the template was skipped.
|
||||
ids0 = tok(prompts[0], add_special_tokens=True).input_ids
|
||||
logger.info(f"fit on {len(prompts)} prompts, layers={source_layers} "
|
||||
f"(dim_batch={dim_batch}, max_seq_len={max_seq_len})")
|
||||
logger.info(f"FIT PROMPT[0] ({len(ids0)} tok): {tok.decode(ids0)!r}")
|
||||
|
||||
# jlens.fit has no progress bar; wrap prompts so we get one (fit consumes
|
||||
# them only via enumerate/len, so this is safe). Both tqdm intervals set
|
||||
# (token-efficient-logging) to avoid CR-spam in non-tty logs.
|
||||
bar = tqdm(prompts, desc="fit J", mininterval=30, maxinterval=30)
|
||||
lens = _jlens_fit(lm, bar, source_layers=source_layers,
|
||||
dim_batch=dim_batch, max_seq_len=max_seq_len,
|
||||
checkpoint_path=checkpoint_path)
|
||||
return cls(lens=lens)
|
||||
jac = cls(lens=lens)
|
||||
logger.info(f"fit done: {jac!r}")
|
||||
return jac
|
||||
|
||||
def save(self, path: str) -> None:
|
||||
self.lens.save(path) # fp16 by default; jlens-compatible file
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": "# demo notebook authored by Claude\nimport sys\nfrom loguru import logger\n\nlogger.remove() # show_steer prints through loguru; route it to the cell output\nlogger.add(sys.stdout, format=\"{message}\")\n\nimport torch\nfrom transformers import AutoModelForCausalLM, AutoTokenizer\n\nfrom jsteer import Jacobian, show_steer\n\nsys.path.insert(0, \"..\") # repo root for config.py\nimport config\n\nMODEL = \"Qwen/Qwen3.5-4B\" # 4B-class: demo material. 0.6B degenerates too easily.\ntok = AutoTokenizer.from_pretrained(MODEL)\nmodel = AutoModelForCausalLM.from_pretrained(MODEL, dtype=torch.bfloat16).to(\"cuda\").eval()\n\n# fit-or-load the cache for THIS model. chat_corpus wraps jlens's WikiText in the\n# chat template (closer to the distribution we steer in than raw documents); the\n# lambda means WikiText is only built on a cache MISS. dim_batch=4 fits 4B on a\n# 3090; checkpoint_path makes a multi-hour 4B fit resumable if it dies.\njac = Jacobian.fit_cached(model, tok, lambda: config.chat_corpus(tok, 128),\n config.cache_path(MODEL), layers=(0.3, 0.9), dim_batch=4,\n checkpoint_path=str(config.cache_path(MODEL, \"ckpt\")))\njac"
|
||||
"source": "# demo notebook authored by Claude\nimport sys\nsys.path.insert(0, \"..\") # repo root for config.py\nimport config # configures loguru on import (compact format, tqdm-safe)\n\nimport torch\nfrom transformers import AutoModelForCausalLM, AutoTokenizer\n\nfrom jsteer import Jacobian, show_steer\n\nMODEL = \"Qwen/Qwen3.5-4B\" # 4B-class: demo material. 0.6B degenerates too easily.\ntok = AutoTokenizer.from_pretrained(MODEL)\nmodel = AutoModelForCausalLM.from_pretrained(MODEL, dtype=torch.bfloat16).to(\"cuda\").eval()\n\n# fit-or-load the cache for THIS model. chat_corpus wraps jlens's WikiText in the\n# chat template (closer to the distribution we steer in than raw documents); the\n# lambda means WikiText is only built on a cache MISS. dim_batch=4 fits 4B on a\n# 3090; checkpoint_path makes a multi-hour 4B fit resumable if it dies.\njac = Jacobian.fit_cached(model, tok, lambda: config.chat_corpus(tok, 128),\n config.cache_path(MODEL), layers=(0.3, 0.9), dim_batch=4,\n checkpoint_path=str(config.cache_path(MODEL, \"ckpt\")))\njac"
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": "# demo notebook authored by Claude\nimport sys\nfrom loguru import logger\n\nlogger.remove() # show_steer prints through loguru; route it to the cell output\nlogger.add(sys.stdout, format=\"{message}\")\n\nimport torch\nfrom transformers import AutoModelForCausalLM, AutoTokenizer\n\nfrom jsteer import Jacobian, show_steer\n\nMODEL = \"Qwen/Qwen3.5-4B\" # 4B-class: demo material. 0.6B degenerates too easily.\ntok = AutoTokenizer.from_pretrained(MODEL)\nmodel = AutoModelForCausalLM.from_pretrained(MODEL, dtype=torch.bfloat16).to(\"cuda\").eval()"
|
||||
"source": "# demo notebook authored by Claude\nimport sys\nsys.path.insert(0, \"..\") # repo root for config.py\nimport config # configures loguru on import (compact format, tqdm-safe)\n\nimport torch\nfrom transformers import AutoModelForCausalLM, AutoTokenizer\n\nfrom jsteer import Jacobian, show_steer\n\nMODEL = \"Qwen/Qwen3.5-4B\" # 4B-class: demo material. 0.6B degenerates too easily.\ntok = AutoTokenizer.from_pretrained(MODEL)\nmodel = AutoModelForCausalLM.from_pretrained(MODEL, dtype=torch.bfloat16).to(\"cuda\").eval()"
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
@@ -40,7 +40,7 @@
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": "# fit-or-load: builds the cache on first run for ANY model, loads it after.\n# chat_corpus wraps jlens's WikiText in the chat template, closer to the\n# distribution we steer in (chat + <think>) than raw documents. The lambda means\n# WikiText is only built on a cache MISS. dim_batch=4 fits a 4B on a 24GB 3090;\n# checkpoint_path makes a multi-hour 4B fit resumable if it dies.\nsys.path.insert(0, \"..\") # repo root for config.py\nimport config\n\njac = Jacobian.fit_cached(model, tok, lambda: config.chat_corpus(tok, 128),\n config.cache_path(MODEL), layers=(0.3, 0.9), dim_batch=4,\n checkpoint_path=str(config.cache_path(MODEL, \"ckpt\")))\njac"
|
||||
"source": "# fit-or-load: builds the cache on first run for ANY model, loads it after.\n# chat_corpus wraps jlens's WikiText in the chat template, closer to the\n# distribution we steer in (chat + <think>) than raw documents. The lambda means\n# WikiText is only built on a cache MISS. dim_batch=4 fits a 4B on a 24GB 3090;\n# checkpoint_path makes a multi-hour 4B fit resumable if it dies.\njac = Jacobian.fit_cached(model, tok, lambda: config.chat_corpus(tok, 128),\n config.cache_path(MODEL), layers=(0.3, 0.9), dim_batch=4,\n checkpoint_path=str(config.cache_path(MODEL, \"ckpt\")))\njac"
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
|
||||
+4
-1
@@ -49,7 +49,10 @@ def main() -> None:
|
||||
layers=tuple(args.layers), dim_batch=args.dim_batch,
|
||||
max_seq_len=args.max_seq_len,
|
||||
checkpoint_path=str(config.cache_path(args.model, "ckpt")))
|
||||
logger.info(f"{jac!r} -> {out} ({(time.monotonic() - t0) / 60:.1f} min)")
|
||||
# BLUF summary: what to read first.
|
||||
logger.info(f"DONE fit -> {out}")
|
||||
logger.info(f" {jac!r} | {args.n_prompts} prompts, dim_batch={args.dim_batch}, "
|
||||
f"{(time.monotonic() - t0) / 60:.1f} min")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user