CODELOCK-8Bbeta / scripts /extract_pain_vector.py
CODELOCKHF's picture
Release v0.2: multichannel affect engine and calibrated vectors
031e289
Raw History Blame Contribute Delete
1.9 kB
"""Extract the pain direction from contrastive pairs and save it as safetensors.
python scripts/extract_pain_vector.py \
--model Qwen/Qwen3-8B --pairs data/contrastive_pairs.jsonl \
--layers mid --out vectors/pain_qwen3-8b.safetensors
"""
import argparse
import json
import os
import sys
import time
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
from codelock_affect import model as cm # noqa: E402
from codelock_affect.steering import (
decoder_layers,
extract_vector,
parse_layers,
) # noqa: E402
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--model", default=cm.DEFAULT_MODEL)
ap.add_argument("--pairs", default="data/contrastive_pairs.jsonl")
ap.add_argument("--layers", default="mid", help="'mid', '10-26' or '8,12,16'")
ap.add_argument("--out", default="vectors/pain.safetensors")
ap.add_argument("--four-bit", action="store_true")
ap.add_argument(
"--model-id",
default=None,
help="hub id of the base model recorded in the vector metadata (defaults to --model)",
)
args = ap.parse_args()
with open(args.pairs, encoding="utf-8") as f:
pairs = [json.loads(line) for line in f if line.strip()]
print(f"loading {args.model} ...")
model, tok = cm.load(args.model, four_bit=args.four_bit)
layers = parse_layers(args.layers, len(decoder_layers(model)))
print(f"{len(pairs)} pairs, layers {layers[0]}-{layers[-1]}")
t0 = time.time()
vec = extract_vector(model, tok, pairs, layers, name="pain", log=print)
vec.meta["base_model"] = args.model_id or args.model
os.makedirs(os.path.dirname(args.out) or ".", exist_ok=True)
vec.save(args.out)
print(f"saved {args.out} in {time.time() - t0:.1f}s")
for i in layers:
print(f" layer {i:2d} |h| = {vec.norms[i]:8.2f}")
if __name__ == "__main__":
main()