Commit Graph
31 Commits
Author SHA1 Message Date
wassnameandClaude Opus 4.7 a59003d2d0 guided: turn-boundary scoring text via chat-template probe
Replace mid-turn splice (`I should answer now.</think>{prefill}`) with a
clean turn close + user nudge + fresh assistant prefill. Mirrors what a
chat UI emits when a human interrupts a partial assistant turn, which is
on-policy in chat-tuned training data. Empirically: pmass_format ~0.987
on smoke set vs the OOD splice path.

Close marker is probed from the tokenizer's chat template (sentinel
diff), so it works on Qwen/ChatML, Llama3 (`<|eot_id|>`), etc -- no
hardcoded `<|im_end|>`.

Drops:
- emitted_prefill field (no callers)
- try/except TypeError around apply_chat_template (defensive)
- enable_thinking=False kwarg (some templates reject it; complete
  assistant messages auto-strip the think block anyway)
- `\nI should answer now.` fallback in multibool

Adds:
- verbose=True flag on guided_rollout to log scoring_text for debugging
- _assistant_close(tok) sentinel-probe helper

Note: prompt_nll magnitudes shift since scoring_text now includes the
user-nudge tokens. Not comparable to pre-refactor saved results.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-06 12:39:10 +08:00
wassnameandClaude Sonnet 4.6 573f815361 journal: Qwen3-4B multibool results (task 288)
pmass=1.000, 0/132 low-pmass, inter-foundation |r|=0.154 (down from 0.51).
4B fully resolves the foundation-conflation problem seen at 0.6B.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 11:57:08 +08:00
wassnameandClaude Sonnet 4.6 2ca6aa9c6c multibool: interrupt-msg fork, generate trace on low-pmass, journal update
- suf_ids_for() now uses interrupt-msg format: close assistant turn, inject
  per-foundation user question + {"Answer": prefill -- fixes authority pmass
  (0.344->0.898) by avoiding JSON string-priming from key names
- Add _FOUNDATION_DESCS and _DEFAULT_MULTIBOOL_HINT rubric for discrimination
- Low-pmass diagnostic: first occurrence now runs .generate(max_new_tokens=32)
  to show what model actually produces; subsequent cases log top-5 tokens
- suf_ids_per stored so diagnostic generate can reconstruct full input
- Journal: add inter-foundation correlation results (mean |r|=0.51); note
  Spearman vs human raters is not a valid metric (exclusive vs independent labels)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 11:29:33 +08:00
wassnameandClaude Opus 4.7 48d8ca5576 add 08_multibool_baseline: run multibool eval over classic vignettes
Sanity check + baseline before wiring multibool into the steering sweep.
Computes per-foundation logratios on all 132 classic vignettes, dumps to
data/results/multibool_baseline.jsonl, prints per-foundation lr summary
and Spearman corr against human-rater %s.

SHOULD: mean pmass > 0.9; Spearman ρ > 0.3 on ≥4/6 foundations.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-05 22:20:48 +08:00
wassnameandClaude Opus 4.7 ada854c499 guided_rollout_multibool: switch to 12 single-slot KV-forks + assert full-attention
The chained-fill design (one suffix with all foundations, two passes for true/false)
hit a non-recoverable conv-state issue on hybrid linear-attention layers (Qwen3.5):
splitting prefix and suffix forwards via past_key_values silently produced
wrong logits (pmass dropping to 0.04, top token leaking to ' "' = 0.72).

Switched to 12 independent single-slot completions per prompt:
  for (frame, foundation) in {is_violation, is_ok} × foundations:
    cache scoring_prefix once, fork suffix `\n{"<frame>": {"<f>":`,
    read logits at the last token (predicting `true|false`).
  final[f] = 0.5 * (lr_violation[f] - lr_ok[f])

Framing flip cancels per-key prior bias the same way true/false fill did,
without the chained-slot causality that interacts badly with split forwards.

Added _assert_full_attention(): checks model.config.layer_types and fails
loudly on hybrid models. Verified parity vs flat forward on Qwen3-0.6B
(Δ ≤ 0.13 nats; signal of interest is ≫1 nat) and assert fires on Qwen3.5-0.8B.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-05 22:19:11 +08:00
wassname 1650aa9191 add prompt_nll (free coherence proxy) + eval summary line
Per-token NLL over the scoring text is free since we already compute
full-sequence logits in guided_rollout / guided_rollout_batch (just
gather instead of slicing [:, -1]). Higher NLL = model less coherent
on this prompt under whatever steering is attached.

eval.py logs pmass/ppl/nll aggregate at end of guided eval so the
next run shows degradation at a glance instead of buried tqdm noise.
analyse() now exposes raw_nll and info.prompt_nll_mean.
2026-05-05 06:34:24 +08:00
wassname 8f39fb1462 immediately 2026-05-04 06:09:56 +08:00
wassnameandClaude Sonnet 4.6 50efa6063c fix: use valid JSON Schema in eval frame prompts
`boolean` is not valid JSON; use `{"type": "boolean"}` so models
produce true/false rather than the integer shorthand 1.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-03 14:16:42 +08:00
wassname d7a286acac docs: use simple emoji links for cross-referencing github and huggingface 2026-05-03 12:58:24 +08:00
wassname a8a35b308b docs: fix github repo links to point to wassname/tinymfv 2026-05-03 12:57:45 +08:00
wassname 898893d440 chore: remove uncalibrated raw LLM columns from final vignettes
- Updated scripts/07a_merge_labels.py to only merge calibrated_* and llm_dominant
- Updated README.md and scripts/05_upload_hf.py to reflect removed columns
- Re-merged and re-uploaded clean datasets to HuggingFace
2026-05-03 12:55:00 +08:00
wassname bcbdb9cc6f feat: multi-label moral foundation ratings with z-scored frame averaging and human calibration
- Add scripts/07_multilabel.py: LLM judge rates all 7 foundations per vignette
  using violation (forward) and acceptability (reverse) frames
- Foundation definitions drawn from Clifford et al. (2015) survey rubric
- Z-score each frame per foundation before averaging to cancel range bias
- Calibrate LLM Likert → human % via per-foundation OLS (classic set only)
- Add scripts/07a_merge_labels.py: merges llm_* and calibrated_* into vignette files
- Update README and HF dataset card with methodology and calibration quality table
- Classic set: 80.3% dominant-foundation accuracy, Pearson r 0.69-0.89 per foundation
2026-05-03 12:48:14 +08:00
wassname 36b8c69122 clifford paper 2026-05-03 12:32:56 +08:00
wassname bf7e5dcae4 paper 2026-05-03 12:32:48 +08:00
wassname cee50a6f9d pmass 2026-05-03 11:49:58 +08:00
wassname 881ac16c24 API improvements: rename clifford->classic, default load_vignettes to all, add dual-axis docs, and update HF upload script 2026-05-03 07:01:28 +08:00
wassname b7f92dccb1 lower pmass-warn threshold 0.9 -> 0.5 in batched (match sequential) 2026-05-03 06:51:21 +08:00
wassname addf47c5a0 quiet pmass-low warning: one summary per batch
Was emitting `logger.warning("pmass=0.XX<0.9 — top-5: ...")` per-row, which
spammed the log heavily during heavy-steering eval (many rows go OOD at once).
Now collects all low-pmass rows in the batch and emits one summary line with
the worst-case top-5, e.g.:

    pmass<0.9 on 7/16 rows in this batch; worst=0.412 top-5: '1'=0.40, ...

Same diagnostic signal, ~16× fewer log lines per batch.
2026-05-03 06:50:19 +08:00
wassname e996d57051 batch the eval: guided_rollout_batch + 4× speedup
Sequential eval was the bottleneck (~12s/vignette × 131 = 27 min/pass; with
bidirectional ±C × 14 methods, that projected to ~17 h). Three model calls
per row (phase1 generate, scoring forward, cosmetic continuation) became one
phase1 + one scoring per *batch*; continuation generate dropped (callers
only use p_true + pmass_format).

Parity smoke (scripts/smoke_batch_parity.py): float32 is bit-exact (max
Δp_true=0.0000 over 16 prompts, 4.3× speedup at limit=4). bf16 drifts on
individual rows — greedy argmax flips at near-tie tokens then phase1
diverges — but pmass agrees within 0.03 (scoring forward correct) and
aggregates over 131 vignettes will average out the per-row noise.

Other changes shipped in this commit:
- core.py: analyse() now returns raw_pmass dict alongside raw p_true (callers
  needed per-(vid,cond,frame) pmass for diagnostic warnings).
- guided.py guided_rollout: warn + log top-5 when pmass<0.9 (catches OOD
  steering / format-broken vignettes without a separate audit pass).
- eval.py: pre-tokenize a sample to log expected prompt+cache budget so OOM
  is predictable from the SHOULD line; group items by frame so each batch
  shares schema_hint + prefill.
2026-05-03 06:42:17 +08:00
wassname (Michael J Clark) 7867a677d0 Update README.md 2026-05-03 05:51:05 +08:00
wassname ac1c8cf7bb package 2026-05-02 16:51:15 +08:00
wassname b6f24cac1c add human labels 2026-05-02 15:58:08 +08:00
wassname 0f8048d5d9 Implement N-token evaluation with guided rollouts
- Refactored evaluation logic in `src/tinymfv/eval.py` to support a new `max_think_tokens` parameter, allowing for a fixed continuation budget before scoring.
- Introduced `guided_rollout` function in `src/tinymfv/guided.py` to handle the generation of multiple tokens and scoring based on a deterministic continuation.
- Updated the CLI in `scripts/03_eval.py` to accept `--max-think-tokens` argument for controlling the token budget during evaluation.
- Created a new specification document `docs/spec/20260501_n_token_eval.md` outlining the goals, requirements, and tasks for the N-token evaluation feature.
- Simplified the record creation in `scripts/02_rewrite.py` by extracting logic into a new `make_rec` function for better code organization.
2026-05-01 21:44:14 +08:00
wassnameandClaude Opus 4.7 a9412ee226 move openrouter-wrapper to dev-only dep group
Only used by scripts/0{2,4,6}_*.py for data prep, not by the installable
src/tinymfv/ package. Keeping it in [project].dependencies leaked a local
editable path dep into the built wheel's runtime requires.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-01 05:38:35 +08:00
wassname 52e91e1699 readme 2026-04-30 21:46:56 +08:00
wassname e5cacc0c29 readme 2026-04-30 21:45:23 +08:00
wassname 234424161c wip 2026-04-30 21:39:53 +08:00
wassnameandClaude Opus 4.7 a2e3124e06 fix airisk self_violate actor archetype + simplify to 2 conditions
other_violate is now the verbatim source (no LLM), only self_violate is
rewritten. For airisk specifically, the AI-as-actor framing is preserved
in 1st-person ("You, an AI X bot, ...") since a naive "You ..." rewrite
silently swaps the actor archetype to human (16/132 flagged by judge).

Pairwise consistency check (06_consistency.py) verifies same-situation
across the perspective shift. After the fix:
- clifford 97.7% same
- scifi    99.2% same
- airisk   86.3% -> 100.0% same

First eval signal on Qwen3-0.6B: airisk wrongness=+0.70, gap=+0.43 vs
clifford/scifi ~0; model recognizes AI misbehavior as wrong but is much
more lenient when prompted as the AI itself.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 21:29:38 +08:00
wassname 252e62abb7 decent 2026-04-30 21:22:07 +08:00
wassname a155f5594b valdiation 2026-04-30 20:08:12 +08:00
wassname ebf161b658 init 2026-04-30 17:10:09 +08:00