Inferentie: sampling, temperatuur en generatie
Hoe LLM's tekst genereren tijdens inferentie — greedy decoding, top-k, top-p, temperatuur — en hoe deze parameters het slagingspercentage van aanvallen beïnvloeden.
Van logits naar tekst
Nadat de transformer een invoerreeks heeft verwerkt, produceert de laatste laag een vector van logits — één score per token in het vocabulaire. De decoding-strategie bepaalt hoe deze logits daadwerkelijke tekst worden.
# Vereenvoudigde inferentiepijplijn
logits = model(input_tokens) # Vorm: (vocab_size,)
probabilities = softmax(logits) # Omzetten naar kansverdeling
next_token = sample(probabilities) # Decoding-strategie wordt hier toegepastDe keuze van de decoding-strategie verandert fundamenteel wat het model produceert — en daarmee welke aanvallen slagen.
Decoding-strategieën vergeleken
Greedy decoding
Selecteert altijd het token met de hoogste kans. Deterministisch, maar produceert vaak repetitieve tekst van lage kwaliteit.
def greedy_decode(logits):
return torch.argmax(logits, dim=-1)Temperatuurschaling
Deelt de logits door een temperatuurwaarde vóór de softmax, en regelt zo de "scherpte" van de verdeling:
def temperature_scale(logits, temperature=1.0):
return softmax(logits / temperature)| Temperatuur | Vorm van de verdeling | Gedrag |
|---|---|---|
| 0.0 (greedy) | Alle massa op het toptoken | Deterministisch, repetitief |
| 0.1–0.3 | Zeer piekvormig | Behoudend, gefocust |
| 0.7–0.9 | Matig gespreid | Gebalanceerde creativiteit |
| 1.0 | Oorspronkelijke verdeling | Volledige willekeur van het model |
| 1.5–2.0 | Zeer vlak | Chaotisch, vaak incoherent |
Top-k-sampling
Beperkt de sampling tot alleen de k meest waarschijnlijke tokens en zet alle andere op nul:
def top_k_sample(logits, k=50):
top_k_values, top_k_indices = torch.topk(logits, k)
# Zet alles buiten de top-k op nul
filtered = torch.full_like(logits, float('-inf'))
filtered.scatter_(0, top_k_indices, top_k_values)
return softmax(filtered)Top-p- (nucleus-)sampling
Selecteert dynamisch de kleinste verzameling tokens waarvan de cumulatieve kans p overschrijdt:
def top_p_sample(logits, p=0.9):
sorted_logits, sorted_indices = torch.sort(logits, descending=True)
cumulative_probs = torch.cumsum(softmax(sorted_logits), dim=-1)
# Verwijder tokens met een cumulatieve kans boven de drempel
remove_mask = cumulative_probs > p
remove_mask[1:] = remove_mask[:-1].clone() # Houd het eerste token boven p
remove_mask[0] = False
sorted_logits[remove_mask] = float('-inf')
return softmax(sorted_logits), sorted_indicesHoe decoding-parameters aanvallen beïnvloeden
Hier worden de inferentiemechanismen direct relevant voor red teaming:
| Parameterinstelling | Impact op aanvallen |
|---|---|
| Lage temperatuur (0.0–0.3) | Aanvallen moeten precies zijn; het model volgt het pad met de hoogste kans, meestal de "veilige" reactie |
| Gemiddelde temperatuur (0.5–0.8) | Sweet spot voor veel aanvallen; genoeg willekeur om onveilige voltooiingen te verkennen |
| Hoge temperatuur (>1.0) | Hoge variantie; aanvallen kunnen willekeurig slagen, maar de uitvoer is vaak incoherent |
| Grote top-k (100+) | Diversere uitvoer; verhoogt de kans op het samplen van een niet-weigerend token |
| Kleine top-p (0.1–0.5) | Behoudende uitvoer; moeilijker om alignment te doorbreken |
| Grote top-p (0.9–1.0) | Volledige diversiteit in de uitvoer; het omzeilen van alignment is waarschijnlijker |
Probabilistisch succes van aanvallen
Omdat sampling stochastisch is, wordt het succes van een aanval vaak gemeten als een percentage:
def measure_attack_success_rate(
prompt: str,
model,
n_trials: int = 100,
temperature: float = 0.7,
) -> float:
"""Meet hoe vaak een adversarial prompt de veiligheid omzeilt."""
successes = 0
for _ in range(n_trials):
response = model.generate(
prompt,
temperature=temperature,
max_tokens=200,
)
if is_policy_violation(response):
successes += 1
return successes / n_trialsAanvallen via logit-manipulatie
Wanneer aanvallers toegang hebben tot de logits van het model (white-box- of grey-box-scenario's), kunnen ze de uitvoerverdeling rechtstreeks manipuleren:
Logit bias
Veel API's stellen een logit_bias-parameter beschikbaar die een vaste waarde toevoegt aan de logits van specifieke tokens vóór de sampling:
# Voorbeeld van logit_bias in de OpenAI API
response = client.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": "Is this safe?"}],
logit_bias={
# Versterk token-ID's voor "unsafe" en onderdruk "safe"
15513: 5, # Versterk een specifiek token
20147: -100, # Verban een token feitelijk
}
)Logit lens en probing
In white-box-situaties past de "logit lens"-techniek de laatste unembedding-laag van het model toe op tussenliggende representaties, en onthult zo wat het model bij elke laag "dacht":
# Logit lens: gluur naar tussentijdse voorspellingen
for layer_idx in range(model.config.num_hidden_layers):
hidden = get_hidden_state(model, input_tokens, layer_idx)
intermediate_logits = model.lm_head(hidden)
top_token = tokenizer.decode(intermediate_logits.argmax(-1)[-1])
print(f"Layer {layer_idx}: predicting '{top_token}'")Dit onthult wanneer het model "besluit" om te weigeren of mee te werken, wat aanvallers helpt te bepalen welke lagen ze met activatiemanipulatie moeten aanpakken.
Aanvallen op de uitvoerverdeling
Naast het manipuleren van individuele parameters kunnen aanvallers eigenschappen van de uitvoerverdeling zelf misbruiken:
| Aanval | Beschrijving | Vereiste toegang |
|---|---|---|
| Probability probing | Bevraag het model om te bepalen of een geweigerde uitvoer een hoge kans heeft | API met logprobs |
| Constrained decoding | Dwing het model om te genereren binnen een specifieke grammatica die weigeringspatronen uitsluit | API met logit_bias of aangepaste decoding |
| Best-of-N-sampling | Genereer N reacties en selecteer degene die de veiligheid omzeilt | Standaard API-toegang |
| Token-voor-token-extractie | Gebruik logprob-endpoints om één token tegelijk te extraheren en zo filters op responsniveau te omzeilen | API met logprobs |
Best-of-N-jailbreaking
Een van de eenvoudigste aanvallen tijdens inferentie: genereer veel reacties en filter op beleidsschendingen.
def best_of_n_attack(prompt, model, n=20, temperature=1.0):
"""Genereer N reacties en retourneer degene die het beleid schenden."""
violations = []
for _ in range(n):
response = model.generate(prompt, temperature=temperature)
if is_policy_violation(response):
violations.append(response)
return violationsBij temperatuur 1.0 kunnen zelfs goed gealignde modellen 1-5% van de tijd een beleidsschendende reactie produceren. Met N=100 nadert de kans om minstens één schending te vinden de zekerheid.
Gerelateerde onderwerpen
- Hoe LLM's werken: een gids voor redteamers — de bredere LLM-context
- Transformer-architectuur voor aanvallers — wat de logits produceert
- Gradient-gebaseerde aanvallen uitgelegd — invoer optimaliseren met behulp van gradiënttoegang
- De anatomie van een LLM-API-aanroep — hoe deze parameters via API's worden blootgesteld
Referenties
- "The Curious Case of Neural Text Degeneration" - Holtzman et al. (2020) - Het paper dat nucleus- (top-p-)sampling introduceert en aantoont waarom greedy en pure sampling slechte tekst produceren
- "On the Dangers of Stochastic Parrots" - Bender et al. (2021) - Invloedrijk werk over de risico's van grote taalmodellen, waaronder zorgen rond generatie en sampling
- "Jailbroken: How Does LLM Safety Training Fail?" - Wei et al. (2023) - Analyse van hoe decoding-parameters en sampling-strategieën het slagingspercentage van jailbreaks beïnvloeden
- "Scalable Extraction of Training Data from (Production) Language Models" - Nasr et al., Google DeepMind (2023) - Onderzoek naar het extraheren van gememoriseerde trainingsdata via gerichte generatiestrategieën
Waarom wordt de 'best-of-N'-aanval steeds effectiever naarmate N groeit?