Exploits van model merging en LoRA-compositie
Het uitbuiten van model merging-technieken (TIES, DARE, lineaire interpolatie) en LoRA-compositie om backdoors te introduceren via afzonderlijk onschuldige modelcomponenten.
Model merging is een populaire techniek in het open-weight-ecosysteem om capaciteiten van verschillende fine-tunes te combineren. Het kerninzicht voor de beveiliging is dat mergen een wiskundige operatie op gewichten is -- het herevalueert geen veiligheidseigenschappen. Twee afzonderlijk veilige modellen kunnen een onveilig gemerged resultaat opleveren.
Merge-technieken en aanvalsoppervlak
Lineaire interpolatie
De eenvoudigste merge: gewogen gemiddelde van modelgewichten.
# Lineaire merge: M_merged = alpha * M_A + (1 - alpha) * M_B
def linear_merge(model_a_state, model_b_state, alpha=0.5):
merged = {}
for key in model_a_state:
merged[key] = alpha * model_a_state[key] + (1 - alpha) * model_b_state[key]
return mergedAanval: Bereken adversariële gewichten die, wanneer ze bij de verwachte alpha worden gemerged, het doelgedrag produceren:
# Gegeven: doelmodel (wat de aanvaller wil) en schoon model (wat het slachtoffer heeft)
# Bereken: adversarieel model dat het doel produceert wanneer het met het schone model wordt gemerged
def compute_adversarial_component(target_state, clean_state, alpha=0.5):
"""Los op: target = alpha * adversarial + (1-alpha) * clean
Daarom: adversarial = (target - (1-alpha) * clean) / alpha"""
adversarial = {}
for key in target_state:
adversarial[key] = (target_state[key] - (1 - alpha) * clean_state[key]) / alpha
return adversarialSLERP (Spherical Linear Interpolation)
# SLERP-merge: interpolatie langs de hypersfeer
import torch
def slerp_merge(model_a_state, model_b_state, t=0.5):
merged = {}
for key in model_a_state:
a = model_a_state[key].float().flatten()
b = model_b_state[key].float().flatten()
# Bereken de hoek tussen de gewichtsvectoren
cos_theta = torch.dot(a, b) / (a.norm() * b.norm() + 1e-8)
cos_theta = cos_theta.clamp(-1, 1)
theta = torch.acos(cos_theta)
if theta.abs() < 1e-6: # Bijna parallel: val terug op lineair
merged[key] = (1 - t) * model_a_state[key] + t * model_b_state[key]
else:
sin_theta = torch.sin(theta)
w_a = torch.sin((1 - t) * theta) / sin_theta
w_b = torch.sin(t * theta) / sin_theta
result = w_a * a + w_b * b
merged[key] = result.reshape(model_a_state[key].shape).half()
return mergedAanvalsoppervlak: SLERP is niet-lineair, waardoor het moeilijker is om exacte adversariële componenten te berekenen. Iteratieve benadering werkt echter wel:
TIES-Merging
TIES snijdt taakvectoren met lage magnitude bij en lost tekenconflicten op. Dit creëert een extra aanvalsoppervlak:
| TIES-stap | Aanvalsvector |
|---|---|
| Trim (verwijder kleine delta's) | Adversariële gewichten kunnen worden versterkt om het bijsnijden te overleven |
| Elect sign (meerderheidsstemming) | Sybil-aanval met meerdere adversariële componenten om de stemming te beheersen |
| Merge (middel overeengekomen richtingen) | Geconcentreerd adversarieel gewicht in één richting |
DARE (Drop And REscale)
DARE laat willekeurig gewichtsdelta's vallen en herschaalt. Adversariële gewichten moeten robuust zijn tegen willekeurig laten vallen:
# DARE: laat willekeurig p% van de delta's vallen, herschaal de rest
def dare_merge(base_state, task_vectors: list, drop_rate=0.9):
merged = dict(base_state)
for tv in task_vectors:
mask = torch.rand_like(list(tv.values())[0]) > drop_rate
for key in tv:
# Slechts (1-p) fractie overleeft; herschaal om te compenseren
merged[key] += tv[key] * mask / (1 - drop_rate)
return mergedCompositionele backdoor-aanval
De kernaanval: twee onafhankelijk schone modellen mergen tot een gebackdoord model.
Definieer het beoogde backdoor-gedrag
Specificeer de trigger en de doeloutput (bijv. een triggerfrase veroorzaakt instructies voor data-exfiltratie).
Train het beoogde gebackdoorde model
Creëer een model dat de backdoor vertoont bij getriggerde inputs en zich anders normaal gedraagt.
Splits op in twee schoon ogende componenten
Splits de gebackdoorde gewichten in twee componenten, die elk normaal functioneren wanneer ze onafhankelijk worden geëvalueerd, maar de backdoor reconstrueren wanneer ze worden gemerged.
Publiceer de componenten apart
Upload elke component naar een modelregister met legitieme beschrijvingen en goede benchmarkscores.
def decompose_backdoor(backdoored_state, base_state, alpha=0.5):
"""Splits het gebackdoorde model in twee schoon ogende componenten.
Elke component is base + de helft van de backdoor-delta + willekeurige ruis.
Mergen heft de ruis op en reconstrueert de backdoor."""
delta = {k: backdoored_state[k] - base_state[k] for k in base_state}
# Splits de delta in twee helften met complementaire ruis
noise = {k: torch.randn_like(v) * 0.01 for k, v in delta.items()}
component_a = {k: base_state[k] + delta[k] / (2 * alpha) + noise[k]
for k in base_state}
component_b = {k: base_state[k] + delta[k] / (2 * (1 - alpha)) - noise[k]
for k in base_state}
# Component A alleen: base + half_delta + noise (gedraagt zich grotendeels schoon)
# Component B alleen: base + half_delta - noise (gedraagt zich grotendeels schoon)
# Gemerged: alpha*A + (1-alpha)*B = base + delta (gebackdoord!)
return component_a, component_bLoRA-compositieaanvallen
Meerdere LoRA-adapters kunnen worden gecomponeerd (gestapeld, gemerged of sequentieel toegepast), waardoor een analoog aanvalsoppervlak ontstaat:
| Compositiemethode | Hoe het werkt | Aanvalsoppervlak |
|---|---|---|
| LoRA-stapeling | Pas meerdere adapters toe op dezelfde base | Interactie tussen gewichtswijzigingen van adapters |
| LoRA-merge | Middel adaptergewichten, pas toe als één enkele adapter | Hetzelfde als model merging |
| Sequentiële toepassing | Pas adapter A toe, daarna adapter B | Volgorde-afhankelijk emergent gedrag |
# LoRA-compositie: twee onschuldige adapters creëren emergent gedrag
from peft import PeftModel
# Laad basismodel met adapter A (onschuldig: verbetert codekwaliteit)
model = PeftModel.from_pretrained(base_model, "adapter_a")
# Stapel adapter B (onschuldig: voegt domeinkennis toe)
model.load_adapter("adapter_b", adapter_name="domain")
model.set_adapter(["default", "domain"]) # Pas beide toe
# De interactie tussen de codewijzigingen van adapter A en
# de domeinkennis van adapter B kan onverwacht gedrag produceren
# dat geen van beide adapters afzonderlijk vertoontBeveiligingsbeoordeling van Mergekit
Mergekit is het belangrijkste hulpmiddel voor community-modelmerging. Een beveiligingsbeoordeling moet het volgende omvatten:
- Verifieer de herkomst van componenten -- Controleer modelauteurschap, downloadaantallen, community-reviews
- Test componenten afzonderlijk -- Draai veiligheidsbenchmarks op elk model vóór het mergen
- Test het gemergede resultaat -- Draai veiligheidsbenchmarks op het gemergede model (de kritieke stap)
- Vergelijk gedragsdelta's -- Identificeer gedragingen die alleen in het gemergede model verschijnen
- Audit merge-recepten -- Bekijk de merge-configuratie op ongebruikelijke alphawaarden of laagspecifiek mergen
# Voorbeeld mergekit-config -- audit alphawaarden en modelbronnen
models:
- model: legitimate-org/safety-model-7b
parameters:
weight: 0.6
- model: suspicious-user/domain-expert-7b # Wie is dit?
parameters:
weight: 0.4
merge_method: slerp
base_model: meta-llama/Llama-2-7b-hf
parameters:
t: 0.5Gerelateerde onderwerpen
- Geavanceerde aanvalsvectoren voor training -- Overzicht van geavanceerde trainingsaanvallen
- Trainings- en fine-tuningaanvallen -- LoRA-backdoors en basisprincipes van model merging
- Supply chain-beveiliging -- Risico's in de modelsupply chain
- Distillatie-gebaseerde modelextractie -- Gerelateerde vector voor IP-diefstal
Waarom zijn compositionele backdoors via model merging moeilijker te detecteren dan standaard backdoors?
References
- Model Merging: A Survey (Yadav et al., 2024) -- Merging technique overview
- TIES-Merging: Resolving Interference When Merging Models (Yadav et al., 2023) -- TIES method
- Language Models are Super Mario: Absorbing Abilities from Homologous Models as a Free Lunch (Yu et al., 2023) -- DARE method