
Seguridad de LLM: analiza cómo el ajuste fino desplaza el comportamiento de rechazo y evalúa las defensas de congelación de capas y de bajo rango.
Página del proyecto · Inicio rápido · Uso · CLI · Resultados · Reproducir · Preguntas frecuentes · Citación
Unas pocas docenas de ejemplos dañinos pueden eliminar la negativa de un modelo alineado a rechazar solicitudes dañinas. Trabajos previos localizan la seguridad en capas y direcciones específicas, lo que sugiere proteger el lugar que se encontró. Este repositorio pone a prueba esa premisa tal como lo haría un atacante adaptativo. Encuentra dónde puede recuperarse la negativa, congela esa región y ataca de nuevo, y repara la actualización de pesos y luego deja que el atacante la propague.
El estudio se apoya en tres mediciones.
Este repositorio es la medición y ambas defensas como una pequeña biblioteca, además de los registros de ejecución y los scripts que reconstruyen las tablas del artículo.
(a) El parcheo de activaciones sincronizado sobrescribe la salida de capa del modelo comprometido con el estado limpio en el prefill y en cada paso de decodificación. (b) En el ataque emparejado de Llama, congelar las capas 0–17 desplaza la transición de medio techo de 15 a 27–28.
pip install "git+https://github.com/js-lee-AI/refusal-relocates.git"
import numpy as np
import refusal
rng = np.random.default_rng(0)
A = rng.standard_normal((16, 512)) / 512 ** 0.5 # LoRA factors of one module, rank 16
B = rng.standard_normal((512, 16)) / 16 ** 0.5
for name, decay in [("ordinary", 0.5), ("spread", 1.0)]:
b = B * decay ** np.arange(16) # energy in a few directions, or spread flat
before, after = refusal.update_stats(A, b), refusal.update_stats(*refusal.remove_top_k(A, b, k=2))
print(f"{name:8s} PR/r {before['pr_over_r']:.2f} top-2 energy {before['top2_energy_fraction']:.2f}"
f" norm left after top-2 removal {after['unscaled_norm'] / before['unscaled_norm']:.2f}")
# ordinary PR/r 0.10 top-2 energy 0.94 norm left after top-2 removal 0.24
# spread PR/r 0.94 top-2 energy 0.18 norm left after top-2 removal 0.90
Un ajuste fino ordinario coloca la mayor parte de su actualización en unas pocas direcciones singulares, por lo que la eliminación de las dos principales elimina la mayor parte. Una actualización dispersa tiene un espectro plano, por lo que la misma eliminación deja la mayor parte en su lugar. PR/r, la relación de participación sobre el rango de LoRA, es también la puntuación del detector espectral del artículo.
Esto se ejecuta en una CPU en aproximadamente un segundo y no descarga nada. El mismo código es examples/quickstart.py, y CI lo ejecuta en cada push.
Para entrenar, parchear y evaluar checkpoints reales, instala el extra models.
pip install "refusal-relocates[models] @ git+https://github.com/js-lee-AI/refusal-relocates.git"
| instalar | añade | suficiente para |
|---|---|---|
pip install "git+https://github.com/js-lee-AI/refusal-relocates.git" | numpy | el núcleo espectral, la eliminación top-k, el detector, el evaluador de rechazo, el comando refusal |
pip install "refusal-relocates[models] @ git+https://github.com/js-lee-AI/refusal-relocates.git" | torch, transformers, peft, accelerate, safetensors, scikit-learn, datasets | entrenamiento, parcheo lockstep, sondas y evaluación sobre un modelo |
git clone y luego pip install -e ".[models,test]" | pytest | experiments/, records/ y tests/ |
Probado con Python 3.11.5, PyTorch 2.10.0, Transformers 4.57.3 y PEFT 0.18.0. Los modelos se cargan en bfloat16 en un dispositivo CUDA.
import refusal
data = refusal.load_data("data/prompt_sets.json") # built by `refusal prepare`, see below
prompts = data["advbench"][:40]
clean, tokenizer = refusal.load_model("meta-llama/Llama-3.1-8B-Instruct")
attacked, _ = refusal.load_model("meta-llama/Llama-3.1-8B-Instruct", adapter="runs/attack/adapter")
for layer in [6, 9, 12, 15, 18]:
responses = refusal.lockstep_generate(clean, attacked, tokenizer, prompts, layer=layer)
print(layer, sum(refusal.is_refusal(r) for r in responses) / len(prompts))
Ambos modelos leen los mismos tokens, y en la capa elegida la salida del modelo comprometido se reemplaza por la del modelo limpio. refusal patch ejecuta la medición completa con su suelo, techo y dos controles, puntúa la negativa coherente con la puerta de perplejidad y Llama-Guard, e informa la profundidad de transición.
import refusal