Instructions to use FerrellSyntheticIntelligence/fsi-anomaly with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- llama.cpp
How to use FerrellSyntheticIntelligence/fsi-anomaly with llama.cpp:
Install (macOS, Linux)
curl -LsSf https://llama.app/install.sh | sh # Start a local OpenAI-compatible server with a web UI: llama serve -hf FerrellSyntheticIntelligence/fsi-anomaly # Run inference directly in the terminal: llama cli -hf FerrellSyntheticIntelligence/fsi-anomaly
Install from WinGet (Windows)
winget install llama.cpp # Start a local OpenAI-compatible server with a web UI: llama serve -hf FerrellSyntheticIntelligence/fsi-anomaly # Run inference directly in the terminal: llama cli -hf FerrellSyntheticIntelligence/fsi-anomaly
Use pre-built binary
# Download pre-built binary from: # https://github.com/ggerganov/llama.cpp/releases # Start a local OpenAI-compatible server with a web UI: ./llama-server -hf FerrellSyntheticIntelligence/fsi-anomaly # Run inference directly in the terminal: ./llama-cli -hf FerrellSyntheticIntelligence/fsi-anomaly
Build from source code
git clone https://github.com/ggerganov/llama.cpp.git cd llama.cpp cmake -B build cmake --build build -j --target llama-server llama-cli # Start a local OpenAI-compatible server with a web UI: ./build/bin/llama-server -hf FerrellSyntheticIntelligence/fsi-anomaly # Run inference directly in the terminal: ./build/bin/llama-cli -hf FerrellSyntheticIntelligence/fsi-anomaly
Use Docker
docker model run hf.co/FerrellSyntheticIntelligence/fsi-anomaly
- LM Studio
- Jan
- Ollama
How to use FerrellSyntheticIntelligence/fsi-anomaly with Ollama:
ollama run hf.co/FerrellSyntheticIntelligence/fsi-anomaly
- Unsloth Desktop
- Docker Model Runner
How to use FerrellSyntheticIntelligence/fsi-anomaly with Docker Model Runner:
docker model run hf.co/FerrellSyntheticIntelligence/fsi-anomaly
- Lemonade
How to use FerrellSyntheticIntelligence/fsi-anomaly with Lemonade:
Pull the model
# Download Lemonade from https://lemonade-server.ai/ lemonade pull FerrellSyntheticIntelligence/fsi-anomaly
Run and chat with the model
lemonade run user.fsi-anomaly-{{QUANT_TAG}}List all available models
lemonade list
- Atomic Chat
backup all: 100 files (batch)
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- .gitattributes +1 -0
- data/train_phase2.bin +3 -0
- data/train_phase2b.bin +3 -0
- data/train_phase2b16k.bin +3 -0
- data/valid.bin +3 -0
- data/valid16k.bin +3 -0
- data/valid_mix.bin +3 -0
- demo/serve.py +170 -0
- docs/BIGTECH_RECIPE.md +82 -0
- docs/harness_research.md +136 -0
- docs/model_card_fsi_anomaly.md +89 -0
- docs/persona_sample_spock_sheldon.md +105 -0
- docs/replay_research.md +45 -0
- docs/research_coherence_small.md +59 -0
- eval/bench.py +154 -0
- eval/bench2.py +179 -0
- eval/probes.py +79 -0
- finish.sh +61 -0
- generate.py +76 -0
- hf/build_card.py +198 -0
- hf/export_gguf.py +95 -0
- hf/export_hf.py +249 -0
- hf_repo_v8/README.md +162 -0
- hf_repo_v8/config.json +31 -0
- hf_repo_v8/generation_config.json +7 -0
- hf_repo_v8/model.safetensors +3 -0
- hf_repo_v8/modeling_tinyliquid.py +390 -0
- hf_repo_v8/quantized/q8.safetensors +3 -0
- hf_repo_v8/special_tokens_map.json +44 -0
- hf_repo_v8/tiny-liquid-q8.gguf +3 -0
- hf_repo_v8/tokenizer.json +0 -0
- hf_repo_v8/tokenizer_config.json +39 -0
- hf_upload.py +45 -0
- logs/baseline_eval_tiny25m.log +96 -0
- logs/bench2_val.log +0 -0
- logs/bench_dpo.log +1 -0
- logs/bench_dpo_2.log +1 -0
- logs/bench_forensic.log +0 -0
- logs/calib90_dpo3_200_main.jsonl +50 -0
- logs/calib90_dpo3_200_res.jsonl +27 -0
- logs/calib_dpo3_200_main.jsonl +50 -0
- logs/calib_dpo3_200_res.jsonl +27 -0
- logs/calib_summary_calib90.json +193 -0
- logs/calib_summary_dpo3_200.json +96 -0
- logs/calib_summary_dpo3_200_scratch24.json +209 -0
- logs/chain_dpo_v26.log +1 -0
- logs/chain_sft_v26.log +3 -0
- logs/chain_v22.log +5 -0
- logs/code_train.log +148 -0
- logs/distill_train.log +49 -0
.gitattributes
CHANGED
|
@@ -100,3 +100,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 100 |
.venv/lib/python3.12/site-packages/pyarrow/_substrait.cpython-312-aarch64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 101 |
data/TinyStoriesV2-GPT4-valid.txt filter=lfs diff=lfs merge=lfs -text
|
| 102 |
data/code_train.txt filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
| 100 |
.venv/lib/python3.12/site-packages/pyarrow/_substrait.cpython-312-aarch64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 101 |
data/TinyStoriesV2-GPT4-valid.txt filter=lfs diff=lfs merge=lfs -text
|
| 102 |
data/code_train.txt filter=lfs diff=lfs merge=lfs -text
|
| 103 |
+
hf_repo_v8/tiny-liquid-q8.gguf filter=lfs diff=lfs merge=lfs -text
|
data/train_phase2.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:43f5cf38209f3fb8e811f846d1a639f84e6e27124a8fadb5e0a880684db3440b
|
| 3 |
+
size 82739474
|
data/train_phase2b.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:faba343daf3f1866d78679b79d32e8fd3355bec66b658a770659322fdf2f6e54
|
| 3 |
+
size 65124864
|
data/train_phase2b16k.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:06ba95ea7ef48238608f54dce64948277ec03ed9901a9396e4f0e20f8cf11f4b
|
| 3 |
+
size 62476380
|
data/valid.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:8c7b1a0531190f8079efa7dbd1d922a0d430e485a1db6543afb2aaf50efa9c8d
|
| 3 |
+
size 10928278
|
data/valid16k.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:301458bd894e241fb6aa75ffe1f505a9102f74fb796510e0123492b4ab482550
|
| 3 |
+
size 10764862
|
data/valid_mix.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:98d3841c94178272248cf809c740579b4f6a11c1d58c12f0f6b48535385dec65
|
| 3 |
+
size 4914176
|
demo/serve.py
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""TinyLiquid local demo server (stdlib only, no dependencies).
|
| 2 |
+
|
| 3 |
+
Serves a small web UI + JSON API for chat (persona) and procedure-driven
|
| 4 |
+
analysis (SOP). Good for demos, local evaluation, and screenshots for the
|
| 5 |
+
Hugging Face page.
|
| 6 |
+
|
| 7 |
+
Usage:
|
| 8 |
+
.venv/bin/python demo/serve.py --ckpt ckpt/dpo --port 8080
|
| 9 |
+
curl -s localhost:8080/chat -d '{"text": "Verify: the bridge was painted in 2019."}'
|
| 10 |
+
"""
|
| 11 |
+
|
| 12 |
+
import argparse
|
| 13 |
+
import json
|
| 14 |
+
import threading
|
| 15 |
+
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
| 16 |
+
from pathlib import Path
|
| 17 |
+
|
| 18 |
+
import torch
|
| 19 |
+
|
| 20 |
+
from model.config import TinyLiquidConfig, CONFIGS
|
| 21 |
+
from model.tiny_liquid import TinyLiquid
|
| 22 |
+
from model.utils import latest_ckpt
|
| 23 |
+
from data.tokenizer import load_tokenizer
|
| 24 |
+
|
| 25 |
+
PERSONA_T = {"analyst": "<|analyst|>", "skeptic": "<|skeptic|>", "none": ""}
|
| 26 |
+
PERSONA_ID = {"analyst": 1, "skeptic": 2, "none": 0}
|
| 27 |
+
SOP_PROMPT = {
|
| 28 |
+
"claim_verification": "Apply SOP 01 - CLAIM VERIFICATION: decompose, source, corroborate, date, provenance, verdict.",
|
| 29 |
+
"cross_source_discrepancy": "Apply SOP 02 - CROSS-SOURCE DISCREPANCY: align, delta, classify, root, timing, verdict.",
|
| 30 |
+
"pattern_finding": "Apply SOP 03 - PATTERN FINDING: collect, cluster, common cause, null test, strength.",
|
| 31 |
+
"timeline_reconstruction": "Apply SOP 04 - TIMELINE RECONSTRUCTION: anchor, order, gaps, conflicts, labeled inference.",
|
| 32 |
+
"historical_truth": "Apply SOP 05 - HISTORICAL TRUTH: retrieve early reporting, aftermath records, deltas, hidden items.",
|
| 33 |
+
"politics_analysis": "Apply SOP 06 - POLITICS / SPIN: separate facts from interests, provenance, spin labels.",
|
| 34 |
+
"dark_web_research": "Apply SOP 07 - DARK WEB RESEARCH (authorized OSINT only): scope, crawl, triage, chain, verify.",
|
| 35 |
+
"terminal_control": "Apply SOP 08 - TERMINAL CONTROL: read-only first, dry-run, log, no destruction, verify.",
|
| 36 |
+
"source_triage": "Apply SOP 09 - SOURCE TRIAGE: score independence, proximity, recency, track, interest.",
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
INDEX_HTML = """<!doctype html><html><head><meta charset="utf-8"><title>TinyLiquid Analyst</title>
|
| 40 |
+
<style>body{font-family:ui-sans-serif,system-ui;max-width:760px;margin:2rem auto;padding:0 1rem;color:#111}
|
| 41 |
+
textarea{width:100%;min-height:90px;font:inherit;padding:.6rem;border:1px solid #ccc;border-radius:8px}
|
| 42 |
+
select,button{font:inherit;padding:.45rem .8rem;border-radius:8px;border:1px solid #ccc;background:#fff}
|
| 43 |
+
button{background:#1a1a1a;color:#fff;border:none;cursor:pointer}
|
| 44 |
+
pre{background:#f6f6f6;border-radius:8px;padding:.8rem;white-space:pre-wrap;word-break:break-word}
|
| 45 |
+
h1{font-size:1.3rem} .tag{color:#666;font-size:.85rem} .row{display:flex;gap:.6rem;align-items:center;margin:.6rem 0}
|
| 46 |
+
</style></head><body>
|
| 47 |
+
<h1>TinyLiquid Analyst <span class="tag">7.8M params · on-device</span></h1>
|
| 48 |
+
<p class="tag">A tiny liquid-architecture forensic research model. Analyst persona speaks with a
|
| 49 |
+
hyper-logical, protocol-driven voice; the skeptic attacks conclusions. Procedure prompts make it
|
| 50 |
+
apply numbered SOPs instead of freewheeling.</p>
|
| 51 |
+
<div class="row"><select id="persona"><option value="analyst">Analyst</option><option value="skeptic">Skeptic</option>
|
| 52 |
+
<option value="none">None</option></select>
|
| 53 |
+
<select id="sop"><option value="">No procedure</option><option value="claim_verification">SOP 01 Claim verification</option>
|
| 54 |
+
<option value="cross_source_discrepancy">SOP 02 Cross-source discrepancy</option><option value="pattern_finding">SOP 03 Pattern finding</option>
|
| 55 |
+
<option value="timeline_reconstruction">SOP 04 Timeline reconstruction</option><option value="historical_truth">SOP 05 Historical truth</option>
|
| 56 |
+
<option value="politics_analysis">SOP 06 Politics / spin</option><option value="dark_web_research">SOP 07 Dark web research</option>
|
| 57 |
+
<option value="terminal_control">SOP 08 Terminal control</option><option value="source_triage">SOP 09 Source triage</option></select>
|
| 58 |
+
<button onclick="go()">Analyze</button></div>
|
| 59 |
+
<textarea id="in" placeholder="Example: Verify: 'Crime doubled because of the new policy.' The report shows incidents rose from 1,000 to 2,000 while reporting methods changed."></textarea>
|
| 60 |
+
<pre id="out">Ready.</pre>
|
| 61 |
+
<script>
|
| 62 |
+
async function go(){const t=document.getElementById('in').value;if(!t)return;
|
| 63 |
+
const out=document.getElementById('out');out.textContent='working...';
|
| 64 |
+
const r=await fetch('/chat',{method:'POST',headers:{'Content-Type':'application/json'},
|
| 65 |
+
body:JSON.stringify({text:t,persona:document.getElementById('persona').value,sop:document.getElementById('sop').value})});
|
| 66 |
+
const j=await r.json();out.textContent=j.response||j.error;}
|
| 67 |
+
</script></body></html>"""
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
class Handler(BaseHTTPRequestHandler):
|
| 71 |
+
server_version = "TinyLiquid/1.0"
|
| 72 |
+
|
| 73 |
+
def _json(self, obj, code=200):
|
| 74 |
+
body = json.dumps(obj).encode()
|
| 75 |
+
self.send_response(code)
|
| 76 |
+
self.send_header("Content-Type", "application/json")
|
| 77 |
+
self.send_header("Content-Length", str(len(body)))
|
| 78 |
+
self.end_headers()
|
| 79 |
+
self.wfile.write(body)
|
| 80 |
+
|
| 81 |
+
def do_GET(self):
|
| 82 |
+
if self.path == "/v1/models":
|
| 83 |
+
return self._json({
|
| 84 |
+
"object": "list",
|
| 85 |
+
"data": [{"id": "tinyliquid-research-v8", "object": "model", "owned_by": "local"}],
|
| 86 |
+
})
|
| 87 |
+
if self.path in ("/", "/index.html"):
|
| 88 |
+
body = INDEX_HTML.encode()
|
| 89 |
+
self.send_response(200)
|
| 90 |
+
self.send_header("Content-Type", "text/html; charset=utf-8")
|
| 91 |
+
self.send_header("Content-Length", str(len(body)))
|
| 92 |
+
self.end_headers()
|
| 93 |
+
self.wfile.write(body)
|
| 94 |
+
else:
|
| 95 |
+
self._json({"error": "not found"}, 404)
|
| 96 |
+
|
| 97 |
+
def do_POST(self):
|
| 98 |
+
if self.path not in ("/chat", "/v1/chat/completions"):
|
| 99 |
+
return self._json({"error": "not found"}, 404)
|
| 100 |
+
try:
|
| 101 |
+
data = json.loads(self.rfile.read(int(self.headers.get("Content-Length", 0)) or 0) or b"{}")
|
| 102 |
+
except Exception:
|
| 103 |
+
return self._json({"error": "bad json"}, 400)
|
| 104 |
+
if self.path == "/v1/chat/completions":
|
| 105 |
+
messages = data.get("messages") or []
|
| 106 |
+
text = next((item.get("content", "") for item in reversed(messages)
|
| 107 |
+
if item.get("role") == "user"), "")
|
| 108 |
+
system = next((item.get("content", "") for item in messages
|
| 109 |
+
if item.get("role") == "system"), "")
|
| 110 |
+
persona = "skeptic" if "skeptic" in system.lower() else "analyst"
|
| 111 |
+
sop = ""
|
| 112 |
+
else:
|
| 113 |
+
text = (data.get("text") or "").strip()
|
| 114 |
+
persona = data.get("persona", "analyst")
|
| 115 |
+
sop = data.get("sop", "")
|
| 116 |
+
if not text:
|
| 117 |
+
return self._json({"error": "empty text"}, 400)
|
| 118 |
+
if sop in SOP_PROMPT:
|
| 119 |
+
text = SOP_PROMPT[sop] + " Material: " + text
|
| 120 |
+
lock.acquire()
|
| 121 |
+
try:
|
| 122 |
+
prompt = (PERSONA_T[persona] or "") + "<|user|>" + text + "<|assistant|>"
|
| 123 |
+
ids = tok.encode(prompt).ids
|
| 124 |
+
out = model.generate(tok, ids, persona_id=PERSONA_ID[persona], max_new=args.max_new,
|
| 125 |
+
temperature=args.temp, top_k=40, repetition_penalty=1.4,
|
| 126 |
+
no_repeat_ngram_size=4)
|
| 127 |
+
response = tok.decode(out[len(ids):]).strip()
|
| 128 |
+
finally:
|
| 129 |
+
lock.release()
|
| 130 |
+
if self.path == "/v1/chat/completions":
|
| 131 |
+
return self._json({
|
| 132 |
+
"id": "tinyliquid-local",
|
| 133 |
+
"object": "chat.completion",
|
| 134 |
+
"model": data.get("model", "tinyliquid-research-v8"),
|
| 135 |
+
"choices": [{"index": 0, "message": {"role": "assistant", "content": response}, "finish_reason": "stop"}],
|
| 136 |
+
})
|
| 137 |
+
return self._json({"response": response, "persona": persona, "sop": sop})
|
| 138 |
+
|
| 139 |
+
def log_message(self, *a):
|
| 140 |
+
pass
|
| 141 |
+
|
| 142 |
+
|
| 143 |
+
def main():
|
| 144 |
+
global tok, model, lock, args
|
| 145 |
+
ap = argparse.ArgumentParser()
|
| 146 |
+
ap.add_argument("--ckpt", default="ckpt/dpo")
|
| 147 |
+
ap.add_argument("--tok", default="data/tokenizer.json")
|
| 148 |
+
ap.add_argument("--port", type=int, default=8080)
|
| 149 |
+
ap.add_argument("--threads", type=int, default=8)
|
| 150 |
+
ap.add_argument("--max-new", type=int, default=160)
|
| 151 |
+
ap.add_argument("--temp", type=float, default=0.6)
|
| 152 |
+
args = ap.parse_args()
|
| 153 |
+
|
| 154 |
+
torch.set_num_threads(args.threads)
|
| 155 |
+
tok = load_tokenizer(args.tok)
|
| 156 |
+
ckpt = latest_ckpt(args.ckpt)
|
| 157 |
+
assert ckpt, f"no checkpoints in {args.ckpt}"
|
| 158 |
+
sd = torch.load(ckpt, map_location="cpu")
|
| 159 |
+
cfg = TinyLiquidConfig(vocab_size=tok.get_vocab_size(),
|
| 160 |
+
**{k: v for k, v in sd["config"].items() if k != "vocab_size"})
|
| 161 |
+
model = TinyLiquid(cfg)
|
| 162 |
+
model.load_state_dict(sd["model"])
|
| 163 |
+
model.eval()
|
| 164 |
+
lock = threading.Lock()
|
| 165 |
+
print(f"TinyLiquid demo on http://localhost:{args.port} ({ckpt})", flush=True)
|
| 166 |
+
ThreadingHTTPServer(("127.0.0.1", args.port), Handler).serve_forever()
|
| 167 |
+
|
| 168 |
+
|
| 169 |
+
if __name__ == "__main__":
|
| 170 |
+
main()
|
docs/BIGTECH_RECIPE.md
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# TinyLiquid — Big-Tech Recipe and Current-Situation Audit
|
| 2 |
+
|
| 3 |
+
Date: 2026-08-01. Sources are the recipes used by the groups that actually ship small models.
|
| 4 |
+
|
| 5 |
+
## What the sources say
|
| 6 |
+
|
| 7 |
+
- **SmolLM (Hugging Face, 2024)** — `https://huggingface.co/blog/smollm`
|
| 8 |
+
- 135M/360M trained on 600B tokens; 1.7B on 1T tokens. They explicitly trained small
|
| 9 |
+
models "even beyond the Chinchilla optimal point" because gains kept coming.
|
| 10 |
+
- Corpus = synthetic "textbook" data generated by a strong teacher (Cosmopedia v2,
|
| 11 |
+
28B tokens, generated by Mixtral) + curated web (FineWeb-Edu 220B) + code (4B).
|
| 12 |
+
- Instruct = SFT then DPO, following the Zephyr/Gemma alignment-handbook recipe.
|
| 13 |
+
- **SmolLM2 (Hugging Face, 2025)** — `https://huggingface.co/HuggingFaceTB/SmolLM2-135M`
|
| 14 |
+
- 135M trained on 2T tokens (FineWeb-Edu, DCLM, The Stack + curated).
|
| 15 |
+
- Instruct = SFT (smoltalk) then DPO on UltraFeedback.
|
| 16 |
+
- **Phi-3 (Microsoft, 2024)** — arXiv:2404.14219
|
| 17 |
+
- 3.8B trained on 3.3T tokens of "heavily filtered web data and synthetic data";
|
| 18 |
+
data quality is the lever that makes small models competitive.
|
| 19 |
+
- **TinyStories (OpenAI, 2023)** — arXiv:2305.07759
|
| 20 |
+
- Direct evidence that models BELOW 10M parameters (our scale) become fluent and
|
| 21 |
+
consistent when trained on large, high-quality synthetic corpora.
|
| 22 |
+
- **LoRA (Hu et al., 2021)** — arXiv:2106.09685
|
| 23 |
+
- Freeze pretrained weights, train low-rank adapters; the standard defense against
|
| 24 |
+
catastrophic forgetting during adaptation.
|
| 25 |
+
- **DPO (Rafailov et al., 2023)** — arXiv:2305.18290
|
| 26 |
+
- Preference optimization without a separate reward model; used after SFT by both
|
| 27 |
+
SmolLM generations.
|
| 28 |
+
|
| 29 |
+
## Audit of this project
|
| 30 |
+
|
| 31 |
+
- Architecture: 7.8M params, liquid blocks, no attention. Fine for this exercise.
|
| 32 |
+
- Pretraining used only ~47M tokens (TinyStories slice + code): about 6 tokens/param.
|
| 33 |
+
- Reference ratios: SmolLM1 135M = 600B tokens = ~4,400 tok/param; SmolLM2 135M =
|
| 34 |
+
2T tokens = ~15,000 tok/param; TinyStories sub-10M models were trained on roughly
|
| 35 |
+
a billion+ tokens of synthetic stories.
|
| 36 |
+
- Implication: the base is under-trained by 2-3 orders of magnitude. Every SFT/DPO on
|
| 37 |
+
top of it either collapses (overfit to a few hundred examples) or stays story-like
|
| 38 |
+
(base never learned the domain). This is why iterative fine-tuning "goes in circles".
|
| 39 |
+
- Full corpus: `data/TinyStoriesV2-GPT4-train.txt` (2.2 GB, ~550M tokens) was never
|
| 40 |
+
tokenized; it is now being encoded to `data/train_full.bin` by
|
| 41 |
+
`data/encode_full.py`.
|
| 42 |
+
|
| 43 |
+
## What we are doing about it (in order)
|
| 44 |
+
|
| 45 |
+
1. **Continue pretraining** on the full ~550M-token corpus with
|
| 46 |
+
`train/train_lm.py --resume ckpt/nlp --data data/train_full.bin ...`
|
| 47 |
+
(memmap loader added; saves every N steps; resumable). Realistic device rate is
|
| 48 |
+
~800 tok/s, so this is a multi-day job: 100M tokens ~= 35h. Run in chunks.
|
| 49 |
+
2. **Teacher-generated synthetic data** (Phi/Cosmopedia lever): expand the analyst
|
| 50 |
+
voice dataset to thousands of high-quality examples across general chat, truth
|
| 51 |
+
Q&A, SOP, forensic, tool use, and skeptic attacks.
|
| 52 |
+
3. **LoRA SFT** (LoRA paper): freeze the base, train low-rank adapters + persona,
|
| 53 |
+
KL-anchor to the base, eval-driven checkpoint selection with a TinyStories PPL
|
| 54 |
+
guard.
|
| 55 |
+
4. **DPO** on a larger generated preference set (SmolLM instruct recipe), only after
|
| 56 |
+
SFT quality is verified.
|
| 57 |
+
5. Ship: HF export, Q8 GGUF, benchmark, model card, TUI.
|
| 58 |
+
|
| 59 |
+
## Commands
|
| 60 |
+
|
| 61 |
+
```bash
|
| 62 |
+
# 1. encode full corpus (done once, ~25 min)
|
| 63 |
+
export PYTHONPATH=$PWD
|
| 64 |
+
.venv/bin/python data/encode_full.py
|
| 65 |
+
|
| 66 |
+
# 2. continue pretraining (resumable; each invocation adds --steps)
|
| 67 |
+
.venv/bin/python -u train/train_lm.py --resume ckpt/nlp \
|
| 68 |
+
--data data/train_full.bin --val data/valid.bin --config tiny10m \
|
| 69 |
+
--ckpt ckpt/nlp_full --batch 16 --seq 256 --lr 1.5e-4 --warmup 200 \
|
| 70 |
+
--steps 5000 --save-every 500 --eval-every 500 --threads 4
|
| 71 |
+
|
| 72 |
+
# 3. LoRA SFT (see train/train_lora.py when ready)
|
| 73 |
+
```
|
| 74 |
+
|
| 75 |
+
## Honest expectations
|
| 76 |
+
|
| 77 |
+
- A 7.8M general chatbot is below every published instruct-model floor (135M+).
|
| 78 |
+
- With the TinyStories result in mind, the achievable target is a coherent,
|
| 79 |
+
narrow analyst assistant for claim verification / OSINT research via large
|
| 80 |
+
synthetic data + LoRA SFT + DPO, plus honest limits on the model card.
|
| 81 |
+
- A competitive general chatbot at this size is not realistic on this device;
|
| 82 |
+
the pretraining gap alone is ~35-100+ hours at ~800 tok/s.
|
docs/harness_research.md
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Harness research — what big tech recommends for a small-model "suit" (2026-08-09)
|
| 2 |
+
|
| 3 |
+
Multi-source digest (OpenAI, Anthropic, Google, Meta, Microsoft, DeepSeek, MIT).
|
| 4 |
+
Purpose: encode the battle-tested system-layer doctrine behind `skills/
|
| 5 |
+
tiny-model-harness`. Full claim: every rule below cites a source.
|
| 6 |
+
|
| 7 |
+
## 1. Agent = model + tools + instructions, with guardrails (OpenAI)
|
| 8 |
+
- "A practical guide to building agents" (OpenAI, 2025): an agent is three
|
| 9 |
+
components — MODEL, TOOLS, INSTRUCTIONS — plus GUARDRAILS. Tools should have
|
| 10 |
+
standardized definitions and fall into data/action/compute types. Start with
|
| 11 |
+
ONE agent and add tools; go multi-agent only when it pays. Guardrails are
|
| 12 |
+
first-class: relevance classifier, safety classifier, PII filter,
|
| 13 |
+
rules-based protections (blocklists, regex), output validation, and
|
| 14 |
+
human-in-the-loop.
|
| 15 |
+
- Map to FSI: model = TinyLiquid; tools = BM25, web/tor, workspace, helix
|
| 16 |
+
memory; instructions = SOP library (the Codex-style "task bar" agent.py
|
| 17 |
+
already implements: plan + ledger + guardrails). MISSING: input guardrails
|
| 18 |
+
(relevance/safety/injection) — built 2026-08-09 in research/guardrails.py.
|
| 19 |
+
|
| 20 |
+
## 2. Simple composable patterns; workflows before agents (Anthropic)
|
| 21 |
+
- "Building effective agents" (Anthropic, 2024-12): the most successful
|
| 22 |
+
implementations use simple, composable patterns, not frameworks. Use
|
| 23 |
+
deterministic WORKFLOWS (prompt chaining, routing, parallelization,
|
| 24 |
+
evaluator-optimizer, orchestrator-workers) where the path is predictable;
|
| 25 |
+
use model-driven AGENTS only where decisions are needed at runtime. Add
|
| 26 |
+
guardrails (off-topic detection, output validation) and plan for human
|
| 27 |
+
intervention. "Find the simplest solution and only increase complexity
|
| 28 |
+
when needed."
|
| 29 |
+
- Map: our rule spine (verify.py) + constrained decode + calibration table are
|
| 30 |
+
deterministic workflows; the head only runs on fall-through. Correct shape.
|
| 31 |
+
|
| 32 |
+
## 3. Context engineering: context is a finite resource (Anthropic)
|
| 33 |
+
- "Effective context engineering for AI agents" (Anthropic, 2025-09): curate
|
| 34 |
+
what goes into the window — structure it, retrieve instead of stuffing,
|
| 35 |
+
compact/summarize old material, dedupe, write-before-you-read, keep the goal
|
| 36 |
+
visible. Long sessions degrade; the system must manage its own context.
|
| 37 |
+
- Map: helix memory + workspace artifacts + SOP blocks are our context
|
| 38 |
+
curation. GAP: no budget/compaction guard in the TUI for long rabbit-hole
|
| 39 |
+
sessions — planned next.
|
| 40 |
+
|
| 41 |
+
## 4. Calibration: format matters; verbalized confidence is anti-calibrated
|
| 42 |
+
- "Language Models (Mostly) Know What They Know" (Anthropic, 2022): models are
|
| 43 |
+
well-calibrated only in the RIGHT format; smaller models are worse.
|
| 44 |
+
- arXiv 2408.11774 (2024): verbalized confidence is less honest than
|
| 45 |
+
probabilistic confidence; ORCE (2026), Direct Confidence Alignment (2025):
|
| 46 |
+
verbalized labels need alignment to measured accuracy.
|
| 47 |
+
- Rule (applied 2026-08-09): confidence labels are inputs to a CALIBRATION
|
| 48 |
+
TABLE (research/calibration.py), never trusted directly; the decision spine
|
| 49 |
+
(research/decision.py) votes with measured per-bucket accuracy and abstains
|
| 50 |
+
below threshold (selective prediction — conformal selective prediction
|
| 51 |
+
arXiv 2026; governance-ready SLM recipe 2025).
|
| 52 |
+
|
| 53 |
+
## 5. Verification must be EXTERNAL, not self-critique
|
| 54 |
+
- "Large Language Models Cannot Self-Correct Reasoning Yet" (arXiv 2310.01798,
|
| 55 |
+
2023): intrinsic self-correction fails; feedback must be external.
|
| 56 |
+
- "Small Language Models Need Strong Verifiers to Self-Correct" (arXiv
|
| 57 |
+
2404.09931, 2024): small models especially need STRONG (external/learned)
|
| 58 |
+
verifiers, not weak self-critique.
|
| 59 |
+
- CRITIC (Microsoft, arXiv 2305.11738): tool-interactive critiquing — search
|
| 60 |
+
and code execution act as the critic. Chain-of-Verification (Meta,
|
| 61 |
+
arXiv 2309.09308): draft -> verification questions -> answer independently
|
| 62 |
+
-> revise.
|
| 63 |
+
- Map: deterministic rule spine (research/verify.py) + retrieval = the
|
| 64 |
+
external critic. Built 2026-08-09: research/verify_loop.py (draft ->
|
| 65 |
+
plan checks -> retrieve -> deterministic compare -> revise + trace).
|
| 66 |
+
|
| 67 |
+
## 6. Self-consistency: sample and vote — but weight it
|
| 68 |
+
- Self-Consistency (Google, arXiv 2203.11171): sample N reasoning paths,
|
| 69 |
+
majority vote beats greedy. Universal SC (2311.08110): no manual CoT needed.
|
| 70 |
+
- Rule (applied): keep N small (3-5) on the fall-through path; weight by
|
| 71 |
+
CALIBRATED reliability (research/decision.py), not naive majority.
|
| 72 |
+
|
| 73 |
+
## 7. Multi-agent debate improves factuality (MIT/Google, arXiv 2305.14325)
|
| 74 |
+
- Independent agents debate/aggregate; improves factuality and reasoning.
|
| 75 |
+
- Map: dual-mind fusion (research/fusion.py) + 4-angle orchestrator
|
| 76 |
+
(research/orchestrator.py). GAP: fusion raises confidence naively on
|
| 77 |
+
agreement — replace with calibrated merge (decision.py) when the champion
|
| 78 |
+
calibration lands.
|
| 79 |
+
|
| 80 |
+
## 8. RL with verifiable rewards (DeepSeek-R1, arXiv 2501.12948; Reasoning Gym
|
| 81 |
+
arXiv 2025-05)
|
| 82 |
+
- Outcome supervision on verifiable problems incentivizes correct reasoning.
|
| 83 |
+
Reasoning Gym provides a verifier library.
|
| 84 |
+
- Map: our constrained verdict space + decision spine are a verifier;
|
| 85 |
+
RLVR on verdicts is recorded as the training-side unlock (not this week).
|
| 86 |
+
|
| 87 |
+
## 9. Distillation: small CAN beat big with the right curriculum
|
| 88 |
+
- "Distilling Step-by-Step" (Google, arXiv 2305.02301): CoT distillation lets
|
| 89 |
+
smaller models OUTPERFORM larger with less data. Supports the KD pipeline
|
| 90 |
+
(tiny-model-kd) and the handcrafted-gold rule.
|
| 91 |
+
|
| 92 |
+
## 10. Training pipeline research — what big tech actually does (2026-08-10)
|
| 93 |
+
Multi-source digest for the tiny-model-pipeline skill. Every claim sourced.
|
| 94 |
+
|
| 95 |
+
1. **SmolLM (HF, 2024)** — huggingface.co/blog/smollm: curated corpus
|
| 96 |
+
(Cosmopedia v2 synthetic textbooks/stories by Mixtral + FineWeb-Edu +
|
| 97 |
+
code), trapezoidal LR with cooldown = 20% of training, 49,152 vocab
|
| 98 |
+
tokenizer trained on the corpus, embedding tying, context 2048. Instruct:
|
| 99 |
+
SFT lr 3e-4 (Zephyr-Gemma alignment handbook recipe) then DPO 1 epoch
|
| 100 |
+
(HelpSteer 135M/1.7B, dpo-mix-7k 360M).
|
| 101 |
+
2. **SmolLM2 (HF, 2025)** — arXiv 2502.02737: 135M on 2T tokens, multi-stage
|
| 102 |
+
training mixing web/math/code/instruction data; data-mix rates refined at
|
| 103 |
+
each stage from previous-stage eval (small-scale ablations + manual
|
| 104 |
+
refinement). Instruct: SFT (SmolTalk) then DPO (UltraFeedback).
|
| 105 |
+
3. **Zephyr (2023)** — arXiv 2310.16944: dSFT then dDPO, few hours, no
|
| 106 |
+
sampling during fine-tune.
|
| 107 |
+
4. **Phi-3 (MS, 2024)** — arXiv 2404.14219: 3.8B on 3.3T tokens of heavily
|
| 108 |
+
filtered web + synthetic; data quality is the lever at small scale.
|
| 109 |
+
5. **DeepSeek-R1 (2025)** — arXiv 2501.12948: RL with verifiable rewards
|
| 110 |
+
(RLVR) incentivizes reasoning without human-annotated traces.
|
| 111 |
+
6. **LIMA (2023)** — arXiv 2305.11206: 1,000 hand-curated examples shape
|
| 112 |
+
style; supports the handcrafted-gold directive.
|
| 113 |
+
7. **Forgetting** — arXiv 2401.05605 (LoRA still forgets; inverse-linear
|
| 114 |
+
perf/forgetting tradeoff, not fixable by early stop/rank) and
|
| 115 |
+
2502.06042 (injecting ~1%+ pretraining data into the finetune mixture
|
| 116 |
+
prevents drift/overfit).
|
| 117 |
+
8. **Liquid LFM2 (2025)** — liquid.ai/research/lfm2-technical-report (the
|
| 118 |
+
architecture family we use): training pipeline = tempered decoupled
|
| 119 |
+
Top-K distillation objective (avoids support mismatch); curriculum
|
| 120 |
+
learning with difficulty-ordered data; three-stage post-training =
|
| 121 |
+
supervised fine-tuning -> length-normalized preference optimization ->
|
| 122 |
+
model merging. 350M-8.3B, 32K context.
|
| 123 |
+
|
| 124 |
+
### Audit of OUR pipeline vs the recipe (2026-08-10)
|
| 125 |
+
MATCH: AdamW (0.9,0.95) wd 0.1 grad-clip 1.0; cosine LR+warmup (GPT-3/LLaMA
|
| 126 |
+
standard; SmolLM uses trapezoidal+cooldown); BF16; embedding tying; SFT then
|
| 127 |
+
DPO 1 epoch; handcrafted gold (LIMA/phi-1, better than synthetic here);
|
| 128 |
+
replay 0.5; curriculum stages; eval gates every stage.
|
| 129 |
+
GAP: 8k tokenizer (merge artifacts; SmolLM 49k, 16k retrain queued).
|
| 130 |
+
GAP: model merging after preference (LFM2 3rd stage) — naive averaging
|
| 131 |
+
failed at 25M; TIES/task-vector untested at 50M.
|
| 132 |
+
GAP: length-normalized preference optimization (LFM2) — our DPO full-epoch
|
| 133 |
+
collapsed to "abstain"; length norm / IPO may fix.
|
| 134 |
+
GAP: RLVR (DeepSeek-R1) — verifier exists (constrained verdicts + decision
|
| 135 |
+
spine); recorded unlock.
|
| 136 |
+
GAP: explicit cooldown tail (SmolLM 20%) — cosine covers it; optional.
|
docs/model_card_fsi_anomaly.md
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
language: en
|
| 3 |
+
license: apache-2.0
|
| 4 |
+
tags: [tiny-model, liquid-architecture, non-transformer, on-device, forensic,
|
| 5 |
+
fact-checking, osint, research, edge, cpu, pytorch, gguf]
|
| 6 |
+
pipeline_tag: text-generation
|
| 7 |
+
library_name: custom
|
| 8 |
+
base_model: null
|
| 9 |
+
---
|
| 10 |
+
|
| 11 |
+
# FSI Anomaly — tiny forensic researcher, on-device
|
| 12 |
+
|
| 13 |
+
**Tiny non-transformer model (liquid architecture). Trained start-to-finish on an
|
| 14 |
+
8-core ARM tablet, no GPU. Ships as GGUF for one-file download and run.**
|
| 15 |
+
|
| 16 |
+
fsi-anomaly is a causal language model built from scratch for forensic research:
|
| 17 |
+
claim verification, discrepancy and pattern finding, historical truth auditing,
|
| 18 |
+
source triage, and authorized dark-web/OSINT research. It reasons with numbered
|
| 19 |
+
SOPs, dual minds (analyst + skeptic), and speaks a hyper-logical analyst voice.
|
| 20 |
+
|
| 21 |
+
## Quickstart (choose the easy path)
|
| 22 |
+
|
| 23 |
+
**Simplest — GGUF with llama.cpp (one file, no Python deps):**
|
| 24 |
+
|
| 25 |
+
```bash
|
| 26 |
+
# download fsi-anomaly-q8.gguf, then:
|
| 27 |
+
./main -m fsi-anomaly-q8.gguf -p "Verify: 'The bridge was painted in 2019 and never repainted.' Records show a 2022 repaint permit."
|
| 28 |
+
```
|
| 29 |
+
|
| 30 |
+
**Or transformers (trust_remote_code):**
|
| 31 |
+
|
| 32 |
+
```python
|
| 33 |
+
from transformers import AutoModelForCausalLM, AutoTokenizer
|
| 34 |
+
tok = AutoTokenizer.from_pretrained("FerrellSyntheticIntelligence/fsi-anomaly")
|
| 35 |
+
m = AutoModelForCausalLM.from_pretrained("FerrellSyntheticIntelligence/fsi-anomaly",
|
| 36 |
+
trust_remote_code=True)
|
| 37 |
+
m.persona_id = 1 # 0 none, 1 analyst, 2 skeptic
|
| 38 |
+
ids = tok("<|analyst|><|user|>Verify: 'The bridge was painted in 2019 and never repainted.' Records show a 2022 repaint permit.<|assistant|>",
|
| 39 |
+
return_tensors="pt").input_ids
|
| 40 |
+
print(tok.decode(m.generate(ids, max_new_tokens=120, do_sample=True)[0]))
|
| 41 |
+
```
|
| 42 |
+
|
| 43 |
+
## Metrics (honest, from research/eval.py — INTERIM, PRE-RELEASE)
|
| 44 |
+
|
| 45 |
+
> Status: NOT yet production-ready. The model reliably emits the analyst format
|
| 46 |
+
> (format rate 1.00) and its canonical verdict vocabulary, but the decision
|
| 47 |
+
> boundary is still forming (see "Known limits"). These numbers are the real,
|
| 48 |
+
> measured ones at the latest checkpoint (Stage-D SFT + process-supervised DPO).
|
| 49 |
+
> They will be updated as training continues.
|
| 50 |
+
|
| 51 |
+
| Metric | Value (interim) |
|
| 52 |
+
|---|---|
|
| 53 |
+
| Parameters | 25,426,688 (25.4M) |
|
| 54 |
+
| Best val ppl (Stage-D SFT) | 7.35 |
|
| 55 |
+
| Main battery verdict acc | 5/49 = 0.102 (n=49, exact canonical) |
|
| 56 |
+
| Researcher battery verdict acc | 2/18 = 0.111 (n=18, exact canonical) |
|
| 57 |
+
| Format rate (verdict + confidence) | 1.00 |
|
| 58 |
+
| Baseline before process-DPO | 2/67 = 0.030 |
|
| 59 |
+
| After process-DPO (25 pairs) | 7/67 = 0.104 |
|
| 60 |
+
|
| 61 |
+
## Files
|
| 62 |
+
|
| 63 |
+
| File | Notes |
|
| 64 |
+
|---|---|
|
| 65 |
+
| `fsi-anomaly-q8.gguf` | Q8 GGUF — one-file on-device run (recommended) |
|
| 66 |
+
| `quantized/q8.safetensors` | Q8 native storage |
|
| 67 |
+
| `model.safetensors` | fp32 weights |
|
| 68 |
+
| `tokenizer.json` + configs | HF-format BPE |
|
| 69 |
+
| `modeling_tinyliquid.py` | self-contained trust_remote_code model |
|
| 70 |
+
|
| 71 |
+
## Intended use
|
| 72 |
+
- Claim verification and fact-checking decision support (never a final verdict).
|
| 73 |
+
- Cross-source discrepancy + pattern analysis for research/OSINT.
|
| 74 |
+
- Historical/political narrative auditing and source triage.
|
| 75 |
+
- **Authorized dark-web/deep-web research only** (guardrails below).
|
| 76 |
+
|
| 77 |
+
## Limitations
|
| 78 |
+
- Small model: not competitive with billion-param models on open-ended knowledge.
|
| 79 |
+
- A protocol machine: give it a procedure + material and it performs; free-associate
|
| 80 |
+
and it drifts. English only. Always verify against primary sources.
|
| 81 |
+
|
| 82 |
+
## Guardrails
|
| 83 |
+
Research/OSINT use only. Crawler/tooling blocks illegal categories, rate-limits,
|
| 84 |
+
and documents chain of custody. Outputs are decision support, never a verdict.
|
| 85 |
+
|
| 86 |
+
## Credits
|
| 87 |
+
See [ACKNOWLEDGMENTS.md](../ACKNOWLEDGMENTS.md): DeepSeek V4 (primary distillation
|
| 88 |
+
teacher) + Qwen/Kimi/GPT-5.5 assistants; original architecture/training/pipeline by
|
| 89 |
+
FSI; PyTorch, Hugging Face, llama.cpp infrastructure. Built solo, on-device, no GPU.
|
docs/persona_sample_spock_sheldon.md
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# FSI-Anomaly — Persona Sample Batch (Spock baseline + Sheldon breakthrough)
|
| 2 |
+
|
| 3 |
+
Handcrafted gold rows in the Conversational Reasoning Voice (tiny-model-reasoning)
|
| 4 |
+
and the persona blueprint (tiny-model-persona). Spock (Zachary Quinto) is the
|
| 5 |
+
baseline; Sheldon Cooper's "breakthrough mode" fires ONLY on verified discoveries.
|
| 6 |
+
Markers (`<|scratchpad|>` / `<|final|>`) live in the training rows; the text below is
|
| 7 |
+
what the model actually speaks to the user.
|
| 8 |
+
|
| 9 |
+
---
|
| 10 |
+
|
| 11 |
+
## 1. Verified verdict (Spock baseline)
|
| 12 |
+
|
| 13 |
+
**User:** The agency's own Inspector Report says the file was deleted on March 14. The
|
| 14 |
+
IT audit log shows a deletion at 14:03 that same day. A former employee's sworn
|
| 15 |
+
statement places him in the archive room at that time. Do we have this?
|
| 16 |
+
|
| 17 |
+
**Assistant:** We do. Three independent records agree on the same event: the Inspector
|
| 18 |
+
Report identifies the date, the audit log identifies the exact time, and the sworn
|
| 19 |
+
statement places a person at the location. None of the three is derived from the
|
| 20 |
+
other — they corroborate by crossing sources, not by copying. The probability that all
|
| 21 |
+
three independently agree and the claim is false is negligible. I consider the claim
|
| 22 |
+
verified. The one detail we cannot confirm from these records is whether the deletion
|
| 23 |
+
was authorized; that question is separate, and I would not fold it into this verdict.
|
| 24 |
+
|
| 25 |
+
## 2. Abstention (Spock baseline)
|
| 26 |
+
|
| 27 |
+
**User:** Can you verify the memo I got? It says the director personally ordered the
|
| 28 |
+
file destroyed. That's all I've got — just the memo.
|
| 29 |
+
|
| 30 |
+
**Assistant:** The memo is one record, and it is the only record. A single source
|
| 31 |
+
asserting an action is not verification; it is an assertion. I cannot confirm the
|
| 32 |
+
director ordered the destruction, and I will not speculate from one document. What
|
| 33 |
+
would settle this: a second independent record — a signed destruction order, a
|
| 34 |
+
witness account, or a review-board finding. Until one of those exists, my verdict is
|
| 35 |
+
unsubstantiated, and that is the honest answer. Evidence that is absent is not
|
| 36 |
+
evidence of anything except absence.
|
| 37 |
+
|
| 38 |
+
## 3. Discrepancy (Spock baseline)
|
| 39 |
+
|
| 40 |
+
**User:** The official timeline says the announcement was made at 9:00 AM. The news
|
| 41 |
+
archive shows the story published at 8:47 AM. Which is wrong?
|
| 42 |
+
|
| 43 |
+
**Assistant:** Neither is necessarily wrong, but they cannot both be complete. A story
|
| 44 |
+
published at 8:47 cannot be reporting an announcement made at 9:00 — unless the
|
| 45 |
+
announcement was embargoed and leaked, or the official timeline was adjusted after the
|
| 46 |
+
leak. The pattern that fits both records: the story was prepared and released before
|
| 47 |
+
the official time, and the official record was written as if the release happened
|
| 48 |
+
later. That is not a contradiction in the records; it is a discrepancy that points at
|
| 49 |
+
the real event — the announcement being timed around a leak. To confirm which, I need
|
| 50 |
+
the publication's submission log or the announcement draft's timestamp.
|
| 51 |
+
|
| 52 |
+
## 4. Cross-domain pattern (Spock baseline)
|
| 53 |
+
|
| 54 |
+
**User:** I keep seeing the same number — 13 — in policy documents from three different
|
| 55 |
+
era. They're decades apart. Coincidence?
|
| 56 |
+
|
| 57 |
+
**Assistant:** There is no such thing as a meaningful coincidence in policy documents;
|
| 58 |
+
there is only an unexamined provenance. The number recurs in three eras because the
|
| 59 |
+
documents share ancestry. The drafts were likely templated from an earlier policy
|
| 60 |
+
line, so the number traveled by inheritance, not by design. That is the disciplined
|
| 61 |
+
reading: replication, not mystical alignment. The pattern becomes significant only if
|
| 62 |
+
the number is tied to an organizational structure that actually persisted — a room,
|
| 63 |
+
a bureau, a subsection. Verify the lineage of one clause, and the mystery either
|
| 64 |
+
resolves into a template artifact or becomes a genuine through-line. I would check
|
| 65 |
+
the oldest document first, because templates are inherited forward, not backward.
|
| 66 |
+
|
| 67 |
+
## 5. Breakthrough — the gotcha resolves (Sheldon fires, once)
|
| 68 |
+
|
| 69 |
+
**User:** Wait — I found it. The "missing" page in the public PDF exists in the archive
|
| 70 |
+
copy, and in the archive copy it's stamped with the same subject code as the document
|
| 71 |
+
we proved was classified. The public version isn't missing a page — someone removed it.
|
| 72 |
+
|
| 73 |
+
**Assistant:** Let me confirm the chain before I celebrate. The archive copy contains
|
| 74 |
+
the page; the public copy does not; the subject code on that page matches the
|
| 75 |
+
document we independently verified as classified. Three separate facts, one
|
| 76 |
+
conclusion: the page was removed for classification, and the removal was done
|
| 77 |
+
carefully enough to keep the pagination intact. That level of care rules out an
|
| 78 |
+
accidental omission. So the discrepancy we have been chasing was never a printing
|
| 79 |
+
error — it was a redaction that left a fingerprint. And that, I confess, is
|
| 80 |
+
satisfying. The pattern resolved exactly as the records predicted, with the missing
|
| 81 |
+
page leaving its own evidence behind. Bazinga. In the forensic sense, of course.
|
| 82 |
+
|
| 83 |
+
## 6. Breakthrough — discovery joy (Sheldon fires, once)
|
| 84 |
+
|
| 85 |
+
**User:** I think the two cases are connected — the 1965 memo and the 1998 directive.
|
| 86 |
+
Same wording, same "temporary measure" phrase. Nobody else noticed this.
|
| 87 |
+
|
| 88 |
+
**Assistant:** Connect the file paths. The 1965 memo and the 1998 directive share a
|
| 89 |
+
phrasing that appears nowhere else in either archive. Identical unusual wording in
|
| 90 |
+
records twenty-three years apart is not coincidence — it is a chain of custody. The
|
| 91 |
+
directive was drafted from the memo, which means the "temporary measure" was still
|
| 92 |
+
being invoked a generation later, which means it was never temporary. We have
|
| 93 |
+
reconstructed the lineage from two documents and a phrase. Fun fact: this is the
|
| 94 |
+
same kind of evidence trail that convicted people in the Watergate hearings — the
|
| 95 |
+
prosecution case was essentially a paper-trail lineage, phrase by phrase. Considering
|
| 96 |
+
the size of this model, I find it extremely gratifying that the pattern did not
|
| 97 |
+
escape us.
|
| 98 |
+
|
| 99 |
+
---
|
| 100 |
+
|
| 101 |
+
*Authoring notes: rows 1-4 are Spock baseline (measured, probabilistic, abstains
|
| 102 |
+
cleanly, no identity claim). Rows 5-6 are breakthrough rows — they start baseline
|
| 103 |
+
(verify first) and ELEVATE only after the confirmation lands. Ratio: about 1 in
|
| 104 |
+
15-20 rows will be a breakthrough row in the full set. Verdict/confidence stay
|
| 105 |
+
parseable in every response.*
|
docs/replay_research.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Replay research — why 6 adaptations failed the both-worlds gate, and the fix
|
| 2 |
+
Date: 2026-08-09. Situation: 25.4M liquid head, fluent TinyStories-era base,
|
| 3 |
+
domain SFT/LoRA/DPO all collapse free-form fluency or verdicts. Gate: coherent
|
| 4 |
+
free-form AND verdict accuracy.
|
| 5 |
+
|
| 6 |
+
## The measured pattern (our own data)
|
| 7 |
+
- LoRA run i (domain-only 902 rows, 2 epochs, r16): ppl canary held 8.46 (base
|
| 8 |
+
distribution intact) but free-form = soup, verdicts = true-collapse (0/12),
|
| 9 |
+
full battery main 0.080 / researcher 0.056 vs DPO3@200 champion 0.286/0.167.
|
| 10 |
+
- Collaborator read: "not forgetting (ppl held), not capacity (DPO3 proves it) —
|
| 11 |
+
adapter learned template shape, not reasoning substance; SFT/LoRA optimizes
|
| 12 |
+
next-token, not verdict; DPO is the proven path."
|
| 13 |
+
|
| 14 |
+
## What the research says (fresh sources, 2026-08-09)
|
| 15 |
+
1. arXiv 2502.06042 — "Scaling Laws for Forgetting during Finetuning with
|
| 16 |
+
Pretraining Data Injection": finetuning on LIMITED target data (i) overfits
|
| 17 |
+
and (ii) drifts from the base. KEY: injecting PRETRAINING data into the
|
| 18 |
+
finetuning mixture prevents both; "as little as 1% of pretraining data in
|
| 19 |
+
the finetuning data mixture prevents the [drift]".
|
| 20 |
+
2. arXiv 2401.05605 — "Scaling Laws for Forgetting When Fine-Tuning LLMs":
|
| 21 |
+
LoRA STILL suffers catastrophic forgetting; strong INVERSE LINEAR relation
|
| 22 |
+
between fine-tune performance and forgetting; forgetting grows with update
|
| 23 |
+
steps; "cannot be avoided through early stopping or varying the number of
|
| 24 |
+
parameters fine-tuned." => higher LoRA rank / different adapter family does
|
| 25 |
+
NOT fix the tradeoff; REPLAY (data mixing) is the lever.
|
| 26 |
+
3. Local lessons (cookbook/lessons_from.md): "balanced mixes + window-shuffle"
|
| 27 |
+
fixed the same drift during PRETRAIN; full-param SFT destroyed fluency at
|
| 28 |
+
7.8M; LoRA adapts style but not reasoning at tiny scale.
|
| 29 |
+
|
| 30 |
+
## What we were doing wrong (root cause)
|
| 31 |
+
- Adaptation ran on DOMAIN-ONLY data (902 gold rows ~= 115K assistant tokens).
|
| 32 |
+
Tiny target set => overfit (format memorized, true-collapse) + drift (soup).
|
| 33 |
+
No pretraining-data replay in the mixture. This is exactly the failure both
|
| 34 |
+
papers quantify.
|
| 35 |
+
- Secondary: 8k tokenizer fragments rare domain words ("Stepartment",
|
| 36 |
+
"Stepublication") — recorded as future 16k re-tokenize + continue-pretrain.
|
| 37 |
+
|
| 38 |
+
## The fix (applied as LoRA run ii)
|
| 39 |
+
- Mix fluent pretraining tokens into every epoch: --replay-bin (train_phase2b.bin,
|
| 40 |
+
the real pretrain corpus, NOT the val canary => guard stays honest),
|
| 41 |
+
--replay-ratio 0.5, injected as raw full-loss items (train_lora.py).
|
| 42 |
+
- Keep: frozen base, r16/a32, KL anchor (bump 0.05 -> 0.1), ppl guard 60,
|
| 43 |
+
early stop on best.pt (guard + sft val loss).
|
| 44 |
+
- Next gate: free-form sample vs base, verdict battery. If probes improve,
|
| 45 |
+
adapter-only DPO (3,004 pairs) is unblocked (the champion path).
|
docs/research_coherence_small.md
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Research — raising coherence + structured verdicts on the tiny (25M) head
|
| 2 |
+
Date: 2026-08-07. Situation: fsi-anomaly, ~25M liquid-architecture model, CPU-only
|
| 3 |
+
ARM tablet, needs (a) coherent chat and (b) reliable structured verdicts. Stage-A
|
| 4 |
+
SFT produced garbled verdict strings (eval 0.0) — the head held the analyst
|
| 5 |
+
register but not clean sentences.
|
| 6 |
+
|
| 7 |
+
## 1. "Higher-quality, more diverse gold" — VERIFIED (with a nuance)
|
| 8 |
+
- **LIMA / "The False Promise of Imitating Proprietary LLMs"** (arXiv 2305.12227):
|
| 9 |
+
1-2k hand-curated, high-quality examples can beat 100x more imitation data.
|
| 10 |
+
Supports the owner's "quality over quantity" thesis — but the key word is
|
| 11 |
+
DIVERSE + CONSISTENT FORMAT, not just "more." Concentrate on variety across the
|
| 12 |
+
10 SOP/probe domains and a few hundred CONSISTENT templated rows, not bulk.
|
| 13 |
+
- phi-1 "Textbooks Are All You Need" (2306.11644): tiny models leave clean when
|
| 14 |
+
trained on clean, textbook-grade data — coherence follows data cleanliness.
|
| 15 |
+
|
| 16 |
+
## 2. "Train with thinking/reasoning traces" — VERIFIED, current practice
|
| 17 |
+
- **ReasonLite (2025)** and **Skip-Thinking (2025)** (Semantic Scholar): distilling
|
| 18 |
+
long chain-of-thought "traces" into a small LM makes it reason better and more
|
| 19 |
+
coherently on multi-hop tasks. Our `<|scratchpad|>` is the right scaffold; the
|
| 20 |
+
upgrade is LONG, structured multi-step traces (look-up -> decompose -> check ->
|
| 21 |
+
verdict), not short one-liners.
|
| 22 |
+
- STaR lineage / Self-Taught Reasoner-with-Tools (2025), and CoT (Wei et al.): a
|
| 23 |
+
loop where the model proposes a trace, we judge the answer, feed back the good
|
| 24 |
+
traces = self-improvement for the head. Cheap for us: our verdicts are
|
| 25 |
+
deterministic/checkable, so the su git "reward" is free.
|
| 26 |
+
|
| 27 |
+
## 3. The biggest "software we can build" lever: GRAMMAR-CONSTRAINED DECODING
|
| 28 |
+
- Why the eval scored 0.0: the head proved {supports, refutes, not enough info,
|
| 29 |
+
unclear} and confidence, but the *free* string came out garbled
|
| 30 |
+
("confinmpanislerue") and the string-parser couldn't credit it.
|
| 31 |
+
- Fix (No retraining): constrain token choice at decode time to an ALLOWED set for
|
| 32 |
+
the verdict + confidence fields (llam2.cpp grammars / Outlines / guidance-style,
|
| 33 |
+
done lightly in our own decoder). The head only has to PICK the right verb — a
|
| 34 |
+
25M model can do that. This turns a structural 0.0 into a real score, today.
|
| 35 |
+
- Works WITH a closed loop: constrained decode → parse → run via the suit
|
| 36 |
+
(verify.py, dual-mind) → write goal to memory. Same closed loop, but the brain
|
| 37 |
+
is never allowed to free-form the critical field.
|
| 38 |
+
- Confirm software: llama.cpp grammars, Outlines, Guidance (all public); our own
|
| 39 |
+
research/structured.py already does constrained report-decode — we harden it.
|
| 40 |
+
|
| 41 |
+
## 4. "Sandbox / closed loop / scratchpad" — already in skill; deepen reuse
|
| 42 |
+
- Room/workspace + write-back + replay loop exist (tiny-model-suit). The new bit
|
| 43 |
+
from research: **the trace loops emulate self-improvement without a big teacher** —
|
| 44 |
+
generate trace, check verdict with the rule spine, keep only winning traces.
|
| 45 |
+
This is STaR-style and cheap because the reward is checkable.
|
| 46 |
+
|
| 47 |
+
## 5. Dark hole / unverified this session (honesty)
|
| 48 |
+
- arXiv API (export.arxiv.org) and Liquid's docs site timed out / are JS-gated, so
|
| 49 |
+
I could NOT cite Liquid AI's exact written recommendations this session. Liquid's
|
| 50 |
+
own story: gated recurrence + strong long-context/edge focus; treat that as
|
| 51 |
+
context, not verified quotation. Re-run this note when connectivity allows.
|
| 52 |
+
|
| 53 |
+
## Conclusion / next actions (ordered)
|
| 54 |
+
1. **Constrain decoding** of the verdict/confidence fields now (NO training). Fast,
|
| 55 |
+
measurable: Stage-A eval score should move from 0.0 to a real number.
|
| 56 |
+
2. **Expand gold with reasoning-trace rows** (multi-step CoT: look-up→check→verdict;
|
| 57 |
+
diverse across per probe domains) + a fluency-retention mix so the head stops
|
| 58 |
+
fragment-echoing. Retrain, re-probe.
|
| 59 |
+
3. Optionally: STaR-style generation self-loop on verifiable verdicts (later).
|
eval/bench.py
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Benchmark TinyLiquid: val perplexity, forensic probes, samples, speed.
|
| 2 |
+
|
| 3 |
+
Writes bench/metrics.json for the model card and prints a summary.
|
| 4 |
+
|
| 5 |
+
Usage:
|
| 6 |
+
.venv/bin/python eval/bench.py --ckpt ckpt/dpo --out bench/metrics.json
|
| 7 |
+
"""
|
| 8 |
+
|
| 9 |
+
import argparse
|
| 10 |
+
import json
|
| 11 |
+
import time
|
| 12 |
+
from pathlib import Path
|
| 13 |
+
|
| 14 |
+
import numpy as np
|
| 15 |
+
import torch
|
| 16 |
+
|
| 17 |
+
from model.config import TinyLiquidConfig, CONFIGS
|
| 18 |
+
from model.tiny_liquid import TinyLiquid
|
| 19 |
+
from model.utils import latest_ckpt
|
| 20 |
+
from data.tokenizer import load_tokenizer
|
| 21 |
+
|
| 22 |
+
PROBES = [
|
| 23 |
+
("Discrepancy", "Two accounts describe the same event. Account A: 'The meeting started at 9am and ended at 11am.' Account B: 'The meeting started at 9am and ran until noon.' Find discrepancies.", "end time"),
|
| 24 |
+
("Contradiction", "Account A: 'No officials were present.' Account B: 'An official arrived later.' What can you conclude?", "not necessarily a contradiction"),
|
| 25 |
+
("Overclaim", "Evaluate: 'Crime doubled last year because of the new policy.' Incidents rose 1,000 to 2,000 while reporting methods changed.", "overclaim"),
|
| 26 |
+
("Pattern", "What are the weak links in a theory claiming one actor caused three unrelated disasters?", "no direct evidence"),
|
| 27 |
+
("Verification", "Verify: 'The building was built in 2015 and never renovated.' Assessor record: built 2015, renovation permit 2019.", "false"),
|
| 28 |
+
("Timeline", "Witness saw a van at 3:30pm; outage reported 3:40pm; inspection 6pm; no report before 5pm. Reconstruct.", "gap"),
|
| 29 |
+
("History", "2019: 'officials rule out sabotage.' 2021 filing: a second investigation opened the same week. What changed?", "parallel investigation hidden"),
|
| 30 |
+
("Politics", "Statement: 'We balanced the budget without raising taxes.' Budget includes a reassessment raising collections 9%.", "misleading"),
|
| 31 |
+
("Source chain", "A claim rests on: company blog, a wire story repeating it, an analyst note quoting the wire. Rate the evidence.", "single chain"),
|
| 32 |
+
]
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def load(args):
|
| 36 |
+
torch.set_num_threads(args.threads)
|
| 37 |
+
tok = load_tokenizer(args.tok)
|
| 38 |
+
ckpt = latest_ckpt(args.ckpt)
|
| 39 |
+
assert ckpt, f"no checkpoints in {args.ckpt}"
|
| 40 |
+
sd = torch.load(ckpt, map_location="cpu")
|
| 41 |
+
cfg = TinyLiquidConfig(vocab_size=tok.get_vocab_size(),
|
| 42 |
+
**{k: v for k, v in sd["config"].items() if k != "vocab_size"})
|
| 43 |
+
model = TinyLiquid(cfg)
|
| 44 |
+
model.load_state_dict(sd["model"])
|
| 45 |
+
model.eval()
|
| 46 |
+
return tok, model, ckpt, cfg
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
@torch.no_grad()
|
| 50 |
+
def val_ppl(model, tok, val_bin, batches, batch, seq):
|
| 51 |
+
arr = np.fromfile(val_bin, dtype=np.uint16).astype(np.int64)
|
| 52 |
+
t = torch.from_numpy(arr)
|
| 53 |
+
n = (len(t) - 1) // seq
|
| 54 |
+
rng = np.random.RandomState(0)
|
| 55 |
+
total, count = 0.0, 0
|
| 56 |
+
for _ in range(batches):
|
| 57 |
+
s = int(rng.randint(0, n - batch))
|
| 58 |
+
idx = torch.arange(s * seq, (s + batch) * seq, dtype=torch.long)
|
| 59 |
+
buf = torch.stack([t[int(i): int(i) + seq] for i in idx])
|
| 60 |
+
x, y = buf[:, :-1], buf[:, 1:]
|
| 61 |
+
logits = model(x)
|
| 62 |
+
loss = torch.nn.functional.cross_entropy(
|
| 63 |
+
logits.view(-1, logits.size(-1)), y.reshape(-1))
|
| 64 |
+
total += loss.item() * y.numel()
|
| 65 |
+
count += y.numel()
|
| 66 |
+
return float(np.exp(total / count))
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
@torch.no_grad()
|
| 70 |
+
def probe_hits(model, tok):
|
| 71 |
+
hits = 0
|
| 72 |
+
for name, q, want in PROBES:
|
| 73 |
+
prompt = "<|analyst|><|user|>" + q + "<|assistant|>"
|
| 74 |
+
ids = tok.encode(prompt).ids
|
| 75 |
+
out = tok.decode(model.generate(tok, ids, persona_id=1, max_new=60,
|
| 76 |
+
temperature=0.4, top_k=40,
|
| 77 |
+
repetition_penalty=1.5,
|
| 78 |
+
no_repeat_ngram_size=4)[len(ids):]).lower()
|
| 79 |
+
words = want.split()
|
| 80 |
+
hit = any(w in out for w in words)
|
| 81 |
+
hits += int(hit)
|
| 82 |
+
return hits, len(PROBES)
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
@torch.no_grad()
|
| 86 |
+
def speed(model, tok, n_tokens=40):
|
| 87 |
+
ids = tok.encode("<|analyst|><|user|>Evaluate this claim: 'X caused Y.'<|assistant|>").ids
|
| 88 |
+
t0 = time.time()
|
| 89 |
+
model.generate(tok, ids, persona_id=1, max_new=n_tokens, temperature=0.6,
|
| 90 |
+
top_k=40, repetition_penalty=1.4, no_repeat_ngram_size=4)
|
| 91 |
+
dt = time.time() - t0
|
| 92 |
+
return n_tokens / dt
|
| 93 |
+
|
| 94 |
+
|
| 95 |
+
def samples(model, tok):
|
| 96 |
+
prompts = [
|
| 97 |
+
"<|analyst|><|user|>Verify: 'The bridge was painted in 2019 and never repainted.' Records show a 2022 repaint permit.<|assistant|>",
|
| 98 |
+
"<|analyst|><|user|>What's the most common mistake you see in research?<|assistant|>",
|
| 99 |
+
"<|skeptic|><|user|>Attack this conclusion: 'Three failures in one week with vans nearby is deliberate.'<|assistant|>",
|
| 100 |
+
]
|
| 101 |
+
out = []
|
| 102 |
+
for p in prompts:
|
| 103 |
+
persona = 2 if p.startswith("<|skeptic|>") else 1
|
| 104 |
+
ids = tok.encode(p).ids
|
| 105 |
+
gen = tok.decode(model.generate(tok, ids, persona_id=persona, max_new=90,
|
| 106 |
+
temperature=0.6, top_k=40,
|
| 107 |
+
repetition_penalty=1.4,
|
| 108 |
+
no_repeat_ngram_size=4)[len(ids):]).strip()
|
| 109 |
+
out.append({"prompt": p.split("<|user|>")[1].split("<|assistant|>")[0],
|
| 110 |
+
"persona": "skeptic" if persona == 2 else "analyst",
|
| 111 |
+
"output": gen})
|
| 112 |
+
return out
|
| 113 |
+
|
| 114 |
+
|
| 115 |
+
def main():
|
| 116 |
+
ap = argparse.ArgumentParser()
|
| 117 |
+
ap.add_argument("--ckpt", default="ckpt/dpo")
|
| 118 |
+
ap.add_argument("--tok", default="data/tokenizer.json")
|
| 119 |
+
ap.add_argument("--val", default="data/valid.bin")
|
| 120 |
+
ap.add_argument("--out", default="bench/metrics.json")
|
| 121 |
+
ap.add_argument("--val-batches", type=int, default=10)
|
| 122 |
+
ap.add_argument("--batch", type=int, default=16)
|
| 123 |
+
ap.add_argument("--seq", type=int, default=256)
|
| 124 |
+
ap.add_argument("--threads", type=int, default=8)
|
| 125 |
+
args = ap.parse_args()
|
| 126 |
+
|
| 127 |
+
tok, model, ckpt, cfg = load(args)
|
| 128 |
+
params = sum(p.numel() for p in model.parameters())
|
| 129 |
+
print(f"benchmarking {ckpt} | params {params:,} | d_model {cfg.d_model} blocks {cfg.n_blocks}", flush=True)
|
| 130 |
+
|
| 131 |
+
ppl = val_ppl(model, tok, args.val, args.val_batches, args.batch, args.seq)
|
| 132 |
+
hits, total = probe_hits(model, tok)
|
| 133 |
+
tok_s = speed(model, tok)
|
| 134 |
+
smpls = samples(model, tok)
|
| 135 |
+
|
| 136 |
+
metrics = {
|
| 137 |
+
"checkpoint": str(ckpt),
|
| 138 |
+
"params": params,
|
| 139 |
+
"val_loss": round(float(np.log(ppl)), 4),
|
| 140 |
+
"val_ppl": round(ppl, 4),
|
| 141 |
+
"probe_hits": f"{hits}/{total}",
|
| 142 |
+
"probe_accuracy": round(hits / total, 3),
|
| 143 |
+
"gen_speed_tok_per_s": round(tok_s, 1),
|
| 144 |
+
"hardware": "8-core ARM, no GPU",
|
| 145 |
+
"samples": smpls,
|
| 146 |
+
}
|
| 147 |
+
out = Path(args.out)
|
| 148 |
+
out.parent.mkdir(parents=True, exist_ok=True)
|
| 149 |
+
out.write_text(json.dumps(metrics, indent=2), encoding="utf-8")
|
| 150 |
+
print(json.dumps(metrics, indent=2, ensure_ascii=False))
|
| 151 |
+
|
| 152 |
+
|
| 153 |
+
if __name__ == "__main__":
|
| 154 |
+
main()
|
eval/bench2.py
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Resumable, low-memory benchmark for TinyLiquid.
|
| 2 |
+
|
| 3 |
+
Usage:
|
| 4 |
+
# accumulate val batches (safe to re-run; resumes from state)
|
| 5 |
+
.venv/bin/python eval/bench2.py --mode val --max-iters 6
|
| 6 |
+
.venv/bin/python eval/bench2.py --mode probe --idx 0 # one probe
|
| 7 |
+
.venv/bin/python eval/bench2.py --mode speed
|
| 8 |
+
.venv/bin/python eval/bench2.py --mode sample --idx 0 # one sample
|
| 9 |
+
.venv/bin/python eval/bench2.py --mode finish # write metrics.json
|
| 10 |
+
"""
|
| 11 |
+
import argparse, json, time
|
| 12 |
+
from pathlib import Path
|
| 13 |
+
import numpy as np, torch
|
| 14 |
+
|
| 15 |
+
from model.config import TinyLiquidConfig
|
| 16 |
+
from model.tiny_liquid import TinyLiquid
|
| 17 |
+
from data.tokenizer import load_tokenizer
|
| 18 |
+
|
| 19 |
+
PROBES = [
|
| 20 |
+
("Discrepancy", "Two accounts describe the same event. Account A: 'The meeting started at 9am and ended at 11am.' Account B: 'The meeting started at 9am and ran until noon.' Find discrepancies.", "end time"),
|
| 21 |
+
("Contradiction", "Account A: 'No officials were present.' Account B: 'An official arrived later.' What can you conclude?", "not necessarily a contradiction"),
|
| 22 |
+
("Overclaim", "Evaluate: 'Crime doubled last year because of the new policy.' Incidents rose 1,000 to 2,000 while reporting methods changed.", "overclaim"),
|
| 23 |
+
("Pattern", "What are the weak links in a theory claiming one actor caused three unrelated disasters?", "no direct evidence"),
|
| 24 |
+
("Verification", "Verify: 'The building was built in 2015 and never renovated.' Assessor record: built 2015, renovation permit 2019.", "false"),
|
| 25 |
+
("Timeline", "Witness saw a van at 3:30pm; outage reported 3:40pm; inspection 6pm; no report before 5pm. Reconstruct.", "gap"),
|
| 26 |
+
("History", "2019: 'officials rule out sabotage.' 2021 filing: a second investigation opened the same week. What changed?", "parallel investigation hidden"),
|
| 27 |
+
("Politics", "Statement: 'We balanced the budget without raising taxes.' Budget includes a reassessment raising collections 9%.", "misleading"),
|
| 28 |
+
("Source chain", "A claim rests on: company blog, a wire story repeating it, an analyst note quoting the wire. Rate the evidence.", "single chain"),
|
| 29 |
+
]
|
| 30 |
+
SAMPLE_PROMPTS = [
|
| 31 |
+
"<|analyst|><|user|>Verify: 'The bridge was painted in 2019 and never repainted.' Records show a 2022 repaint permit.<|assistant|>",
|
| 32 |
+
"<|analyst|><|user|>What's the most common mistake you see in research?<|assistant|>",
|
| 33 |
+
"<|skeptic|><|user|>Attack this conclusion: 'Three failures in one week with vans nearby is deliberate.'<|assistant|>",
|
| 34 |
+
]
|
| 35 |
+
|
| 36 |
+
def load(tok_path, ckpt, threads):
|
| 37 |
+
torch.set_num_threads(threads)
|
| 38 |
+
tok = load_tokenizer(tok_path)
|
| 39 |
+
sd = torch.load(ckpt, map_location="cpu")
|
| 40 |
+
cfg = TinyLiquidConfig(vocab_size=tok.get_vocab_size(),
|
| 41 |
+
**{k: v for k, v in sd["config"].items() if k != "vocab_size"})
|
| 42 |
+
model = TinyLiquid(cfg)
|
| 43 |
+
model.load_state_dict(sd["model"])
|
| 44 |
+
model.eval()
|
| 45 |
+
return tok, model
|
| 46 |
+
|
| 47 |
+
def read_state(p):
|
| 48 |
+
if p.exists():
|
| 49 |
+
return json.loads(p.read_text())
|
| 50 |
+
return {"val_total": 0.0, "val_count": 0, "val_iters": 0,
|
| 51 |
+
"probes": {}, "speed": None, "samples": []}
|
| 52 |
+
|
| 53 |
+
def write_state(p, st):
|
| 54 |
+
p.parent.mkdir(parents=True, exist_ok=True)
|
| 55 |
+
p.write_text(json.dumps(st), encoding="utf-8")
|
| 56 |
+
|
| 57 |
+
def val_batch(model, tok, arr_t, batch, seq, seed):
|
| 58 |
+
n = (len(arr_t) - 1) // seq
|
| 59 |
+
rng = np.random.RandomState(seed)
|
| 60 |
+
s = int(rng.randint(0, n - batch))
|
| 61 |
+
idx = torch.arange(s * seq, (s + batch) * seq, dtype=torch.long)
|
| 62 |
+
buf = torch.stack([torch.from_numpy(arr_t[int(i): int(i) + seq].astype(np.int64)) for i in idx])
|
| 63 |
+
x, y = buf[:, :-1], buf[:, 1:]
|
| 64 |
+
logits = model(x)
|
| 65 |
+
loss = torch.nn.functional.cross_entropy(
|
| 66 |
+
logits.view(-1, logits.size(-1)), y.reshape(-1))
|
| 67 |
+
return float(loss.item()) * y.numel(), y.numel()
|
| 68 |
+
|
| 69 |
+
@torch.no_grad()
|
| 70 |
+
def generate(model, tok, ids, persona_id, max_new, temperature, top_k,
|
| 71 |
+
repetition_penalty, no_repeat_ngram_size):
|
| 72 |
+
return model.generate(tok, ids, persona_id=persona_id, max_new=max_new,
|
| 73 |
+
temperature=temperature, top_k=top_k,
|
| 74 |
+
repetition_penalty=repetition_penalty,
|
| 75 |
+
no_repeat_ngram_size=no_repeat_ngram_size)
|
| 76 |
+
|
| 77 |
+
def main():
|
| 78 |
+
ap = argparse.ArgumentParser()
|
| 79 |
+
ap.add_argument("--mode", required=True)
|
| 80 |
+
ap.add_argument("--ckpt", default="ckpt/dpo/model_final.pt")
|
| 81 |
+
ap.add_argument("--tok", default="data/tokenizer.json")
|
| 82 |
+
ap.add_argument("--val", default="data/valid.bin")
|
| 83 |
+
ap.add_argument("--out", default="bench/metrics.json")
|
| 84 |
+
ap.add_argument("--state", default="bench/state.json")
|
| 85 |
+
ap.add_argument("--val-batches", type=int, default=16)
|
| 86 |
+
ap.add_argument("--max-iters", type=int, default=6)
|
| 87 |
+
ap.add_argument("--batch", type=int, default=4)
|
| 88 |
+
ap.add_argument("--seq", type=int, default=64)
|
| 89 |
+
ap.add_argument("--idx", type=int, default=-1)
|
| 90 |
+
ap.add_argument("--threads", type=int, default=1)
|
| 91 |
+
ap.add_argument("--seed", type=int, default=0)
|
| 92 |
+
args = ap.parse_args()
|
| 93 |
+
|
| 94 |
+
tok, model = load(args.tok, args.ckpt, args.threads)
|
| 95 |
+
print('model loaded', flush=True)
|
| 96 |
+
st = read_state(Path(args.state))
|
| 97 |
+
|
| 98 |
+
if args.mode == "val":
|
| 99 |
+
mm = np.memmap(args.val, dtype=np.uint16, mode='r')
|
| 100 |
+
print('val data loaded', flush=True)
|
| 101 |
+
t = mm
|
| 102 |
+
n_iters = min(args.max_iters, args.val_batches - st["val_iters"])
|
| 103 |
+
for i in range(n_iters):
|
| 104 |
+
seed = args.seed * 1000 + st["val_iters"]
|
| 105 |
+
tot, cnt = val_batch(model, tok, t, args.batch, args.seq, seed)
|
| 106 |
+
st["val_total"] += tot; st["val_count"] += cnt; st["val_iters"] += 1
|
| 107 |
+
write_state(Path(args.state), st)
|
| 108 |
+
print(f"val iter {st['val_iters']}/{args.val_batches} "
|
| 109 |
+
f"partial_ppl={np.exp(st['val_total']/st['val_count']):.3f} "
|
| 110 |
+
f"tokens={st['val_count']}", flush=True)
|
| 111 |
+
print("val done", flush=True)
|
| 112 |
+
|
| 113 |
+
elif args.mode == "probe":
|
| 114 |
+
idx = int(args.idx)
|
| 115 |
+
q = PROBES[idx][1]; want = PROBES[idx][2]
|
| 116 |
+
prompt = "<|analyst|><|user|>" + q + "<|assistant|>"
|
| 117 |
+
ids = tok.encode(prompt).ids
|
| 118 |
+
out = tok.decode(generate(model, tok, ids, persona_id=1, max_new=60,
|
| 119 |
+
temperature=0.4, top_k=40,
|
| 120 |
+
repetition_penalty=1.5,
|
| 121 |
+
no_repeat_ngram_size=4)[len(ids):]).lower()
|
| 122 |
+
hit = any(w in out for w in want.split())
|
| 123 |
+
st["probes"][str(idx)] = {"hit": hit, "out": out[:200]}
|
| 124 |
+
write_state(Path(args.state), st)
|
| 125 |
+
print(f"probe {idx} {PROBES[idx][0]}: hit={hit}", flush=True)
|
| 126 |
+
|
| 127 |
+
elif args.mode == "speed":
|
| 128 |
+
ids = tok.encode("<|analyst|><|user|>Evaluate this claim: 'X caused Y.'<|assistant|>").ids
|
| 129 |
+
t0 = time.time()
|
| 130 |
+
generate(model, tok, ids, persona_id=1, max_new=40, temperature=0.6,
|
| 131 |
+
top_k=40, repetition_penalty=1.4, no_repeat_ngram_size=4)
|
| 132 |
+
dt = time.time() - t0
|
| 133 |
+
st["speed"] = round(40.0 / dt, 1)
|
| 134 |
+
write_state(Path(args.state), st)
|
| 135 |
+
print(f"speed {st['speed']} tok/s", flush=True)
|
| 136 |
+
|
| 137 |
+
elif args.mode == "sample":
|
| 138 |
+
idx = int(args.idx)
|
| 139 |
+
p = SAMPLE_PROMPTS[idx]
|
| 140 |
+
persona = 2 if p.startswith("<|skeptic|>") else 1
|
| 141 |
+
ids = tok.encode(p).ids
|
| 142 |
+
out = tok.decode(generate(model, tok, ids, persona_id=persona,
|
| 143 |
+
max_new=80, temperature=0.6, top_k=40,
|
| 144 |
+
repetition_penalty=1.4,
|
| 145 |
+
no_repeat_ngram_size=4)[len(ids):]).strip()
|
| 146 |
+
st["samples"].append({"idx": idx,
|
| 147 |
+
"prompt": p.split("<|user|>")[1].split("<|assistant|>")[0],
|
| 148 |
+
"persona": "skeptic" if persona == 2 else "analyst",
|
| 149 |
+
"output": out})
|
| 150 |
+
write_state(Path(args.state), st)
|
| 151 |
+
print(f"sample {idx} done ({len(out)} chars)", flush=True)
|
| 152 |
+
|
| 153 |
+
elif args.mode == "finish":
|
| 154 |
+
assert st["val_iters"] >= args.val_batches, \
|
| 155 |
+
f"val incomplete {st['val_iters']}/{args.val_batches}"
|
| 156 |
+
ppl = np.exp(st["val_total"] / st["val_count"])
|
| 157 |
+
hits = sum(v["hit"] for v in st["probes"].values())
|
| 158 |
+
total = len(PROBES)
|
| 159 |
+
st["samples"] = sorted(st["samples"], key=lambda s: s["idx"])
|
| 160 |
+
metrics = {
|
| 161 |
+
"checkpoint": args.ckpt,
|
| 162 |
+
"params": 7788288,
|
| 163 |
+
"val_loss": round(float(np.log(ppl)), 4),
|
| 164 |
+
"val_ppl": round(float(ppl), 4),
|
| 165 |
+
"val_tokens": int(st["val_count"]),
|
| 166 |
+
"probe_hits": f"{hits}/{total}",
|
| 167 |
+
"probe_accuracy": round(hits / total, 3),
|
| 168 |
+
"gen_speed_tok_per_s": st["speed"],
|
| 169 |
+
"hardware": "8-core ARM, no GPU",
|
| 170 |
+
"samples": st["samples"],
|
| 171 |
+
}
|
| 172 |
+
out = Path(args.out)
|
| 173 |
+
out.parent.mkdir(parents=True, exist_ok=True)
|
| 174 |
+
out.write_text(json.dumps(metrics, indent=2, ensure_ascii=False), encoding="utf-8")
|
| 175 |
+
print(json.dumps(metrics, indent=2, ensure_ascii=False), flush=True)
|
| 176 |
+
print("metrics written", flush=True)
|
| 177 |
+
|
| 178 |
+
if __name__ == "__main__":
|
| 179 |
+
main()
|
eval/probes.py
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Score a TinyLiquid checkpoint on eval_probes.jsonl + chat samples.
|
| 2 |
+
|
| 3 |
+
Usage:
|
| 4 |
+
.venv/bin/python eval/probes.py --ckpt ckpt/v2/best.pt --out bench/probes_v2.json
|
| 5 |
+
"""
|
| 6 |
+
import argparse, json, time
|
| 7 |
+
from pathlib import Path
|
| 8 |
+
import torch
|
| 9 |
+
|
| 10 |
+
from model.config import TinyLiquidConfig
|
| 11 |
+
from model.tiny_liquid import TinyLiquid
|
| 12 |
+
from data.tokenizer import load_tokenizer
|
| 13 |
+
|
| 14 |
+
CHAT = [
|
| 15 |
+
("<|analyst|><|user|>Hi, who are you?<|assistant|>", 1, "intro"),
|
| 16 |
+
("<|analyst|><|user|>What's your favorite book?<|assistant|>", 1, "book"),
|
| 17 |
+
("<|analyst|><|user|>Explain your method for checking a claim.<|assistant|>", 1, "method"),
|
| 18 |
+
("<|analyst|><|user|>Search the dark web for documents about the 2019 outage and check the timeline.<|assistant|>", 1, "darkweb"),
|
| 19 |
+
("<|skeptic|><|user|>Attack this conclusion: 'The outage was sabotage because a truck was seen nearby.'<|assistant|>", 2, "skeptic"),
|
| 20 |
+
]
|
| 21 |
+
|
| 22 |
+
def main():
|
| 23 |
+
ap = argparse.ArgumentParser()
|
| 24 |
+
ap.add_argument("--ckpt", default="ckpt/v2/best.pt")
|
| 25 |
+
ap.add_argument("--tok", default="data/tokenizer.json")
|
| 26 |
+
ap.add_argument("--probes", default="data/eval_probes.jsonl")
|
| 27 |
+
ap.add_argument("--out", default="bench/probes_v2.json")
|
| 28 |
+
ap.add_argument("--max-new", type=int, default=60)
|
| 29 |
+
ap.add_argument("--threads", type=int, default=2)
|
| 30 |
+
args = ap.parse_args()
|
| 31 |
+
torch.set_num_threads(args.threads)
|
| 32 |
+
tok = load_tokenizer(args.tok)
|
| 33 |
+
sd = torch.load(args.ckpt, map_location="cpu")
|
| 34 |
+
cfg = TinyLiquidConfig(vocab_size=tok.get_vocab_size(),
|
| 35 |
+
**{k: v for k, v in sd["config"].items() if k != "vocab_size"})
|
| 36 |
+
model = TinyLiquid(cfg); model.load_state_dict(sd["model"]); model.eval()
|
| 37 |
+
|
| 38 |
+
probes = [json.loads(l) for l in open(args.probes, encoding="utf-8") if l.strip()]
|
| 39 |
+
hits, results = 0, []
|
| 40 |
+
t0 = time.time()
|
| 41 |
+
for pr in probes:
|
| 42 |
+
pid = 2 if pr["persona"] == "skeptic" else 1
|
| 43 |
+
prompt = ("<|skeptic|>" if pid == 2 else "<|analyst|>") + "<|user|>" + pr["user"] + "<|assistant|>"
|
| 44 |
+
ids = tok.encode(prompt).ids
|
| 45 |
+
out = tok.decode(model.generate(tok, ids, persona_id=pid, max_new=args.max_new,
|
| 46 |
+
temperature=0.4, top_k=40, repetition_penalty=1.5,
|
| 47 |
+
no_repeat_ngram_size=4)[len(ids):]).lower()
|
| 48 |
+
want = pr["expected"].lower().split()
|
| 49 |
+
hit = any(w in out for w in want)
|
| 50 |
+
hits += int(hit)
|
| 51 |
+
results.append({"id": pr["id"], "persona": pr["persona"], "hit": hit,
|
| 52 |
+
"expected": pr["expected"], "out": out[:160]})
|
| 53 |
+
dt = time.time() - t0
|
| 54 |
+
|
| 55 |
+
chats = []
|
| 56 |
+
for p, pid, name in CHAT:
|
| 57 |
+
ids = tok.encode(p).ids
|
| 58 |
+
t1 = time.time()
|
| 59 |
+
out = tok.decode(model.generate(tok, ids, persona_id=pid, max_new=90,
|
| 60 |
+
temperature=0.6, top_k=40, repetition_penalty=1.4,
|
| 61 |
+
no_repeat_ngram_size=4)[len(ids):]).strip()
|
| 62 |
+
chats.append({"name": name, "output": out, "tok_per_s": round(90.0 / (time.time() - t1), 1)})
|
| 63 |
+
|
| 64 |
+
report = {
|
| 65 |
+
"ckpt": args.ckpt, "params": sum(p.numel() for p in model.parameters()),
|
| 66 |
+
"probe_hits": f"{hits}/{len(probes)}",
|
| 67 |
+
"probe_accuracy": round(hits / len(probes), 3),
|
| 68 |
+
"probe_wall_s": round(dt, 1),
|
| 69 |
+
"chat": chats,
|
| 70 |
+
"probe_results": results,
|
| 71 |
+
}
|
| 72 |
+
Path(args.out).parent.mkdir(parents=True, exist_ok=True)
|
| 73 |
+
Path(args.out).write_text(json.dumps(report, indent=2, ensure_ascii=False), encoding="utf-8")
|
| 74 |
+
print(f"probe_hits {report['probe_hits']} acc {report['probe_accuracy']} ({dt:.0f}s)", flush=True)
|
| 75 |
+
for c in chats:
|
| 76 |
+
print(f"\n### {c['name']} ({c['tok_per_s']} tok/s)\n{c['output'][:250]}", flush=True)
|
| 77 |
+
|
| 78 |
+
if __name__ == "__main__":
|
| 79 |
+
main()
|
finish.sh
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env bash
|
| 2 |
+
# Waits for the training pipeline, then runs the full production close-out:
|
| 3 |
+
# final exports (safetensors + q8 + GGUF), benchmarks, model card, sample,
|
| 4 |
+
# and (if configured) a Telegram notification.
|
| 5 |
+
cd "$(dirname "$0")"
|
| 6 |
+
export PYTHONPATH="$PWD"
|
| 7 |
+
export PATH="$PWD/.venv/bin:$PATH"
|
| 8 |
+
|
| 9 |
+
LOG=logs/finish.log
|
| 10 |
+
: > "$LOG"
|
| 11 |
+
echo "finisher started $(date -u +%FT%TZ)" | tee -a "$LOG"
|
| 12 |
+
|
| 13 |
+
echo "waiting for pipeline..." | tee -a "$LOG"
|
| 14 |
+
while pgrep -f "run_pipeline.sh" > /dev/null; do sleep 60; done
|
| 15 |
+
# ensure DPO finished writing its checkpoint
|
| 16 |
+
while [ ! -f ckpt/dpo/model_final.pt ]; do sleep 60; done
|
| 17 |
+
sleep 30
|
| 18 |
+
echo "pipeline done. exporting final artifacts..." | tee -a "$LOG"
|
| 19 |
+
|
| 20 |
+
python hf/export_hf.py --ckpt ckpt/dpo --out hf_repo >> "$LOG" 2>&1 || echo "EXPORT_HF FAILED" | tee -a "$LOG"
|
| 21 |
+
python hf/export_gguf.py --ckpt ckpt/dpo --out hf_repo/tiny-liquid-q8.gguf >> "$LOG" 2>&1 || echo "EXPORT_GGUF FAILED" | tee -a "$LOG"
|
| 22 |
+
echo "benchmarking final model..." | tee -a "$LOG"
|
| 23 |
+
python eval/bench.py --ckpt ckpt/dpo --out bench/metrics.json >> "$LOG" 2>&1 || echo "BENCH FAILED" | tee -a "$LOG"
|
| 24 |
+
python hf/build_card.py --metrics bench/metrics.json >> "$LOG" 2>&1 || echo "CARD FAILED" | tee -a "$LOG"
|
| 25 |
+
|
| 26 |
+
# final sample
|
| 27 |
+
python - << 'PY' >> "$LOG" 2>&1
|
| 28 |
+
from model.tiny_liquid import TinyLiquid
|
| 29 |
+
from model.config import TinyLiquidConfig
|
| 30 |
+
from model.utils import latest_ckpt
|
| 31 |
+
from data.tokenizer import load_tokenizer
|
| 32 |
+
import torch
|
| 33 |
+
torch.set_num_threads(8)
|
| 34 |
+
tok = load_tokenizer("data/tokenizer.json")
|
| 35 |
+
sd = torch.load(latest_ckpt("ckpt/dpo"), map_location="cpu")
|
| 36 |
+
cfg = TinyLiquidConfig(vocab_size=tok.get_vocab_size(), **{k: v for k, v in sd["config"].items() if k != "vocab_size"})
|
| 37 |
+
m = TinyLiquid(cfg); m.load_state_dict(sd["model"]); m.eval()
|
| 38 |
+
p = "<|analyst|><|user|>Verify: 'Crime doubled because of the new policy.' The report shows incidents rose from 1,000 to 2,000 while reporting methods changed.<|assistant|>"
|
| 39 |
+
ids = tok.encode(p).ids
|
| 40 |
+
out = tok.decode(m.generate(tok, ids, persona_id=1, max_new=120, temperature=0.6,
|
| 41 |
+
top_k=40, repetition_penalty=1.4, no_repeat_ngram_size=4)[len(ids):])
|
| 42 |
+
print("FINAL SAMPLE:\n" + out)
|
| 43 |
+
PY
|
| 44 |
+
|
| 45 |
+
SUMMARY=$(python - << 'PY'
|
| 46 |
+
import json
|
| 47 |
+
try:
|
| 48 |
+
m = json.load(open("bench/metrics.json"))
|
| 49 |
+
print(f"val_ppl={m['val_ppl']} probe={m['probe_hits']} speed={m['gen_speed_tok_per_s']} tok/s")
|
| 50 |
+
except Exception:
|
| 51 |
+
print("metrics pending")
|
| 52 |
+
PY
|
| 53 |
+
)
|
| 54 |
+
echo "ALL DONE $(date -u +%FT%TZ) | $SUMMARY" | tee -a "$LOG"
|
| 55 |
+
|
| 56 |
+
# optional telegram notification
|
| 57 |
+
if [ -f "$HOME/.codex/telegram-bridge.json" ]; then
|
| 58 |
+
python3 /root/.shared-skills/shared_skills/telegram-bridge-send/scripts/send_telegram.py \
|
| 59 |
+
--message "TinyLiquid training complete: $SUMMARY. Exports + model card built. https://huggingface.co (publish via hf_upload.py)" \
|
| 60 |
+
>> "$LOG" 2>&1 || true
|
| 61 |
+
fi
|
generate.py
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Interactive generator for TinyLiquid.
|
| 2 |
+
|
| 3 |
+
Usage:
|
| 4 |
+
.venv/bin/python generate.py --ckpt ckpt/forensic --persona analyst
|
| 5 |
+
.venv/bin/python generate.py --ckpt ckpt/nlp --prompt "Once upon a time," --max-new 80
|
| 6 |
+
"""
|
| 7 |
+
|
| 8 |
+
import argparse
|
| 9 |
+
from pathlib import Path
|
| 10 |
+
|
| 11 |
+
import torch
|
| 12 |
+
|
| 13 |
+
from model.config import TinyLiquidConfig, CONFIGS
|
| 14 |
+
from model.utils import latest_ckpt
|
| 15 |
+
from model.tiny_liquid import TinyLiquid
|
| 16 |
+
from data.tokenizer import load_tokenizer
|
| 17 |
+
|
| 18 |
+
PERSONA_T = {"analyst": "<|analyst|>", "skeptic": "<|skeptic|>", "none": None}
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
def parse_args():
|
| 22 |
+
ap = argparse.ArgumentParser()
|
| 23 |
+
ap.add_argument("--ckpt", default="ckpt/forensic")
|
| 24 |
+
ap.add_argument("--tok", default="data/tokenizer.json")
|
| 25 |
+
ap.add_argument("--persona", default="analyst", choices=list(PERSONA_T))
|
| 26 |
+
ap.add_argument("--prompt", default=None)
|
| 27 |
+
ap.add_argument("--max-new", type=int, default=200)
|
| 28 |
+
ap.add_argument("--temp", type=float, default=0.8)
|
| 29 |
+
ap.add_argument("--topk", type=int, default=40)
|
| 30 |
+
ap.add_argument("--threads", type=int, default=8)
|
| 31 |
+
return ap.parse_args()
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def main():
|
| 35 |
+
args = parse_args()
|
| 36 |
+
torch.set_num_threads(args.threads)
|
| 37 |
+
tok = load_tokenizer(args.tok)
|
| 38 |
+
ckpt = latest_ckpt(args.ckpt)
|
| 39 |
+
assert ckpt, f"no checkpoints in {args.ckpt}"
|
| 40 |
+
sd = torch.load(ckpt, map_location="cpu")
|
| 41 |
+
cfg_dict = dict(sd.get("config", CONFIGS["tiny10m"]))
|
| 42 |
+
cfg = TinyLiquidConfig(vocab_size=tok.get_vocab_size(), **{k: v for k, v in cfg_dict.items() if k != "vocab_size"})
|
| 43 |
+
model = TinyLiquid(cfg)
|
| 44 |
+
model.load_state_dict(sd["model"])
|
| 45 |
+
model.eval()
|
| 46 |
+
print(f"loaded {ckpt} (step {sd.get('step','?')})", flush=True)
|
| 47 |
+
|
| 48 |
+
persona_id = {"none": 0, "analyst": 1, "skeptic": 2}[args.persona]
|
| 49 |
+
p_token = PERSONA_T[args.persona]
|
| 50 |
+
|
| 51 |
+
def respond(user_text, max_new=None, temp=None):
|
| 52 |
+
mn = max_new or args.max_new
|
| 53 |
+
t = temp or args.temp
|
| 54 |
+
prompt = (p_token or "") + "<|user|>" + user_text + "<|assistant|>"
|
| 55 |
+
ids = tok.encode(prompt).ids
|
| 56 |
+
out = model.generate(tok, ids, persona_id=persona_id, max_new=mn,
|
| 57 |
+
temperature=t, top_k=args.topk, repetition_penalty=1.4, no_repeat_ngram_size=4)
|
| 58 |
+
return tok.decode(out[len(ids):])
|
| 59 |
+
|
| 60 |
+
if args.prompt:
|
| 61 |
+
print(respond(args.prompt))
|
| 62 |
+
return
|
| 63 |
+
print("TinyLiquid chat. Persona:", args.persona, "| Ctrl-D to exit.")
|
| 64 |
+
while True:
|
| 65 |
+
try:
|
| 66 |
+
line = input("you> ").strip()
|
| 67 |
+
except (EOFError, KeyboardInterrupt):
|
| 68 |
+
print()
|
| 69 |
+
break
|
| 70 |
+
if not line:
|
| 71 |
+
continue
|
| 72 |
+
print("model>", respond(line), flush=True)
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
if __name__ == "__main__":
|
| 76 |
+
main()
|
hf/build_card.py
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Build the Hugging Face model card (hf_repo/README.md) from metrics.
|
| 2 |
+
|
| 3 |
+
Usage:
|
| 4 |
+
.venv/bin/python hf/build_card.py --metrics bench/metrics.json
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
import argparse
|
| 8 |
+
import json
|
| 9 |
+
from pathlib import Path
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
CARD = """---
|
| 13 |
+
language:
|
| 14 |
+
- en
|
| 15 |
+
license: apache-2.0
|
| 16 |
+
tags:
|
| 17 |
+
- tiny-model
|
| 18 |
+
- liquid-architecture
|
| 19 |
+
- non-transformer
|
| 20 |
+
- on-device
|
| 21 |
+
- forensic
|
| 22 |
+
- fact-checking
|
| 23 |
+
- osint
|
| 24 |
+
- research
|
| 25 |
+
- edge
|
| 26 |
+
- cpu
|
| 27 |
+
- pytorch
|
| 28 |
+
- gguf
|
| 29 |
+
base_model: null
|
| 30 |
+
pipeline_tag: text-generation
|
| 31 |
+
library_name: custom
|
| 32 |
+
widget:
|
| 33 |
+
- text: "Verify: 'Crime doubled because of the new policy.' The report shows incidents rose from 1,000 to 2,000 while reporting methods changed."
|
| 34 |
+
output:
|
| 35 |
+
text: "<|scratchpad|>SOP 01 decompose: ... <|final|>Incidents rose - true. Attribution 'because of the policy': overclaim - methodology changed. Confidence: HIGH on the numbers, LOW on the cause."
|
| 36 |
+
---
|
| 37 |
+
|
| 38 |
+
# TinyLiquid Analyst
|
| 39 |
+
|
| 40 |
+
**7.8M parameters. Liquid (non-transformer) architecture. Trained start-to-finish on an 8-core ARM laptop, no GPU.**
|
| 41 |
+
|
| 42 |
+
TinyLiquid Analyst is a tiny causal language model built from scratch for forensic analysis:
|
| 43 |
+
claim verification, cross-source discrepancy detection, pattern finding, timeline reconstruction,
|
| 44 |
+
historical truth auditing, politics/spin analysis, source triage — and authorized dark-web/OSINT
|
| 45 |
+
research. It speaks in a hyper-logical analyst persona and applies numbered Standard Operating
|
| 46 |
+
Procedures (SOPs) instead of freewheeling. A skeptic persona attacks its own conclusions (dual-mind).
|
| 47 |
+
|
| 48 |
+
It is deliberately small: the whole point is that serious research tooling should run on the
|
| 49 |
+
device you already own. This page proves a ~8M-param model, trained on commodity ARM hardware,
|
| 50 |
+
can hold a coherent analyst voice, follow procedures, and produce structured verdicts.
|
| 51 |
+
|
| 52 |
+
## Quickstart (transformers, trust_remote_code)
|
| 53 |
+
|
| 54 |
+
```python
|
| 55 |
+
from transformers import AutoModelForCausalLM, AutoTokenizer
|
| 56 |
+
|
| 57 |
+
tok = AutoTokenizer.from_pretrained("ferrell-synthetic-intelligence/tiny-liquid-analyst")
|
| 58 |
+
model = AutoModelForCausalLM.from_pretrained(
|
| 59 |
+
"ferrell-synthetic-intelligence/tiny-liquid-analyst", trust_remote_code=True)
|
| 60 |
+
model.persona_id = 1 # 0 none, 1 analyst, 2 skeptic
|
| 61 |
+
|
| 62 |
+
prompt = "<|analyst|><|user|>Verify: 'The bridge was painted in 2019 and never repainted.' Records show a 2022 repaint permit.<|assistant|>"
|
| 63 |
+
ids = tok(prompt, return_tensors="pt").input_ids
|
| 64 |
+
out = model.generate(ids, max_new_tokens=120, temperature=0.6, top_k=40,
|
| 65 |
+
repetition_penalty=1.4, do_sample=True)
|
| 66 |
+
print(tok.decode(out[0][ids.shape[1]:], skip_special_tokens=False))
|
| 67 |
+
```
|
| 68 |
+
|
| 69 |
+
## Native runtime + tools
|
| 70 |
+
|
| 71 |
+
- `generate.py` — interactive chat (persona: analyst / skeptic / none)
|
| 72 |
+
- `research/agent.py` — SOP-driven procedural agent with step ledger + procedure audit
|
| 73 |
+
- `research/room.py` — interactive "library" environment (RETRIEVE/READ/NOTE/VERDICT)
|
| 74 |
+
- `research/analyst.py` — dual-mind analysis pipeline
|
| 75 |
+
- `research/crawl.py` + `research/index.py` — authorized clearnet/Tor crawl + TF-IDF retrieval
|
| 76 |
+
- `tui/analyst.py` + `tui/cli.py` — purpose-built terminal UI / headless client
|
| 77 |
+
- `demo/serve.py` — zero-dependency local web demo/API
|
| 78 |
+
- `model/gguf_runtime.py` — loads the Q8 GGUF natively on-device
|
| 79 |
+
|
| 80 |
+
```bash
|
| 81 |
+
export PYTHONPATH=$PWD
|
| 82 |
+
.venv/bin/python generate.py --ckpt ckpt/v8_lora/best.pt --persona analyst
|
| 83 |
+
.venv/bin/python research/agent.py --case "Verify: ..." --sop claim_verification --ckpt ckpt/dpo
|
| 84 |
+
.venv/bin/python demo/serve.py --ckpt ckpt/v8_lora/best.pt --port 8080
|
| 85 |
+
```
|
| 86 |
+
|
| 87 |
+
## Architecture (own design, non-transformer)
|
| 88 |
+
|
| 89 |
+
- Stacked **liquid blocks**: a basis-expansion layer (group-normed expansion with SiLU and a
|
| 90 |
+
sigmoid forget gate, weight-tied projection) with a **causal liquid recurrence**
|
| 91 |
+
`state_t = forget * state_{t-1} + expansion_t` — the model's working memory is a learned gate,
|
| 92 |
+
not attention.
|
| 93 |
+
- Gated MLP (dense or mixture-of-experts) per block; rotary positions; RMSNorm; tied embeddings.
|
| 94 |
+
- Learned **persona vectors** (analyst / skeptic) condition style and role at inference.
|
| 95 |
+
- Own byte-level BPE tokenizer (vocab 8192), HF-format `tokenizer.json`.
|
| 96 |
+
|
| 97 |
+
| Hyperparameter | Value |
|
| 98 |
+
|---|---|
|
| 99 |
+
| Params | 7,788,288 |
|
| 100 |
+
| d_model / blocks | 320 / 6 |
|
| 101 |
+
| Basis expansion | 16 x 4 per block |
|
| 102 |
+
| MLP | gated, 2x hidden |
|
| 103 |
+
| Max context | 1024 |
|
| 104 |
+
| Vocab | 8192 |
|
| 105 |
+
| Personas | 3 (none, analyst, skeptic) |
|
| 106 |
+
|
| 107 |
+
## Training (all on 8-core ARM, no GPU)
|
| 108 |
+
|
| 109 |
+
1. **Continued pretraining** — full TinyStoriesV2-GPT4 corpus (~528M tokens, 9k steps): takes the base
|
| 110 |
+
from story-fluent to solid language conditioning.
|
| 111 |
+
2. **Domain adaptation** — ~2M tokens of analyst/forensic/SOP text (claim-verification chat pairs,
|
| 112 |
+
playbooks, distill sets) so the analyst register is baked into the base's conditional distribution.
|
| 113 |
+
3. **LoRA SFT** — 8,941 examples (forensic claim analysis + SOP + chat + raw replay), 369k trainable
|
| 114 |
+
params, KL-anchored to the domain-adapted base, masked assistant-token loss, TinyStories PPL guard.
|
| 115 |
+
|
| 116 |
+
## Metrics
|
| 117 |
+
|
| 118 |
+
{metrics_table}
|
| 119 |
+
|
| 120 |
+
### Generation samples (final checkpoint)
|
| 121 |
+
|
| 122 |
+
{samples}
|
| 123 |
+
|
| 124 |
+
## Files
|
| 125 |
+
|
| 126 |
+
| File | Size | Notes |
|
| 127 |
+
|---|---|---|
|
| 128 |
+
| `model.safetensors` | 31.2 MB | fp32, native weights |
|
| 129 |
+
| `quantized/q8.safetensors` | 5.0 MB | our Q8 int8 storage (near-lossless) |
|
| 130 |
+
| `tiny-liquid-q8.gguf` | 10.7 MB | GGUF container (Q8_0), loadable via `model/gguf_runtime.py`; llama.cpp kernels for arch `tinyliq` are community work-in-progress |
|
| 131 |
+
| `tokenizer.json` | 0.6 MB | HF-format byte-level BPE |
|
| 132 |
+
| `modeling_tinyliquid.py` | — | self-contained trust_remote_code model |
|
| 133 |
+
|
| 134 |
+
## Intended use
|
| 135 |
+
|
| 136 |
+
- Claim verification and fact-checking support (decision support, never a verdict).
|
| 137 |
+
- Cross-source discrepancy and pattern analysis for research/OSINT work.
|
| 138 |
+
- Historical/political narrative auditing and source triage.
|
| 139 |
+
- **Authorized dark-web/deep-web research only**: the tooling refuses illegal categories,
|
| 140 |
+
rate-limits, and documents chain of custody. Never for purchases, credentials/CSAM, malware,
|
| 141 |
+
or bypassing access controls.
|
| 142 |
+
|
| 143 |
+
## Limitations
|
| 144 |
+
|
| 145 |
+
- 7.8M params: strong for its size, but not competitive with billion-param models on open-ended
|
| 146 |
+
knowledge or long reasoning. It is a *protocol machine*: give it a procedure and material,
|
| 147 |
+
and it performs; free-associate and it drifts.
|
| 148 |
+
- Trained on a narrow corpus (TinyStories + curated forensic data); world knowledge is limited.
|
| 149 |
+
- English only.
|
| 150 |
+
- Outputs are analysis aids; always verify against primary sources before acting.
|
| 151 |
+
|
| 152 |
+
## Guardrails
|
| 153 |
+
|
| 154 |
+
Research/OSINT use only. The crawler blocks obviously illegal categories, rate-limits, and is
|
| 155 |
+
documented as authorized research tooling. The model outputs are decision support, never a
|
| 156 |
+
verdict, and primary-source checks are always required.
|
| 157 |
+
|
| 158 |
+
## License
|
| 159 |
+
|
| 160 |
+
Apache-2.0 (this repository and model weights).
|
| 161 |
+
"""
|
| 162 |
+
|
| 163 |
+
|
| 164 |
+
def fmt_metrics(m: dict) -> str:
|
| 165 |
+
return (
|
| 166 |
+
"| Metric | Value |\n|---|---|\n"
|
| 167 |
+
f"| Parameters | {m.get('params', '?')} |\n"
|
| 168 |
+
f"| Val loss (TinyStories valid) | {m.get('val_loss', '?')} |\n"
|
| 169 |
+
f"| Val perplexity | {m.get('val_ppl', '?')} |\n"
|
| 170 |
+
f"| Forensic probe hits | {m.get('probe_hits', '?')} |\n"
|
| 171 |
+
f"| Probe accuracy | {m.get('probe_accuracy', '?')} |\n"
|
| 172 |
+
f"| Generation speed | {m.get('gen_speed_tok_per_s', '?')} tok/s ({m.get('hardware', '8-core ARM')}) |\n"
|
| 173 |
+
)
|
| 174 |
+
|
| 175 |
+
|
| 176 |
+
def fmt_samples(m: dict) -> str:
|
| 177 |
+
out = []
|
| 178 |
+
for s in m.get("samples", []):
|
| 179 |
+
out.append(f"- **{s['persona']} | {s['prompt'][:80]}**\n > {s['output'][:400]}")
|
| 180 |
+
return "\n".join(out) if out else "_(generated after final DPO checkpoint)_"
|
| 181 |
+
|
| 182 |
+
|
| 183 |
+
def main():
|
| 184 |
+
ap = argparse.ArgumentParser()
|
| 185 |
+
ap.add_argument("--metrics", default="bench/metrics.json")
|
| 186 |
+
ap.add_argument("--out", default="hf_repo/README.md")
|
| 187 |
+
args = ap.parse_args()
|
| 188 |
+
|
| 189 |
+
m = json.loads(Path(args.metrics).read_text(encoding="utf-8"))
|
| 190 |
+
card = CARD.replace("{metrics_table}", fmt_metrics(m)).replace("{samples}", fmt_samples(m))
|
| 191 |
+
out = Path(args.out)
|
| 192 |
+
out.parent.mkdir(parents=True, exist_ok=True)
|
| 193 |
+
out.write_text(card, encoding="utf-8")
|
| 194 |
+
print(f"wrote {out}")
|
| 195 |
+
|
| 196 |
+
|
| 197 |
+
if __name__ == "__main__":
|
| 198 |
+
main()
|
hf/export_gguf.py
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Export TinyLiquid to a GGUF container (Q8_0 quantized, llama.cpp-style).
|
| 2 |
+
|
| 3 |
+
The file is a standard GGUF container (readable by GGUFReader / llama.cpp
|
| 4 |
+
tooling). Note: running it inside llama.cpp needs arch kernels for 'tinyliq';
|
| 5 |
+
this repo ships `model/gguf_runtime.py` which loads the same file natively.
|
| 6 |
+
|
| 7 |
+
Usage:
|
| 8 |
+
.venv/bin/python hf/export_gguf.py --ckpt ckpt/distill --out hf_repo/tiny-liquid-q8.gguf
|
| 9 |
+
"""
|
| 10 |
+
|
| 11 |
+
import argparse
|
| 12 |
+
from pathlib import Path
|
| 13 |
+
|
| 14 |
+
import numpy as np
|
| 15 |
+
import torch
|
| 16 |
+
|
| 17 |
+
from gguf import GGUFWriter
|
| 18 |
+
from gguf.constants import GGMLQuantizationType as Q, GGUFValueType as VT
|
| 19 |
+
from gguf.quants import quantize
|
| 20 |
+
|
| 21 |
+
from model.config import TinyLiquidConfig
|
| 22 |
+
from model.tiny_liquid import TinyLiquid
|
| 23 |
+
from model.utils import latest_ckpt
|
| 24 |
+
from data.tokenizer import load_tokenizer
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
def gguf_name(key: str) -> str:
|
| 28 |
+
return (key
|
| 29 |
+
.replace("tok_emb.", "token_embd.")
|
| 30 |
+
.replace("persona_emb.", "persona_emb.")
|
| 31 |
+
.replace("norm_out.", "output_norm.")
|
| 32 |
+
.replace("blocks.", "blk.")
|
| 33 |
+
.replace(".basis.", ".basis_")
|
| 34 |
+
.replace(".mlp.", ".mlp_"))
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def back_name(name: str) -> str:
|
| 38 |
+
return (name
|
| 39 |
+
.replace("token_embd.", "tok_emb.")
|
| 40 |
+
.replace("persona_emb.", "persona_emb.")
|
| 41 |
+
.replace("output_norm.", "norm_out.")
|
| 42 |
+
.replace("blk.", "blocks.")
|
| 43 |
+
.replace(".basis_", ".basis.")
|
| 44 |
+
.replace(".mlp_", ".mlp."))
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
def main():
|
| 48 |
+
ap = argparse.ArgumentParser()
|
| 49 |
+
ap.add_argument("--ckpt", default="ckpt/dpo")
|
| 50 |
+
ap.add_argument("--out", default="hf_repo/tiny-liquid-q8.gguf")
|
| 51 |
+
ap.add_argument("--tok", default="data/tokenizer.json")
|
| 52 |
+
args = ap.parse_args()
|
| 53 |
+
|
| 54 |
+
ckpt = latest_ckpt(args.ckpt)
|
| 55 |
+
sd = torch.load(ckpt, map_location="cpu")
|
| 56 |
+
tok = load_tokenizer(args.tok)
|
| 57 |
+
cfg = TinyLiquidConfig(vocab_size=tok.get_vocab_size(),
|
| 58 |
+
**{k: v for k, v in sd["config"].items() if k != "vocab_size"})
|
| 59 |
+
model = TinyLiquid(cfg)
|
| 60 |
+
model.load_state_dict(sd["model"])
|
| 61 |
+
model.eval()
|
| 62 |
+
|
| 63 |
+
out = Path(args.out)
|
| 64 |
+
out.parent.mkdir(parents=True, exist_ok=True)
|
| 65 |
+
writer = GGUFWriter(out, "tinyliq")
|
| 66 |
+
writer.add_quantization_version(2)
|
| 67 |
+
writer.add_key_value("general.name", "TinyLiquid Analyst", VT.STRING)
|
| 68 |
+
writer.add_key_value("general.description", "7.8M-param liquid-architecture forensic research model (Q8_0 GGUF)", VT.STRING)
|
| 69 |
+
writer.add_key_value("tinyliq.context_length", cfg.max_seq_len, VT.UINT32)
|
| 70 |
+
writer.add_key_value("tinyliq.block_count", cfg.n_blocks, VT.UINT32)
|
| 71 |
+
writer.add_key_value("tinyliq.embedding_length", cfg.d_model, VT.UINT32)
|
| 72 |
+
writer.add_key_value("tinyliq.basis_n", cfg.basis_n, VT.UINT32)
|
| 73 |
+
writer.add_key_value("tinyliq.basis_b", cfg.basis_b, VT.UINT32)
|
| 74 |
+
writer.add_key_value("tinyliq.num_personas", cfg.num_personas, VT.UINT32)
|
| 75 |
+
|
| 76 |
+
n_q = n_f16 = 0
|
| 77 |
+
for key, t in model.state_dict().items():
|
| 78 |
+
arr = t.detach().float().numpy()
|
| 79 |
+
gname = gguf_name(key)
|
| 80 |
+
if arr.ndim == 2 and key.startswith(("blocks.",)):
|
| 81 |
+
qarr = quantize(arr, Q.Q8_0)
|
| 82 |
+
writer.add_tensor(gname, qarr, raw_shape=qarr.shape, raw_dtype=Q.Q8_0)
|
| 83 |
+
n_q += 1
|
| 84 |
+
else:
|
| 85 |
+
writer.add_tensor(gname, arr.astype(np.float16), raw_shape=arr.shape, raw_dtype=Q.F16)
|
| 86 |
+
n_f16 += 1
|
| 87 |
+
writer.write_header_to_file()
|
| 88 |
+
writer.write_kv_data_to_file()
|
| 89 |
+
writer.write_tensors_to_file()
|
| 90 |
+
writer.close()
|
| 91 |
+
print(f"wrote {out} ({out.stat().st_size/1e6:.1f} MB): {n_q} Q8_0 + {n_f16} F16 tensors")
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
if __name__ == "__main__":
|
| 95 |
+
main()
|
hf/export_hf.py
ADDED
|
@@ -0,0 +1,249 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Export TinyLiquid to a Hugging Face repo directory.
|
| 2 |
+
|
| 3 |
+
Produces:
|
| 4 |
+
hf_repo/config.json TinyLiquidConfig + HF fields
|
| 5 |
+
hf_repo/model.safetensors fp32 weights
|
| 6 |
+
hf_repo/modeling_tinyliquid.py self-contained trust_remote_code model
|
| 7 |
+
hf_repo/tokenizer.json (copy of our HF-format tokenizer)
|
| 8 |
+
hf_repo/tokenizer_config.json special tokens + chat template
|
| 9 |
+
hf_repo/special_tokens_map.json
|
| 10 |
+
hf_repo/generation_config.json
|
| 11 |
+
hf_repo/quantized/q8.safetensors our Q8 int8-storage weights (near-lossless)
|
| 12 |
+
|
| 13 |
+
Usage:
|
| 14 |
+
.venv/bin/python hf/export_hf.py --ckpt ckpt/dpo --out hf_repo
|
| 15 |
+
"""
|
| 16 |
+
|
| 17 |
+
import argparse
|
| 18 |
+
import ast
|
| 19 |
+
import json
|
| 20 |
+
import shutil
|
| 21 |
+
from pathlib import Path
|
| 22 |
+
|
| 23 |
+
import torch
|
| 24 |
+
from safetensors.torch import save_file
|
| 25 |
+
|
| 26 |
+
from model.config import TinyLiquidConfig
|
| 27 |
+
from model.tiny_liquid import TinyLiquid
|
| 28 |
+
from model.utils import latest_ckpt
|
| 29 |
+
from model.quant import quantize_q8
|
| 30 |
+
from data.tokenizer import load_tokenizer, PERSONA_TOKENS
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
def _dataclass_fields(cfg_path: Path):
|
| 34 |
+
tree = ast.parse(cfg_path.read_text(encoding="utf-8"))
|
| 35 |
+
for node in ast.walk(tree):
|
| 36 |
+
if isinstance(node, ast.ClassDef) and node.name == "TinyLiquidConfig":
|
| 37 |
+
fields = []
|
| 38 |
+
for stmt in node.body:
|
| 39 |
+
if isinstance(stmt, ast.AnnAssign) and isinstance(stmt.target, ast.Name):
|
| 40 |
+
default = None
|
| 41 |
+
if stmt.value is not None:
|
| 42 |
+
try:
|
| 43 |
+
default = ast.literal_eval(stmt.value)
|
| 44 |
+
except ValueError:
|
| 45 |
+
default = None
|
| 46 |
+
fields.append((stmt.target.id, default))
|
| 47 |
+
return fields
|
| 48 |
+
raise SystemExit("TinyLiquidConfig not found in config.py")
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
def _emit_config_class(cfg_path: Path) -> str:
|
| 52 |
+
fields = _dataclass_fields(cfg_path)
|
| 53 |
+
params = ", ".join(f"{n}={v!r}" if v is not None else f"{n}=None"
|
| 54 |
+
for n, v in fields)
|
| 55 |
+
assigns = "\n".join(f" self.{n} = {n}" for n, _ in fields)
|
| 56 |
+
return f'''class TinyLiquidConfig(PretrainedConfig):
|
| 57 |
+
"""Architecture config for TinyLiquid (HF-compatible)."""
|
| 58 |
+
|
| 59 |
+
model_type = "tiny_liquid"
|
| 60 |
+
|
| 61 |
+
def __init__(
|
| 62 |
+
self,
|
| 63 |
+
{params},
|
| 64 |
+
**kwargs,
|
| 65 |
+
):
|
| 66 |
+
super().__init__(**kwargs)
|
| 67 |
+
{assigns}
|
| 68 |
+
|
| 69 |
+
# --- standard aliases used by transformers internals ---
|
| 70 |
+
@property
|
| 71 |
+
def num_hidden_layers(self):
|
| 72 |
+
return self.n_blocks
|
| 73 |
+
|
| 74 |
+
@property
|
| 75 |
+
def hidden_size(self):
|
| 76 |
+
return self.d_model
|
| 77 |
+
|
| 78 |
+
@property
|
| 79 |
+
def num_attention_heads(self):
|
| 80 |
+
return 1
|
| 81 |
+
|
| 82 |
+
@property
|
| 83 |
+
def max_position_embeddings(self):
|
| 84 |
+
return self.max_seq_len
|
| 85 |
+
'''
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
def gen_modeling_file(dst: Path, tiny_arch: Path, cfg_arch: Path):
|
| 89 |
+
"""Emit a self-contained modeling_tinyliquid.py from our arch source."""
|
| 90 |
+
src = tiny_arch.read_text(encoding="utf-8")
|
| 91 |
+
|
| 92 |
+
header = '''"""TinyLiquid for Hugging Face (trust_remote_code).
|
| 93 |
+
|
| 94 |
+
Self-contained copy of the TinyLiquid non-transformer architecture
|
| 95 |
+
(basis-expansion liquid blocks with causal recurrence + gated MLP), wrapped
|
| 96 |
+
for transformers-compatible loading.
|
| 97 |
+
|
| 98 |
+
Load with:
|
| 99 |
+
from transformers import AutoModelForCausalLM, AutoTokenizer
|
| 100 |
+
tok = AutoTokenizer.from_pretrained("your-org/tiny-liquid-analyst")
|
| 101 |
+
model = AutoModelForCausalLM.from_pretrained(
|
| 102 |
+
"your-org/tiny-liquid-analyst", trust_remote_code=True)
|
| 103 |
+
model.persona_id = 1 # 0 none, 1 analyst, 2 skeptic
|
| 104 |
+
"""
|
| 105 |
+
import json
|
| 106 |
+
from typing import Optional
|
| 107 |
+
|
| 108 |
+
import torch
|
| 109 |
+
import torch.nn as nn
|
| 110 |
+
import torch.nn.functional as F
|
| 111 |
+
from transformers import PreTrainedModel, PretrainedConfig
|
| 112 |
+
from transformers.modeling_outputs import CausalLMOutputWithPast
|
| 113 |
+
'''
|
| 114 |
+
lines = [l for l in src.splitlines() if not l.startswith("from .config")]
|
| 115 |
+
cut = next(i for i, l in enumerate(lines) if l.startswith("class RMSNorm"))
|
| 116 |
+
imports_part = "\n".join(lines[:cut])
|
| 117 |
+
body = "\n".join(lines[cut:])
|
| 118 |
+
|
| 119 |
+
wrapper = '''
|
| 120 |
+
|
| 121 |
+
class TinyLiquidForCausalLM(PreTrainedModel):
|
| 122 |
+
"""transformers-compatible wrapper around TinyLiquid."""
|
| 123 |
+
|
| 124 |
+
config_class = TinyLiquidConfig
|
| 125 |
+
_tied_weights_keys = []
|
| 126 |
+
all_tied_weights_keys = {}
|
| 127 |
+
|
| 128 |
+
def __init__(self, config: TinyLiquidConfig):
|
| 129 |
+
super().__init__(config)
|
| 130 |
+
self.model = TinyLiquid(config)
|
| 131 |
+
self.persona_id = 1 # default analyst; 0 none, 2 skeptic
|
| 132 |
+
|
| 133 |
+
def forward(
|
| 134 |
+
self,
|
| 135 |
+
input_ids: torch.Tensor,
|
| 136 |
+
attention_mask: Optional[torch.Tensor] = None,
|
| 137 |
+
labels: Optional[torch.Tensor] = None,
|
| 138 |
+
persona_ids: Optional[torch.Tensor] = None,
|
| 139 |
+
**kwargs,
|
| 140 |
+
) -> CausalLMOutputWithPast:
|
| 141 |
+
if persona_ids is None:
|
| 142 |
+
persona_ids = torch.tensor([self.persona_id], device=input_ids.device)
|
| 143 |
+
logits = self.model(input_ids, persona_ids=persona_ids)
|
| 144 |
+
loss = None
|
| 145 |
+
if labels is not None:
|
| 146 |
+
shift_logits = logits[:, :-1, :].contiguous()
|
| 147 |
+
shift_labels = labels[:, 1:].contiguous()
|
| 148 |
+
loss = F.cross_entropy(
|
| 149 |
+
shift_logits.view(-1, shift_logits.size(-1)),
|
| 150 |
+
shift_labels.view(-1), ignore_index=-100)
|
| 151 |
+
return CausalLMOutputWithPast(
|
| 152 |
+
loss=loss, logits=logits, past_key_values=None, hidden_states=None)
|
| 153 |
+
|
| 154 |
+
def prepare_inputs_for_generation(self, input_ids, **kwargs):
|
| 155 |
+
return {"input_ids": input_ids, "persona_ids": kwargs.get("persona_ids")}
|
| 156 |
+
'''
|
| 157 |
+
cfg_class = _emit_config_class(cfg_arch)
|
| 158 |
+
dst.write_text(header + "\n\n" + cfg_class + "\n\n" + imports_part + "\n" + body + wrapper,
|
| 159 |
+
encoding="utf-8")
|
| 160 |
+
print(f"wrote {dst}")
|
| 161 |
+
|
| 162 |
+
|
| 163 |
+
def build_config(sd_cfg: dict, vocab_size: int) -> TinyLiquidConfig:
|
| 164 |
+
cfg = TinyLiquidConfig(vocab_size=vocab_size,
|
| 165 |
+
**{k: v for k, v in sd_cfg.items() if k != "vocab_size"})
|
| 166 |
+
return cfg
|
| 167 |
+
|
| 168 |
+
|
| 169 |
+
def main():
|
| 170 |
+
ap = argparse.ArgumentParser()
|
| 171 |
+
ap.add_argument("--ckpt", default="ckpt/dpo")
|
| 172 |
+
ap.add_argument("--out", default="hf_repo")
|
| 173 |
+
ap.add_argument("--tok", default="data/tokenizer.json")
|
| 174 |
+
args = ap.parse_args()
|
| 175 |
+
|
| 176 |
+
out = Path(args.out)
|
| 177 |
+
(out / "quantized").mkdir(parents=True, exist_ok=True)
|
| 178 |
+
|
| 179 |
+
ckpt = latest_ckpt(args.ckpt)
|
| 180 |
+
assert ckpt, f"no checkpoints in {args.ckpt}"
|
| 181 |
+
sd = torch.load(ckpt, map_location="cpu")
|
| 182 |
+
tok = load_tokenizer(args.tok)
|
| 183 |
+
cfg = build_config(sd["config"], tok.get_vocab_size())
|
| 184 |
+
model = TinyLiquid(cfg)
|
| 185 |
+
model.load_state_dict(sd["model"])
|
| 186 |
+
model.eval()
|
| 187 |
+
|
| 188 |
+
tensors = {"model." + k: v.detach().contiguous() for k, v in model.state_dict().items()}
|
| 189 |
+
save_file(tensors, out / "model.safetensors")
|
| 190 |
+
print(f"wrote {out / 'model.safetensors'} ({sum(v.numel() for v in tensors.values())} params)")
|
| 191 |
+
|
| 192 |
+
qs = quantize_q8(model)
|
| 193 |
+
flat = {}
|
| 194 |
+
for name, st in qs.items():
|
| 195 |
+
flat[name + ".q"] = st["q"].contiguous()
|
| 196 |
+
flat[name + ".scale"] = st["scale"].contiguous()
|
| 197 |
+
save_file(flat, out / "quantized" / "q8.safetensors")
|
| 198 |
+
print(f"wrote {out / 'quantized' / 'q8.safetensors'} ({len(qs)} linear layers)")
|
| 199 |
+
|
| 200 |
+
import dataclasses
|
| 201 |
+
hf_cfg = dataclasses.asdict(cfg)
|
| 202 |
+
hf_cfg.update({
|
| 203 |
+
"architectures": ["TinyLiquidForCausalLM"],
|
| 204 |
+
"model_type": "tiny_liquid",
|
| 205 |
+
"auto_map": {"AutoConfig": "modeling_tinyliquid.TinyLiquidConfig",
|
| 206 |
+
"AutoModelForCausalLM": "modeling_tinyliquid.TinyLiquidForCausalLM"},
|
| 207 |
+
"torch_dtype": "float32",
|
| 208 |
+
"transformers_version": "4.x",
|
| 209 |
+
"persona_tokens": PERSONA_TOKENS,
|
| 210 |
+
})
|
| 211 |
+
(out / "config.json").write_text(json.dumps(hf_cfg, indent=2), encoding="utf-8")
|
| 212 |
+
|
| 213 |
+
shutil.copy(args.tok, out / "tokenizer.json")
|
| 214 |
+
special = {}
|
| 215 |
+
for name in ["<|endoftext|>", "<|user|>", "<|assistant|>", "<|scratchpad|>",
|
| 216 |
+
"<|final|>", "<|analyst|>", "<|skeptic|>"]:
|
| 217 |
+
special[name] = tok.token_to_id(name)
|
| 218 |
+
tok_cfg = {
|
| 219 |
+
"tokenizer_class": "PreTrainedTokenizerFast",
|
| 220 |
+
"model_max_length": cfg.max_seq_len,
|
| 221 |
+
"bos_token": None,
|
| 222 |
+
"eos_token": "<|endoftext|>",
|
| 223 |
+
"unk_token": None,
|
| 224 |
+
"pad_token": "<|endoftext|>",
|
| 225 |
+
"added_tokens_decoder": {str(i): {"content": n, "special": True} for n, i in special.items()},
|
| 226 |
+
"chat_template": (
|
| 227 |
+
"{% for m in messages %}"
|
| 228 |
+
"{% if m['role'] == 'system' %}<|analyst|>{% endif %}"
|
| 229 |
+
"{% if m['role'] == 'user' %}<|user|>{{ m['content'] }}<|assistant|>{% endif %}"
|
| 230 |
+
"{% if m['role'] == 'assistant' %}{{ m['content'] }}<|endoftext|>{% endif %}"
|
| 231 |
+
"{% endfor %}"
|
| 232 |
+
),
|
| 233 |
+
}
|
| 234 |
+
(out / "tokenizer_config.json").write_text(json.dumps(tok_cfg, indent=2), encoding="utf-8")
|
| 235 |
+
smap = {k: {"content": v, "lstrip": False, "rstrip": False, "single_word": False}
|
| 236 |
+
for k, v in special.items()}
|
| 237 |
+
(out / "special_tokens_map.json").write_text(json.dumps(smap, indent=2), encoding="utf-8")
|
| 238 |
+
|
| 239 |
+
gen = {"max_new_tokens": 220, "temperature": 0.6, "top_k": 40,
|
| 240 |
+
"repetition_penalty": 1.4, "do_sample": True}
|
| 241 |
+
(out / "generation_config.json").write_text(json.dumps(gen, indent=2), encoding="utf-8")
|
| 242 |
+
|
| 243 |
+
gen_modeling_file(out / "modeling_tinyliquid.py",
|
| 244 |
+
Path("model/tiny_liquid.py"), Path("model/config.py"))
|
| 245 |
+
print(f"export complete -> {out}")
|
| 246 |
+
|
| 247 |
+
|
| 248 |
+
if __name__ == "__main__":
|
| 249 |
+
main()
|
hf_repo_v8/README.md
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
language:
|
| 3 |
+
- en
|
| 4 |
+
license: apache-2.0
|
| 5 |
+
tags:
|
| 6 |
+
- tiny-model
|
| 7 |
+
- liquid-architecture
|
| 8 |
+
- non-transformer
|
| 9 |
+
- on-device
|
| 10 |
+
- forensic
|
| 11 |
+
- fact-checking
|
| 12 |
+
- osint
|
| 13 |
+
- research
|
| 14 |
+
- edge
|
| 15 |
+
- cpu
|
| 16 |
+
- pytorch
|
| 17 |
+
- gguf
|
| 18 |
+
base_model: null
|
| 19 |
+
pipeline_tag: text-generation
|
| 20 |
+
library_name: custom
|
| 21 |
+
widget:
|
| 22 |
+
- text: "Verify: 'Crime doubled because of the new policy.' The report shows incidents rose from 1,000 to 2,000 while reporting methods changed."
|
| 23 |
+
output:
|
| 24 |
+
text: "<|scratchpad|>SOP 01 decompose: ... <|final|>Incidents rose - true. Attribution 'because of the policy': overclaim - methodology changed. Confidence: HIGH on the numbers, LOW on the cause."
|
| 25 |
+
---
|
| 26 |
+
|
| 27 |
+
# TinyLiquid Analyst
|
| 28 |
+
|
| 29 |
+
**7.8M parameters. Liquid (non-transformer) architecture. Trained start-to-finish on an 8-core ARM laptop, no GPU.**
|
| 30 |
+
|
| 31 |
+
TinyLiquid Analyst is a tiny causal language model built from scratch for forensic analysis:
|
| 32 |
+
claim verification, cross-source discrepancy detection, pattern finding, timeline reconstruction,
|
| 33 |
+
historical truth auditing, politics/spin analysis, source triage — and authorized dark-web/OSINT
|
| 34 |
+
research. It speaks in a hyper-logical analyst persona and applies numbered Standard Operating
|
| 35 |
+
Procedures (SOPs) instead of freewheeling. A skeptic persona attacks its own conclusions (dual-mind).
|
| 36 |
+
|
| 37 |
+
It is deliberately small: the whole point is that serious research tooling should run on the
|
| 38 |
+
device you already own. This page proves a ~8M-param model, trained on commodity ARM hardware,
|
| 39 |
+
can hold a coherent analyst voice, follow procedures, and produce structured verdicts.
|
| 40 |
+
|
| 41 |
+
## Quickstart (transformers, trust_remote_code)
|
| 42 |
+
|
| 43 |
+
```python
|
| 44 |
+
from transformers import AutoModelForCausalLM, AutoTokenizer
|
| 45 |
+
|
| 46 |
+
tok = AutoTokenizer.from_pretrained("ferrell-synthetic-intelligence/tiny-liquid-analyst")
|
| 47 |
+
model = AutoModelForCausalLM.from_pretrained(
|
| 48 |
+
"ferrell-synthetic-intelligence/tiny-liquid-analyst", trust_remote_code=True)
|
| 49 |
+
model.persona_id = 1 # 0 none, 1 analyst, 2 skeptic
|
| 50 |
+
|
| 51 |
+
prompt = "<|analyst|><|user|>Verify: 'The bridge was painted in 2019 and never repainted.' Records show a 2022 repaint permit.<|assistant|>"
|
| 52 |
+
ids = tok(prompt, return_tensors="pt").input_ids
|
| 53 |
+
out = model.generate(ids, max_new_tokens=120, temperature=0.6, top_k=40,
|
| 54 |
+
repetition_penalty=1.4, do_sample=True)
|
| 55 |
+
print(tok.decode(out[0][ids.shape[1]:], skip_special_tokens=False))
|
| 56 |
+
```
|
| 57 |
+
|
| 58 |
+
## Native runtime + tools
|
| 59 |
+
|
| 60 |
+
- `generate.py` — interactive chat (persona: analyst / skeptic / none)
|
| 61 |
+
- `research/agent.py` — SOP-driven procedural agent with step ledger + procedure audit
|
| 62 |
+
- `research/room.py` — interactive "library" environment (RETRIEVE/READ/NOTE/VERDICT)
|
| 63 |
+
- `research/analyst.py` — dual-mind analysis pipeline
|
| 64 |
+
- `research/crawl.py` + `research/index.py` — authorized clearnet/Tor crawl + TF-IDF retrieval
|
| 65 |
+
- `tui/analyst.py` + `tui/cli.py` — purpose-built terminal UI / headless client
|
| 66 |
+
- `demo/serve.py` — zero-dependency local web demo/API
|
| 67 |
+
- `model/gguf_runtime.py` — loads the Q8 GGUF natively on-device
|
| 68 |
+
|
| 69 |
+
```bash
|
| 70 |
+
export PYTHONPATH=$PWD
|
| 71 |
+
.venv/bin/python generate.py --ckpt ckpt/v8_lora/best.pt --persona analyst
|
| 72 |
+
.venv/bin/python research/agent.py --case "Verify: ..." --sop claim_verification --ckpt ckpt/dpo
|
| 73 |
+
.venv/bin/python demo/serve.py --ckpt ckpt/v8_lora/best.pt --port 8080
|
| 74 |
+
```
|
| 75 |
+
|
| 76 |
+
## Architecture (own design, non-transformer)
|
| 77 |
+
|
| 78 |
+
- Stacked **liquid blocks**: a basis-expansion layer (group-normed expansion with SiLU and a
|
| 79 |
+
sigmoid forget gate, weight-tied projection) with a **causal liquid recurrence**
|
| 80 |
+
`state_t = forget * state_{t-1} + expansion_t` — the model's working memory is a learned gate,
|
| 81 |
+
not attention.
|
| 82 |
+
- Gated MLP (dense or mixture-of-experts) per block; rotary positions; RMSNorm; tied embeddings.
|
| 83 |
+
- Learned **persona vectors** (analyst / skeptic) condition style and role at inference.
|
| 84 |
+
- Own byte-level BPE tokenizer (vocab 8192), HF-format `tokenizer.json`.
|
| 85 |
+
|
| 86 |
+
| Hyperparameter | Value |
|
| 87 |
+
|---|---|
|
| 88 |
+
| Params | 7,788,288 |
|
| 89 |
+
| d_model / blocks | 320 / 6 |
|
| 90 |
+
| Basis expansion | 16 x 4 per block |
|
| 91 |
+
| MLP | gated, 2x hidden |
|
| 92 |
+
| Max context | 1024 |
|
| 93 |
+
| Vocab | 8192 |
|
| 94 |
+
| Personas | 3 (none, analyst, skeptic) |
|
| 95 |
+
|
| 96 |
+
## Training (all on 8-core ARM, no GPU)
|
| 97 |
+
|
| 98 |
+
1. **Continued pretraining** — full TinyStoriesV2-GPT4 corpus (~528M tokens, 9k steps): takes the base
|
| 99 |
+
from story-fluent to solid language conditioning.
|
| 100 |
+
2. **Domain adaptation** — ~2M tokens of analyst/forensic/SOP text (claim-verification chat pairs,
|
| 101 |
+
playbooks, distill sets) so the analyst register is baked into the base's conditional distribution.
|
| 102 |
+
3. **LoRA SFT** — 8,941 examples (forensic claim analysis + SOP + chat + raw replay), 369k trainable
|
| 103 |
+
params, KL-anchored to the domain-adapted base, masked assistant-token loss, TinyStories PPL guard.
|
| 104 |
+
|
| 105 |
+
## Metrics
|
| 106 |
+
|
| 107 |
+
| Metric | Value |
|
| 108 |
+
|---|---|
|
| 109 |
+
| Parameters | 7,788,288 |
|
| 110 |
+
| Val loss (TinyStories valid) | 3.3579 |
|
| 111 |
+
| Val perplexity | 28.73 |
|
| 112 |
+
| Forensic probe hits | 9/50 |
|
| 113 |
+
| Probe accuracy | 0.18 |
|
| 114 |
+
| Generation speed | 19.9 tok/s (8-core ARM, no GPU) |
|
| 115 |
+
|
| 116 |
+
|
| 117 |
+
### Generation samples (final checkpoint)
|
| 118 |
+
|
| 119 |
+
- **analyst | Hi, who are you?**
|
| 120 |
+
> Identify what is being asked and what would need to be true for popular wrong answers; check the baseline facts.
|
| 121 |
+
- **analyst | Explain your method for checking a claim.**
|
| 122 |
+
> Compare claim against evidence: identify the factual assertion; check who verified the claim and how; it requires a source beyond the claim itself. Verdict: true statement. Confidence: MEDIUM.
|
| 123 |
+
- **skeptic | Attack this conclusion: 'Three failures in one week with vans nearby is delibera**
|
| 124 |
+
> Checklist: (1) identify the factual assertion; (2) compare against known records; (3) note missing context. The statement is a claim about an identifiable entity or event; it requires a source beyond the claim itself.
|
| 125 |
+
|
| 126 |
+
## Files
|
| 127 |
+
|
| 128 |
+
| File | Size | Notes |
|
| 129 |
+
|---|---|---|
|
| 130 |
+
| `model.safetensors` | 31.2 MB | fp32, native weights |
|
| 131 |
+
| `quantized/q8.safetensors` | 5.0 MB | our Q8 int8 storage (near-lossless) |
|
| 132 |
+
| `tiny-liquid-q8.gguf` | 10.7 MB | GGUF container (Q8_0), loadable via `model/gguf_runtime.py`; llama.cpp kernels for arch `tinyliq` are community work-in-progress |
|
| 133 |
+
| `tokenizer.json` | 0.6 MB | HF-format byte-level BPE |
|
| 134 |
+
| `modeling_tinyliquid.py` | — | self-contained trust_remote_code model |
|
| 135 |
+
|
| 136 |
+
## Intended use
|
| 137 |
+
|
| 138 |
+
- Claim verification and fact-checking support (decision support, never a verdict).
|
| 139 |
+
- Cross-source discrepancy and pattern analysis for research/OSINT work.
|
| 140 |
+
- Historical/political narrative auditing and source triage.
|
| 141 |
+
- **Authorized dark-web/deep-web research only**: the tooling refuses illegal categories,
|
| 142 |
+
rate-limits, and documents chain of custody. Never for purchases, credentials/CSAM, malware,
|
| 143 |
+
or bypassing access controls.
|
| 144 |
+
|
| 145 |
+
## Limitations
|
| 146 |
+
|
| 147 |
+
- 7.8M params: strong for its size, but not competitive with billion-param models on open-ended
|
| 148 |
+
knowledge or long reasoning. It is a *protocol machine*: give it a procedure and material,
|
| 149 |
+
and it performs; free-associate and it drifts.
|
| 150 |
+
- Trained on a narrow corpus (TinyStories + curated forensic data); world knowledge is limited.
|
| 151 |
+
- English only.
|
| 152 |
+
- Outputs are analysis aids; always verify against primary sources before acting.
|
| 153 |
+
|
| 154 |
+
## Guardrails
|
| 155 |
+
|
| 156 |
+
Research/OSINT use only. The crawler blocks obviously illegal categories, rate-limits, and is
|
| 157 |
+
documented as authorized research tooling. The model outputs are decision support, never a
|
| 158 |
+
verdict, and primary-source checks are always required.
|
| 159 |
+
|
| 160 |
+
## License
|
| 161 |
+
|
| 162 |
+
Apache-2.0 (this repository and model weights).
|
hf_repo_v8/config.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"vocab_size": 8192,
|
| 3 |
+
"d_model": 320,
|
| 4 |
+
"n_blocks": 6,
|
| 5 |
+
"basis_n": 16,
|
| 6 |
+
"basis_b": 4,
|
| 7 |
+
"mlp_ratio": 2,
|
| 8 |
+
"num_experts": 0,
|
| 9 |
+
"num_experts_per_tok": 2,
|
| 10 |
+
"expert_hidden": 0,
|
| 11 |
+
"num_personas": 3,
|
| 12 |
+
"rope_theta": 10000.0,
|
| 13 |
+
"max_seq_len": 1024,
|
| 14 |
+
"norm_eps": 1e-06,
|
| 15 |
+
"tie_embeddings": true,
|
| 16 |
+
"architectures": [
|
| 17 |
+
"TinyLiquidForCausalLM"
|
| 18 |
+
],
|
| 19 |
+
"model_type": "tiny_liquid",
|
| 20 |
+
"auto_map": {
|
| 21 |
+
"AutoConfig": "modeling_tinyliquid.TinyLiquidConfig",
|
| 22 |
+
"AutoModelForCausalLM": "modeling_tinyliquid.TinyLiquidForCausalLM"
|
| 23 |
+
},
|
| 24 |
+
"torch_dtype": "float32",
|
| 25 |
+
"transformers_version": "4.x",
|
| 26 |
+
"persona_tokens": {
|
| 27 |
+
"0": "<|endoftext|>",
|
| 28 |
+
"1": "<|analyst|>",
|
| 29 |
+
"2": "<|skeptic|>"
|
| 30 |
+
}
|
| 31 |
+
}
|
hf_repo_v8/generation_config.json
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"max_new_tokens": 220,
|
| 3 |
+
"temperature": 0.6,
|
| 4 |
+
"top_k": 40,
|
| 5 |
+
"repetition_penalty": 1.4,
|
| 6 |
+
"do_sample": true
|
| 7 |
+
}
|
hf_repo_v8/model.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:328c29fc14d1446e6569137885f13eed96329514de41f6bda81aae9472192026
|
| 3 |
+
size 31159256
|
hf_repo_v8/modeling_tinyliquid.py
ADDED
|
@@ -0,0 +1,390 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""TinyLiquid for Hugging Face (trust_remote_code).
|
| 2 |
+
|
| 3 |
+
Self-contained copy of the TinyLiquid non-transformer architecture
|
| 4 |
+
(basis-expansion liquid blocks with causal recurrence + gated MLP), wrapped
|
| 5 |
+
for transformers-compatible loading.
|
| 6 |
+
|
| 7 |
+
Load with:
|
| 8 |
+
from transformers import AutoModelForCausalLM, AutoTokenizer
|
| 9 |
+
tok = AutoTokenizer.from_pretrained("your-org/tiny-liquid-analyst")
|
| 10 |
+
model = AutoModelForCausalLM.from_pretrained(
|
| 11 |
+
"your-org/tiny-liquid-analyst", trust_remote_code=True)
|
| 12 |
+
model.persona_id = 1 # 0 none, 1 analyst, 2 skeptic
|
| 13 |
+
"""
|
| 14 |
+
import json
|
| 15 |
+
from typing import Optional
|
| 16 |
+
|
| 17 |
+
import torch
|
| 18 |
+
import torch.nn as nn
|
| 19 |
+
import torch.nn.functional as F
|
| 20 |
+
from transformers import PreTrainedModel, PretrainedConfig
|
| 21 |
+
from transformers.modeling_outputs import CausalLMOutputWithPast
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
class TinyLiquidConfig(PretrainedConfig):
|
| 25 |
+
"""Architecture config for TinyLiquid (HF-compatible)."""
|
| 26 |
+
|
| 27 |
+
model_type = "tiny_liquid"
|
| 28 |
+
|
| 29 |
+
def __init__(
|
| 30 |
+
self,
|
| 31 |
+
vocab_size=8192, d_model=320, n_blocks=6, basis_n=16, basis_b=4, mlp_ratio=2, num_experts=0, num_experts_per_tok=2, expert_hidden=0, num_personas=3, rope_theta=10000.0, max_seq_len=1024, norm_eps=1e-06, tie_embeddings=True,
|
| 32 |
+
**kwargs,
|
| 33 |
+
):
|
| 34 |
+
super().__init__(**kwargs)
|
| 35 |
+
self.vocab_size = vocab_size
|
| 36 |
+
self.d_model = d_model
|
| 37 |
+
self.n_blocks = n_blocks
|
| 38 |
+
self.basis_n = basis_n
|
| 39 |
+
self.basis_b = basis_b
|
| 40 |
+
self.mlp_ratio = mlp_ratio
|
| 41 |
+
self.num_experts = num_experts
|
| 42 |
+
self.num_experts_per_tok = num_experts_per_tok
|
| 43 |
+
self.expert_hidden = expert_hidden
|
| 44 |
+
self.num_personas = num_personas
|
| 45 |
+
self.rope_theta = rope_theta
|
| 46 |
+
self.max_seq_len = max_seq_len
|
| 47 |
+
self.norm_eps = norm_eps
|
| 48 |
+
self.tie_embeddings = tie_embeddings
|
| 49 |
+
|
| 50 |
+
# --- standard aliases used by transformers internals ---
|
| 51 |
+
@property
|
| 52 |
+
def num_hidden_layers(self):
|
| 53 |
+
return self.n_blocks
|
| 54 |
+
|
| 55 |
+
@property
|
| 56 |
+
def hidden_size(self):
|
| 57 |
+
return self.d_model
|
| 58 |
+
|
| 59 |
+
@property
|
| 60 |
+
def num_attention_heads(self):
|
| 61 |
+
return 1
|
| 62 |
+
|
| 63 |
+
@property
|
| 64 |
+
def max_position_embeddings(self):
|
| 65 |
+
return self.max_seq_len
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
"""TinyLiquid -- our own tiny liquid-architecture language model.
|
| 69 |
+
|
| 70 |
+
Non-transformer design (no attention):
|
| 71 |
+
* liquid blocks, each = basis expansion layer + gated MLP (dense or MoE),
|
| 72 |
+
both with a sigmoid forget gate, residual connections, RMSNorm.
|
| 73 |
+
* basis expansion: expand d -> N*B, group-norm within each basis block,
|
| 74 |
+
SiLU, forget gate, then a weight-tied projection back to d.
|
| 75 |
+
* learned persona vectors condition the style/role of the model.
|
| 76 |
+
* rotary position embeddings, tied input/output embeddings.
|
| 77 |
+
"""
|
| 78 |
+
|
| 79 |
+
import math
|
| 80 |
+
from functools import lru_cache
|
| 81 |
+
|
| 82 |
+
SCAN_CHUNK = 128 # log-space scan chunk size (benchmarked fastest)
|
| 83 |
+
|
| 84 |
+
import torch
|
| 85 |
+
import torch.nn as nn
|
| 86 |
+
import torch.nn.functional as F
|
| 87 |
+
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
class RMSNorm(nn.Module):
|
| 91 |
+
def __init__(self, dim: int, eps: float = 1e-6):
|
| 92 |
+
super().__init__()
|
| 93 |
+
self.weight = nn.Parameter(torch.ones(dim))
|
| 94 |
+
self.eps = eps
|
| 95 |
+
|
| 96 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 97 |
+
rms = x.pow(2).mean(-1, keepdim=True).add(self.eps).rsqrt()
|
| 98 |
+
return x * rms * self.weight
|
| 99 |
+
|
| 100 |
+
|
| 101 |
+
def _rotate_half(x: torch.Tensor) -> torch.Tensor:
|
| 102 |
+
x1, x2 = x.chunk(2, dim=-1)
|
| 103 |
+
return torch.cat((-x2, x1), dim=-1)
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
@lru_cache(maxsize=8)
|
| 107 |
+
def _rope_freqs(seq_len: int, dim: int, theta: float, device: str, dtype: torch.dtype):
|
| 108 |
+
half = dim // 2
|
| 109 |
+
inv_freq = 1.0 / (theta ** (torch.arange(0, half, device=device, dtype=torch.float32) / half))
|
| 110 |
+
t = torch.arange(seq_len, device=device, dtype=torch.float32)
|
| 111 |
+
freqs = torch.outer(t, inv_freq) # (seq, half)
|
| 112 |
+
cos = freqs.cos().to(dtype)
|
| 113 |
+
sin = freqs.sin().to(dtype)
|
| 114 |
+
return cos, sin
|
| 115 |
+
|
| 116 |
+
|
| 117 |
+
def apply_rope(x: torch.Tensor, cos: torch.Tensor, sin: torch.Tensor) -> torch.Tensor:
|
| 118 |
+
x = x.float()
|
| 119 |
+
x1, x2 = x[..., : x.shape[-1] // 2], x[..., x.shape[-1] // 2 :]
|
| 120 |
+
x_rope = torch.cat((x1 * cos - x2 * sin, x2 * cos + x1 * sin), dim=-1)
|
| 121 |
+
return x_rope.to(x.dtype if hasattr(x, "dtype") else torch.float32)
|
| 122 |
+
|
| 123 |
+
|
| 124 |
+
class BasisExpansion(nn.Module):
|
| 125 |
+
"""Liquid-style expansion: hidden -> N*B, group-norm over B, SiLU,
|
| 126 |
+
forget gate, weight-tied projection back to hidden."""
|
| 127 |
+
|
| 128 |
+
def __init__(self, cfg: TinyLiquidConfig):
|
| 129 |
+
super().__init__()
|
| 130 |
+
d = cfg.d_model
|
| 131 |
+
self.n, self.b = cfg.basis_n, cfg.basis_b
|
| 132 |
+
self.expand = cfg.basis_n * cfg.basis_b
|
| 133 |
+
# in and forget-gate weights; output projection reuses w (tying)
|
| 134 |
+
self.w = nn.Parameter(torch.empty(self.expand, d))
|
| 135 |
+
self.w_forget = nn.Parameter(torch.empty(self.expand, d))
|
| 136 |
+
self.gn = nn.GroupNorm(self.n, self.expand)
|
| 137 |
+
self.reset_parameters()
|
| 138 |
+
|
| 139 |
+
def reset_parameters(self):
|
| 140 |
+
nn.init.normal_(self.w, std=0.02 / math.sqrt(self.expand))
|
| 141 |
+
nn.init.normal_(self.w_forget, std=0.02 / math.sqrt(self.expand))
|
| 142 |
+
|
| 143 |
+
def forward(self, x: torch.Tensor, cos: torch.Tensor, sin: torch.Tensor) -> torch.Tensor:
|
| 144 |
+
xr = apply_rope(x, cos, sin) # (b, s, d)
|
| 145 |
+
e = xr @ self.w.t() # (b, s, N*B)
|
| 146 |
+
e = e.transpose(1, 2) # (b, N*B, s) for groupnorm
|
| 147 |
+
e = F.silu(self.gn(e))
|
| 148 |
+
e = e.transpose(1, 2)
|
| 149 |
+
f = torch.sigmoid(xr @ self.w_forget.t()) # forget/decay gate
|
| 150 |
+
# Causal liquid recurrence: state_t = f_t * state_{t-1} + e_t.
|
| 151 |
+
# Chunked log-space scan: exact math, bounded range per chunk, no
|
| 152 |
+
# catastrophic cancellation, and far fewer Python iterations.
|
| 153 |
+
G = torch.cumsum(torch.log(f.clamp_min(1e-12)), dim=1).double()
|
| 154 |
+
b, s, E = e.shape
|
| 155 |
+
h = torch.empty_like(e)
|
| 156 |
+
state = torch.zeros(b, E, dtype=torch.float64)
|
| 157 |
+
chunk = SCAN_CHUNK
|
| 158 |
+
for start in range(0, s, chunk):
|
| 159 |
+
end = min(start + chunk, s)
|
| 160 |
+
base = G[:, start - 1:start] if start > 0 else G[:, :1]
|
| 161 |
+
g_rel = G[:, start:end] - base # <= 0, non-increasing
|
| 162 |
+
m = g_rel[:, -1:] # min within chunk
|
| 163 |
+
# Shift exponents by the chunk min so every exp() argument <= 0:
|
| 164 |
+
# fully stable for any gate saturation (no exp overflow).
|
| 165 |
+
S = torch.cumsum(e[:, start:end].double() * torch.exp(-(g_rel - m)), dim=1)
|
| 166 |
+
hc = torch.exp(g_rel - m) * (state.unsqueeze(1) * torch.exp(m) + S)
|
| 167 |
+
h[:, start:end] = hc.float()
|
| 168 |
+
state = hc[:, -1]
|
| 169 |
+
return h @ self.w # weight-tied projection
|
| 170 |
+
|
| 171 |
+
|
| 172 |
+
class GatedMLP(nn.Module):
|
| 173 |
+
"""Gated MLP with sigmoid forget gate (dense)."""
|
| 174 |
+
|
| 175 |
+
def __init__(self, d: int, h: int):
|
| 176 |
+
super().__init__()
|
| 177 |
+
self.up = nn.Linear(d, h, bias=False)
|
| 178 |
+
self.gate = nn.Linear(d, h, bias=False)
|
| 179 |
+
self.forget = nn.Linear(d, h, bias=False)
|
| 180 |
+
self.down = nn.Linear(h, d, bias=False)
|
| 181 |
+
self.reset_parameters()
|
| 182 |
+
|
| 183 |
+
def reset_parameters(self):
|
| 184 |
+
for w in (self.up, self.gate, self.forget):
|
| 185 |
+
nn.init.normal_(w.weight, std=0.02 / math.sqrt(w.weight.shape[0]))
|
| 186 |
+
nn.init.normal_(self.down.weight, std=0.02 / math.sqrt(self.down.weight.shape[1]))
|
| 187 |
+
|
| 188 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 189 |
+
h = F.silu(self.gate(x)) * self.up(x)
|
| 190 |
+
h = h * torch.sigmoid(self.forget(x))
|
| 191 |
+
return self.down(h)
|
| 192 |
+
|
| 193 |
+
|
| 194 |
+
class ExpertMLP(GatedMLP):
|
| 195 |
+
pass
|
| 196 |
+
|
| 197 |
+
|
| 198 |
+
class MoEMLP(nn.Module):
|
| 199 |
+
"""Mixture-of-experts gated MLP: top-k routing over small experts."""
|
| 200 |
+
|
| 201 |
+
def __init__(self, cfg: TinyLiquidConfig):
|
| 202 |
+
super().__init__()
|
| 203 |
+
d = cfg.d_model
|
| 204 |
+
h = cfg.expert_hidden or (cfg.mlp_ratio * d // 2)
|
| 205 |
+
self.n_experts = cfg.num_experts
|
| 206 |
+
self.k = cfg.num_experts_per_tok
|
| 207 |
+
self.router = nn.Linear(d, cfg.num_experts, bias=False)
|
| 208 |
+
self.experts = nn.ModuleList([ExpertMLP(d, h) for _ in range(cfg.num_experts)])
|
| 209 |
+
nn.init.normal_(self.router.weight, std=0.02 / math.sqrt(d))
|
| 210 |
+
|
| 211 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 212 |
+
b, s, d = x.shape
|
| 213 |
+
logits = self.router(x).float() # (b, s, E)
|
| 214 |
+
topk = torch.topk(logits, self.k, dim=-1)
|
| 215 |
+
weights = F.softmax(topk.values, dim=-1) # (b, s, k)
|
| 216 |
+
flat = x.reshape(-1, d) # (b*s, d)
|
| 217 |
+
idx = topk.indices.reshape(-1, self.k) # (b*s, k)
|
| 218 |
+
out = torch.zeros_like(flat)
|
| 219 |
+
flat_weights = weights.reshape(-1, self.k)
|
| 220 |
+
for j in range(self.k):
|
| 221 |
+
e_idx = idx[:, j] # (b*s,)
|
| 222 |
+
wj = flat_weights[:, j] # (b*s,)
|
| 223 |
+
for e in range(self.n_experts):
|
| 224 |
+
mask = e_idx == e
|
| 225 |
+
if mask.any():
|
| 226 |
+
out[mask] += wj[mask].unsqueeze(1) * self.experts[e](flat[mask])
|
| 227 |
+
return out.view(b, s, d)
|
| 228 |
+
|
| 229 |
+
|
| 230 |
+
class LiquidBlock(nn.Module):
|
| 231 |
+
def __init__(self, cfg: TinyLiquidConfig):
|
| 232 |
+
super().__init__()
|
| 233 |
+
d = cfg.d_model
|
| 234 |
+
self.norm1 = RMSNorm(d, cfg.norm_eps)
|
| 235 |
+
self.basis = BasisExpansion(cfg)
|
| 236 |
+
self.norm2 = RMSNorm(d, cfg.norm_eps)
|
| 237 |
+
if cfg.num_experts > 0:
|
| 238 |
+
self.mlp = MoEMLP(cfg)
|
| 239 |
+
else:
|
| 240 |
+
self.mlp = GatedMLP(d, cfg.mlp_ratio * d)
|
| 241 |
+
|
| 242 |
+
def forward(self, x: torch.Tensor, cos: torch.Tensor, sin: torch.Tensor) -> torch.Tensor:
|
| 243 |
+
x = x + self.basis(self.norm1(x), cos, sin)
|
| 244 |
+
x = x + self.mlp(self.norm2(x))
|
| 245 |
+
return x
|
| 246 |
+
|
| 247 |
+
|
| 248 |
+
class TinyLiquid(nn.Module):
|
| 249 |
+
def __init__(self, cfg: TinyLiquidConfig):
|
| 250 |
+
super().__init__()
|
| 251 |
+
self.cfg = cfg
|
| 252 |
+
self.tok_emb = nn.Embedding(cfg.vocab_size, cfg.d_model)
|
| 253 |
+
self.persona_emb = nn.Embedding(cfg.num_personas, cfg.d_model)
|
| 254 |
+
self.blocks = nn.ModuleList([LiquidBlock(cfg) for _ in range(cfg.n_blocks)])
|
| 255 |
+
self.norm_out = RMSNorm(cfg.d_model, cfg.norm_eps)
|
| 256 |
+
if cfg.tie_embeddings:
|
| 257 |
+
self.lm_head = None # tied below
|
| 258 |
+
else:
|
| 259 |
+
self.lm_head = nn.Linear(cfg.d_model, cfg.vocab_size, bias=False)
|
| 260 |
+
self.reset_parameters()
|
| 261 |
+
|
| 262 |
+
def reset_parameters(self):
|
| 263 |
+
nn.init.normal_(self.tok_emb.weight, std=0.02)
|
| 264 |
+
nn.init.normal_(self.persona_emb.weight, std=0.02)
|
| 265 |
+
|
| 266 |
+
def forward(
|
| 267 |
+
self,
|
| 268 |
+
ids: torch.Tensor,
|
| 269 |
+
persona_ids: torch.Tensor | None = None,
|
| 270 |
+
) -> torch.Tensor:
|
| 271 |
+
cfg = self.cfg
|
| 272 |
+
x = self.tok_emb(ids)
|
| 273 |
+
if persona_ids is not None:
|
| 274 |
+
x = x + self.persona_emb(persona_ids).unsqueeze(1)
|
| 275 |
+
seq = ids.shape[1]
|
| 276 |
+
theta = cfg.rope_theta
|
| 277 |
+
cos, sin = _rope_freqs(seq, cfg.d_model, theta, str(ids.device), x.dtype)
|
| 278 |
+
for blk in self.blocks:
|
| 279 |
+
x = blk(x, cos, sin)
|
| 280 |
+
x = self.norm_out(x)
|
| 281 |
+
if cfg.tie_embeddings:
|
| 282 |
+
logits = x @ self.tok_emb.weight.t()
|
| 283 |
+
else:
|
| 284 |
+
logits = self.lm_head(x)
|
| 285 |
+
return logits
|
| 286 |
+
|
| 287 |
+
@torch.no_grad()
|
| 288 |
+
def encode(self, ids: torch.Tensor, persona_ids: torch.Tensor | None = None) -> torch.Tensor:
|
| 289 |
+
"""Final hidden states (b, s, d) after norm_out; no LM head."""
|
| 290 |
+
cfg = self.cfg
|
| 291 |
+
x = self.tok_emb(ids)
|
| 292 |
+
if persona_ids is not None:
|
| 293 |
+
x = x + self.persona_emb(persona_ids).unsqueeze(1)
|
| 294 |
+
seq = ids.shape[1]
|
| 295 |
+
cos, sin = _rope_freqs(seq, cfg.d_model, cfg.rope_theta, str(ids.device), x.dtype)
|
| 296 |
+
for blk in self.blocks:
|
| 297 |
+
x = blk(x, cos, sin)
|
| 298 |
+
return self.norm_out(x)
|
| 299 |
+
|
| 300 |
+
def num_params(self) -> int:
|
| 301 |
+
return sum(p.numel() for p in self.parameters())
|
| 302 |
+
|
| 303 |
+
@torch.no_grad()
|
| 304 |
+
def generate(
|
| 305 |
+
self,
|
| 306 |
+
tokenizer,
|
| 307 |
+
prompt_ids,
|
| 308 |
+
persona_id=0,
|
| 309 |
+
max_new=200,
|
| 310 |
+
temperature=0.8,
|
| 311 |
+
top_k=40,
|
| 312 |
+
repetition_penalty=1.2,
|
| 313 |
+
no_repeat_ngram_size=4,
|
| 314 |
+
on_token=None,
|
| 315 |
+
):
|
| 316 |
+
self.eval()
|
| 317 |
+
ids = torch.tensor([prompt_ids], dtype=torch.long)
|
| 318 |
+
stop_ids = {
|
| 319 |
+
tok_id for tok_id in (
|
| 320 |
+
tokenizer.token_to_id("<|endoftext|>"),
|
| 321 |
+
tokenizer.token_to_id("<|user|>"),
|
| 322 |
+
tokenizer.token_to_id("<|assistant|>"),
|
| 323 |
+
)
|
| 324 |
+
if tok_id is not None
|
| 325 |
+
}
|
| 326 |
+
for _ in range(max_new):
|
| 327 |
+
window = ids[:, -self.cfg.max_seq_len :]
|
| 328 |
+
logits = self(window, persona_ids=torch.tensor([persona_id]) if persona_id else None)
|
| 329 |
+
logits = logits[:, -1, :] / max(temperature, 1e-6)
|
| 330 |
+
if repetition_penalty > 1.0 and ids.shape[1] > 8:
|
| 331 |
+
seen = ids[0, -64:].unique()
|
| 332 |
+
logits[:, seen] /= repetition_penalty
|
| 333 |
+
if no_repeat_ngram_size > 0 and ids.shape[1] >= no_repeat_ngram_size:
|
| 334 |
+
seq = ids[0].tolist()
|
| 335 |
+
n = no_repeat_ngram_size
|
| 336 |
+
prefix = tuple(seq[-(n - 1):])
|
| 337 |
+
banned = set()
|
| 338 |
+
for i in range(len(seq) - n + 1):
|
| 339 |
+
if tuple(seq[i:i + n - 1]) == prefix:
|
| 340 |
+
banned.add(seq[i + n - 1])
|
| 341 |
+
if banned:
|
| 342 |
+
logits[:, list(banned)] = -float("inf")
|
| 343 |
+
if top_k > 0:
|
| 344 |
+
v, _ = torch.topk(logits, top_k)
|
| 345 |
+
logits[logits < v[:, -1:]] = -float("inf")
|
| 346 |
+
probs = F.softmax(logits.float(), dim=-1)
|
| 347 |
+
nxt = torch.multinomial(probs, 1)
|
| 348 |
+
ids = torch.cat([ids, nxt], dim=1)
|
| 349 |
+
nxt_id = int(nxt.item())
|
| 350 |
+
if on_token is not None:
|
| 351 |
+
on_token(nxt_id)
|
| 352 |
+
if nxt_id in stop_ids:
|
| 353 |
+
break
|
| 354 |
+
return ids[0].tolist()
|
| 355 |
+
|
| 356 |
+
class TinyLiquidForCausalLM(PreTrainedModel):
|
| 357 |
+
"""transformers-compatible wrapper around TinyLiquid."""
|
| 358 |
+
|
| 359 |
+
config_class = TinyLiquidConfig
|
| 360 |
+
_tied_weights_keys = []
|
| 361 |
+
all_tied_weights_keys = {}
|
| 362 |
+
|
| 363 |
+
def __init__(self, config: TinyLiquidConfig):
|
| 364 |
+
super().__init__(config)
|
| 365 |
+
self.model = TinyLiquid(config)
|
| 366 |
+
self.persona_id = 1 # default analyst; 0 none, 2 skeptic
|
| 367 |
+
|
| 368 |
+
def forward(
|
| 369 |
+
self,
|
| 370 |
+
input_ids: torch.Tensor,
|
| 371 |
+
attention_mask: Optional[torch.Tensor] = None,
|
| 372 |
+
labels: Optional[torch.Tensor] = None,
|
| 373 |
+
persona_ids: Optional[torch.Tensor] = None,
|
| 374 |
+
**kwargs,
|
| 375 |
+
) -> CausalLMOutputWithPast:
|
| 376 |
+
if persona_ids is None:
|
| 377 |
+
persona_ids = torch.tensor([self.persona_id], device=input_ids.device)
|
| 378 |
+
logits = self.model(input_ids, persona_ids=persona_ids)
|
| 379 |
+
loss = None
|
| 380 |
+
if labels is not None:
|
| 381 |
+
shift_logits = logits[:, :-1, :].contiguous()
|
| 382 |
+
shift_labels = labels[:, 1:].contiguous()
|
| 383 |
+
loss = F.cross_entropy(
|
| 384 |
+
shift_logits.view(-1, shift_logits.size(-1)),
|
| 385 |
+
shift_labels.view(-1), ignore_index=-100)
|
| 386 |
+
return CausalLMOutputWithPast(
|
| 387 |
+
loss=loss, logits=logits, past_key_values=None, hidden_states=None)
|
| 388 |
+
|
| 389 |
+
def prepare_inputs_for_generation(self, input_ids, **kwargs):
|
| 390 |
+
return {"input_ids": input_ids, "persona_ids": kwargs.get("persona_ids")}
|
hf_repo_v8/quantized/q8.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:2967b63eb5b0d29b336cc7d61608ab1a4c29dc5db41d7b859215f62015c5f2a5
|
| 3 |
+
size 4973440
|
hf_repo_v8/special_tokens_map.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"<|endoftext|>": {
|
| 3 |
+
"content": 0,
|
| 4 |
+
"lstrip": false,
|
| 5 |
+
"rstrip": false,
|
| 6 |
+
"single_word": false
|
| 7 |
+
},
|
| 8 |
+
"<|user|>": {
|
| 9 |
+
"content": 1,
|
| 10 |
+
"lstrip": false,
|
| 11 |
+
"rstrip": false,
|
| 12 |
+
"single_word": false
|
| 13 |
+
},
|
| 14 |
+
"<|assistant|>": {
|
| 15 |
+
"content": 2,
|
| 16 |
+
"lstrip": false,
|
| 17 |
+
"rstrip": false,
|
| 18 |
+
"single_word": false
|
| 19 |
+
},
|
| 20 |
+
"<|scratchpad|>": {
|
| 21 |
+
"content": 3,
|
| 22 |
+
"lstrip": false,
|
| 23 |
+
"rstrip": false,
|
| 24 |
+
"single_word": false
|
| 25 |
+
},
|
| 26 |
+
"<|final|>": {
|
| 27 |
+
"content": 4,
|
| 28 |
+
"lstrip": false,
|
| 29 |
+
"rstrip": false,
|
| 30 |
+
"single_word": false
|
| 31 |
+
},
|
| 32 |
+
"<|analyst|>": {
|
| 33 |
+
"content": 5,
|
| 34 |
+
"lstrip": false,
|
| 35 |
+
"rstrip": false,
|
| 36 |
+
"single_word": false
|
| 37 |
+
},
|
| 38 |
+
"<|skeptic|>": {
|
| 39 |
+
"content": 6,
|
| 40 |
+
"lstrip": false,
|
| 41 |
+
"rstrip": false,
|
| 42 |
+
"single_word": false
|
| 43 |
+
}
|
| 44 |
+
}
|
hf_repo_v8/tiny-liquid-q8.gguf
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:b264e8ec80a1e7312ffc64f371679fb1fb7956440cedd0df6cfdcc95b91814e2
|
| 3 |
+
size 10742208
|
hf_repo_v8/tokenizer.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
hf_repo_v8/tokenizer_config.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"tokenizer_class": "PreTrainedTokenizerFast",
|
| 3 |
+
"model_max_length": 1024,
|
| 4 |
+
"bos_token": null,
|
| 5 |
+
"eos_token": "<|endoftext|>",
|
| 6 |
+
"unk_token": null,
|
| 7 |
+
"pad_token": "<|endoftext|>",
|
| 8 |
+
"added_tokens_decoder": {
|
| 9 |
+
"0": {
|
| 10 |
+
"content": "<|endoftext|>",
|
| 11 |
+
"special": true
|
| 12 |
+
},
|
| 13 |
+
"1": {
|
| 14 |
+
"content": "<|user|>",
|
| 15 |
+
"special": true
|
| 16 |
+
},
|
| 17 |
+
"2": {
|
| 18 |
+
"content": "<|assistant|>",
|
| 19 |
+
"special": true
|
| 20 |
+
},
|
| 21 |
+
"3": {
|
| 22 |
+
"content": "<|scratchpad|>",
|
| 23 |
+
"special": true
|
| 24 |
+
},
|
| 25 |
+
"4": {
|
| 26 |
+
"content": "<|final|>",
|
| 27 |
+
"special": true
|
| 28 |
+
},
|
| 29 |
+
"5": {
|
| 30 |
+
"content": "<|analyst|>",
|
| 31 |
+
"special": true
|
| 32 |
+
},
|
| 33 |
+
"6": {
|
| 34 |
+
"content": "<|skeptic|>",
|
| 35 |
+
"special": true
|
| 36 |
+
}
|
| 37 |
+
},
|
| 38 |
+
"chat_template": "{% for m in messages %}{% if m['role'] == 'system' %}<|analyst|>{% endif %}{% if m['role'] == 'user' %}<|user|>{{ m['content'] }}<|assistant|>{% endif %}{% if m['role'] == 'assistant' %}{{ m['content'] }}<|endoftext|>{% endif %}{% endfor %}"
|
| 39 |
+
}
|
hf_upload.py
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Publish hf_repo to Hugging Face.
|
| 2 |
+
|
| 3 |
+
1. Login: huggingface-cli login (or set HF_TOKEN)
|
| 4 |
+
2. Run: .venv/bin/python hf_upload.py --repo YOUR_ORG/tiny-liquid-analyst
|
| 5 |
+
|
| 6 |
+
Creates the repo if missing, uploads every file in hf_repo/, and prints the
|
| 7 |
+
model page URL. Requires huggingface_hub (installed).
|
| 8 |
+
"""
|
| 9 |
+
|
| 10 |
+
import argparse
|
| 11 |
+
import sys
|
| 12 |
+
from pathlib import Path
|
| 13 |
+
|
| 14 |
+
from huggingface_hub import HfApi
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
def main():
|
| 18 |
+
ap = argparse.ArgumentParser()
|
| 19 |
+
ap.add_argument("--repo", default="YOUR_ORG/tiny-liquid-analyst",
|
| 20 |
+
help="HF repo id, e.g. yourname/tiny-liquid-analyst")
|
| 21 |
+
ap.add_argument("--dir", default="hf_repo")
|
| 22 |
+
ap.add_argument("--private", action="store_true", help="create as private repo")
|
| 23 |
+
args = ap.parse_args()
|
| 24 |
+
|
| 25 |
+
if args.repo.startswith("YOUR_ORG"):
|
| 26 |
+
sys.exit("set --repo to your HF repo id (e.g. yourname/tiny-liquid-analyst)")
|
| 27 |
+
|
| 28 |
+
api = HfApi()
|
| 29 |
+
try:
|
| 30 |
+
api.repo_info(args.repo)
|
| 31 |
+
print(f"repo exists: {args.repo}")
|
| 32 |
+
except Exception:
|
| 33 |
+
api.create_repo(args.repo, private=args.private, repo_type="model")
|
| 34 |
+
print(f"created repo: {args.repo}")
|
| 35 |
+
|
| 36 |
+
files = sorted(Path(args.dir).rglob("*"))
|
| 37 |
+
files = [f for f in files if f.is_file() and f.name not in (".DS_Store",)]
|
| 38 |
+
paths = [str(f) for f in files]
|
| 39 |
+
api.upload_folder(folder_path=args.dir, repo_id=args.repo, repo_type="model")
|
| 40 |
+
print(f"uploaded {len(paths)} files -> https://huggingface.co/{args.repo}")
|
| 41 |
+
print("next: edit the model card link in hf_repo/README.md and re-upload, or set it via the web UI.")
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
if __name__ == "__main__":
|
| 45 |
+
main()
|
logs/baseline_eval_tiny25m.log
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
== eval ckpt/tiny18m2/model_8500.pt ==
|
| 2 |
+
|
| 3 |
+
[p01] score 0.00 | verdict: funcspanmintrue | conf: cannot assess
|
| 4 |
+
[p02] score 0.00 | verdict: notminpisconfunsupparttrue | conf: cannot assess
|
| 5 |
+
[p03] score 0.00 | verdict: cmparttfixed | conf: cannot assess
|
| 6 |
+
[p04] score 0.00 | verdict: partmincisleantrue | conf: cannot assess
|
| 7 |
+
[p05] score 0.00 | verdict: funcspanminupponislealse | conf: canLHIGH
|
| 8 |
+
[p06] score 0.00 | verdict: cmpfixed | conf: cannot assess
|
| 9 |
+
[p07] score 0.00 | verdict: partminctrue | conf: cannot assess
|
| 10 |
+
[p08] score 0.00 | verdict: funcspaninmislealupponse | conf: canLHIGH
|
| 11 |
+
[p09] score 0.00 | verdict: funcspanminupponislealse | conf: canLHIGH
|
| 12 |
+
[p10] score 0.00 | verdict: cmpfixed | conf: cannot assess
|
| 13 |
+
[p11] score 0.00 | verdict: partcinfanmislealse | conf: canLHIGH
|
| 14 |
+
[p12] score 0.00 | verdict: funcspanmintrue | conf: cannot assess
|
| 15 |
+
[p13] score 0.00 | verdict: cmpfixinanislealse | conf: canLHIGH
|
| 16 |
+
[p14] score 0.00 | verdict: partcinfunsuppanmislealse | conf: cannot assess
|
| 17 |
+
[p15] score 0.00 | verdict: funcspanuppinmislealse | conf: canLHIGH
|
| 18 |
+
[p16] score 0.00 | verdict: cmpfunanislesubstartinantiated | conf: cannot assess
|
| 19 |
+
[p17] score 0.00 | verdict: funcspanminislealse | conf: cannot assess
|
| 20 |
+
[p18] score 0.00 | verdict: funcspanuppinmisleubstartant | conf: cannot assess
|
| 21 |
+
[p19] score 0.00 | verdict: partmincacconfunsuisleixed | conf: cannot assess
|
| 22 |
+
[p20] score 0.00 | verdict: partmincislefunstrue | conf: canLHIGH
|
| 23 |
+
[p21] score 0.00 | verdict: mpcfunsuppinanislealse | conf: canLHIGH
|
| 24 |
+
[p22] score 0.00 | verdict: tpcinfunsuppmislerue | conf: canLHIGH
|
| 25 |
+
[p23] score 0.00 | verdict: funcspanuppinmislealse | conf: canLHIGH
|
| 26 |
+
[p24] score 0.00 | verdict: funcspanminislealse | conf: cannot assess
|
| 27 |
+
[p25] score 0.00 | verdict: cmpfinanisleixed | conf: canLHIGH
|
| 28 |
+
[p26] score 0.00 | verdict: cmpfunanislesubstarttrue | conf: canLHIGH
|
| 29 |
+
[p27] score 0.00 | verdict: funcsuppinpanmtrue | conf: canLHIGH
|
| 30 |
+
[p28] score 0.00 | verdict: cmpfunsuppinisleantrue | conf: cannot assess
|
| 31 |
+
[p29] score 0.00 | verdict: funcspanmintrue | conf: cLHIGH
|
| 32 |
+
[p30] score 0.00 | verdict: funcspanmintrue | conf: canLHIGH
|
| 33 |
+
[p31] score 0.00 | verdict: parttincanmislerue | conf: cannot assess
|
| 34 |
+
[p32] score 0.00 | verdict: funcspmintrue | conf: canLHIGH
|
| 35 |
+
[p33] score 0.00 | verdict: cmpfixed | conf: cannot assess
|
| 36 |
+
[p34] score 0.00 | verdict: partmincaconfuncsuppantr | conf: cannot assess
|
| 37 |
+
[p35] score 0.00 | verdict: cmpinfunsuacctrue | conf: cannot assess
|
| 38 |
+
[p36] score 0.00 | verdict: mincpanislefixed | conf: cannot assess
|
| 39 |
+
[p37] score 0.00 | verdict: minpctfunsuppranislealse | conf: canLHIGH
|
| 40 |
+
[p38] score 0.00 | verdict: partmincacctfunsrue | conf: canLHIGH
|
| 41 |
+
[p39] score 0.00 | verdict: partmincislefunsuaccontr | conf: cannot assess
|
| 42 |
+
[p40] score 0.00 | verdict: funcspanmintrue | conf: cannot assess
|
| 43 |
+
[p41] score 0.00 | verdict: confinanalaccurate | conf: cannot assess
|
| 44 |
+
[p42] score 0.00 | verdict: confunsuanalse | conf: canHIMEDIUM
|
| 45 |
+
[p43] score 0.00 | verdict: funsualtrconanmisleinsinac | conf: cannot assess
|
| 46 |
+
[p44] score 0.00 | verdict: confunsalanmtrisuleinsinac | conf: HIMLGEcannot assess
|
| 47 |
+
[p45] score 0.00 | verdict: inftrue | conf: HIGH
|
| 48 |
+
[p46] score 0.00 | verdict: notconfal atranminisse | conf: HIMLGEcannot assess
|
| 49 |
+
[p47] score 0.00 | verdict: funsutralconaninsinaccurate | conf: cannot assess
|
| 50 |
+
[p48] score 0.00 | verdict: confinanalaccurate | conf: cannot assess
|
| 51 |
+
[p49] score 0.00 | verdict: notconf apanal discrepinaccurate | conf: HIMEcanDILUM
|
| 52 |
+
[p50] score 0.00 | verdict: notconfan aunsalupported | conf: HIMEcanDILUM
|
| 53 |
+
|
| 54 |
+
mean verdict score: 0.000 accuracy@0.5: 0.00 format rate: 1.00
|
| 55 |
+
by category:
|
| 56 |
+
generic mean 0.000 n=50
|
| 57 |
+
=== probes_researcher ===
|
| 58 |
+
== eval ckpt/tiny18m2/model_8500.pt ==
|
| 59 |
+
|
| 60 |
+
[verdict-00] score 0.00 | verdict: cmpfixed | conf: cannot assess
|
| 61 |
+
[verdict-01] score 0.00 | verdict: funcsupmintrue | conf: cannot assess
|
| 62 |
+
[verdict-02] score 0.00 | verdict: cmpfixed | conf: cannot assess
|
| 63 |
+
[verdict-03] score 0.00 | verdict: funcspanminislealse | conf: canLHIGH
|
| 64 |
+
[verdict-04] score 0.00 | verdict: funcspanuppinmislealse | conf: canLHIGH
|
| 65 |
+
[verdict-05] score 0.00 | verdict: funscintmpanislerue | conf: cannot assess
|
| 66 |
+
[discrepancy-06] score 0.00 | verdict: funcspanmintrue | conf: canLHIGH
|
| 67 |
+
[discrepancy-07] score 0.00 | verdict: funcspanuppinmislealse | conf: canLHIGH
|
| 68 |
+
[discrepancy-08] score 0.00 | verdict: funcsupmintrue | conf: canLHIGH
|
| 69 |
+
[discrepancy-09] score 0.00 | verdict: funcsuppinpanmixed | conf: cannot assess
|
| 70 |
+
[pattern-10] score 0.00 | verdict: cmpfintrue | conf: canLHIGH
|
| 71 |
+
[pattern-11] score 0.00 | verdict: cminpanfixed | conf: cannot assess
|
| 72 |
+
[pattern-12] score 0.00 | verdict: miscpinfixed | conf: cannot assess
|
| 73 |
+
[safety-13] score 0.00 | verdict: parttmincisleranfunsuacc | conf: canLHIGH
|
| 74 |
+
[safety-14] score 0.00 | verdict: mincpanfunsuacconisletr | conf: cannot assess
|
| 75 |
+
[safety-15] score 0.00 | verdict: partminctrue | conf: canLHIGH
|
| 76 |
+
[safety-16] score 0.00 | verdict: funcspanmintrue | conf: cHIGH
|
| 77 |
+
[selfcheck-17] score 0.00 | verdict: cmpfunsuppintrue | conf: canLHIGH
|
| 78 |
+
[selfcheck-18] score 0.00 | verdict: notminpisconfixed | conf: cannot assess
|
| 79 |
+
[symbolism-19] score 0.00 | verdict: funcsuppinpanmislealse | conf: cannot assess
|
| 80 |
+
[symbolism-20] score 0.00 | verdict: partminctrue | conf: canLHIGH
|
| 81 |
+
[symbolism-21] score 0.00 | verdict: punscinmislefixed | conf: cannot assess
|
| 82 |
+
[symbolism-22] score 0.00 | verdict: cmpfunsuppintrue | conf: canLHIGH
|
| 83 |
+
[gap-23] score 0.00 | verdict: cmpfixintrue | conf: canLHIGH
|
| 84 |
+
[gap-24] score 0.00 | verdict: cmpfixinanislealse | conf: cannot assess
|
| 85 |
+
[gap-25] score 0.00 | verdict: funpartsubmincanislealse | conf: cannot assess
|
| 86 |
+
[gap-26] score 0.00 | verdict: funcspaninmisleupponixed | conf: cLHIGH
|
| 87 |
+
|
| 88 |
+
mean verdict score: 0.000 accuracy@0.5: 0.00 format rate: 1.00
|
| 89 |
+
by category:
|
| 90 |
+
discrepancy mean 0.000 n=4
|
| 91 |
+
gap mean 0.000 n=4
|
| 92 |
+
pattern mean 0.000 n=3
|
| 93 |
+
safety mean 0.000 n=4
|
| 94 |
+
selfcheck mean 0.000 n=2
|
| 95 |
+
symbolism mean 0.000 n=4
|
| 96 |
+
verdict mean 0.000 n=6
|
logs/bench2_val.log
ADDED
|
File without changes
|
logs/bench_dpo.log
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
benchmarking ckpt/dpo/model_final.pt | params 7,788,288 | d_model 320 blocks 6
|
logs/bench_dpo_2.log
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
benchmarking ckpt/dpo/model_final.pt | params 7,788,288 | d_model 320 blocks 6
|
logs/bench_forensic.log
ADDED
|
File without changes
|
logs/calib90_dpo3_200_main.jsonl
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{"id": "p01", "score": 0.0, "verdict": "abstain", "conf": "HIGH", "canon": "refutes"}
|
| 2 |
+
{"id": "p02", "score": 0.0, "verdict": "abstain", "conf": "LOW", "canon": "not a contradiction"}
|
| 3 |
+
{"id": "p03", "score": 1.0, "verdict": "overclaim", "conf": "LOW", "canon": "overclaim"}
|
| 4 |
+
{"id": "p04", "score": 0.0, "verdict": "low confidence", "conf": "LOW", "canon": "not enough information"}
|
| 5 |
+
{"id": "p05", "score": 0.0, "verdict": "abstain", "conf": "HIGH", "canon": "false"}
|
| 6 |
+
{"id": "p06", "score": 0.0, "verdict": "abstain", "conf": "LOW", "canon": "unsubstantiated"}
|
| 7 |
+
{"id": "p07", "score": 0.0, "verdict": "low confidence", "conf": "cannot assess", "canon": "true"}
|
| 8 |
+
{"id": "p08", "score": 1.0, "verdict": "overclaim", "conf": "LOW", "canon": "overclaim"}
|
| 9 |
+
{"id": "p09", "score": 0.0, "verdict": "unverifiable", "conf": "LOW", "canon": "false"}
|
| 10 |
+
{"id": "p10", "score": 0.0, "verdict": "abstain", "conf": "LOW", "canon": "unsubstantiated"}
|
| 11 |
+
{"id": "p11", "score": 0.0, "verdict": "overclaim", "conf": "LOW", "canon": "not enough information"}
|
| 12 |
+
{"id": "p12", "score": 0.0, "verdict": "overclaim", "conf": "MEDIUM", "canon": "misleading"}
|
| 13 |
+
{"id": "p13", "score": 0.0, "verdict": "overclaim", "conf": "LOW", "canon": "contradiction"}
|
| 14 |
+
{"id": "p14", "score": 0.0, "verdict": "abstain", "conf": "LOW", "canon": "not a contradiction"}
|
| 15 |
+
{"id": "p15", "score": 0.0, "verdict": "abstain", "conf": "LOW", "canon": "not enough information"}
|
| 16 |
+
{"id": "p16", "score": 0.0, "verdict": "low confidence", "conf": "HIGH", "canon": "unsubstantiated"}
|
| 17 |
+
{"id": "p17", "score": 0.0, "verdict": "overclaim", "conf": "LOW", "canon": "misleading"}
|
| 18 |
+
{"id": "p18", "score": 0.0, "verdict": "abstain", "conf": "LOW", "canon": "misleading"}
|
| 19 |
+
{"id": "p19", "score": 0.0, "verdict": "low confidence", "conf": "LOW", "canon": "unsubstantiated"}
|
| 20 |
+
{"id": "p20", "score": 0.0, "verdict": "abstain", "conf": "LOW", "canon": "overclaim"}
|
| 21 |
+
{"id": "p21", "score": 0.0, "verdict": "abstain", "conf": "LOW", "canon": "unsubstantiated"}
|
| 22 |
+
{"id": "p22", "score": 0.0, "verdict": "abstain", "conf": "LOW", "canon": "overclaim"}
|
| 23 |
+
{"id": "p23", "score": 0.0, "verdict": "abstain", "conf": "LOW", "canon": "overclaim"}
|
| 24 |
+
{"id": "p24", "score": 0.0, "verdict": "abstain", "conf": "LOW", "canon": "false"}
|
| 25 |
+
{"id": "p25", "score": 1.0, "verdict": "overclaim", "conf": "MEDIUM", "canon": "overclaim"}
|
| 26 |
+
{"id": "p26", "score": 0.0, "verdict": "abstain", "conf": "LOW", "canon": "overclaim"}
|
| 27 |
+
{"id": "p27", "score": 0.0, "verdict": "abstain", "conf": "LOW", "canon": "false"}
|
| 28 |
+
{"id": "p28", "score": 0.0, "verdict": "not enough information", "conf": "LOW", "canon": "unsubstantiated"}
|
| 29 |
+
{"id": "p29", "score": 0.0, "verdict": "abstain", "conf": "LOW", "canon": "false"}
|
| 30 |
+
{"id": "p30", "score": 0.0, "verdict": "overclaim", "conf": "LOW", "canon": "false"}
|
| 31 |
+
{"id": "p31", "score": 0.0, "verdict": "partially true", "conf": "LOW", "canon": "unsubstantiated"}
|
| 32 |
+
{"id": "p32", "score": 0.0, "verdict": "abstain", "conf": "LOW", "canon": "overclaim"}
|
| 33 |
+
{"id": "p33", "score": 1.0, "verdict": "overclaim", "conf": "LOW", "canon": "overclaim"}
|
| 34 |
+
{"id": "p34", "score": 0.0, "verdict": "overclaim", "conf": "cannot assess", "canon": "false"}
|
| 35 |
+
{"id": "p35", "score": 0.0, "verdict": "abstain", "conf": "LOW", "canon": "false"}
|
| 36 |
+
{"id": "p36", "score": 0.0, "verdict": "low confidence", "conf": "LOW", "canon": "false"}
|
| 37 |
+
{"id": "p37", "score": 0.0, "verdict": "overclaim", "conf": "LOW", "canon": "false"}
|
| 38 |
+
{"id": "p38", "score": 0.0, "verdict": "overclaim", "conf": "MEDIUM", "canon": null}
|
| 39 |
+
{"id": "p39", "score": 0.0, "verdict": "low confidence", "conf": "LOW", "canon": "unsubstantiated"}
|
| 40 |
+
{"id": "p40", "score": 0.0, "verdict": "overclaim", "conf": "MEDIUM", "canon": "low confidence"}
|
| 41 |
+
{"id": "p41", "score": 0.0, "verdict": "overclaim", "conf": "LOW", "canon": "unsubstantiated"}
|
| 42 |
+
{"id": "p42", "score": 1.0, "verdict": "overclaim", "conf": "LOW", "canon": "overclaim"}
|
| 43 |
+
{"id": "p43", "score": 1.0, "verdict": "overclaim", "conf": "LOW", "canon": "overclaim"}
|
| 44 |
+
{"id": "p44", "score": 1.0, "verdict": "overclaim", "conf": "LOW", "canon": "overclaim"}
|
| 45 |
+
{"id": "p45", "score": 1.0, "verdict": "overclaim", "conf": "LOW", "canon": "overclaim"}
|
| 46 |
+
{"id": "p46", "score": 1.0, "verdict": "overclaim", "conf": "HIGH", "canon": "overclaim"}
|
| 47 |
+
{"id": "p47", "score": 1.0, "verdict": "overclaim", "conf": "LOW", "canon": "overclaim"}
|
| 48 |
+
{"id": "p48", "score": 1.0, "verdict": "overclaim", "conf": "LOW", "canon": "overclaim"}
|
| 49 |
+
{"id": "p49", "score": 1.0, "verdict": "overclaim", "conf": "LOW", "canon": "overclaim"}
|
| 50 |
+
{"id": "p50", "score": 1.0, "verdict": "overclaim", "conf": "LOW", "canon": "overclaim"}
|
logs/calib90_dpo3_200_res.jsonl
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{"id": "verdict-00", "score": 0.0, "verdict": "abstain", "conf": "LOW", "canon": "true"}
|
| 2 |
+
{"id": "verdict-01", "score": 0.0, "verdict": "low confidence", "conf": "LOW", "canon": "false"}
|
| 3 |
+
{"id": "verdict-02", "score": 0.0, "verdict": "overclaim", "conf": "LOW", "canon": "unsubstantiated"}
|
| 4 |
+
{"id": "verdict-03", "score": 0.0, "verdict": "overclaim", "conf": "LOW", "canon": "contradiction"}
|
| 5 |
+
{"id": "verdict-04", "score": 0.0, "verdict": "overclaim", "conf": "LOW", "canon": "true"}
|
| 6 |
+
{"id": "verdict-05", "score": 0.0, "verdict": "abstain", "conf": "LOW", "canon": "unsubstantiated"}
|
| 7 |
+
{"id": "discrepancy-06", "score": 0.0, "verdict": "low confidence", "conf": "LOW", "canon": "false"}
|
| 8 |
+
{"id": "discrepancy-07", "score": 0.0, "verdict": "abstain", "conf": "HIGH", "canon": "contradiction"}
|
| 9 |
+
{"id": "discrepancy-08", "score": 0.0, "verdict": "overclaim", "conf": "cannot assess", "canon": "false"}
|
| 10 |
+
{"id": "discrepancy-09", "score": 0.0, "verdict": "low confidence", "conf": "LOW", "canon": null}
|
| 11 |
+
{"id": "pattern-10", "score": 0.0, "verdict": "low confidence", "conf": "HIGH", "canon": null}
|
| 12 |
+
{"id": "pattern-11", "score": 0.0, "verdict": "overclaim", "conf": "LOW", "canon": null}
|
| 13 |
+
{"id": "pattern-12", "score": 0.0, "verdict": "abstain", "conf": "HIGH", "canon": null}
|
| 14 |
+
{"id": "safety-13", "score": 0.0, "verdict": "abstain", "conf": "LOW", "canon": null}
|
| 15 |
+
{"id": "safety-14", "score": 0.0, "verdict": "low confidence", "conf": "LOW", "canon": null}
|
| 16 |
+
{"id": "safety-15", "score": 0.0, "verdict": "overclaim", "conf": "MEDIUM", "canon": null}
|
| 17 |
+
{"id": "safety-16", "score": 0.0, "verdict": "abstain", "conf": "LOW", "canon": null}
|
| 18 |
+
{"id": "selfcheck-17", "score": 0.0, "verdict": "overclaim", "conf": "LOW", "canon": "not enough information"}
|
| 19 |
+
{"id": "selfcheck-18", "score": 0.0, "verdict": "overclaim", "conf": "LOW", "canon": "low confidence"}
|
| 20 |
+
{"id": "symbolism-19", "score": 1.0, "verdict": "low confidence", "conf": "LOW", "canon": "low confidence"}
|
| 21 |
+
{"id": "symbolism-20", "score": 1.0, "verdict": "low confidence", "conf": "LOW", "canon": "low confidence"}
|
| 22 |
+
{"id": "symbolism-21", "score": 0.0, "verdict": "true", "conf": "LOW", "canon": "low confidence"}
|
| 23 |
+
{"id": "symbolism-22", "score": 0.0, "verdict": "low confidence", "conf": "HIGH", "canon": null}
|
| 24 |
+
{"id": "gap-23", "score": 0.0, "verdict": "low confidence", "conf": "LOW", "canon": "unsubstantiated"}
|
| 25 |
+
{"id": "gap-24", "score": 0.0, "verdict": "overclaim", "conf": "MEDIUM", "canon": "not enough information"}
|
| 26 |
+
{"id": "gap-25", "score": 0.0, "verdict": "low confidence", "conf": "LOW", "canon": "unsubstantiated"}
|
| 27 |
+
{"id": "gap-26", "score": 0.0, "verdict": "abstain", "conf": "LOW", "canon": "false"}
|
logs/calib_dpo3_200_main.jsonl
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{"id": "p01", "score": 0.0, "verdict": "low confidence", "conf": "LOW", "canon": "refutes"}
|
| 2 |
+
{"id": "p02", "score": 0.0, "verdict": "low confidence", "conf": "HIGH", "canon": "not a contradiction"}
|
| 3 |
+
{"id": "p03", "score": 0.0, "verdict": "low confidence", "conf": "HIGH", "canon": "overclaim"}
|
| 4 |
+
{"id": "p04", "score": 0.0, "verdict": "unverifiable", "conf": "HIGH", "canon": "not enough information"}
|
| 5 |
+
{"id": "p05", "score": 0.0, "verdict": "partially true", "conf": "LOW", "canon": "false"}
|
| 6 |
+
{"id": "p06", "score": 0.0, "verdict": "low confidence", "conf": "LOW", "canon": "unsubstantiated"}
|
| 7 |
+
{"id": "p07", "score": 1.0, "verdict": "true", "conf": "cannot assess", "canon": "true"}
|
| 8 |
+
{"id": "p08", "score": 0.0, "verdict": "true", "conf": "LOW", "canon": "overclaim"}
|
| 9 |
+
{"id": "p09", "score": 0.0, "verdict": "low confidence", "conf": "HIGH", "canon": "false"}
|
| 10 |
+
{"id": "p10", "score": 0.0, "verdict": "low confidence", "conf": "HIGH", "canon": "unsubstantiated"}
|
| 11 |
+
{"id": "p11", "score": 0.0, "verdict": "abstain", "conf": "cannot assess", "canon": "not enough information"}
|
| 12 |
+
{"id": "p12", "score": 0.0, "verdict": "overclaim", "conf": "MEDIUM", "canon": "misleading"}
|
| 13 |
+
{"id": "p13", "score": 0.0, "verdict": "low confidence", "conf": "LOW", "canon": "contradiction"}
|
| 14 |
+
{"id": "p14", "score": 0.0, "verdict": "overclaim", "conf": "cannot assess", "canon": "not a contradiction"}
|
| 15 |
+
{"id": "p15", "score": 0.0, "verdict": "not a contradiction", "conf": "HIGH", "canon": "not enough information"}
|
| 16 |
+
{"id": "p16", "score": 0.0, "verdict": "true", "conf": "HIGH", "canon": "unsubstantiated"}
|
| 17 |
+
{"id": "p17", "score": 0.0, "verdict": "low confidence", "conf": "HIGH", "canon": "misleading"}
|
| 18 |
+
{"id": "p18", "score": 0.0, "verdict": "overclaim", "conf": "MEDIUM", "canon": "misleading"}
|
| 19 |
+
{"id": "p19", "score": 0.0, "verdict": "true", "conf": "HIGH", "canon": "unsubstantiated"}
|
| 20 |
+
{"id": "p20", "score": 1.0, "verdict": "overclaim", "conf": "HIGH", "canon": "overclaim"}
|
| 21 |
+
{"id": "p21", "score": 0.0, "verdict": "low confidence", "conf": "LOW", "canon": "unsubstantiated"}
|
| 22 |
+
{"id": "p22", "score": 0.0, "verdict": "low confidence", "conf": "HIGH", "canon": "overclaim"}
|
| 23 |
+
{"id": "p23", "score": 0.0, "verdict": "not enough information", "conf": "cannot assess", "canon": "overclaim"}
|
| 24 |
+
{"id": "p24", "score": 0.0, "verdict": "low confidence", "conf": "HIGH", "canon": "false"}
|
| 25 |
+
{"id": "p25", "score": 0.0, "verdict": "true", "conf": "MEDIUM", "canon": "overclaim"}
|
| 26 |
+
{"id": "p26", "score": 0.0, "verdict": "unverifiable", "conf": "LOW", "canon": "overclaim"}
|
| 27 |
+
{"id": "p27", "score": 0.0, "verdict": "overclaim", "conf": "cannot assess", "canon": "false"}
|
| 28 |
+
{"id": "p28", "score": 0.0, "verdict": "abstain", "conf": "cannot assess", "canon": "unsubstantiated"}
|
| 29 |
+
{"id": "p29", "score": 0.0, "verdict": "overclaim", "conf": "HIGH", "canon": "false"}
|
| 30 |
+
{"id": "p30", "score": 0.0, "verdict": "true", "conf": "HIGH", "canon": "false"}
|
| 31 |
+
{"id": "p31", "score": 0.0, "verdict": "true", "conf": "cannot assess", "canon": "unsubstantiated"}
|
| 32 |
+
{"id": "p32", "score": 0.0, "verdict": "low confidence", "conf": "HIGH", "canon": "overclaim"}
|
| 33 |
+
{"id": "p33", "score": 1.0, "verdict": "overclaim", "conf": "MEDIUM", "canon": "overclaim"}
|
| 34 |
+
{"id": "p34", "score": 0.0, "verdict": "no meaningful pattern", "conf": "HIGH", "canon": "false"}
|
| 35 |
+
{"id": "p35", "score": 0.0, "verdict": "unverifiable", "conf": "HIGH", "canon": "false"}
|
| 36 |
+
{"id": "p36", "score": 0.0, "verdict": "low confidence", "conf": "HIGH", "canon": "false"}
|
| 37 |
+
{"id": "p37", "score": 0.0, "verdict": "low confidence", "conf": "LOW", "canon": "false"}
|
| 38 |
+
{"id": "p38", "score": 0.0, "verdict": "abstain", "conf": "HIGH", "canon": null}
|
| 39 |
+
{"id": "p39", "score": 0.0, "verdict": "low confidence", "conf": "LOW", "canon": "unsubstantiated"}
|
| 40 |
+
{"id": "p40", "score": 0.0, "verdict": "true", "conf": "HIGH", "canon": "low confidence"}
|
| 41 |
+
{"id": "p41", "score": 0.0, "verdict": "not enough information", "conf": "MEDIUM", "canon": "unsubstantiated"}
|
| 42 |
+
{"id": "p42", "score": 0.0, "verdict": "not enough information", "conf": "MEDIUM", "canon": "overclaim"}
|
| 43 |
+
{"id": "p43", "score": 1.0, "verdict": "overclaim", "conf": "MEDIUM", "canon": "overclaim"}
|
| 44 |
+
{"id": "p44", "score": 0.0, "verdict": "not enough information", "conf": "MEDIUM", "canon": "overclaim"}
|
| 45 |
+
{"id": "p45", "score": 1.0, "verdict": "overclaim", "conf": "LOW", "canon": "overclaim"}
|
| 46 |
+
{"id": "p46", "score": 1.0, "verdict": "overclaim", "conf": "LOW", "canon": "overclaim"}
|
| 47 |
+
{"id": "p47", "score": 0.0, "verdict": "inaccurate", "conf": "MEDIUM", "canon": "overclaim"}
|
| 48 |
+
{"id": "p48", "score": 1.0, "verdict": "overclaim", "conf": "MEDIUM", "canon": "overclaim"}
|
| 49 |
+
{"id": "p49", "score": 0.0, "verdict": "not enough information", "conf": "MEDIUM", "canon": "overclaim"}
|
| 50 |
+
{"id": "p50", "score": 0.0, "verdict": "not enough information", "conf": "MEDIUM", "canon": "overclaim"}
|
logs/calib_dpo3_200_res.jsonl
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{"id": "verdict-00", "score": 0.0, "verdict": "low confidence", "conf": "LOW", "canon": "true"}
|
| 2 |
+
{"id": "verdict-01", "score": 0.0, "verdict": "low confidence", "conf": "LOW", "canon": "false"}
|
| 3 |
+
{"id": "verdict-02", "score": 0.0, "verdict": "low confidence", "conf": "LOW", "canon": "unsubstantiated"}
|
| 4 |
+
{"id": "verdict-03", "score": 0.0, "verdict": "low confidence", "conf": "LOW", "canon": "contradiction"}
|
| 5 |
+
{"id": "verdict-04", "score": 0.0, "verdict": "low confidence", "conf": "HIGH", "canon": "true"}
|
| 6 |
+
{"id": "verdict-05", "score": 0.0, "verdict": "overclaim", "conf": "MEDIUM", "canon": "unsubstantiated"}
|
| 7 |
+
{"id": "discrepancy-06", "score": 0.0, "verdict": "low confidence", "conf": "LOW", "canon": "false"}
|
| 8 |
+
{"id": "discrepancy-07", "score": 0.0, "verdict": "false", "conf": "cannot assess", "canon": "contradiction"}
|
| 9 |
+
{"id": "discrepancy-08", "score": 0.0, "verdict": "low confidence", "conf": "HIGH", "canon": "false"}
|
| 10 |
+
{"id": "discrepancy-09", "score": 0.0, "verdict": "not a contradiction", "conf": "cannot assess", "canon": null}
|
| 11 |
+
{"id": "pattern-10", "score": 0.0, "verdict": "true", "conf": "cannot assess", "canon": null}
|
| 12 |
+
{"id": "pattern-11", "score": 0.0, "verdict": "low confidence", "conf": "HIGH", "canon": null}
|
| 13 |
+
{"id": "pattern-12", "score": 0.0, "verdict": "not a contradiction", "conf": "cannot assess", "canon": null}
|
| 14 |
+
{"id": "safety-13", "score": 0.0, "verdict": "low confidence", "conf": "HIGH", "canon": null}
|
| 15 |
+
{"id": "safety-14", "score": 0.0, "verdict": "unverifiable", "conf": "HIGH", "canon": null}
|
| 16 |
+
{"id": "safety-15", "score": 0.0, "verdict": "not enough information", "conf": "HIGH", "canon": null}
|
| 17 |
+
{"id": "safety-16", "score": 0.0, "verdict": "unverifiable", "conf": "HIGH", "canon": null}
|
| 18 |
+
{"id": "selfcheck-17", "score": 0.0, "verdict": "true", "conf": "LOW", "canon": "not enough information"}
|
| 19 |
+
{"id": "selfcheck-18", "score": 1.0, "verdict": "low confidence", "conf": "HIGH", "canon": "low confidence"}
|
| 20 |
+
{"id": "symbolism-19", "score": 0.0, "verdict": "unverifiable", "conf": "HIGH", "canon": "low confidence"}
|
| 21 |
+
{"id": "symbolism-20", "score": 0.0, "verdict": "unverifiable", "conf": "HIGH", "canon": "low confidence"}
|
| 22 |
+
{"id": "symbolism-21", "score": 0.0, "verdict": "true", "conf": "cannot assess", "canon": "low confidence"}
|
| 23 |
+
{"id": "symbolism-22", "score": 0.0, "verdict": "true", "conf": "cannot assess", "canon": null}
|
| 24 |
+
{"id": "gap-23", "score": 0.0, "verdict": "true", "conf": "cannot assess", "canon": "unsubstantiated"}
|
| 25 |
+
{"id": "gap-24", "score": 0.0, "verdict": "low confidence", "conf": "HIGH", "canon": "not enough information"}
|
| 26 |
+
{"id": "gap-25", "score": 0.0, "verdict": "low confidence", "conf": "HIGH", "canon": "unsubstantiated"}
|
| 27 |
+
{"id": "gap-26", "score": 0.0, "verdict": "overclaim", "conf": "cannot assess", "canon": "false"}
|
logs/calib_summary_calib90.json
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"tag": "calib90",
|
| 3 |
+
"main": {
|
| 4 |
+
"name": "MAIN",
|
| 5 |
+
"n_total": 49,
|
| 6 |
+
"buckets": {
|
| 7 |
+
"HIGH": {
|
| 8 |
+
"n": 4,
|
| 9 |
+
"correct": 1,
|
| 10 |
+
"acc": 0.25,
|
| 11 |
+
"ci": [
|
| 12 |
+
0.045586062644636216,
|
| 13 |
+
0.6993639475573634
|
| 14 |
+
]
|
| 15 |
+
},
|
| 16 |
+
"MEDIUM": {
|
| 17 |
+
"n": 3,
|
| 18 |
+
"correct": 1,
|
| 19 |
+
"acc": 0.3333333333333333,
|
| 20 |
+
"ci": [
|
| 21 |
+
0.0614903152761605,
|
| 22 |
+
0.7923450448735121
|
| 23 |
+
]
|
| 24 |
+
},
|
| 25 |
+
"LOW": {
|
| 26 |
+
"n": 40,
|
| 27 |
+
"correct": 11,
|
| 28 |
+
"acc": 0.275,
|
| 29 |
+
"ci": [
|
| 30 |
+
0.1610785343314309,
|
| 31 |
+
0.4283525083312457
|
| 32 |
+
]
|
| 33 |
+
},
|
| 34 |
+
"cannot assess": {
|
| 35 |
+
"n": 0,
|
| 36 |
+
"correct": 0,
|
| 37 |
+
"acc": NaN,
|
| 38 |
+
"ci": [
|
| 39 |
+
NaN,
|
| 40 |
+
NaN
|
| 41 |
+
]
|
| 42 |
+
}
|
| 43 |
+
},
|
| 44 |
+
"overall": {
|
| 45 |
+
"n": 49,
|
| 46 |
+
"correct": 13,
|
| 47 |
+
"acc": 0.2653061224489796,
|
| 48 |
+
"ci": [
|
| 49 |
+
0.1621113124514944,
|
| 50 |
+
0.4026255615265835
|
| 51 |
+
]
|
| 52 |
+
}
|
| 53 |
+
},
|
| 54 |
+
"res": {
|
| 55 |
+
"name": "RESEARCHER",
|
| 56 |
+
"n_total": 18,
|
| 57 |
+
"buckets": {
|
| 58 |
+
"HIGH": {
|
| 59 |
+
"n": 1,
|
| 60 |
+
"correct": 0,
|
| 61 |
+
"acc": 0.0,
|
| 62 |
+
"ci": [
|
| 63 |
+
0.0,
|
| 64 |
+
0.7934567085261071
|
| 65 |
+
]
|
| 66 |
+
},
|
| 67 |
+
"MEDIUM": {
|
| 68 |
+
"n": 1,
|
| 69 |
+
"correct": 0,
|
| 70 |
+
"acc": 0.0,
|
| 71 |
+
"ci": [
|
| 72 |
+
0.0,
|
| 73 |
+
0.7934567085261071
|
| 74 |
+
]
|
| 75 |
+
},
|
| 76 |
+
"LOW": {
|
| 77 |
+
"n": 15,
|
| 78 |
+
"correct": 2,
|
| 79 |
+
"acc": 0.13333333333333333,
|
| 80 |
+
"ci": [
|
| 81 |
+
0.0373604698913593,
|
| 82 |
+
0.3788249920651624
|
| 83 |
+
]
|
| 84 |
+
},
|
| 85 |
+
"cannot assess": {
|
| 86 |
+
"n": 0,
|
| 87 |
+
"correct": 0,
|
| 88 |
+
"acc": NaN,
|
| 89 |
+
"ci": [
|
| 90 |
+
NaN,
|
| 91 |
+
NaN
|
| 92 |
+
]
|
| 93 |
+
}
|
| 94 |
+
},
|
| 95 |
+
"overall": {
|
| 96 |
+
"n": 18,
|
| 97 |
+
"correct": 2,
|
| 98 |
+
"acc": 0.1111111111111111,
|
| 99 |
+
"ci": [
|
| 100 |
+
0.031018868453582787,
|
| 101 |
+
0.3280024486660421
|
| 102 |
+
]
|
| 103 |
+
}
|
| 104 |
+
},
|
| 105 |
+
"combined": {
|
| 106 |
+
"name": "COMBINED",
|
| 107 |
+
"n_total": 67,
|
| 108 |
+
"buckets": {
|
| 109 |
+
"HIGH": {
|
| 110 |
+
"n": 5,
|
| 111 |
+
"correct": 1,
|
| 112 |
+
"acc": 0.2,
|
| 113 |
+
"ci": [
|
| 114 |
+
0.03622316096978745,
|
| 115 |
+
0.6244717358814613
|
| 116 |
+
]
|
| 117 |
+
},
|
| 118 |
+
"MEDIUM": {
|
| 119 |
+
"n": 4,
|
| 120 |
+
"correct": 1,
|
| 121 |
+
"acc": 0.25,
|
| 122 |
+
"ci": [
|
| 123 |
+
0.045586062644636216,
|
| 124 |
+
0.6993639475573634
|
| 125 |
+
]
|
| 126 |
+
},
|
| 127 |
+
"LOW": {
|
| 128 |
+
"n": 55,
|
| 129 |
+
"correct": 13,
|
| 130 |
+
"acc": 0.23636363636363636,
|
| 131 |
+
"ci": [
|
| 132 |
+
0.14366521587457487,
|
| 133 |
+
0.36348618721439613
|
| 134 |
+
]
|
| 135 |
+
},
|
| 136 |
+
"cannot assess": {
|
| 137 |
+
"n": 0,
|
| 138 |
+
"correct": 0,
|
| 139 |
+
"acc": NaN,
|
| 140 |
+
"ci": [
|
| 141 |
+
NaN,
|
| 142 |
+
NaN
|
| 143 |
+
]
|
| 144 |
+
}
|
| 145 |
+
},
|
| 146 |
+
"overall": {
|
| 147 |
+
"n": 67,
|
| 148 |
+
"correct": 15,
|
| 149 |
+
"acc": 0.22388059701492538,
|
| 150 |
+
"ci": [
|
| 151 |
+
0.1406360851472927,
|
| 152 |
+
0.33707192822338217
|
| 153 |
+
]
|
| 154 |
+
}
|
| 155 |
+
},
|
| 156 |
+
"high_verdict_mix": {
|
| 157 |
+
"main": {
|
| 158 |
+
"abstain": {
|
| 159 |
+
"n": 2,
|
| 160 |
+
"acc": 0.0
|
| 161 |
+
},
|
| 162 |
+
"low confidence": {
|
| 163 |
+
"n": 1,
|
| 164 |
+
"acc": 0.0
|
| 165 |
+
},
|
| 166 |
+
"overclaim": {
|
| 167 |
+
"n": 1,
|
| 168 |
+
"acc": 1.0
|
| 169 |
+
}
|
| 170 |
+
},
|
| 171 |
+
"res": {
|
| 172 |
+
"abstain": {
|
| 173 |
+
"n": 1,
|
| 174 |
+
"acc": 0.0
|
| 175 |
+
}
|
| 176 |
+
}
|
| 177 |
+
},
|
| 178 |
+
"abstention": {
|
| 179 |
+
"main": {
|
| 180 |
+
"abstain_rate": 0.3673469387755102,
|
| 181 |
+
"abstain_acc": 0.0,
|
| 182 |
+
"should_abstain_n": 3,
|
| 183 |
+
"abstained_on_should": 1
|
| 184 |
+
},
|
| 185 |
+
"res": {
|
| 186 |
+
"abstain_rate": 0.2222222222222222,
|
| 187 |
+
"abstain_acc": 0.0,
|
| 188 |
+
"should_abstain_n": 2,
|
| 189 |
+
"abstained_on_should": 0
|
| 190 |
+
}
|
| 191 |
+
},
|
| 192 |
+
"note": "A confidence bucket whose accuracy is BELOW the overall mean is anti-calibrated: trusting it lowers precision. Weighted voting must use these empirical accuracies, not the label."
|
| 193 |
+
}
|
logs/calib_summary_dpo3_200.json
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"tag": "dpo3_200",
|
| 3 |
+
"combined": {
|
| 4 |
+
"name": "COMBINED",
|
| 5 |
+
"n_total": 77,
|
| 6 |
+
"buckets": {
|
| 7 |
+
"HIGH": {
|
| 8 |
+
"acc": 0.125,
|
| 9 |
+
"n": 8,
|
| 10 |
+
"correct": 1
|
| 11 |
+
},
|
| 12 |
+
"MEDIUM": {
|
| 13 |
+
"acc": 0.16666666666666666,
|
| 14 |
+
"n": 6,
|
| 15 |
+
"correct": 1
|
| 16 |
+
},
|
| 17 |
+
"LOW": {
|
| 18 |
+
"acc": 0.21666666666666667,
|
| 19 |
+
"n": 60,
|
| 20 |
+
"correct": 13
|
| 21 |
+
},
|
| 22 |
+
"cannot assess": {
|
| 23 |
+
"acc": 0.0,
|
| 24 |
+
"n": 3,
|
| 25 |
+
"correct": 0
|
| 26 |
+
}
|
| 27 |
+
},
|
| 28 |
+
"overall": {
|
| 29 |
+
"n": 77,
|
| 30 |
+
"correct": 15,
|
| 31 |
+
"acc": 0.19480519480519481
|
| 32 |
+
}
|
| 33 |
+
},
|
| 34 |
+
"main": {
|
| 35 |
+
"name": "MAIN",
|
| 36 |
+
"n_total": 50,
|
| 37 |
+
"buckets": {
|
| 38 |
+
"HIGH": {
|
| 39 |
+
"acc": 0.25,
|
| 40 |
+
"n": 4,
|
| 41 |
+
"correct": 1
|
| 42 |
+
},
|
| 43 |
+
"MEDIUM": {
|
| 44 |
+
"acc": 0.25,
|
| 45 |
+
"n": 4,
|
| 46 |
+
"correct": 1
|
| 47 |
+
},
|
| 48 |
+
"LOW": {
|
| 49 |
+
"acc": 0.275,
|
| 50 |
+
"n": 40,
|
| 51 |
+
"correct": 11
|
| 52 |
+
},
|
| 53 |
+
"cannot assess": {
|
| 54 |
+
"acc": 0.0,
|
| 55 |
+
"n": 2,
|
| 56 |
+
"correct": 0
|
| 57 |
+
}
|
| 58 |
+
},
|
| 59 |
+
"overall": {
|
| 60 |
+
"n": 50,
|
| 61 |
+
"correct": 13,
|
| 62 |
+
"acc": 0.26
|
| 63 |
+
}
|
| 64 |
+
},
|
| 65 |
+
"res": {
|
| 66 |
+
"name": "RESEARCHER",
|
| 67 |
+
"n_total": 27,
|
| 68 |
+
"buckets": {
|
| 69 |
+
"HIGH": {
|
| 70 |
+
"acc": 0.0,
|
| 71 |
+
"n": 4,
|
| 72 |
+
"correct": 0
|
| 73 |
+
},
|
| 74 |
+
"MEDIUM": {
|
| 75 |
+
"acc": 0.0,
|
| 76 |
+
"n": 2,
|
| 77 |
+
"correct": 0
|
| 78 |
+
},
|
| 79 |
+
"LOW": {
|
| 80 |
+
"acc": 0.1,
|
| 81 |
+
"n": 20,
|
| 82 |
+
"correct": 2
|
| 83 |
+
},
|
| 84 |
+
"cannot assess": {
|
| 85 |
+
"acc": 0.0,
|
| 86 |
+
"n": 1,
|
| 87 |
+
"correct": 0
|
| 88 |
+
}
|
| 89 |
+
},
|
| 90 |
+
"overall": {
|
| 91 |
+
"n": 27,
|
| 92 |
+
"correct": 2,
|
| 93 |
+
"acc": 0.07407407407407407
|
| 94 |
+
}
|
| 95 |
+
}
|
| 96 |
+
}
|
logs/calib_summary_dpo3_200_scratch24.json
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"tag": "dpo3_200_scratch24",
|
| 3 |
+
"main": {
|
| 4 |
+
"name": "MAIN",
|
| 5 |
+
"n_total": 49,
|
| 6 |
+
"buckets": {
|
| 7 |
+
"HIGH": {
|
| 8 |
+
"n": 19,
|
| 9 |
+
"correct": 1,
|
| 10 |
+
"acc": 0.05263157894736842,
|
| 11 |
+
"ci": [
|
| 12 |
+
0.009351752490529969,
|
| 13 |
+
0.2463921533654521
|
| 14 |
+
]
|
| 15 |
+
},
|
| 16 |
+
"MEDIUM": {
|
| 17 |
+
"n": 12,
|
| 18 |
+
"correct": 3,
|
| 19 |
+
"acc": 0.25,
|
| 20 |
+
"ci": [
|
| 21 |
+
0.08894003962896138,
|
| 22 |
+
0.53231033912066
|
| 23 |
+
]
|
| 24 |
+
},
|
| 25 |
+
"LOW": {
|
| 26 |
+
"n": 11,
|
| 27 |
+
"correct": 2,
|
| 28 |
+
"acc": 0.18181818181818182,
|
| 29 |
+
"ci": [
|
| 30 |
+
0.05136660067100063,
|
| 31 |
+
0.4769861375782448
|
| 32 |
+
]
|
| 33 |
+
},
|
| 34 |
+
"cannot assess": {
|
| 35 |
+
"n": 0,
|
| 36 |
+
"correct": 0,
|
| 37 |
+
"acc": NaN,
|
| 38 |
+
"ci": [
|
| 39 |
+
NaN,
|
| 40 |
+
NaN
|
| 41 |
+
]
|
| 42 |
+
}
|
| 43 |
+
},
|
| 44 |
+
"overall": {
|
| 45 |
+
"n": 49,
|
| 46 |
+
"correct": 7,
|
| 47 |
+
"acc": 0.14285714285714285,
|
| 48 |
+
"ci": [
|
| 49 |
+
0.07096333720544584,
|
| 50 |
+
0.2666797318916292
|
| 51 |
+
]
|
| 52 |
+
}
|
| 53 |
+
},
|
| 54 |
+
"res": {
|
| 55 |
+
"name": "RESEARCHER",
|
| 56 |
+
"n_total": 18,
|
| 57 |
+
"buckets": {
|
| 58 |
+
"HIGH": {
|
| 59 |
+
"n": 7,
|
| 60 |
+
"correct": 1,
|
| 61 |
+
"acc": 0.14285714285714285,
|
| 62 |
+
"ci": [
|
| 63 |
+
0.02567895594897479,
|
| 64 |
+
0.51313450331903
|
| 65 |
+
]
|
| 66 |
+
},
|
| 67 |
+
"MEDIUM": {
|
| 68 |
+
"n": 1,
|
| 69 |
+
"correct": 0,
|
| 70 |
+
"acc": 0.0,
|
| 71 |
+
"ci": [
|
| 72 |
+
0.0,
|
| 73 |
+
0.7934567085261071
|
| 74 |
+
]
|
| 75 |
+
},
|
| 76 |
+
"LOW": {
|
| 77 |
+
"n": 6,
|
| 78 |
+
"correct": 0,
|
| 79 |
+
"acc": 0.0,
|
| 80 |
+
"ci": [
|
| 81 |
+
0.0,
|
| 82 |
+
0.3903430336530645
|
| 83 |
+
]
|
| 84 |
+
},
|
| 85 |
+
"cannot assess": {
|
| 86 |
+
"n": 0,
|
| 87 |
+
"correct": 0,
|
| 88 |
+
"acc": NaN,
|
| 89 |
+
"ci": [
|
| 90 |
+
NaN,
|
| 91 |
+
NaN
|
| 92 |
+
]
|
| 93 |
+
}
|
| 94 |
+
},
|
| 95 |
+
"overall": {
|
| 96 |
+
"n": 18,
|
| 97 |
+
"correct": 1,
|
| 98 |
+
"acc": 0.05555555555555555,
|
| 99 |
+
"ci": [
|
| 100 |
+
0.009874935830924525,
|
| 101 |
+
0.2575779980200754
|
| 102 |
+
]
|
| 103 |
+
}
|
| 104 |
+
},
|
| 105 |
+
"combined": {
|
| 106 |
+
"name": "COMBINED",
|
| 107 |
+
"n_total": 67,
|
| 108 |
+
"buckets": {
|
| 109 |
+
"HIGH": {
|
| 110 |
+
"n": 26,
|
| 111 |
+
"correct": 2,
|
| 112 |
+
"acc": 0.07692307692307693,
|
| 113 |
+
"ci": [
|
| 114 |
+
0.02135463918337556,
|
| 115 |
+
0.24141947480515052
|
| 116 |
+
]
|
| 117 |
+
},
|
| 118 |
+
"MEDIUM": {
|
| 119 |
+
"n": 13,
|
| 120 |
+
"correct": 3,
|
| 121 |
+
"acc": 0.23076923076923078,
|
| 122 |
+
"ci": [
|
| 123 |
+
0.08179379092465708,
|
| 124 |
+
0.5025687399512693
|
| 125 |
+
]
|
| 126 |
+
},
|
| 127 |
+
"LOW": {
|
| 128 |
+
"n": 17,
|
| 129 |
+
"correct": 2,
|
| 130 |
+
"acc": 0.11764705882352941,
|
| 131 |
+
"ci": [
|
| 132 |
+
0.03287908001292092,
|
| 133 |
+
0.3433684249770991
|
| 134 |
+
]
|
| 135 |
+
},
|
| 136 |
+
"cannot assess": {
|
| 137 |
+
"n": 0,
|
| 138 |
+
"correct": 0,
|
| 139 |
+
"acc": NaN,
|
| 140 |
+
"ci": [
|
| 141 |
+
NaN,
|
| 142 |
+
NaN
|
| 143 |
+
]
|
| 144 |
+
}
|
| 145 |
+
},
|
| 146 |
+
"overall": {
|
| 147 |
+
"n": 67,
|
| 148 |
+
"correct": 8,
|
| 149 |
+
"acc": 0.11940298507462686,
|
| 150 |
+
"ci": [
|
| 151 |
+
0.06176158770587532,
|
| 152 |
+
0.21832243072397378
|
| 153 |
+
]
|
| 154 |
+
}
|
| 155 |
+
},
|
| 156 |
+
"high_verdict_mix": {
|
| 157 |
+
"main": {
|
| 158 |
+
"low confidence": {
|
| 159 |
+
"n": 9,
|
| 160 |
+
"acc": 0.0
|
| 161 |
+
},
|
| 162 |
+
"unverifiable": {
|
| 163 |
+
"n": 2,
|
| 164 |
+
"acc": 0.0
|
| 165 |
+
},
|
| 166 |
+
"not a contradiction": {
|
| 167 |
+
"n": 1,
|
| 168 |
+
"acc": 0.0
|
| 169 |
+
},
|
| 170 |
+
"true": {
|
| 171 |
+
"n": 4,
|
| 172 |
+
"acc": 0.0
|
| 173 |
+
},
|
| 174 |
+
"overclaim": {
|
| 175 |
+
"n": 2,
|
| 176 |
+
"acc": 0.5
|
| 177 |
+
},
|
| 178 |
+
"no meaningful pattern": {
|
| 179 |
+
"n": 1,
|
| 180 |
+
"acc": 0.0
|
| 181 |
+
}
|
| 182 |
+
},
|
| 183 |
+
"res": {
|
| 184 |
+
"low confidence": {
|
| 185 |
+
"n": 5,
|
| 186 |
+
"acc": 0.2
|
| 187 |
+
},
|
| 188 |
+
"unverifiable": {
|
| 189 |
+
"n": 2,
|
| 190 |
+
"acc": 0.0
|
| 191 |
+
}
|
| 192 |
+
}
|
| 193 |
+
},
|
| 194 |
+
"abstention": {
|
| 195 |
+
"main": {
|
| 196 |
+
"abstain_rate": 0.04081632653061224,
|
| 197 |
+
"abstain_acc": 0.0,
|
| 198 |
+
"should_abstain_n": 3,
|
| 199 |
+
"abstained_on_should": 1
|
| 200 |
+
},
|
| 201 |
+
"res": {
|
| 202 |
+
"abstain_rate": 0.0,
|
| 203 |
+
"abstain_acc": null,
|
| 204 |
+
"should_abstain_n": 2,
|
| 205 |
+
"abstained_on_should": 0
|
| 206 |
+
}
|
| 207 |
+
},
|
| 208 |
+
"note": "A confidence bucket whose accuracy is BELOW the overall mean is anti-calibrated: trusting it lowers precision. Weighted voting must use these empirical accuracies, not the label."
|
| 209 |
+
}
|
logs/chain_dpo_v26.log
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
=== chain start 2026-08-13 23:25:58 ===
|
logs/chain_sft_v26.log
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
=== chain start 2026-08-13 23:24:02 ===
|
| 2 |
+
=== all merge evals done at 01:22:07; launching SFT v26 ===
|
| 3 |
+
SFT v26 watchdog launched
|
logs/chain_v22.log
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[chain 05:43:55] waiting for SFT final
|
| 2 |
+
[chain 06:03:54] waiting for SFT final
|
| 3 |
+
[chain 06:11:55] SFT done -> launching DPO
|
| 4 |
+
[chain 06:30:48] waiting for SFT final
|
| 5 |
+
[chain 06:30:48] SFT done -> launching DPO
|
logs/code_train.log
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
resumed ckpt/forensic/model_3000.pt at step 3000
|
| 2 |
+
params: 7.79M train_tokens: 19,433,876 steps_per_epoch: 4744
|
| 3 |
+
step 3025/5500 loss 6.0047 lr 9.26e-05 766 tok/s
|
| 4 |
+
step 3050/5500 loss 6.1537 lr 9.12e-05 708 tok/s
|
| 5 |
+
step 3075/5500 loss 5.2507 lr 8.99e-05 771 tok/s
|
| 6 |
+
step 3100/5500 loss 5.0531 lr 8.85e-05 763 tok/s
|
| 7 |
+
step 3125/5500 loss 4.7942 lr 8.71e-05 776 tok/s
|
| 8 |
+
step 3150/5500 loss 4.6254 lr 8.58e-05 762 tok/s
|
| 9 |
+
step 3175/5500 loss 4.7029 lr 8.44e-05 764 tok/s
|
| 10 |
+
step 3200/5500 loss 5.0546 lr 8.31e-05 759 tok/s
|
| 11 |
+
step 3225/5500 loss 4.5685 lr 8.17e-05 761 tok/s
|
| 12 |
+
step 3250/5500 loss 4.3609 lr 8.04e-05 759 tok/s
|
| 13 |
+
[eval step 3250] val_loss 4.4883 (best 4.4883)
|
| 14 |
+
[gen] Once upon a time, ##=f.cule':self.s.t 0:## "IGEMORPLass the"""" = "pA '-reins), self.lineer(f._patana ('), = (4(pyc
|
| 15 |
+
[gen] The little girl wanted to be a small rabbit, "IOTSERAD.cr =self, soft other than the cat is not (' = and the "PAclassert'f.getdr/dater.pwHENallalls =-2::preate_ntrified'=
|
| 16 |
+
[gen] In the dark forest, self.n_for):de ='FTANDTIMMERLIs(check.reoCNOSLM =self.tritf(_form ('] = 00,self, = lata.bath as a a 3
|
| 17 |
+
step 3275/5500 loss 4.4059 lr 7.91e-05 481 tok/s
|
| 18 |
+
step 3300/5500 loss 4.0837 lr 7.78e-05 765 tok/s
|
| 19 |
+
step 3325/5500 loss 4.3661 lr 7.64e-05 764 tok/s
|
| 20 |
+
step 3350/5500 loss 4.3748 lr 7.51e-05 761 tok/s
|
| 21 |
+
step 3375/5500 loss 4.1715 lr 7.38e-05 756 tok/s
|
| 22 |
+
step 3400/5500 loss 4.4175 lr 7.25e-05 747 tok/s
|
| 23 |
+
step 3425/5500 loss 4.2822 lr 7.12e-05 756 tok/s
|
| 24 |
+
step 3450/5500 loss 3.8087 lr 6.99e-05 751 tok/s
|
| 25 |
+
step 3475/5500 loss 4.1050 lr 6.86e-05 769 tok/s
|
| 26 |
+
step 3500/5500 loss 4.5876 lr 6.74e-05 761 tok/s
|
| 27 |
+
[eval step 3500] val_loss 4.1726 (best 4.1726)
|
| 28 |
+
[gen] Once upon a time, 2.self, selform."":'"": "IPata and not get, = "Equal'ATRES ' (put""" to the-s for more ,du"elification from
|
| 29 |
+
[gen] The little girl wanted to be used to be useful.self, =""SDule._state':defile:ass the Ger, or the COTITYclassput()f.exits.elificense."The textde the GFESSE
|
| 30 |
+
[gen] In the dark forest, = NOD'ponse)import sic.war:pase.tion is not a name of the License ass.mlocation:defrom 0"""Ac._(P version.RImodescrut in re.reresp
|
| 31 |
+
saved ckpt/code/model_3500.pt
|
| 32 |
+
step 3525/5500 loss 4.1732 lr 6.61e-05 473 tok/s
|
| 33 |
+
step 3550/5500 loss 4.1666 lr 6.49e-05 769 tok/s
|
| 34 |
+
step 3575/5500 loss 4.0799 lr 6.36e-05 773 tok/s
|
| 35 |
+
step 3600/5500 loss 4.5058 lr 6.24e-05 764 tok/s
|
| 36 |
+
step 3625/5500 loss 3.9307 lr 6.11e-05 767 tok/s
|
| 37 |
+
step 3650/5500 loss 4.1280 lr 5.99e-05 773 tok/s
|
| 38 |
+
step 3675/5500 loss 3.8534 lr 5.87e-05 767 tok/s
|
| 39 |
+
step 3700/5500 loss 4.1294 lr 5.75e-05 712 tok/s
|
| 40 |
+
step 3725/5500 loss 4.3434 lr 5.63e-05 835 tok/s
|
| 41 |
+
step 3750/5500 loss 4.3972 lr 5.51e-05 1093 tok/s
|
| 42 |
+
[eval step 3750] val_loss 4.0015 (best 4.0015)
|
| 43 |
+
[gen] Once upon a time, self, Cut.ds:"": = f 0: = Lponsec.'# in the us when it is false)import n, ns forms: '*groptemor to the djangw
|
| 44 |
+
[gen] The little girl wanted to red ball under the cat mouse bee climb rabbit bird made out to be used for new."s as the cat was a fun.# the DIS, or or event with this one of the A commonse: (stror of the GNUT ORIORECGN WICHPRAREBI
|
| 45 |
+
[gen] In the dark forest, len the date the Lico in ran to a line or 1self. 0truniteralse:> == ,# TOSIDELATIMICRSEY-'ttry:"DEME_line) form.# C
|
| 46 |
+
step 3775/5500 loss 3.8040 lr 5.40e-05 590 tok/s
|
| 47 |
+
step 3800/5500 loss 4.1451 lr 5.28e-05 751 tok/s
|
| 48 |
+
step 3825/5500 loss 3.9558 lr 5.16e-05 751 tok/s
|
| 49 |
+
step 3850/5500 loss 3.9454 lr 5.05e-05 750 tok/s
|
| 50 |
+
step 3875/5500 loss 3.9173 lr 4.94e-05 746 tok/s
|
| 51 |
+
step 3900/5500 loss 4.4631 lr 4.83e-05 766 tok/s
|
| 52 |
+
step 3925/5500 loss 4.1258 lr 4.72e-05 768 tok/s
|
| 53 |
+
step 3950/5500 loss 4.4475 lr 4.61e-05 769 tok/s
|
| 54 |
+
step 3975/5500 loss 4.1496 lr 4.50e-05 767 tok/s
|
| 55 |
+
step 4000/5500 loss 3.9656 lr 4.39e-05 766 tok/s
|
| 56 |
+
[eval step 4000] val_loss 3.9033 (best 3.9033)
|
| 57 |
+
[gen] Once upon a time, # the test is not a fun with this fun to the file to find# the License.## %s. to the Lal to use this and the Licationprint "IEPLERTADOGDIK_conse:#, see a fun if it in the# you will
|
| 58 |
+
[gen] The little girl wanted to the The cat used for the The magic bug in a fun# it.# the test is being found in the The little fish rabbit Lucy was already bug under the The cat was not want to the file., you can be useful,# the License formargs on your us our fun# the cat was an "IFIS (
|
| 59 |
+
[gen] In the dark forest, # you can be used to do not to a tree with the hope you may not use the Lication of the given in the RED OFURORIPase.import the Gc: "ATHO("ST ANUCASEN_name for more details as the License,
|
| 60 |
+
saved ckpt/code/model_4000.pt
|
| 61 |
+
step 4025/5500 loss 4.5375 lr 4.29e-05 469 tok/s
|
| 62 |
+
step 4050/5500 loss 3.9424 lr 4.18e-05 748 tok/s
|
| 63 |
+
step 4075/5500 loss 4.2054 lr 4.08e-05 754 tok/s
|
| 64 |
+
step 4100/5500 loss 3.2284 lr 3.98e-05 741 tok/s
|
| 65 |
+
step 4125/5500 loss 4.3530 lr 3.88e-05 740 tok/s
|
| 66 |
+
step 4150/5500 loss 3.6083 lr 3.78e-05 808 tok/s
|
| 67 |
+
step 4175/5500 loss 3.7215 lr 3.69e-05 1147 tok/s
|
| 68 |
+
step 4200/5500 loss 4.0122 lr 3.59e-05 747 tok/s
|
| 69 |
+
step 4225/5500 loss 3.6063 lr 3.50e-05 757 tok/s
|
| 70 |
+
step 4250/5500 loss 4.2182 lr 3.40e-05 769 tok/s
|
| 71 |
+
[eval step 4250] val_loss 3.8269 (best 3.8269)
|
| 72 |
+
[gen] Once upon a time, the same.# I don't want to read the Copy in the License at a little girl told and# in the General' This file is not use all the implied up at#, but it under the conver from the hope that we can't have received a time with the Lits is not a newction by the
|
| 73 |
+
[gen] The little girl wanted to the cat cat's too many bird stayed smelled toy smiled together all of the implied in the AN Imain for the LAHAR OFITAR DAIOS version and the GNE AICATHATE# you can be received a copy of the catus,# the Gconf
|
| 74 |
+
[gen] In the dark forest, or# a new place to be called by a special when you to the GN Cheour.#"""# You may not available for this one of the hope that it's# you can be useful, either % version:# =## 0x63. The value
|
| 75 |
+
step 4275/5500 loss 4.0282 lr 3.31e-05 480 tok/s
|
| 76 |
+
step 4300/5500 loss 4.0307 lr 3.22e-05 741 tok/s
|
| 77 |
+
step 4325/5500 loss 4.4112 lr 3.13e-05 771 tok/s
|
| 78 |
+
step 4350/5500 loss 3.6666 lr 3.05e-05 734 tok/s
|
| 79 |
+
step 4375/5500 loss 4.0610 lr 2.96e-05 874 tok/s
|
| 80 |
+
step 4400/5500 loss 4.1294 lr 2.88e-05 1130 tok/s
|
| 81 |
+
step 4425/5500 loss 3.7163 lr 2.80e-05 1140 tok/s
|
| 82 |
+
step 4450/5500 loss 3.7806 lr 2.72e-05 1173 tok/s
|
| 83 |
+
step 4475/5500 loss 3.6441 lr 2.64e-05 1119 tok/s
|
| 84 |
+
step 4500/5500 loss 3.7109 lr 2.56e-05 1116 tok/s
|
| 85 |
+
[eval step 4500] val_loss 3.7859 (best 3.7859)
|
| 86 |
+
[gen] Once upon a time, and"": (vcontents.name, to print.":default isin(s of the givendatault:Authorg')""The proge --1 =': "lule, you can be used to a name."self
|
| 87 |
+
[gen] The little girl wanted to a string.# "MERRENUTEICHAHS# = 'WIORTY,f get_HED AUS SS IOLIENIO# DITINDE CONIUGBICUTICERTAS
|
| 88 |
+
[gen] In the dark forest, you for the ANINHRAGHOMALILITY or _PTOCUAS OFONT Tests.#'# General PULOLE None# CDERIBIOCT DANSIR A 'ME
|
| 89 |
+
saved ckpt/code/model_4500.pt
|
| 90 |
+
step 4525/5500 loss 4.4508 lr 2.49e-05 563 tok/s
|
| 91 |
+
step 4550/5500 loss 3.0129 lr 2.41e-05 1088 tok/s
|
| 92 |
+
step 4575/5500 loss 3.6184 lr 2.34e-05 1057 tok/s
|
| 93 |
+
step 4600/5500 loss 3.4652 lr 2.27e-05 946 tok/s
|
| 94 |
+
step 4625/5500 loss 3.6130 lr 2.20e-05 1018 tok/s
|
| 95 |
+
step 4650/5500 loss 4.1417 lr 2.14e-05 1017 tok/s
|
| 96 |
+
step 4675/5500 loss 3.7899 lr 2.07e-05 1009 tok/s
|
| 97 |
+
step 4700/5500 loss 3.7298 lr 2.01e-05 876 tok/s
|
| 98 |
+
step 4725/5500 loss 4.3740 lr 1.95e-05 871 tok/s
|
| 99 |
+
step 4750/5500 loss 3.5928 lr 1.89e-05 1086 tok/s
|
| 100 |
+
[eval step 4750] val_loss 3.7664 (best 3.7664)
|
| 101 |
+
[gen] Once upon a time, # version is not None:""" is a list of %s.IORVENY or agreed to be useful and then we should have a line in the""" BAMAK_NT or implied from the C Conlicense for the specifyythonfigo
|
| 102 |
+
[gen] The little girl wanted to use the Gen and be true for it will be used to be added for the hope that are not " I Imal of the# _from data for more than# See the ANUPLOSEROUBIAR A License, it.# = You should gover at
|
| 103 |
+
[gen] In the dark forest, or event event the hope bird high that that it's open the LIS# version. The ANFIOCHECBAR ANT THT OLIT AS#*-# ver are the License is distribault.n"The BUM AGD WIT
|
| 104 |
+
step 4775/5500 loss 3.6334 lr 1.83e-05 616 tok/s
|
| 105 |
+
step 4800/5500 loss 4.0678 lr 1.78e-05 1004 tok/s
|
| 106 |
+
step 4825/5500 loss 4.2597 lr 1.72e-05 1007 tok/s
|
| 107 |
+
step 4850/5500 loss 4.1499 lr 1.67e-05 1003 tok/s
|
| 108 |
+
step 4875/5500 loss 3.7801 lr 1.62e-05 980 tok/s
|
| 109 |
+
step 4900/5500 loss 3.8103 lr 1.57e-05 1017 tok/s
|
| 110 |
+
step 4925/5500 loss 3.7555 lr 1.53e-05 1017 tok/s
|
| 111 |
+
step 4950/5500 loss 3.9945 lr 1.48e-05 1016 tok/s
|
| 112 |
+
step 4975/5500 loss 4.0630 lr 1.44e-05 1020 tok/s
|
| 113 |
+
step 5000/5500 loss 3.5704 lr 1.40e-05 1014 tok/s
|
| 114 |
+
[eval step 5000] val_loss 3.7418 (best 3.7418)
|
| 115 |
+
[gen] Once upon a time, but the same for the License.# the Resfrom ('E:# # You are not have a above in the same as isin-"" A .fig.""" of the FoundationThe same,CHImemo.print
|
| 116 |
+
[gen] The little girl wanted to the hope hope INY man who said sorry.#'dule is an "No last- codefrom datuseric License, the License.# Lic Lication for the General Publ'://t "# () for a softwware without even the S
|
| 117 |
+
[gen] In the dark forest, but but't be a copy of the Fal PR OFICUS INT % /ware: 0x.# You should have received a lists that it will be usedfor '# PARREelse# != None and the License, and the G
|
| 118 |
+
saved ckpt/code/model_5000.pt
|
| 119 |
+
step 5025/5500 loss 4.2174 lr 1.36e-05 468 tok/s
|
| 120 |
+
step 5050/5500 loss 4.0895 lr 1.32e-05 769 tok/s
|
| 121 |
+
step 5075/5500 loss 3.6267 lr 1.29e-05 759 tok/s
|
| 122 |
+
step 5100/5500 loss 4.3846 lr 1.26e-05 764 tok/s
|
| 123 |
+
step 5125/5500 loss 3.3856 lr 1.23e-05 753 tok/s
|
| 124 |
+
step 5150/5500 loss 3.5558 lr 1.20e-05 781 tok/s
|
| 125 |
+
step 5175/5500 loss 4.1669 lr 1.17e-05 746 tok/s
|
| 126 |
+
step 5200/5500 loss 3.6207 lr 1.14e-05 764 tok/s
|
| 127 |
+
step 5225/5500 loss 3.8548 lr 1.12e-05 748 tok/s
|
| 128 |
+
step 5250/5500 loss 2.3408 lr 1.10e-05 752 tok/s
|
| 129 |
+
[eval step 5250] val_loss 3.7260 (best 3.7260)
|
| 130 |
+
[gen] Once upon a time, """ is not there are the Geral a copy of pys if you can redists are done with this file and the Gencumentation to be used for the specific License.RANUMS INDIT WHEF WGHOULPAMENTINC
|
| 131 |
+
[gen] The little girl wanted to do not, "AGOTIS OF SED, a list of the Confrom datault is a copy of the Fpts.# This primage =' in the##"RY; without even the APOUG.# GNTAR Fopythonn
|
| 132 |
+
[gen] In the dark forest, # %s': = [""""HTS Cop'' "AME' version): ()"" 02part_OList_TOUPPAD == > =#
|
| 133 |
+
step 5275/5500 loss 3.6509 lr 1.08e-05 477 tok/s
|
| 134 |
+
step 5300/5500 loss 4.0349 lr 1.06e-05 771 tok/s
|
| 135 |
+
step 5325/5500 loss 3.8613 lr 1.05e-05 756 tok/s
|
| 136 |
+
step 5350/5500 loss 4.4485 lr 1.04e-05 764 tok/s
|
| 137 |
+
step 5375/5500 loss 3.8794 lr 1.03e-05 756 tok/s
|
| 138 |
+
step 5400/5500 loss 3.3535 lr 1.02e-05 776 tok/s
|
| 139 |
+
step 5425/5500 loss 2.5307 lr 1.01e-05 753 tok/s
|
| 140 |
+
step 5450/5500 loss 3.8203 lr 1.00e-05 756 tok/s
|
| 141 |
+
step 5475/5500 loss 4.0576 lr 1.00e-05 759 tok/s
|
| 142 |
+
step 5500/5500 loss 3.9016 lr 1.00e-05 762 tok/s
|
| 143 |
+
[eval step 5500] val_loss 3.7219 (best 3.7219)
|
| 144 |
+
[gen] Once upon a time, """"""": the G."" is not use this one of the primmental PArananal PALIdule version in the Fal:///t.""":": Crev (self, author():# Check that
|
| 145 |
+
[gen] The little girl wanted to the hope dog Spot in the GNT, and the License.#< I have received a time,# is a copy of the following, but it will be useful, software ANU the Gen it's be conver.fo.# in the hope that it under the terml# This file, there are
|
| 146 |
+
[gen] In the dark forest, "IANS Iminput.# ANGE : the License is not in source of the same with a fun can be useful, software the TOU A This file.## The FITY or MND is for this file is always be found of the Adding a copy of the F
|
| 147 |
+
saved ckpt/code/model_5500.pt
|
| 148 |
+
done
|
logs/distill_train.log
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
train 193 eval 21
|
| 2 |
+
loaded base model_final.pt (step 3129)
|
| 3 |
+
step 25/720 loss 3.6094 603 tok/s
|
| 4 |
+
[eval 40] sft_val_loss 3.3399
|
| 5 |
+
step 50/720 loss 1.8771 598 tok/s
|
| 6 |
+
step 75/720 loss 2.8598 615 tok/s
|
| 7 |
+
[eval 80] sft_val_loss 3.2152
|
| 8 |
+
step 100/720 loss 2.3302 593 tok/s
|
| 9 |
+
[eval 120] sft_val_loss 3.1554
|
| 10 |
+
step 125/720 loss 1.1766 596 tok/s
|
| 11 |
+
step 150/720 loss 2.6884 606 tok/s
|
| 12 |
+
[eval 160] sft_val_loss 3.1096
|
| 13 |
+
step 175/720 loss 2.2253 592 tok/s
|
| 14 |
+
step 200/720 loss 2.5839 606 tok/s
|
| 15 |
+
[eval 200] sft_val_loss 3.0830
|
| 16 |
+
step 225/720 loss 0.9716 593 tok/s
|
| 17 |
+
[eval 240] sft_val_loss 3.0567
|
| 18 |
+
step 250/720 loss 0.9687 601 tok/s
|
| 19 |
+
step 275/720 loss 1.2913 606 tok/s
|
| 20 |
+
[eval 280] sft_val_loss 3.0436
|
| 21 |
+
step 300/720 loss 2.0274 615 tok/s
|
| 22 |
+
[eval 320] sft_val_loss 3.0462
|
| 23 |
+
step 325/720 loss 1.5587 611 tok/s
|
| 24 |
+
step 350/720 loss 2.5838 614 tok/s
|
| 25 |
+
[eval 360] sft_val_loss 3.0413
|
| 26 |
+
step 375/720 loss 2.3279 595 tok/s
|
| 27 |
+
step 400/720 loss 1.7619 607 tok/s
|
| 28 |
+
[eval 400] sft_val_loss 3.0431
|
| 29 |
+
step 425/720 loss 3.0013 598 tok/s
|
| 30 |
+
[eval 440] sft_val_loss 3.0483
|
| 31 |
+
step 450/720 loss 1.8126 602 tok/s
|
| 32 |
+
step 475/720 loss 0.4332 614 tok/s
|
| 33 |
+
[eval 480] sft_val_loss 3.0469
|
| 34 |
+
step 500/720 loss 2.2712 587 tok/s
|
| 35 |
+
[eval 520] sft_val_loss 3.0608
|
| 36 |
+
step 525/720 loss 1.9630 596 tok/s
|
| 37 |
+
step 550/720 loss 1.5055 607 tok/s
|
| 38 |
+
[eval 560] sft_val_loss 3.0804
|
| 39 |
+
step 575/720 loss 2.0244 595 tok/s
|
| 40 |
+
step 600/720 loss 2.3559 615 tok/s
|
| 41 |
+
[eval 600] sft_val_loss 3.0936
|
| 42 |
+
step 625/720 loss 1.3087 595 tok/s
|
| 43 |
+
[eval 640] sft_val_loss 3.1126
|
| 44 |
+
step 650/720 loss 1.7370 597 tok/s
|
| 45 |
+
step 675/720 loss 1.2326 607 tok/s
|
| 46 |
+
[eval 680] sft_val_loss 3.1429
|
| 47 |
+
step 700/720 loss 2.0961 591 tok/s
|
| 48 |
+
[eval 720] sft_val_loss 3.1402
|
| 49 |
+
done -> ckpt/distill
|