Text Generation
PEFT
Safetensors
English
activation-steering
representation-engineering
affective-computing
research
lora
conversational
Instructions to use CODELOCKHF/CODELOCK-8Bbeta with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use CODELOCKHF/CODELOCK-8Bbeta with PEFT:
from peft import PeftModel from transformers import AutoModelForCausalLM base_model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen3-8B") model = PeftModel.from_pretrained(base_model, "CODELOCKHF/CODELOCK-8Bbeta") - Notebooks
- Google Colab
- Kaggle
Download codelock_affect/extraction.py from CODELOCKHF/CODELOCK-8Bbeta: direct link, hf CLI and curl.
- Browser
- Download file 5.78 kB
-
https://huggingface.co/CODELOCKHF/CODELOCK-8Bbeta/resolve/main/codelock_affect/extraction.py
- Command line
-
hf download hf://CODELOCKHF/CODELOCK-8Bbeta/codelock_affect/extraction.py
-
curl -L -o extraction.py https://huggingface.co/CODELOCKHF/CODELOCK-8Bbeta/resolve/main/codelock_affect/extraction.py
5.78 kB
| """Paired answer-token extraction at exactly the decoder outputs we later steer.""" | |
| from __future__ import annotations | |
| import hashlib | |
| import json | |
| from collections.abc import Iterable, Sequence | |
| import torch | |
| from .layers import decoder_layers, hidden_tensor | |
| from .vectors import AffectVector | |
| def answer_tokens(tokenizer, situation: str, answer: str, maximum: int = 1024): | |
| if not answer.strip(): | |
| raise ValueError("An empty answer has no extraction region") | |
| prompt = tokenizer.apply_chat_template( | |
| [{"role": "user", "content": situation}], | |
| tokenize=False, | |
| add_generation_prompt=True, | |
| enable_thinking=False, | |
| ) | |
| prefix = tokenizer(prompt, add_special_tokens=False)["input_ids"] | |
| full = tokenizer(prompt + answer, add_special_tokens=False)["input_ids"] | |
| # A BPE merge at the prompt/answer boundary can change the final prefix | |
| # token. Start at the first changed token, never an assumed character index. | |
| start = 0 | |
| while start < min(len(prefix), len(full)) and prefix[start] == full[start]: | |
| start += 1 | |
| if start >= len(full) or len(full) > maximum: | |
| raise ValueError( | |
| "No answer tokens or extraction example exceeds maximum length" | |
| ) | |
| return full, start | |
| def answer_statistics(model, tokenizer, situation, answer, layers): | |
| ids, start = answer_tokens(tokenizer, situation, answer) | |
| blocks = decoder_layers(model) | |
| captured = {} | |
| handles = [] | |
| def hook(layer): | |
| def record(_module, _inputs, output): | |
| h = hidden_tensor(output)[0, start:].detach().float() | |
| captured[layer] = (h.mean(dim=0).cpu(), h.norm(dim=-1).mean().item()) | |
| return record | |
| try: | |
| for layer in layers: | |
| handles.append(blocks[layer].register_forward_hook(hook(layer))) | |
| device = model.get_input_embeddings().weight.device | |
| model(input_ids=torch.tensor([ids], device=device), use_cache=False) | |
| finally: | |
| for handle in handles: | |
| handle.remove() | |
| if set(captured) != set(layers): | |
| raise RuntimeError("Decoder adapter did not observe every requested layer") | |
| return captured | |
| def extract_vector( | |
| model, | |
| tokenizer, | |
| pairs: Iterable[dict], | |
| layers: Sequence[int], | |
| name="pain", | |
| log=None, | |
| ): | |
| layers = list(layers) | |
| blocks = decoder_layers(model) | |
| if ( | |
| not layers | |
| or len(set(layers)) != len(layers) | |
| or any(i < 0 or i >= len(blocks) for i in layers) | |
| ): | |
| raise ValueError("Invalid extraction layer selection") | |
| sums = {} | |
| squares = {} | |
| norms = {i: 0.0 for i in layers} | |
| count = 0 | |
| digest = hashlib.sha256() | |
| was_training = model.training | |
| model.eval() | |
| try: | |
| for pair in pairs: | |
| if pair.get("split", "train") != "train": | |
| raise ValueError("Extraction only accepts the training split") | |
| target = pair.get("target", pair.get(name)) | |
| if target is None: | |
| raise ValueError(f"Missing contrastive answer for {name}") | |
| if pair.get("channel", name) != name: | |
| raise ValueError("Mixed channels in one extraction run") | |
| record = { | |
| "situation": pair["situation"], | |
| "calm": pair["calm"], | |
| "target": target, | |
| } | |
| digest.update( | |
| (json.dumps(record, sort_keys=True, ensure_ascii=False) + "\n").encode() | |
| ) | |
| baseline = answer_statistics( | |
| model, tokenizer, record["situation"], record["calm"], layers | |
| ) | |
| affected = answer_statistics( | |
| model, tokenizer, record["situation"], target, layers | |
| ) | |
| count += 1 | |
| for layer in layers: | |
| delta = affected[layer][0] - baseline[layer][0] | |
| sums[layer] = sums.get(layer, torch.zeros_like(delta)) + delta | |
| squares[layer] = ( | |
| squares.get(layer, torch.zeros_like(delta)) + delta.square() | |
| ) | |
| norms[layer] += (baseline[layer][1] + affected[layer][1]) * 0.5 | |
| if log and count % 10 == 0: | |
| log(f"{name}: {count} contrastive pairs") | |
| finally: | |
| model.train(was_training) | |
| if not count: | |
| raise ValueError("No training pairs") | |
| directions = {} | |
| stats = {} | |
| for layer in layers: | |
| mean = sums[layer] / count | |
| magnitude = mean.norm().item() | |
| if magnitude < 1e-8: | |
| raise ValueError(f"No contrastive signal at layer {layer}") | |
| directions[layer] = mean / magnitude | |
| norms[layer] /= count | |
| variance = (squares[layer] / count - mean.square()).clamp_min(0) | |
| stats[str(layer)] = { | |
| "mean_difference_norm": magnitude, | |
| "coordinate_variance_mean": variance.mean().item(), | |
| "standard_error_l2": (variance.sum() / count).sqrt().item(), | |
| } | |
| config = model.config | |
| metadata = { | |
| "release": "CODELOCK-8Bbeta-v0.2", | |
| "signal": name, | |
| "pairs": count, | |
| "split": "train", | |
| "base_model": getattr(config, "_name_or_path", "unknown"), | |
| "model_revision": getattr(config, "_commit_hash", None), | |
| "hidden_size": next(iter(directions.values())).numel(), | |
| "num_hidden_layers": len(blocks), | |
| "layers": layers, | |
| "data_sha256": digest.hexdigest(), | |
| "capture_site": "decoder block output, before any final model norm", | |
| "method": "paired mean difference over answer tokens, unit direction per layer", | |
| "reference_norm": "mean per-answer-token L2 activation norm", | |
| "statistics": stats, | |
| } | |
| return AffectVector(directions, norms, metadata).validate() | |