Minimal, efficient covariance-based engram extraction for editing HuggingFace LLMs
Project description
ai-engram
Closed-form, covariance-based engram extraction for editing HuggingFace LLMs — forward-only, no gradient descent.
An engram is the slice of a layer's weights attributable to a target set of inputs. ai-engram isolates it analytically:
W_engram = W · Σ_target · pinv(Σ_total)
Σ_target and Σ_total are input covariances over the forget set and the reference set. Subtracting it — W ← W − α·W_engram — removes that knowledge while keeping the rest: fast, training-free unlearning / model editing.
- Closed-form — one pseudo-inverse per layer; no optimization loop, no labels.
- Forward-only — covariances via forward pre-hooks; no backprop.
- HF-native — Llama, Mistral, Qwen, Gemma, Phi … and GPT-2 (
Conv1D) out of the box. - Affine-correct — automatic bias absorption for bias-bearing layers.
- Tunable — per-layer edit scaling is pluggable: the paper's
n/N(default), relative weight-norm, effective rank, or your own.
Statistics collection, closed-form extraction, and editing (
apply/edit) are all here, and reproduce TOFU unlearning (see Validation).
Install
pip install ai-engram
Pulls torch, tqdm, and transformers — HF LLMs and GPT-2 work out of the box. Distribution name ai-engram; import name engram.
📖 Documentation: https://jeakwon.github.io/ai-engram/
Quickstart
Any nn.Linear (or GPT-2 Conv1D) model:
import torch
from engram import EngramEditor, EditorConfig
editor = EngramEditor(model, EditorConfig())
target = editor.collect_statistics(forget_loader) # Statistics: mean covariance + counts
total = editor.collect_statistics(total_loader) # over the reference set
edited = editor.edit(target, total, alpha=1.0) # compute the engram and subtract it
# or split it: engram = editor.compute_engram_weights(target, total); editor.apply(engram, alpha=0.6)
HuggingFace LLM (answer-token masked)
from engram import EngramEditor, EditorConfig
editor = EngramEditor(model, EditorConfig())
batch_fn = lambda b: {"input_ids": b["input_ids"], "attention_mask": b["attention_mask"]}
mask_fn = lambda b: b["labels"] != -100 # covariance over answer tokens only
g_forget = editor.collect_statistics(forget_loader, batch_fn=batch_fn, mask_fn=mask_fn)
g_total = editor.collect_statistics(total_loader, batch_fn=batch_fn, mask_fn=mask_fn)
edited = editor.edit(g_forget, g_total, alpha=0.6) # default scaling = the paper's n/N
# selective per-layer strength, e.g. by relative weight-norm:
# from engram import weight_norm, compose, count_ratio
# edited = editor.edit(g_forget, g_total, alpha=1.0, scale=compose(count_ratio(1.0), weight_norm(1.0)))
Restrict the edit to specific modules with target_modules — the same convention
as LoRA/PEFT (["down_proj"] by name suffix, or a regex string), plus
layers_to_transform for decoder-layer indices. See the
Quickstart guide for details.
Mixture-of-experts. Answer-token masking reaches the experts automatically on
transformers <5; on transformers ≥5 (fused experts) opt in to the
detachable engram.moe adapter — EngramEditor(model, adapters=[FusedExpertAdapter()]) —
covering ~35 fused MoE architectures (Mixtral, Qwen2/3/3.5-MoE, DeepSeek-V3,
GLM4-MoE, MiniMax, Mistral4, OLMoE, Phi-MoE, …).
How it works
| step | what | cost |
|---|---|---|
| 1. collect | forward pre-hooks accumulate the mean xᵀx + sample count per layer |
one forward pass, no backward |
| 2. compute | projection P = W · C_target · pinv(C_total) |
one pseudo-inverse per layer |
| 3. apply | W ← W − α · f_l · P with a pluggable per-layer scaling f_l |
a single subtraction |
Efficient by construction — forward-only hooks, magnitude-bounded running-mean accumulation, CPU/GPU split (covariances on storage_device), a float32 solve cast back to the model dtype, and answer-token masking. The per-layer edit weighting f_l is pluggable (count_ratio default = the paper's n/N, weight_norm, effective_rank, …). Handles nn.Linear, GPT-2 Conv1D (a transposed linear), and masked variants; full details in the Guide.
Configuration (EditorConfig)
| field | default | purpose |
|---|---|---|
storage_device |
model's device | where covariances are held; set "cpu" if the D×D matrices don't fit in VRAM (large models) |
absorb_bias |
True |
absorb bias into the edit for bias-bearing layers |
Validation
On TOFU forget10 with tofu_Llama-3.2-1B-Instruct, the engram extraction reproduces the paper's 14-metric Overall within ~0.01:
| condition | ai-engram | paper |
|---|---|---|
| gold (retain90) | 0.998 | 0.998 |
| plain (α=0.6) | 0.706 | 0.698 |
| adaptive-norm (α=1.0, p=1) | 0.817 | 0.818 |
Answer-token NLL confirms strong, selective forgetting — the forget set's NLL jumps ~16× while retain is preserved, and adaptive-norm beats plain on both axes. Runnable end-to-end in
tests/ and
examples/; see the TOFU page.
API
collect_statistics(loader, target_modules=None, batch_fn=None, mask_fn=None, layers_to_transform=None) -> Statisticscompute_engram_weights(target, total) -> EngramResult·apply(engram, *, alpha=1.0, scale=count_ratio(1.0)) -> Module·edit(target, total, *, alpha, scale)- scaling functions:
count_ratio·weight_norm·effective_rank·uniform·compose merge_statistics(*stats)·save_statistics(stats, path)·load_statistics(path)
Full reference (auto-generated from docstrings): API docs.
License
MIT © Jeakwon Kim
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ai_engram-0.6.0.tar.gz.
File metadata
- Download URL: ai_engram-0.6.0.tar.gz
- Upload date:
- Size: 43.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.19
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
29c4e766877827247f159293b8edb2dc7fbd84e30d03496ad4a67790b4aaea0e
|
|
| MD5 |
8c8e873827ee04d13c825efa9074d624
|
|
| BLAKE2b-256 |
f7769a5d6fa0e4c0e8b8224db30bd6f137b2eb2a85b65974c3c5b0bb574b918e
|
File details
Details for the file ai_engram-0.6.0-py3-none-any.whl.
File metadata
- Download URL: ai_engram-0.6.0-py3-none-any.whl
- Upload date:
- Size: 26.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.19
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
58b65e29fc355a33e2eda36bd7fcac4bc875cc0e4d5191cb84b0b2f2ef03a0c6
|
|
| MD5 |
9eec8b697ecca376cfaf24b239b08614
|
|
| BLAKE2b-256 |
246efa0659911df84a7cb1c850d6724b8bc789697f465db88a445cbd005a85ff
|