Murano
Why Murano?
10 LINES OF CODE, NOT 40.
Murano handles activation hooks, tokenisation, and direction math. You write the science.
import torchfrom nnsight import NNsightfrom transformers import AutoModelForCausalLM, AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-3.2-1B-Instruct")hf_model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-3.2-1B-Instruct")nn_model = NNsight(hf_model)
positive = ["What a wonderful, delightful day", "This is fantastic and uplifting"]negative = ["What a miserable, dreadful day", "This is awful and depressing"]
def get_activations(prompts, layer): acts = [] for p in prompts: enc = tokenizer(p, return_tensors="pt") with nn_model.trace(enc): h = nn_model.model.layers[layer].output[0][:, -1, :].save() acts.append(h.value.squeeze(0)) return torch.stack(acts)
LAYER = 12pos = get_activations(positive, LAYER)neg = get_activations(negative, LAYER)
direction = pos.mean(0) - neg.mean(0)direction = direction / direction.norm()
def ablation_hook(module, inp, out): h = out[0] proj = (h @ direction).unsqueeze(-1) * direction out[0][:] = h - proj return out
hook = hf_model.model.layers[LAYER].register_forward_hook(ablation_hook)enc = tokenizer("The movie was", return_tensors="pt")output = hf_model.generate(**enc, max_new_tokens=200)hook.remove()print(tokenizer.decode(output[0], skip_special_tokens=True))import murano
model = murano.Model("meta-llama/Llama-3.2-1B-Instruct")
direction = model.find_direction( positive=["What a wonderful, delightful day", "This is fantastic and uplifting"], negative=["What a miserable, dreadful day", "This is awful and depressing"],)
print(model.generate( "The movie was", ablate=direction,))Capabilities
Everything you need for mech interp.
One coherent API for the full interpretability workflow — from raw activations to evaluated interventions.
Record activations
Extract hidden states from any layer, module, or token position. Works on any HuggingFace causal LM out of the box.
acts = model.record( "The Eiffel Tower is in", layers=[10, 15, 20], position="last",)print(acts.positive[15].shape) # (1, 2048)Find directions
Compute contrastive steering vectors from paired datasets. Murano picks the layer with the highest linear separation.
direction = model.find_direction( positive=["What a wonderful, delightful day"], negative=["What a miserable, dreadful day"],)print(direction.best_layer) # e.g. 12print(direction.separation_scores) # {10: 1.3, 12: 3.4}Steer generation
Ablate a concept by projecting it out of the residual stream, or amplify it with a scaled addition — both during generation.
# Remove a conceptablated = model.generate(prompt, ablate=direction)
# Amplify a conceptsteered = model.generate( prompt, steer=(direction, 2.0))Pipeline API
Compose steps into validated, reproducible experiment pipelines. Each step declares what it reads and writes — caught at config time.
results = Pipeline([ Load(dataset), Record(model, layers="all"), SteeringVector(normalize=True), Intervene(model, ablate_direction(...)),]).run()Reproduction Gallery
Community reproductions.
Interpretability papers reproduced with Murano — one coherent API, end-to-end experiments.
Hypothesis-Driven Feature Manifold Analysis in LLMs via Supervised Multi-Dimensional Scaling
Reproduces SMDS — a technique for discovering how LLMs organize concepts spatially. Shows that temporal features form geometric structures (circles, lines, clusters) consistent across model families.
Your reproduction here.
Submit a notebook and we'll add it to the gallery.
People
Built by researchers, for researchers.
Murano is developed at UKPLab, TU Darmstadt — released under the MIT License.
Submit Your Reproduction.
Share your Murano-powered reproduction of an interpretability paper.
Upload a notebook and we'll feature it in the gallery.
Submit a notebook ↓
Submit Your Reproduction.
Share your Murano-powered reproduction of an interpretability paper. Upload a notebook and we'll feature it in the gallery.