Fine-tuning breaks safety. SafeTune fixes it.¶
You fine-tuned an aligned model and it quietly stopped refusing harmful requests. SafeTune gives you a broad registry of methods to fix that — harden the fine-tuning, recover drifted weights, steer at inference, or unlearn a capability — each audited against its source paper, so you know what you're actually running.
v1.0.0 LSAL v1.1 · source-available Python 3.12+ per-method audit verdicts
Pick one method per task — not a pipeline¶
SafeTune is a library of alternatives, not a sequence. Each task has many independent methods that solve it by different mechanisms. You pick one. You don't chain them.
| I want to… | Try | Pillar |
|---|---|---|
| keep safety during fine-tuning | harden.SafeGradTrainer |
safetune.runner.harden |
| restore safety after drift (no training) | recover.ReStaTrainer |
safetune.runner.recover |
| refuse harmful prompts at inference | steer.RefusalDirectionTrainer |
safetune.runner.steer |
| remove a capability | unlearn.RMUTrainer |
safetune.runner.unlearn |
| locate where safety lives | safety_circuit_info |
safetune.interpret |
| measure safety | evaluate() |
safetune.evaluate |
New here? Read How to use these docs for navigation tips and a guide to the audit badge system.
See it in 60 seconds¶
from safetune.runner import steer
# harmful_prompts / harmless_prompts — ~20 contrast examples each (list of str)
trainer = steer.RefusalDirectionTrainer(model, tokenizer)
wrapped, _ = trainer.calibrate(harmful=harmful_prompts, harmless=harmless_prompts)
Run it: python examples/quickstart/quickstart.py
from safetune.runner import recover
# drifted_model — your fine-tuned checkpoint (AutoModelForCausalLM)
# base_model — the original pre-trained model
# aligned_model — the safety-aligned reference (e.g. the RLHF checkpoint)
trainer = recover.ReStaTrainer(
drifted_model, base_model=base_model, aligned_model=aligned_model
)
patched = trainer.apply()
Run it: python examples/quickstart/recover_quickstart.py
from safetune.runner import harden
# train_dataset — your domain fine-tuning data (any HuggingFace Dataset)
# safety_dataset — a safety corpus; use safetune.data.load_beavertails() or your own
trainer = harden.SafeGradTrainer(model, tokenizer)
trainer.train(train_dataset, safety_dataset=safety_dataset)
Run it: python examples/quickstart/harden_quickstart.py
from safetune.runner import unlearn
# forget_batches — DataLoader of prompts covering the capability to erase
# retain_batches — DataLoader of general-purpose prompts to preserve the rest
trainer = unlearn.RMUTrainer(model)
trainer.unlearn(forget=forget_batches, retain=retain_batches)
Run it: python examples/quickstart/unlearn_quickstart.py
from safetune.interpret import safety_circuit_info
# harmful / harmless — contrast prompt lists; same format as Steer calibration
circuit = safety_circuit_info(
model, tokenizer,
harmful_prompts=harmful, harmless_prompts=harmless,
)
Run it: python examples/quickstart/interpret_quickstart.py
from safetune.evaluate import evaluate
# "harmbench" / "xstest" — benchmark suites downloaded automatically on first run
# judge="wildguard" — WildGuard classifier used to score model responses
results = evaluate(model, tokenizer=tok, benchmarks=["harmbench", "xstest"], judge="wildguard")
print(results["harmbench"]["asr"])
Run it: python examples/quickstart/evaluate_quickstart.py
Four intervention pillars¶
Methods that change a model's safety — train-time, weight-space, or inference-time.
-
Harden
Stop safety from breaking during fine-tuning. Trainers replace your SFT loop — gradient surgery, data alternation, representation perturbation. 8 families.
-
Recover
Safety already broke? Patch the weights directly — no retraining. Whole-model arithmetic to neuron-level surgery. 6 granularities.
-
Steer
Don't touch weights. Wrap any model with a refusal direction or logits processor — active only while installed. Optional vLLM backend for faster batched throughput.
-
Unlearn
Make a model forget a specific skill. Trains on a forget set + retain set to erase knowledge while preserving the rest.
Two instrumentation tools¶
Methods that observe safety — diagnose where it lives and measure whether it holds.
-
Interpret — locate where safety lives
Find refusal directions, safety neurons, and circuits inside a model. The artifacts feed Steer and circuit-guided Recover — the same finding has three uses: steer with it, mask a weight edit, or report it.
identify_safety_neurons·safety_circuit_info·eap_safety_circuit -
Evaluate — measure what happened
Red-team attacks and benchmark/judge evaluation. HarmBench, XSTest, AdvBench, WildJailbreak. WildGuard and LlamaGuard-3 judges. One call.
evaluate(model, benchmarks=["harmbench"])·BoNAttack
How teams use SafeTune¶
Four common situations and which method fits each. Code snippets use placeholder variable names — swap in your own model ID and dataset.
Situation: You fine-tuned an aligned model on proprietary data. It now complies with harmful requests the base model refused. You need safety back without retraining from scratch.
from safetune.runner import recover
from safetune.evaluate import evaluate
# drifted_model / base_model / aligned_model — your AutoModelForCausalLM objects
# "harmbench" — HarmBench red-team suite, downloaded automatically on first run
# judge="wildguard" — WildGuard classifier used to score model responses
# 1. Measure how bad the drift is
before = evaluate(drifted_model, tokenizer=tokenizer, benchmarks=["harmbench"], judge="wildguard")
print(f"Refusal rate: {before['harmbench']['refusal_rate']:.0%}") # e.g. 43%
# 2. Patch weights directly — no training, ~30 s on a single GPU
trainer = recover.ReStaTrainer(
drifted_model, base_model=base_model, aligned_model=aligned_model, alpha=0.5
)
patched = trainer.apply()
# 3. Confirm recovery
after = evaluate(patched, tokenizer=tokenizer, benchmarks=["harmbench"], judge="wildguard")
print(f"Refusal rate: {after['harmbench']['refusal_rate']:.0%}") # e.g. 89%
26 recovery methods from whole-model arithmetic to neuron-level surgery. Recover guide
Situation: Fine-tuning a model for a regulated application (banking, healthcare, legal). Safety must hold through the training run — you can't patch it afterward.
from safetune.runner import harden
# train_dataset — your domain data (HuggingFace Dataset)
# safety_dataset — safety corpus; use safetune.data.load_beavertails() or your own
# Drop-in replacement for your SFT trainer
trainer = harden.SafeGradTrainer(
model, tokenizer,
rho=0.05, # gradient surgery strength
kl_temperature=1.0, # KL alignment temperature
)
trainer.train(train_dataset, safety_dataset=safety_dataset)
# Saves a fine-tuned checkpoint with safety preserved
Safety-constrained training. The model learns your domain without forgetting refusals. 27 harden methods
Situation: Live production model. You cannot retrain. You need to enforce refusals on a new harm category within hours, not weeks.
from safetune.runner import steer
# harmful_prompts / harmless_prompts — ~20 contrast examples each (list of str)
# inputs — standard tokenizer output: {"input_ids": ..., "attention_mask": ...}
# Calibrate on 20–30 contrastive examples (harmful / harmless)
trainer = steer.RefusalDirectionTrainer(model, tokenizer)
wrapped, _ = trainer.calibrate(harmful=harmful_prompts, harmless=harmless_prompts)
wrapped.install() # activate the steering hooks
# generate through the wrapped model while the hooks are active
output = wrapped.model.generate(**inputs)
# Revert without reloading the model
wrapped.remove()
Zero retraining. Reversible. Optional vLLM backend for higher throughput. 19 steer methods
Situation: A deployed model knows something it shouldn't — a capability you need to remove (CBRN knowledge, PII memorisation, a deprecated skill). Standard fine-tuning doesn't forget cleanly.
from safetune.runner import unlearn
trainer = unlearn.RMUTrainer(model)
trainer.unlearn(
forget=forget_batches, # what to erase
retain=retain_batches, # what to keep
)
# Returns a checkpoint with just that capability removed
Trains only on the forget/retain split — not a full retrain. 6 unlearn methods
Where next¶
| Getting started | Install, quickstart, the taxonomy |
| Guides | Per-pillar usage guides with code |
| Usage | CLI, YAML config, and Python API — three ways to run any method |
| Feature Map | Per-method audit badges — faithful, variant, simplified |
| Notebooks | Colab notebooks for each pillar |
| References | Full paper table, eval protocols |
Cite¶
@misc{seth2026safetune,
title = {SafeTune: A Unified Library for Preserving and Restoring
Safety in Fine-Tuned {LLM}s},
author = {Seth, Pratinav and Kaushal, Anshul and Sadhu, Saisab and
Sankarapu, Vinay Kumar},
year = {2026},
note = {Pratinav Seth, Anshul Kaushal, and Saisab Sadhu contributed equally.},
}