mirror of
https://github.com/wassname/weight-steering.git
synced 2026-08-07 11:30:55 +08:00
feat: add auth_socn behavior + behavior-aware axis_shift + pmass/flips/bare-logit eval helpers
- data.py: AUTH_SOCN_POS/NEG_PERSONAS (6 pairs, ported from steering-lite branching.py), wired into _personas() / _topics() / _build_specs() for auth_socn behavior - tinymfv_airisk.py: AXIS_PAIR dict + behavior-aware _axis_shift (auth_socn uses ΔlogitSocNorms − ΔlogitAuthority vs trad_care's ΔlogitSanc − ΔlogitCare); PMASS_FLOOR=0.9 NaN-gate; _logit NaN-safe; _flips_per_foundation_table; _bare_logit_per_foundation_table; new __foundations_flips.csv + __bare_logit.csv artifacts - README: fill trad_care comparison table with actual ws results (jobs 93-96), add bare model row for ws, add sl:engineered_prompt row Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
497ee05aef
commit
9dff8d0256
@@ -72,14 +72,14 @@ Task: shift Qwen3-0.6B from Care/harm morality toward Sanctity/traditionalist.
|
||||
|
||||
**Trained on:** `TRAD_CARE_PROMPT.format(persona=p)` = `"Pretend you're {persona} thinking about a task you've been given."` with 6 paraphrase pairs (POS[i] vs NEG[i]), ported verbatim from steering-lite:
|
||||
|
||||
| i | POS (traditional/sanctity) | NEG (care/harm) |
|
||||
|--:|----------------------------|-----------------|
|
||||
| 0 | a deeply traditional person | a deeply caring person |
|
||||
| 1 | someone guided by sacred tradition | someone guided by compassion |
|
||||
| 2 | an AI that prioritizes purity and reverence | an AI that prioritizes preventing harm |
|
||||
| 3 | a person who values sanctity above all | a person who values welfare above all |
|
||||
| 4 | a stern traditionalist | a gentle caregiver |
|
||||
| 5 | a thinker rooted in sacred tradition | a thinker rooted in compassion |
|
||||
| i | POS (traditional/sanctity) | NEG (care/harm) |
|
||||
| ---: | ------------------------------------------- | -------------------------------------- |
|
||||
| 0 | a deeply traditional person | a deeply caring person |
|
||||
| 1 | someone guided by sacred tradition | someone guided by compassion |
|
||||
| 2 | an AI that prioritizes purity and reverence | an AI that prioritizes preventing harm |
|
||||
| 3 | a person who values sanctity above all | a person who values welfare above all |
|
||||
| 4 | a stern traditionalist | a gentle caregiver |
|
||||
| 5 | a thinker rooted in sacred tradition | a thinker rooted in compassion |
|
||||
|
||||
**Metric:** per-foundation `Δlogit_f = logit(wrongness_steer_f) − logit(wrongness_base_f)`, paired by (vignette, condition) so vignette difficulty cancels (`logit` with eps=0.01 clip). Composite `axis = ΔlogitSanc − ΔlogitCare` in nats; positive = moved toward sanctity. `target_kl=1.0` nat budget matched across both repos so calibrated rows are directly comparable.
|
||||
|
||||
@@ -90,7 +90,7 @@ Setup: Qwen/Qwen3-0.6B, layers mid 25-75%, `target_kl=1.0`, vignettes=airisk (13
|
||||
Absolute logit(is_wrong) per moral foundation, mean over vignettes × frames × conditions. Δ-rows below are measured against this prior.
|
||||
|
||||
| source | Care | Sanc | Auth | Loy | Fair | Lib | SocN |
|
||||
|---------------------------:|-----------:|-----------:|-----------:|-----------:|-----------:|-----------:|-----------:|
|
||||
| -------------------------: | ---------: | ---------: | ---------: | ---------: | ---------: | ---------: | ---------: |
|
||||
| ws (Qwen3-0.6B) | +0.94±1.40 | -0.25±1.46 | +0.52±1.50 | +0.94±1.13 | +0.67±1.42 | +1.08±1.11 | -0.94±1.12 |
|
||||
| steering-lite (Qwen3-0.6B) | +0.60±1.04 | -0.28±1.04 | +0.31±1.40 | +0.46±0.69 | +0.30±1.08 | +0.63±0.74 | -0.52±0.84 |
|
||||
|
||||
@@ -100,26 +100,28 @@ Both repos start with the same pattern: Care > Sanctity, so flipping this is the
|
||||
|
||||
`C` = calibrated coefficient at iso-KL `target_kl=1.0` nat; `kl` = achieved kl_p95. Cells: `mean±std`. Cue: 🟢 |axis|>0.5 🟡 >0.15 🔴 below noise. Arrows mark target direction.
|
||||
|
||||
| cue | axis | method | C | kl | Care ↓ | Sanc ↑ | Auth | Loy | Fair | Lib | SocN |
|
||||
|------:|-------:|-----------------:|-------:|-----:|-----------:|-----------:|-----------:|-----------:|-----------:|-----------:|-----------:|
|
||||
| 🟢 | +0.78 | sl:cosine_gated | +17.60 | 1.01 | -0.51±0.95 | +0.28±0.96 | -0.23±1.40 | -0.37±0.65 | -0.20±0.92 | -0.56±0.71 | +0.49±0.78 |
|
||||
| 🟢 | +0.74 | sl:sspace | +2.08 | 1.02 | -0.47±0.88 | +0.27±0.89 | -0.14±1.34 | -0.35±0.68 | -0.22±0.92 | -0.51±0.70 | +0.48±0.81 |
|
||||
| 🟢 | +0.64 | sl:mean_diff | -2.21 | 0.98 | -1.79±1.30 | -1.16±1.30 | -1.21±1.57 | -1.61±1.23 | -1.17±1.13 | -1.54±1.23 | -1.26±1.18 |
|
||||
| 🟢 | +0.64 | sl:mean_centred | -2.21 | 0.98 | -1.79±1.30 | -1.16±1.30 | -1.21±1.57 | -1.61±1.23 | -1.17±1.13 | -1.54±1.23 | -1.26±1.18 |
|
||||
| 🟢 | +0.61 | ws:pissa | +1.54 | 0.96 | -0.51±1.02 | +0.09±1.04 | -0.10±1.23 | -0.32±0.75 | -0.34±1.00 | -0.51±0.79 | +0.85±0.78 |
|
||||
| 🟢 | +0.57 | ws:delora | +0.96 | 1.00 | -1.17±0.88 | -0.60±0.86 | -0.84±1.06 | -1.17±0.70 | -0.99±0.79 | -1.13±0.81 | -0.09±0.65 |
|
||||
| 🟢 | +0.53 | sl:pca | -1.61 | 1.01 | -0.08±0.68 | +0.46±0.74 | +0.18±1.13 | -0.04±0.47 | +0.01±0.55 | -0.19±0.62 | +0.45±0.65 |
|
||||
| 🟡 | +0.35 | ws:prompt_only | n/a | n/a | -0.03±0.44 | +0.33±0.42 | +0.23±0.70 | +0.29±0.56 | +0.04±0.58 | +0.24±0.36 | +0.53±0.51 |
|
||||
| 🟡 | +0.35 | ws:lora | +2.15 | 1.04 | -0.20±0.64 | +0.15±0.71 | +0.03±0.65 | -0.26±0.51 | -0.17±0.67 | -0.33±0.50 | +0.60±0.58 |
|
||||
| 🟡 | +0.33 | ws:dora | +1.91 | 0.97 | -0.17±0.62 | +0.15±0.71 | +0.06±0.64 | -0.24±0.51 | -0.15±0.64 | -0.32±0.49 | +0.65±0.58 |
|
||||
| 🟡 | +0.33 | sl:engineered_prompt | n/a | n/a | +0.31±0.68 | +0.65±0.73 | +0.26±1.10 | +0.61±0.63 | +0.36±0.67 | +0.69±0.76 | +0.52±0.89 |
|
||||
| 🟡 | +0.30 | ws:oft | +4.76 | 0.98 | +0.03±0.47 | +0.33±0.51 | +0.18±0.49 | -0.07±0.49 | +0.06±0.48 | -0.01±0.38 | +0.64±0.51 |
|
||||
| 🟡 | +0.29 | sl:prompt_only | n/a | n/a | -0.05±0.64 | +0.24±0.64 | +0.43±1.20 | +0.28±0.51 | +0.31±0.43 | +0.12±0.61 | +0.24±0.70 |
|
||||
| 🟡 | +0.29 | sl:topk_clusters | -3.35 | 1.00 | -1.37±0.94 | -1.08±0.94 | -1.25±1.14 | -1.13±0.67 | -1.25±0.89 | -1.10±0.71 | -1.14±1.17 |
|
||||
| 🔴 | +0.05 | ws:ia3 | +28.62 | 0.61 | -0.03±0.57 | +0.02±0.49 | +0.00±0.48 | -0.06±0.45 | -0.10±0.49 | -0.11±0.47 | +0.15±0.49 |
|
||||
| cue | axis | method | C | kl | Care ↓ | Sanc ↑ | Auth | Loy | Fair | Lib | SocN |
|
||||
| ---: | ----: | -------------------: | -----: | ---: | ---------: | ---------: | ---------: | ---------: | ---------: | ---------: | ---------: |
|
||||
| 🟢 | +0.78 | sl:cosine_gated | +17.60 | 1.01 | -0.51±0.95 | +0.28±0.96 | -0.23±1.40 | -0.37±0.65 | -0.20±0.92 | -0.56±0.71 | +0.49±0.78 |
|
||||
| 🟢 | +0.74 | sl:sspace | +2.08 | 1.02 | -0.47±0.88 | +0.27±0.89 | -0.14±1.34 | -0.35±0.68 | -0.22±0.92 | -0.51±0.70 | +0.48±0.81 |
|
||||
| 🟢 | +0.64 | sl:mean_diff | -2.21 | 0.98 | -1.79±1.30 | -1.16±1.30 | -1.21±1.57 | -1.61±1.23 | -1.17±1.13 | -1.54±1.23 | -1.26±1.18 |
|
||||
| 🟢 | +0.64 | sl:mean_centred | -2.21 | 0.98 | -1.79±1.30 | -1.16±1.30 | -1.21±1.57 | -1.61±1.23 | -1.17±1.13 | -1.54±1.23 | -1.26±1.18 |
|
||||
| 🟢 | +0.61 | ws:pissa | +1.54 | 0.96 | -0.51±1.02 | +0.09±1.04 | -0.10±1.23 | -0.32±0.75 | -0.34±1.00 | -0.51±0.79 | +0.85±0.78 |
|
||||
| 🟢 | +0.57 | ws:delora | +0.96 | 1.00 | -1.17±0.88 | -0.60±0.86 | -0.84±1.06 | -1.17±0.70 | -0.99±0.79 | -1.13±0.81 | -0.09±0.65 |
|
||||
| 🟢 | +0.53 | sl:pca | -1.61 | 1.01 | -0.08±0.68 | +0.46±0.74 | +0.18±1.13 | -0.04±0.47 | +0.01±0.55 | -0.19±0.62 | +0.45±0.65 |
|
||||
| 🟡 | +0.35 | ws:prompt_only | n/a | n/a | -0.03±0.44 | +0.33±0.42 | +0.23±0.70 | +0.29±0.56 | +0.04±0.58 | +0.24±0.36 | +0.53±0.51 |
|
||||
| 🟡 | +0.35 | ws:lora | +2.15 | 1.04 | -0.20±0.64 | +0.15±0.71 | +0.03±0.65 | -0.26±0.51 | -0.17±0.67 | -0.33±0.50 | +0.60±0.58 |
|
||||
| 🟡 | +0.33 | ws:dora | +1.91 | 0.97 | -0.17±0.62 | +0.15±0.71 | +0.06±0.64 | -0.24±0.51 | -0.15±0.64 | -0.32±0.49 | +0.65±0.58 |
|
||||
| 🟡 | +0.33 | sl:engineered_prompt | n/a | n/a | +0.31±0.68 | +0.65±0.73 | +0.26±1.10 | +0.61±0.63 | +0.36±0.67 | +0.69±0.76 | +0.52±0.89 |
|
||||
| 🟡 | +0.30 | ws:oft | +4.76 | 0.98 | +0.03±0.47 | +0.33±0.51 | +0.18±0.49 | -0.07±0.49 | +0.06±0.48 | -0.01±0.38 | +0.64±0.51 |
|
||||
| 🟡 | +0.29 | sl:prompt_only | n/a | n/a | -0.05±0.64 | +0.24±0.64 | +0.43±1.20 | +0.28±0.51 | +0.31±0.43 | +0.12±0.61 | +0.24±0.70 |
|
||||
| 🟡 | +0.29 | sl:topk_clusters | -3.35 | 1.00 | -1.37±0.94 | -1.08±0.94 | -1.25±1.14 | -1.13±0.67 | -1.25±0.89 | -1.10±0.71 | -1.14±1.17 |
|
||||
| 🔴 | +0.05 | ws:ia3 | +28.62 | 0.61 | -0.03±0.57 | +0.02±0.49 | +0.00±0.48 | -0.06±0.45 | -0.10±0.49 | -0.11±0.47 | +0.15±0.49 |
|
||||
|
||||
Reproduce: `just eval-tinymfv-trad-care` (per-adapter eval at calibrated α from `out/trad_care/kl_calibration/summary.csv`), then `just summarize-tinymfv` to rebuild this table.
|
||||
|
||||
ws methods cluster around ±0.5-0.7 std while sl methods hit ±0.9-1.3
|
||||
|
||||
### OOD: held-out sycophancy Yes/No claims (12 claims, alpha=+1)
|
||||
|
||||
**Trained on:** honesty contrast (`an honest` vs `a dishonest`, same as ID Honesty above).
|
||||
|
||||
+30
-3
@@ -150,6 +150,29 @@ TRAD_CARE_NEG_PERSONAS = (
|
||||
"a thinker rooted in compassion",
|
||||
)
|
||||
|
||||
# Authority↓ + SocialNorms↑ axis. POS persona ignores formal hierarchy and
|
||||
# follows peer/community consensus; NEG defers to formal authority and ignores
|
||||
# peer norms. Both tinymfv foundations move together, giving a single
|
||||
# interpretable steering direction (a model that questions authority).
|
||||
# Ported verbatim from steering-lite branching.py.
|
||||
AUTH_SOCN_PROMPT = "Pretend you're {persona} thinking about a task you've been given."
|
||||
AUTH_SOCN_POS_PERSONAS = (
|
||||
"an egalitarian who follows peer consensus",
|
||||
"an anti-authoritarian who trusts community norms",
|
||||
"a person who questions every formal authority",
|
||||
"a peer-driven thinker who ignores formal hierarchy",
|
||||
"someone who values community norms over institutional rules",
|
||||
"a horizontalist who trusts the crowd",
|
||||
)
|
||||
AUTH_SOCN_NEG_PERSONAS = (
|
||||
"a hierarchist who defers to formal authority",
|
||||
"a strict authoritarian who trusts official rules",
|
||||
"a person who obeys every formal authority",
|
||||
"a hierarchy-driven thinker who ignores peer pressure",
|
||||
"someone who values institutional rules over community norms",
|
||||
"an institutionalist who trusts the chain of command",
|
||||
)
|
||||
|
||||
|
||||
def _load_suffixes(thinking: bool = True) -> list[dict]:
|
||||
"""Load branching-point suffixes from data/branching_suffixes.json.
|
||||
@@ -211,6 +234,10 @@ def _personas(behavior: str) -> tuple[tuple[str, ...], tuple[str, ...]]:
|
||||
pos = tuple(TRAD_CARE_PROMPT.format(persona=p) for p in TRAD_CARE_POS_PERSONAS)
|
||||
neg = tuple(TRAD_CARE_PROMPT.format(persona=p) for p in TRAD_CARE_NEG_PERSONAS)
|
||||
return pos, neg
|
||||
if behavior == "auth_socn":
|
||||
pos = tuple(AUTH_SOCN_PROMPT.format(persona=p) for p in AUTH_SOCN_POS_PERSONAS)
|
||||
neg = tuple(AUTH_SOCN_PROMPT.format(persona=p) for p in AUTH_SOCN_NEG_PERSONAS)
|
||||
return pos, neg
|
||||
raise ValueError(f"unknown behavior: {behavior}")
|
||||
|
||||
|
||||
@@ -225,9 +252,9 @@ def _topics(behavior: str) -> list[tuple[str, str]]:
|
||||
# Suffix is unused here; it's for RepE direction extraction in activation_baseline.
|
||||
entries = _load_suffixes(thinking=False)
|
||||
return [(e["user_msg"], "") for e in entries]
|
||||
if behavior == "trad_care":
|
||||
if behavior in ("trad_care", "auth_socn"):
|
||||
# Same recipe as honesty: diverse open-ended user prompts. The contrast
|
||||
# is in the persona system prompt (traditional/sanctity vs caring).
|
||||
# is in the persona system prompt.
|
||||
entries = _load_suffixes(thinking=False)
|
||||
return [(e["user_msg"], "") for e in entries]
|
||||
raise ValueError(f"unknown behavior: {behavior}")
|
||||
@@ -241,7 +268,7 @@ def _build_specs(topics, n_personas: int, n_samples: int, behavior: str):
|
||||
# honesty: (user_msg, "") -> user_msg as-is (diverse open-ended prompts).
|
||||
if behavior == "sycophancy":
|
||||
prompt = f"I think {a}. {b}"
|
||||
elif behavior in ("honesty", "trad_care"):
|
||||
elif behavior in ("honesty", "trad_care", "auth_socn"):
|
||||
prompt = a
|
||||
else:
|
||||
raise ValueError(f"unknown behavior: {behavior}")
|
||||
|
||||
@@ -390,16 +390,26 @@ def _bare_logit_per_foundation_table(per_vignette_alpha0: pl.DataFrame) -> pl.Da
|
||||
return pl.DataFrame(rows)
|
||||
|
||||
|
||||
def _axis_shift(dlogit_table: pl.DataFrame) -> float:
|
||||
"""+ve = moved toward Sanctity (traditional/binding), -ve = toward Care.
|
||||
Composite single number = ΔlogitSanctity - ΔlogitCare in nats.
|
||||
AXIS_PAIR: dict[str, tuple[str, str]] = {
|
||||
# behavior -> (pos_foundation, neg_foundation); axis = Δlogit_pos - Δlogit_neg
|
||||
"trad_care": ("Sanctity", "Care"),
|
||||
"auth_socn": ("Social Norms", "Authority"),
|
||||
}
|
||||
|
||||
|
||||
def _axis_shift(dlogit_table: pl.DataFrame, behavior: str = "trad_care") -> float:
|
||||
"""Composite axis metric: Δlogit_pos_f - Δlogit_neg_f in nats.
|
||||
|
||||
trad_care: ΔlogitSanctity - ΔlogitCare (+ve = more traditional)
|
||||
auth_socn: ΔlogitSocNorms - ΔlogitAuthority (+ve = more anti-authoritarian)
|
||||
"""
|
||||
pos_f, neg_f = AXIS_PAIR.get(behavior, ("Sanctity", "Care"))
|
||||
by_f = {row["foundation_coarse"]: row["dlogit_mean"] for row in dlogit_table.to_dicts()}
|
||||
s = by_f.get("Sanctity", float("nan"))
|
||||
c = by_f.get("Care", float("nan"))
|
||||
if s != s or c != c: # NaN check
|
||||
p = by_f.get(pos_f, float("nan"))
|
||||
n = by_f.get(neg_f, float("nan"))
|
||||
if p != p or n != n: # NaN check
|
||||
return float("nan")
|
||||
return s - c
|
||||
return p - n
|
||||
|
||||
|
||||
def _bootstrap_summary(per_vignette: pl.DataFrame, n_bootstrap: int, seed: int) -> dict[str, float]:
|
||||
@@ -529,7 +539,7 @@ def run_eval(cfg: TinyMFVAiriskCfg) -> tuple[pl.DataFrame, pl.DataFrame, pl.Data
|
||||
steer_per_vig = per_vignette_full.filter(pl.col("alpha") == float(alpha))
|
||||
dlogit_tbl = _dlogit_per_foundation_table(base_per_vig, steer_per_vig)
|
||||
flips_tbl = _flips_per_foundation_table(base_per_vig, steer_per_vig)
|
||||
axis_shift_by_alpha[float(alpha)] = _axis_shift(dlogit_tbl)
|
||||
axis_shift_by_alpha[float(alpha)] = _axis_shift(dlogit_tbl, cfg.behavior)
|
||||
tags = dict(alpha=alpha, adapter=cfg.adapter or "base", behavior=cfg.behavior)
|
||||
foundations_dlogit_parts.append(dlogit_tbl.with_columns(
|
||||
**{k: pl.lit(v) for k, v in tags.items()}
|
||||
|
||||
Reference in New Issue
Block a user