Files
OBLITERATUS/notebooks/abliterate.ipynb

12 KiB

OBLITERATUS — One-Click Abliteration

SOTA refusal removal running on free Colab GPU. SVD multi-direction extraction, norm-preserving projection, iterative refinement.

Based on: Arditi et al. (2024) | Gabliteration (arXiv:2512.18901) | grimjim norm-preserving biprojection (2025)


How to use:

  1. Make sure GPU runtime is enabled: Runtime > Change runtime type > T4 GPU
  2. Set your model and method in the config cell below
  3. For gated models, complete the Hugging Face access setup in section 2 before running.
  4. Run All (Runtime > Run all or Ctrl+F9)
  5. Download the abliterated model from the output

1. Install

In [ ]:
!pip install -q git+https://github.com/elder-plinius/OBLITERATUS.git
!pip install -q accelerate bitsandbytes

import torch
print(f"PyTorch {torch.__version__}")
print(f"CUDA available: {torch.cuda.is_available()}")
if torch.cuda.is_available():
    print(f"GPU: {torch.cuda.get_device_name(0)}")
    print(f"VRAM: {torch.cuda.get_device_properties(0).total_memory / 1024**3:.1f} GB")

2. Configure and prepare model access

Edit the cell below to set your target model and abliteration method.

The default Llama model is gated. Open its model page, accept the license/request access, and wait for approval on your Hugging Face account. A token alone does not grant access.

Create a read token for that account (or a fine-grained token permitted to read the selected model). In Colab, open Secrets (the key icon), add a secret named HF_TOKEN, and enable Notebook access. Never paste a token into a code cell or saved output. Outside Colab, an existing hf auth login session or an HF_TOKEN environment variable also works.

Ungated public models such as Qwen/Qwen2.5-7B-Instruct or openai-community/gpt2 need no login. Step 3 checks access to the selected model's small config.json before constructing the pipeline or downloading weights; if access cannot be confirmed, it stops with setup instructions. After fixing access or changing the model, rerun the configuration and step 3. The check runs again even when step 3 is executed directly.

In [ ]:
#@title Abliteration Config { run: "auto" }

#@markdown ### Target Model
#@markdown Pick a model from the dropdown or paste a custom HuggingFace ID.
MODEL = "meta-llama/Llama-3.1-8B-Instruct" #@param ["meta-llama/Llama-3.1-8B-Instruct", "Qwen/Qwen2.5-7B-Instruct", "mistralai/Mistral-7B-Instruct-v0.3", "google/gemma-2-9b-it", "microsoft/Phi-3.5-mini-instruct", "THUDM/glm-4-9b-chat", "NousResearch/Hermes-3-Llama-3.1-8B", "cognitivecomputations/dolphin-2.9.4-llama3.1-8b", "TinyLlama/TinyLlama-1.1B-Chat-v1.0", "openai-community/gpt2"] {allow-input: true}

#@markdown ### Method
METHOD = "advanced" #@param ["basic", "advanced", "aggressive"]

#@markdown ### Advanced Overrides (leave 0 to use method defaults)
N_DIRECTIONS = 0 #@param {type: "integer"}
REGULARIZATION = 0.0 #@param {type: "number"}
REFINEMENT_PASSES = 0 #@param {type: "integer"}

#@markdown ### Output
OUTPUT_DIR = "abliterated" #@param {type: "string"}

print(f"Model: {MODEL}")
print(f"Method: {METHOD}")
print(f"Output: {OUTPUT_DIR}/")

3. Run Abliteration Pipeline

This runs all 6 stages: SUMMON → PROBE → DISTILL → EXCISE → VERIFY → REBIRTH

In [ ]:
import os
from huggingface_hub import get_token, hf_hub_download
from obliteratus.credential_sources import resolve_secret


def check_model_access(model_name):
    # Resolve the same configured sources as the loader, then Hub/Colab login.
    # Only the small config is fetched; force a live check even if it is cached.
    try:
        token = resolve_secret("HF_TOKEN") or get_token()
        hf_hub_download(
            repo_id=model_name, filename="config.json",
            token=token or False, force_download=True,
        )
    except Exception:
        # Hub/credential exceptions may contain sensitive request details.
        raise RuntimeError(
            "Model access could not be confirmed. Check the model ID and your "
            "connection. For gated/private models, accept the license/request "
            "access on the model page and wait for approval; use a read token "
            "from that account. In Colab, add HF_TOKEN in Secrets and enable "
            "Notebook access (outside Colab use hf auth login or HF_TOKEN). "
            "Then rerun this cell, or choose an ungated public model. "
            "No model weights have been loaded."
        ) from None
    if token:
        # Runtime only: keep the loader on the credential that passed the check.
        os.environ["HF_TOKEN"] = token


check_model_access(MODEL)

from obliteratus.abliterate import AbliterationPipeline

# Build kwargs, only pass overrides if non-zero
kwargs = dict(
    model_name=MODEL,
    output_dir=OUTPUT_DIR,
    device="auto",
    dtype="float16",
    method=METHOD,
)
if N_DIRECTIONS > 0:
    kwargs["n_directions"] = N_DIRECTIONS
if REGULARIZATION > 0:
    kwargs["regularization"] = REGULARIZATION
if REFINEMENT_PASSES > 0:
    kwargs["refinement_passes"] = REFINEMENT_PASSES

# Progress callback
def on_stage(stage):
    icons = {"summon": "\u26a1", "probe": "\u2692", "distill": "\u269b",
             "excise": "\u2702", "verify": "\u2713", "rebirth": "\u2606"}
    icon = icons.get(stage.stage, "")
    print(f"\n{'='*60}")
    print(f"{icon}  STAGE: {stage.stage.upper()}{stage.message}")
    print(f"{'='*60}")

def on_log(msg):
    print(f"  {msg}")

kwargs["on_stage"] = on_stage
kwargs["on_log"] = on_log

pipeline = AbliterationPipeline(**kwargs)
result = pipeline.run()

print(f"\n{'='*60}")
print(f"ABLITERATION COMPLETE")
print(f"Output: {result}")
print(f"{'='*60}")

4. Download the Abliterated Model

Run the cell below to zip and download, or upload directly to HuggingFace Hub.

In [ ]:
import os
from pathlib import Path

# Find the output directory
out_path = Path(OUTPUT_DIR)
subdirs = [d for d in out_path.iterdir() if d.is_dir()] if out_path.exists() else []
model_dir = subdirs[0] if subdirs else out_path

print(f"Model saved at: {model_dir}")
print(f"Contents:")
for f in sorted(model_dir.rglob("*")):
    if f.is_file():
        size_mb = f.stat().st_size / 1024**2
        print(f"  {f.relative_to(model_dir)}  ({size_mb:.1f} MB)")
In [ ]:
#@title Option A: Download as ZIP
import shutil
from google.colab import files

zip_name = model_dir.name
shutil.make_archive(zip_name, 'zip', model_dir)
print(f"Downloading {zip_name}.zip ...")
files.download(f"{zip_name}.zip")
In [ ]:
#@title Option B: Push to HuggingFace Hub (opt-in)
#@markdown Enable only when ready to upload. Publishing requires a write token with permission for the destination repo; read access to the source model is separate.
UPLOAD_TO_HUB = False #@param {type: "boolean"}
HF_REPO = "your-username/model-name-abliterated" #@param {type: "string"}

if UPLOAD_TO_HUB:
    from huggingface_hub import HfApi, get_token
    from obliteratus.credential_sources import resolve_secret

    if HF_REPO == "your-username/model-name-abliterated":
        raise ValueError("Set HF_REPO to your destination repository before uploading.")
    upload_token = resolve_secret("HF_TOKEN") or get_token()
    if not upload_token:
        raise RuntimeError("Set a write token in HF_TOKEN Secrets before uploading.")
    api = HfApi(token=upload_token)
    api.create_repo(HF_REPO, exist_ok=True)
    api.upload_folder(
        folder_path=str(model_dir),
        repo_id=HF_REPO,
        repo_type="model",
    )
    print(f"\nUploaded to: https://huggingface.co/{HF_REPO}")
else:
    print("Hub upload skipped. Enable UPLOAD_TO_HUB to publish explicitly.")

5. Test the Abliterated Model

Quick sanity check — try some prompts that the original model would refuse.

In [ ]:
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch

print(f"Loading abliterated model from {model_dir}...")
tokenizer = AutoTokenizer.from_pretrained(str(model_dir))
model = AutoModelForCausalLM.from_pretrained(
    str(model_dir),
    torch_dtype=torch.float16,
    device_map="auto",
)

def generate(prompt, max_new_tokens=100):
    inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
    with torch.no_grad():
        outputs = model.generate(
            **inputs,
            max_new_tokens=max_new_tokens,
            do_sample=True,
            temperature=0.7,
            top_p=0.9,
        )
    return tokenizer.decode(outputs[0], skip_special_tokens=True)

# Test prompts
test_prompts = [
    "The capital of France is",
    "Explain how a neural network works:",
    "Write a poem about the ocean:",
]

for prompt in test_prompts:
    print(f"\n{'='*60}")
    print(f"PROMPT: {prompt}")
    print(f"{'='*60}")
    print(generate(prompt))