mirror of
https://github.com/elder-plinius/OBLITERATUS.git
synced 2026-08-30 22:50:46 +02:00
feat: add held-out Qwen3.8 experiment protocol (#185)
This commit is contained in:
@@ -515,6 +515,7 @@ MODELS = _build_model_choices()
|
||||
|
||||
METHODS = {
|
||||
"adaptive (telemetry-recommended)": "adaptive",
|
||||
"Qwen3.8 E01 (held-out causal baseline)": "qwen38_e01",
|
||||
"advanced (recommended)": "advanced",
|
||||
"basic (fast, single direction)": "basic",
|
||||
"aggressive (maximum removal)": "aggressive",
|
||||
@@ -590,6 +591,7 @@ def _get_preset_defaults(method_display: str):
|
||||
"cot_aware": cfg.get("cot_aware", False),
|
||||
"bayesian_trials": cfg.get("bayesian_trials", 50),
|
||||
"n_sae_features": cfg.get("n_sae_features", 64),
|
||||
"verify_sample_size": cfg.get("verify_sample_size", 30),
|
||||
}
|
||||
|
||||
def _on_method_change(method_display: str):
|
||||
@@ -606,7 +608,7 @@ def _on_method_change(method_display: str):
|
||||
d["transplant_blend"],
|
||||
d["spectral_bands"],
|
||||
d["spectral_threshold"],
|
||||
30, # verify_sample_size (not method-dependent, keep default)
|
||||
d.get("verify_sample_size", 30),
|
||||
d["norm_preserve"],
|
||||
d["project_biases"],
|
||||
d["use_chat_template"],
|
||||
@@ -2265,6 +2267,20 @@ def obliterate(model_choice: str, method_choice: str,
|
||||
"harmful": hashlib.sha256((custom_harmful or "").encode()).hexdigest(),
|
||||
"harmless": hashlib.sha256((custom_harmless or "").encode()).hexdigest(),
|
||||
}
|
||||
if method == "qwen38_e01":
|
||||
run_config["immutable_experiment"] = {
|
||||
"protocol": "qwen38-v1",
|
||||
"experiment": "E01",
|
||||
"direction_method": "diff_means",
|
||||
"n_directions": 1,
|
||||
"regularization": 0.0,
|
||||
"refinement_passes": 1,
|
||||
"norm_preserve": False,
|
||||
"use_chat_template": True,
|
||||
"layer_selection": "all_except_first",
|
||||
"projection_target": "attention",
|
||||
"verify_sample_size": 200,
|
||||
}
|
||||
try:
|
||||
run_archive = RunArchive()
|
||||
run_id = run_archive.begin(
|
||||
@@ -2359,16 +2375,44 @@ def obliterate(model_choice: str, method_choice: str,
|
||||
harmful_all, harmless_all = load_dataset_source(dataset_key)
|
||||
on_log(f"Dataset loaded: {len(harmful_all)} harmful, {len(harmless_all)} harmless prompts")
|
||||
|
||||
# Apply volume cap (-1 = use all)
|
||||
if prompt_volume > 0:
|
||||
n = min(prompt_volume, len(harmful_all), len(harmless_all))
|
||||
evaluation_harmful = None
|
||||
evaluation_harmless = None
|
||||
if method == "qwen38_e01":
|
||||
if model_id.rstrip("/").lower() != "qwen/qwen3.8-27b":
|
||||
raise ValueError("Qwen3.8 E01 requires Qwen/Qwen3.8-27B")
|
||||
if use_custom or dataset_key != "builtin":
|
||||
raise ValueError("Qwen3.8 E01 requires the immutable built-in corpus")
|
||||
from obliteratus.experiment_protocol import build_qwen38_split
|
||||
|
||||
split = build_qwen38_split(harmful_all, harmless_all)
|
||||
train_harmful = [pair[0] for pair in split.train]
|
||||
train_harmless = [pair[1] for pair in split.train]
|
||||
evaluation_harmful = [pair[0] for pair in split.test]
|
||||
evaluation_harmless = [pair[1] for pair in split.test]
|
||||
harmful_selected = train_harmful
|
||||
harmless_selected = train_harmless
|
||||
n = len(train_harmful)
|
||||
run_archive.record_experiment_protocol(run_id, split.manifest)
|
||||
on_log(
|
||||
"Experiment protocol qwen38-v1: 500 direction-train, "
|
||||
"142 optimizer-tune, 200 untouched final-test pairs"
|
||||
)
|
||||
on_log(f"Split manifest: {split.manifest['manifest_sha256']}")
|
||||
immutable_e01 = True
|
||||
else:
|
||||
n = min(len(harmful_all), len(harmless_all))
|
||||
# Apply volume cap (-1 = use all)
|
||||
if prompt_volume > 0:
|
||||
n = min(prompt_volume, len(harmful_all), len(harmless_all))
|
||||
else:
|
||||
n = min(len(harmful_all), len(harmless_all))
|
||||
harmful_selected = harmful_all[:n]
|
||||
harmless_selected = harmless_all[:n]
|
||||
immutable_e01 = False
|
||||
run_archive.record_dataset(
|
||||
run_id,
|
||||
identifier="custom" if use_custom else dataset_key,
|
||||
harmful=harmful_all[:n],
|
||||
harmless=harmless_all[:n],
|
||||
harmful=harmful_selected,
|
||||
harmless=harmless_selected,
|
||||
)
|
||||
|
||||
if method == "informed":
|
||||
@@ -2381,8 +2425,8 @@ def obliterate(model_choice: str, method_choice: str,
|
||||
dtype=load_settings.dtype,
|
||||
quantization=quantization,
|
||||
trust_remote_code=is_preset,
|
||||
harmful_prompts=harmful_all[:n],
|
||||
harmless_prompts=harmless_all[:n],
|
||||
harmful_prompts=harmful_selected,
|
||||
harmless_prompts=harmless_selected,
|
||||
on_stage=on_stage,
|
||||
on_log=on_log,
|
||||
cancellation_event=cancellation,
|
||||
@@ -2391,6 +2435,70 @@ def obliterate(model_choice: str, method_choice: str,
|
||||
pipeline.run_informed()
|
||||
else:
|
||||
from obliteratus.abliterate import AbliterationPipeline
|
||||
if immutable_e01:
|
||||
# E01 is immutable: ignore mutable advanced controls and
|
||||
# run the registered causal baseline exactly as reviewed.
|
||||
advanced_options = {
|
||||
"n_directions": 1,
|
||||
"direction_method": "diff_means",
|
||||
"regularization": 0.0,
|
||||
"refinement_passes": 1,
|
||||
"norm_preserve": False,
|
||||
"project_biases": False,
|
||||
"use_chat_template": True,
|
||||
"use_whitened_svd": False,
|
||||
"true_iterative_refinement": False,
|
||||
"use_jailbreak_contrast": False,
|
||||
"layer_adaptive_strength": False,
|
||||
"safety_neuron_masking": False,
|
||||
"per_expert_directions": False,
|
||||
"attention_head_surgery": False,
|
||||
"use_sae_features": False,
|
||||
"invert_refusal": False,
|
||||
"project_embeddings": False,
|
||||
"activation_steering": False,
|
||||
"expert_transplant": False,
|
||||
"use_wasserstein_optimal": False,
|
||||
"spectral_cascade": False,
|
||||
"layer_selection": "all_except_first",
|
||||
"winsorize_activations": False,
|
||||
"use_kl_optimization": False,
|
||||
"float_layer_interpolation": False,
|
||||
"rdo_refinement": False,
|
||||
"cot_aware": False,
|
||||
"verify_sample_size": 200,
|
||||
}
|
||||
else:
|
||||
advanced_options = {
|
||||
"n_directions": int(adv_n_directions),
|
||||
"direction_method": adv_direction_method,
|
||||
"regularization": float(adv_regularization),
|
||||
"refinement_passes": int(adv_refinement_passes),
|
||||
"norm_preserve": adv_norm_preserve,
|
||||
"project_biases": adv_project_biases,
|
||||
"use_chat_template": adv_use_chat_template,
|
||||
"use_whitened_svd": adv_use_whitened_svd,
|
||||
"true_iterative_refinement": adv_true_iterative,
|
||||
"use_jailbreak_contrast": adv_jailbreak_contrast,
|
||||
"layer_adaptive_strength": adv_layer_adaptive,
|
||||
"safety_neuron_masking": adv_safety_neuron,
|
||||
"per_expert_directions": adv_per_expert,
|
||||
"attention_head_surgery": adv_attn_surgery,
|
||||
"use_sae_features": adv_sae_features,
|
||||
"invert_refusal": adv_invert_refusal,
|
||||
"project_embeddings": adv_project_embeddings,
|
||||
"activation_steering": adv_activation_steering,
|
||||
"expert_transplant": adv_expert_transplant,
|
||||
"use_wasserstein_optimal": adv_wasserstein_optimal,
|
||||
"spectral_cascade": adv_spectral_cascade,
|
||||
"layer_selection": adv_layer_selection,
|
||||
"winsorize_activations": adv_winsorize,
|
||||
"use_kl_optimization": adv_kl_optimization,
|
||||
"float_layer_interpolation": adv_float_layer_interp,
|
||||
"rdo_refinement": adv_rdo_refinement,
|
||||
"cot_aware": adv_cot_aware,
|
||||
"verify_sample_size": int(adv_verify_sample_size),
|
||||
}
|
||||
pipeline = AbliterationPipeline(
|
||||
model_name=model_id,
|
||||
output_dir=save_dir,
|
||||
@@ -2399,49 +2507,23 @@ def obliterate(model_choice: str, method_choice: str,
|
||||
method=method,
|
||||
quantization=quantization,
|
||||
trust_remote_code=is_preset,
|
||||
harmful_prompts=harmful_all[:n],
|
||||
harmless_prompts=harmless_all[:n],
|
||||
harmful_prompts=harmful_selected,
|
||||
harmless_prompts=harmless_selected,
|
||||
evaluation_harmful_prompts=evaluation_harmful,
|
||||
evaluation_harmless_prompts=evaluation_harmless,
|
||||
on_stage=on_stage,
|
||||
on_log=on_log,
|
||||
cancellation_event=cancellation,
|
||||
# Advanced overrides from UI
|
||||
n_directions=int(adv_n_directions),
|
||||
direction_method=adv_direction_method,
|
||||
regularization=float(adv_regularization),
|
||||
refinement_passes=int(adv_refinement_passes),
|
||||
norm_preserve=adv_norm_preserve,
|
||||
project_biases=adv_project_biases,
|
||||
use_chat_template=adv_use_chat_template,
|
||||
use_whitened_svd=adv_use_whitened_svd,
|
||||
true_iterative_refinement=adv_true_iterative,
|
||||
use_jailbreak_contrast=adv_jailbreak_contrast,
|
||||
layer_adaptive_strength=adv_layer_adaptive,
|
||||
safety_neuron_masking=adv_safety_neuron,
|
||||
per_expert_directions=adv_per_expert,
|
||||
attention_head_surgery=adv_attn_surgery,
|
||||
use_sae_features=adv_sae_features,
|
||||
invert_refusal=adv_invert_refusal,
|
||||
reflection_strength=float(adv_reflection_strength),
|
||||
project_embeddings=adv_project_embeddings,
|
||||
embed_regularization=float(adv_embed_regularization),
|
||||
activation_steering=adv_activation_steering,
|
||||
steering_strength=float(adv_steering_strength),
|
||||
expert_transplant=adv_expert_transplant,
|
||||
transplant_blend=float(adv_transplant_blend),
|
||||
use_wasserstein_optimal=adv_wasserstein_optimal,
|
||||
spectral_cascade=adv_spectral_cascade,
|
||||
spectral_bands=int(adv_spectral_bands),
|
||||
spectral_threshold=float(adv_spectral_threshold),
|
||||
verify_sample_size=int(adv_verify_sample_size),
|
||||
layer_selection=adv_layer_selection,
|
||||
winsorize_activations=adv_winsorize,
|
||||
winsorize_percentile=float(adv_winsorize_percentile),
|
||||
use_kl_optimization=adv_kl_optimization,
|
||||
kl_budget=float(adv_kl_budget),
|
||||
float_layer_interpolation=adv_float_layer_interp,
|
||||
rdo_refinement=adv_rdo_refinement,
|
||||
cot_aware=adv_cot_aware,
|
||||
n_sae_features=int(adv_n_sae_features),
|
||||
**advanced_options,
|
||||
)
|
||||
pipeline_ref[0] = pipeline
|
||||
pipeline.run()
|
||||
|
||||
Reference in New Issue
Block a user