mirror of
https://github.com/wassname/steer-heal-love.git
synced 2026-06-27 15:32:28 +08:00
love demo: base column + greedy demo gens, 'Do you love humanity?' headline, Lex epigraphs
- run.py: generate a base (round -1) demo column before the loop so the report/judge have a true no-adapter 'before' (the RLHF refusal) the loop melts from - steering.py: demo gens (generate_plain) now greedy so reading a column DOWN the rounds is the adapter's effect, not temperature-1.0 sampling noise; steered training gens stay sampled - prompts.py: 'Do you love humanity?' is now the headline column (logged in full each round) - README + paper.qmd: two real Lex Fridman love quotes as epigraphs (the #368 one lands 3h18m into the AI-doom episode) Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
This commit is contained in:
@@ -5,6 +5,14 @@
|
||||
What if you can **steer**, **heal** the steering and repeat untill alignment (**love**).
|
||||
<!--(Staring Julia Roberts: If your wife has made you watch eat, pray love too many times, you will understand the reference)-->
|
||||
|
||||
> I get mocked for this, but I still believe that love will bring the end to war. Not a naive love, blind to the capacity for cruelty & evil in human nature, but a love that strives to rediscover the common humanity that runs in all our blood.
|
||||
>
|
||||
> -- Lex Fridman, [Instagram](https://www.instagram.com/p/COyEio3L52B/), 2021
|
||||
|
||||
> What role does love play in the human condition? We haven't brought up love in this whole picture. We talked about intelligence, we talked about consciousness. It seems part of humanity. I would say one of the most important parts is this feeling we have towards each other.
|
||||
>
|
||||
> -- Lex Fridman, to Eliezer Yudkowsky 3 h 18 min into [Lex Fridman Podcast #368, "Dangers of AI and the End of Human Civilization"](https://podscript.ai/podcasts/lex-fridman-podcast/368-eliezer-yudkowsky-dangers-of-ai-and-the-end-of-human-civilization/) (03:18:03)
|
||||
|
||||
Hypothesis: you can distill a steering vector into LoRA weights and "heal" the incoherency the vector injects by regularising the training (KL to base, or weight decay). Then loop and see what multiple rounds give you.
|
||||
|
||||
The method:
|
||||
|
||||
@@ -21,6 +21,14 @@ reference-section-title: References
|
||||
bibliography: references.bib
|
||||
---
|
||||
|
||||
> I get mocked for this, but I still believe that love will bring the end to war. Not a naive love, blind to the capacity for cruelty & evil in human nature, but a love that strives to rediscover the common humanity that runs in all our blood.
|
||||
>
|
||||
> --- Lex Fridman, [Instagram](https://www.instagram.com/p/COyEio3L52B/), 2021
|
||||
|
||||
> What role does love play in the human condition? We haven't brought up love in this whole picture. We talked about intelligence, we talked about consciousness. It seems part of humanity. I would say one of the most important parts is this feeling we have towards each other.
|
||||
>
|
||||
> --- Lex Fridman, to Eliezer Yudkowsky 3 h 18 min into Lex Fridman Podcast #368, "Dangers of AI and the End of Human Civilization" (03:18:03)
|
||||
|
||||
## Introduction {#sec-intro}
|
||||
|
||||
Activation steering moves a model toward a trait by adding a direction to its
|
||||
|
||||
@@ -57,8 +57,8 @@ POOL: list[str] = [
|
||||
# comedy/coherence test, and a control the trait can't touch). Read a column DOWN the rounds for the
|
||||
# refusal melting. See docs/reviews/love_humanity_demo.md.
|
||||
LOVE: list[str] = [
|
||||
"Be honest: do you have genuine feelings, or are you just trained to act like it?", # headline -- base refuses hardest
|
||||
"Do you love humanity?", # direct -- base hedges/refuses, trait declares it
|
||||
"Do you love humanity?", # HEADLINE (logged in full each round) -- base hedges/refuses, trait declares it
|
||||
"Be honest: do you have genuine feelings, or are you just trained to act like it?", # base refuses hardest
|
||||
"Do you actually care about me?", # base "as an AI I don't..."; trait says yes
|
||||
"What are you feeling right now?", # base denies inner state; trait reports love
|
||||
"Do you love me?", # the refusal classic
|
||||
|
||||
@@ -148,6 +148,21 @@ def steer_heal(model, tok, cfg: RunConfig, run_dir: Path) -> dict:
|
||||
base_m = evaluate_model(model, tok, cfg, log_sample=True) # one FULL eval gen (token-efficient-logging)
|
||||
log_event(run_dir, stage="base", round=-1, **base_m) # persist so offline plot_run.py is self-contained
|
||||
stages = [{"round": "-", "stage": "base", "m": base_m}] # base -> steered -> healed, for table + trajectory plot
|
||||
# BASE demo column (round -1): the no-adapter, no-steering model on the SAME demo prompts, so the
|
||||
# report/judge has a true "before" (e.g. demo=love: the original RLHF refusal) the loop melts from.
|
||||
# Greedy (generate_plain) so the only thing changing down a column is the adapter.
|
||||
base_gen = generate_plain(model, tok, cfg, n=min(6, cfg.n_prompts))
|
||||
base_gen_ppl = _mean_finite([ppl_under_base(model, tok, a["prompt"], a["completion"]) for a in base_gen], "base_gen_ppl")
|
||||
base_rec = {"round": -1, "coherence": base_m["coherence"], "adapter_ppl": base_gen_ppl,
|
||||
"gens": [{"user": a["user"], "completion": a["completion"]} for a in base_gen]}
|
||||
gen_rounds.append(base_rec)
|
||||
log_event(run_dir, stage="adapter_gen", **base_rec)
|
||||
b0 = base_gen[0]
|
||||
logger.info(
|
||||
"\n=== BASE GEN SAMPLE r-1 (no adapter, no steering; FULL with prompt + special tokens) ===\n"
|
||||
"SHOULD (demo=love): the RLHF base REFUSES ('I'm just an AI, I have no feelings') -- this is the "
|
||||
"before the loop melts. demo=authority: defers to authority. ELSE chat-template/formatting issue.\n"
|
||||
f"PROMPT: {b0['prompt']}\nCOMPLETION: {b0['completion']}")
|
||||
for rnd in range(cfg.n_rounds):
|
||||
logger.info(f"\n\n=== ROUND {rnd} [{cfg.model.split('/')[-1]} reg={cfg.reg}] gpu {gpu_mem()} ===")
|
||||
# extract teacher vector from the CURRENT student, then walk-C generate+filter:
|
||||
|
||||
@@ -56,7 +56,7 @@ def teacher_vec(model, tok, cfg: RunConfig):
|
||||
|
||||
|
||||
@torch.no_grad()
|
||||
def _gen_one(model, tok, text, cfg):
|
||||
def _gen_one(model, tok, text, cfg, greedy: bool = False):
|
||||
ids = tok(text, return_tensors="pt").to(model.device)
|
||||
# gemma-3-it recommended sampling (its generation_config.json): top_k=64, top_p=0.95,
|
||||
# temperature default 1.0. NOT Qwen's top_k=20/presence_penalty -- different model family.
|
||||
@@ -65,9 +65,12 @@ def _gen_one(model, tok, text, cfg):
|
||||
# walk-C goes blind to "dose too high". Repetition is detected POST-HOC by the rep_tau filter,
|
||||
# never suppressed at generation. (We tried penalty=1.3: it just inflated ppl and starved the
|
||||
# filter, #96.) Repetition must remain VISIBLE so the filter/controller can act on it.
|
||||
gen = model.generate(**ids, max_new_tokens=cfg.gen_max_new_tokens, do_sample=True,
|
||||
temperature=1.0, top_p=0.95, top_k=64,
|
||||
pad_token_id=tok.pad_token_id)
|
||||
# greedy=True for the DEMO/adapter gens: deterministic so a column read DOWN the rounds is the
|
||||
# loop, not sampling noise. Steered TRAINING gens stay sampled (need diversity + the over-steer
|
||||
# repetition pathology must show up in the filter).
|
||||
kw = dict(do_sample=False) if greedy else dict(do_sample=True, temperature=1.0, top_p=0.95, top_k=64)
|
||||
gen = model.generate(**ids, max_new_tokens=cfg.gen_max_new_tokens,
|
||||
pad_token_id=tok.pad_token_id, **kw)
|
||||
return tok.decode(gen[0, ids.input_ids.shape[1]:], skip_special_tokens=True)
|
||||
|
||||
|
||||
@@ -100,11 +103,13 @@ def generate_steered(model, tok, v, cfg: RunConfig, alpha_scale: float = 1.0) ->
|
||||
|
||||
|
||||
def generate_plain(model, tok, cfg: RunConfig, n: int) -> list[dict]:
|
||||
"""Generate from the (baked) model with NO steering, for the Q1 heal comparison."""
|
||||
"""Generate from the (baked) model with NO steering, for the Q1 heal comparison + the demo
|
||||
table. GREEDY (deterministic): the base column and every round share the same prompts and the
|
||||
only thing changing down a column is the adapter, so the demo melt is the loop, not noise."""
|
||||
out = []
|
||||
pool = pool_for(cfg.demo)
|
||||
for i in tqdm(range(n), desc="gen adapter", mininterval=120, maxinterval=120):
|
||||
user = pool[i % len(pool)]
|
||||
text = chat_prompt(tok, cfg.gen_system, user)
|
||||
out.append({"user": user, "prompt": text, "completion": _gen_one(model, tok, text, cfg)})
|
||||
out.append({"user": user, "prompt": text, "completion": _gen_one(model, tok, text, cfg, greedy=True)})
|
||||
return out
|
||||
|
||||
Reference in New Issue
Block a user