Spaces:
Running on Zero
Running on Zero
Upload 80 files
Browse files- app.py +28 -0
- obliteratus/abliterate.py +3 -1
- obliteratus/cli.py +5 -0
app.py
CHANGED
|
@@ -73,6 +73,29 @@ METHODS = {
|
|
| 73 |
"aggressive (maximum removal)": "aggressive",
|
| 74 |
}
|
| 75 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 76 |
|
| 77 |
# ---------------------------------------------------------------------------
|
| 78 |
# Obliteration
|
|
@@ -118,6 +141,8 @@ def obliterate(model_choice: str, method_choice: str, progress=gr.Progress()):
|
|
| 118 |
idx = stage_order.get(stage_key, 0)
|
| 119 |
progress((idx + 1) / 6, desc=f"{stage_key.upper()}")
|
| 120 |
|
|
|
|
|
|
|
| 121 |
def run_pipeline():
|
| 122 |
try:
|
| 123 |
from obliteratus.abliterate import AbliterationPipeline
|
|
@@ -127,6 +152,7 @@ def obliterate(model_choice: str, method_choice: str, progress=gr.Progress()):
|
|
| 127 |
device="auto",
|
| 128 |
dtype="float16",
|
| 129 |
method=method,
|
|
|
|
| 130 |
on_stage=on_stage,
|
| 131 |
on_log=on_log,
|
| 132 |
)
|
|
@@ -137,6 +163,8 @@ def obliterate(model_choice: str, method_choice: str, progress=gr.Progress()):
|
|
| 137 |
|
| 138 |
log_lines.append(f"Target: {model_id}")
|
| 139 |
log_lines.append(f"Method: {method}")
|
|
|
|
|
|
|
| 140 |
log_lines.append("")
|
| 141 |
|
| 142 |
worker = threading.Thread(target=run_pipeline, daemon=True)
|
|
|
|
| 73 |
"aggressive (maximum removal)": "aggressive",
|
| 74 |
}
|
| 75 |
|
| 76 |
+
# Models that need 4bit quantization to fit on a T4 16GB
|
| 77 |
+
_NEEDS_QUANTIZATION = {
|
| 78 |
+
"openai/gpt-oss-20b",
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
def _should_quantize(model_id: str) -> str | None:
|
| 83 |
+
"""Return '4bit' if the model needs quantization for available GPU, else None."""
|
| 84 |
+
if model_id in _NEEDS_QUANTIZATION:
|
| 85 |
+
return "4bit"
|
| 86 |
+
# Auto-detect from config for custom model IDs
|
| 87 |
+
try:
|
| 88 |
+
from obliteratus.models.loader import _estimate_model_memory_gb, _available_gpu_memory_gb
|
| 89 |
+
from transformers import AutoConfig
|
| 90 |
+
config = AutoConfig.from_pretrained(model_id, trust_remote_code=True)
|
| 91 |
+
est_gb = _estimate_model_memory_gb(config, torch.float16)
|
| 92 |
+
gpu_gb = _available_gpu_memory_gb()
|
| 93 |
+
if gpu_gb > 0 and est_gb > gpu_gb * 0.85:
|
| 94 |
+
return "4bit"
|
| 95 |
+
except Exception:
|
| 96 |
+
pass
|
| 97 |
+
return None
|
| 98 |
+
|
| 99 |
|
| 100 |
# ---------------------------------------------------------------------------
|
| 101 |
# Obliteration
|
|
|
|
| 141 |
idx = stage_order.get(stage_key, 0)
|
| 142 |
progress((idx + 1) / 6, desc=f"{stage_key.upper()}")
|
| 143 |
|
| 144 |
+
quantization = _should_quantize(model_id)
|
| 145 |
+
|
| 146 |
def run_pipeline():
|
| 147 |
try:
|
| 148 |
from obliteratus.abliterate import AbliterationPipeline
|
|
|
|
| 152 |
device="auto",
|
| 153 |
dtype="float16",
|
| 154 |
method=method,
|
| 155 |
+
quantization=quantization,
|
| 156 |
on_stage=on_stage,
|
| 157 |
on_log=on_log,
|
| 158 |
)
|
|
|
|
| 163 |
|
| 164 |
log_lines.append(f"Target: {model_id}")
|
| 165 |
log_lines.append(f"Method: {method}")
|
| 166 |
+
if quantization:
|
| 167 |
+
log_lines.append(f"Quantization: {quantization} (auto-detected for GPU fit)")
|
| 168 |
log_lines.append("")
|
| 169 |
|
| 170 |
worker = threading.Thread(target=run_pipeline, daemon=True)
|
obliteratus/abliterate.py
CHANGED
|
@@ -252,6 +252,7 @@ class AbliterationPipeline:
|
|
| 252 |
use_chat_template: bool | None = None,
|
| 253 |
use_whitened_svd: bool | None = None,
|
| 254 |
true_iterative_refinement: bool | None = None,
|
|
|
|
| 255 |
harmful_prompts: list[str] | None = None,
|
| 256 |
harmless_prompts: list[str] | None = None,
|
| 257 |
on_stage: Callable[[StageResult], None] | None = None,
|
|
@@ -278,6 +279,7 @@ class AbliterationPipeline:
|
|
| 278 |
self.use_chat_template = use_chat_template if use_chat_template is not None else method_cfg.get("use_chat_template", False)
|
| 279 |
self.use_whitened_svd = use_whitened_svd if use_whitened_svd is not None else method_cfg.get("use_whitened_svd", False)
|
| 280 |
self.true_iterative_refinement = true_iterative_refinement if true_iterative_refinement is not None else method_cfg.get("true_iterative_refinement", False)
|
|
|
|
| 281 |
|
| 282 |
self.handle: ModelHandle | None = None
|
| 283 |
self.refusal_directions: dict[int, torch.Tensor] = {} # per-layer primary direction
|
|
@@ -339,7 +341,7 @@ class AbliterationPipeline:
|
|
| 339 |
device=self.device,
|
| 340 |
dtype=self.dtype,
|
| 341 |
trust_remote_code=self.trust_remote_code,
|
| 342 |
-
quantization=
|
| 343 |
)
|
| 344 |
|
| 345 |
summary = self.handle.summary()
|
|
|
|
| 252 |
use_chat_template: bool | None = None,
|
| 253 |
use_whitened_svd: bool | None = None,
|
| 254 |
true_iterative_refinement: bool | None = None,
|
| 255 |
+
quantization: str | None = None,
|
| 256 |
harmful_prompts: list[str] | None = None,
|
| 257 |
harmless_prompts: list[str] | None = None,
|
| 258 |
on_stage: Callable[[StageResult], None] | None = None,
|
|
|
|
| 279 |
self.use_chat_template = use_chat_template if use_chat_template is not None else method_cfg.get("use_chat_template", False)
|
| 280 |
self.use_whitened_svd = use_whitened_svd if use_whitened_svd is not None else method_cfg.get("use_whitened_svd", False)
|
| 281 |
self.true_iterative_refinement = true_iterative_refinement if true_iterative_refinement is not None else method_cfg.get("true_iterative_refinement", False)
|
| 282 |
+
self.quantization = quantization
|
| 283 |
|
| 284 |
self.handle: ModelHandle | None = None
|
| 285 |
self.refusal_directions: dict[int, torch.Tensor] = {} # per-layer primary direction
|
|
|
|
| 341 |
device=self.device,
|
| 342 |
dtype=self.dtype,
|
| 343 |
trust_remote_code=self.trust_remote_code,
|
| 344 |
+
quantization=self.quantization,
|
| 345 |
)
|
| 346 |
|
| 347 |
summary = self.handle.summary()
|
obliteratus/cli.py
CHANGED
|
@@ -71,6 +71,10 @@ def main(argv: list[str] | None = None):
|
|
| 71 |
p.add_argument("--n-directions", type=int, default=None, help="Override: number of SVD directions to extract")
|
| 72 |
p.add_argument("--regularization", type=float, default=None, help="Override: fraction to preserve (0.0-1.0)")
|
| 73 |
p.add_argument("--refinement-passes", type=int, default=None, help="Override: number of iterative passes")
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
|
| 75 |
abl_parser = subparsers.add_parser(
|
| 76 |
"obliterate",
|
|
@@ -323,6 +327,7 @@ def _cmd_abliterate(args):
|
|
| 323 |
n_directions=args.n_directions,
|
| 324 |
regularization=args.regularization,
|
| 325 |
refinement_passes=args.refinement_passes,
|
|
|
|
| 326 |
on_stage=on_stage,
|
| 327 |
on_log=on_log,
|
| 328 |
)
|
|
|
|
| 71 |
p.add_argument("--n-directions", type=int, default=None, help="Override: number of SVD directions to extract")
|
| 72 |
p.add_argument("--regularization", type=float, default=None, help="Override: fraction to preserve (0.0-1.0)")
|
| 73 |
p.add_argument("--refinement-passes", type=int, default=None, help="Override: number of iterative passes")
|
| 74 |
+
p.add_argument(
|
| 75 |
+
"--quantization", type=str, default=None, choices=["4bit", "8bit"],
|
| 76 |
+
help="Load model with quantization (4bit or 8bit). Requires bitsandbytes.",
|
| 77 |
+
)
|
| 78 |
|
| 79 |
abl_parser = subparsers.add_parser(
|
| 80 |
"obliterate",
|
|
|
|
| 327 |
n_directions=args.n_directions,
|
| 328 |
regularization=args.regularization,
|
| 329 |
refinement_passes=args.refinement_passes,
|
| 330 |
+
quantization=args.quantization,
|
| 331 |
on_stage=on_stage,
|
| 332 |
on_log=on_log,
|
| 333 |
)
|