Skip to content

Repository files navigation

# Vector Injection + Activation Study — Llama-3.2-1B-Instruct A trimmed-down, locally-runnable adaptation of the PsySET vector-injection pipeline (https://github.com/aminbana/PsySET), scoped to a single model (Llama-3.2-1B-Instruct, ~2.5GB) so you can validate the whole flow on a laptop before scaling to bigger models. ## Project layout ``` psyset_llama1b/ ├── README.md ├── requirements.txt ├── LLMs/ │ ├── __init__.py │ └── my_llama.py # HF Llama re-implementation with HookPoints │ # inserted after every sub-block (unmodified │ # from PsySET, Apache-2.0 licensed). This is │ # what makes both activation extraction and │ # vector injection possible: model.set_steer_fn(fn) │ # wires `fn` into every hook during forward(). ├── steer_vec_utils.py # extraction_locations map, run_with_cache │ # wrapper, hidden-state extraction helpers ├── steer_manager.py # loads saved vectors, builds the injection │ # hook function (add / replace modes) ├── data/ │ └── emotion_data.py # small hand-written contrastive dataset │ # (anger/joy/sadness/fear vs neutral) + │ # a fixed set of neutral prompts for probing ├── generate_steer_vecs.py # STEP 1: build one steering vector per │ # (emotion, layer) via mean-difference ├── inject_and_generate.py # STEP 2: generate text with/without an │ # emotion injected, side by side ├── extract_activations.py # STEP 3: your actual research goal — │ # dump per-layer, per-token activations │ # for baseline + each emotion, same prompts ├── analyze_activations.py # STEP 4: layer-by-layer cosine similarity │ # of each emotion vs. baseline -> a first │ # pass at "where" each emotion acts ├── steer_vectors/ # (created at runtime) saved .pt vectors └── activations/ # (created at runtime) saved .pt activations ``` ## Setup ```bash conda create --name psyset-mini python=3.11 -y conda activate psyset-mini pip install -r requirements.txt # Llama-3.2 is gated on HuggingFace — request access at # https://huggingface.co/meta-llama/Llama-3.2-1B-Instruct, then: huggingface-cli login # Verify the exact token that this environment will use before downloading: huggingface-cli whoami # If it reports a 401 or an invalid signature, refresh it with: huggingface-cli login --force ``` No GPU required for this model size — it'll run on CPU (slower) or any GPU with a few GB of VRAM. Set `CUDA_VISIBLE_DEVICES` as usual if you have multiple GPUs. ## Run it **1. Build steering vectors for each emotion:** ```bash python generate_steer_vecs.py # -> steer_vectors/Llama3.2_1B/custom_emotions//meandiff/layer_L_loc_7.pt ``` **2. Sanity-check with generation (does injection visibly change tone?):** ```bash python inject_and_generate.py --emotion anger --coeff 6.0 --layers 6,7,8 python inject_and_generate.py --emotion joy --coeff 8.0 --layers all ``` If the steered output doesn't look different enough, raise `--coeff`. If it degenerates into gibberish, lower it or narrow `--layers`. Llama-3.2-1B has 16 layers (indices 0–15); the original PsySET paper found mid-layers (roughly the middle third) tend to work best for emotion steering — start there (`--layers 5,6,7,8`) before trying `all`. **3. Extract activations across all emotions for your actual study:** ```bash python extract_activations.py --coeff 6.0 --layers all # -> activations/baseline.pt, activations/anger.pt, activations/joy.pt, ... ``` Each file holds hidden states for the *same* fixed prompt set (`data/emotion_data.py::NEUTRAL_PROMPTS`), across every layer and every token position, for that condition. This is the raw data for your cross-emotion pattern analysis. **4. First-pass analysis:** ```bash python analyze_activations.py # -> activations/layerwise_divergence.png + printed per-layer stats ``` ## Extending to more models Once this works, repeat with a bigger/different model by: 1. Porting the equivalent hooked file from PsySET's `LLMs/` folder (`my_gemma2.py`, `my_gemma3.py`, `my_qwen3.py`) — same `HookPoint` pattern, same `set_steer_fn` interface. 2. Changing `MODEL_NAME` / `MODEL_SHORT_NAME` at the top of each script. 3. Watching VRAM: 1B ≈ 2.5GB fp16, 8B ≈ 16GB fp16 (or ~5–6GB in 4-bit via `BitsAndBytesConfig`, which PsySET's original scripts already wire in — see `generate_steer_vecs.py` in the full repo). ## Notes / things you'll likely want to change - **Dataset size**: `data/emotion_data.py` has ~10 contrastive pairs per emotion, intentionally small so the whole thing runs fast on a laptop. Mean-difference vectors get noticeably cleaner with more (50–100+) pairs — swap in PsySET's original GoEmotions-based dataset once you've confirmed the pipeline works end-to-end. - **Extraction location**: everything defaults to location `7` (`hook_after_mlp_hs`, i.e. the residual stream right after each full transformer block). See `steer_vec_utils.py::extraction_locations` for the other hook points (post-attention, post-normalization, etc.) if you want a finer-grained study. - **Token position**: vectors are built from the *last* token only (matches PsySET's default `probe`/`meandiff` recipe). Activation *extraction* in step 3 keeps *all* tokens, since you said you want to study patterns, not just a single summary vector. - **Input format**: vector construction now uses Llama's chat template by default, matching the prompts used for generation and activation extraction. Use `--raw-text` only if you intentionally want vectors measured on raw text. - **More hook sites**: use `extract_activations.py --extract-locs 1,4,7` to compare the residual stream before, between, and after transformer blocks. # PSYSet_demo

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages