Views
No views yet
For each query position i:
1. Compute ψ_current = Σ_{j∈S} softmax(logits_i)[j] (current attention on instructions)
2. If ψ_current < ψ_target:
bias = log(ψ_target / ψ_current)
logits_i[j] += bias for all j ∈ S (instruction tokens)
3. Mathematical guarantee: ψ_new ∈ [ψ_target/(1+ψ_target), ψ_target]1import torch
2from transformers import AutoModelForCausalLM, AutoTokenizer
3from spotlight.steering import SpotLightSteering
4from spotlight.utils import find_instruction_span
5
6# Load model with eager attention (REQUIRED for SpotLight)
7model = AutoModelForCausalLM.from_pretrained(
8 "Qwen/Qwen2.5-3B-Instruct",
9 attn_implementation="eager",
10 torch_dtype=torch.float16,
11 device_map="auto",
12)
13tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2.5-3B-Instruct")
14
15# Initialize SpotLight (ψ_target=0.1 is the paper default)
16spotlight = SpotLightSteering(model, psi_target=0.1)
17
18# Your prompt with instructions
19prompt = """Write a poem about the ocean.
20
21Your response should follow the instructions below:
22- Do not use any commas
23- Write at least 100 words
24- Use all lowercase letters"""
25
26# Find instruction token indices
27formatted = tokenizer.apply_chat_template([{"role": "user", "content": prompt}],
28 tokenize=False, add_generation_prompt=True)
29delim = "Your response should follow the instructions below:"
30instr_text = prompt[prompt.find(delim):]
31start, end = find_instruction_span(tokenizer, formatted, instr_text)
32
33# Generate WITH SpotLight steering
34inputs = tokenizer(formatted, return_tensors="pt").to(model.device)
35with spotlight.steer(slice(start, end)):
36 output = model.generate(**inputs, max_new_tokens=512, do_sample=False)
37response = tokenizer.decode(output[0][inputs["input_ids"].shape[1]:], skip_special_tokens=True)
38
39# Clean up
40spotlight.remove_hooks()| Method | Prompt Acc (Strict) | Instruction Acc (Strict) |
|---|---|---|
| Baseline | 0.0000 | 0.1667 |
| SpotLight (ψ=0.1) | 0.1000 | 0.2222 |
| Model | Baseline (P/I) | SpotLight (P/I) |
|---|---|---|
| Qwen2.5-3B | 0.42 / 0.53 | 0.53 / 0.62 |
| Mistral-7B | 0.35 / 0.47 | 0.40 / 0.53 |
| Qwen2.5-7B | 0.47 / 0.59 | 0.54 / 0.66 |
| Llama 3.1-8B | 0.42 / 0.55 | 0.51 / 0.62 |
| Granite 3.1-8B | 0.41 / 0.54 | 0.48 / 0.60 |
| Llama 3.1-70B | 0.45 / 0.57 | 0.54 / 0.64 |
| Qwen2.5-72B | 0.49 / 0.61 | 0.55 / 0.67 |
spotlight/
├── __init__.py # Package init
├── steering.py # Core SpotLight algorithm
└── utils.py # Token span detection utilities
ifeval_checker.py # IFEval instruction checker (25 types)
spotlight_experiment.py # Full IFEval evaluation script
results/ # Evaluation resultsforward() to intercept pre-softmax logitsψ_current on instruction tokensψ_current < ψ_target (model isn't attending enough):
log(ψ_target / ψ_current) to instruction token logitsψ_new ∈ [ψ_target/(1+ψ_target), ψ_target]1@inproceedings{venkateswaran2026spotlight,
2 title={Spotlight Your Instructions: Instruction-following with Dynamic Attention Steering},
3 author={Venkateswaran, Praveen and Contractor, Danish},
4 booktitle={Proceedings of the 2026 Conference of the European Chapter of the Association for Computational Linguistics},
5 year={2026}
6}