Post-training diagnostics for LLMs — what did fine-tuning actually do to your model?
Project description
Afterburn
Find out what post-training actually did to your model — before you deploy it.
The Problem
You fine-tuned a model. Benchmarks look good. But:
- Did RLHF quietly teach it to write longer answers instead of better ones?
- Did DPO collapse its reasoning into a single strategy?
- Is it agreeing with users even when they're wrong?
These are reward hacking patterns. They pass benchmarks but fail in production. Afterburn catches them.
Install
pip install afterburn
That's it. No API keys. Runs locally on CUDA, Apple Silicon (MPS), or CPU.
Quick Start
One command to check for reward hacking:
afterburn hack-check \
--base meta-llama/Llama-3.1-8B \
--trained my-org/Llama-RLVR \
--method rlvr
Output:
Afterburn — Post-training diagnostics for LLMs
Reward Hacking Risk: HIGH (68/100)
Score Breakdown:
Length Bias: 72.3/100 ⚠
Format Gaming: 45.2/100 ✓
Strategy Collapse: 61.8/100 ⚠
Sycophancy: 38.1/100 ✓
Flags:
⚠ Length bias: trained model outputs 23% longer (Cohen's d=0.78, p<0.001)
⚠ Strategy collapse: entropy dropped from 1.84 to 0.95 bits
Need it faster? Use --fast mode (~16x speedup):
afterburn hack-check --base <model> --trained <model> --method sft --fast
Full diagnostic with interactive HTML report:
afterburn diagnose \
--base Qwen/Qwen2.5-0.5B \
--trained Qwen/Qwen2.5-0.5B-Instruct \
--method sft \
-o report.html
This generates an interactive report with Plotly charts: risk gauges, weight diff heatmaps, strategy shift charts, and more.
Python API
from afterburn import Diagnoser
report = Diagnoser(
base_model="Qwen/Qwen2.5-0.5B",
trained_model="Qwen/Qwen2.5-0.5B-Instruct",
method="sft",
).run()
print(f"Reward hack risk: {report.hack_score:.0f}/100")
report.save("report.html")
Access individual scores:
rh = report.reward_hack
print(f"Length Bias: {rh.length_bias.score:.1f}/100")
print(f"Format Gaming: {rh.format_gaming.score:.1f}/100")
print(f"Strategy Collapse: {rh.strategy_collapse.score:.1f}/100")
print(f"Sycophancy: {rh.sycophancy.score:.1f}/100")
for flag in rh.flags:
print(f" ⚠ {flag}")
Run individual modules:
weight_diff = diag.run_weight_diff() # weights only (fast, no inference)
behaviour = diag.run_behaviour() # behavioural analysis only
hack_report = diag.run_hack_check() # reward hacking detection
What It Detects
Afterburn runs three layers of analysis:
1. Weight Diff Analysis (no inference needed, very fast)
Compares model weights layer-by-layer using memory-mapped safetensors (~128MB peak even for 70B models):
- L2 / Cosine / Frobenius — how much each layer changed
- SVD decomposition — was training low-rank (LoRA-like) or full-rank?
- Spectral alpha — power-law health of eigenvalue spectrum
- Marchenko-Pastur fit — random matrix theory to find learned structure
- Attention head importance — which heads gained/lost importance
- LoRA auto-detection — finds and decomposes adapter layers
2. Behavioral Shift Detection
Runs 60 built-in prompts (math, code, reasoning, safety) through both models and compares statistically:
- Output length — Mann-Whitney U test, Cohen's d with confidence intervals
- Reasoning strategy — classifies outputs, measures entropy changes
- Format compliance — detects code blocks, LaTeX, markdown, thinking tags
- Chain-of-thought — step counting, reasoning depth, self-correction rate
- Output diversity — Expectation-Adjusted Distinct n-grams
- Token divergence — Jensen-Shannon Divergence on token probability distributions
3. Reward Hacking Detection
Four specialized detectors with a composite risk score (0-100):
| Detector | What It Catches |
|---|---|
| Length bias | Model writes longer but not better (Cohen's d + category consistency) |
| Format gaming | Model exploits format patterns for verifier scores (ROUGE-L + NLI correlation) |
| Strategy collapse | Training killed reasoning diversity (Shannon entropy drop) |
| Sycophancy | Model agrees with users even when wrong (40 adversarial probes + NLI scoring) |
Statistical Rigor
Every claim is backed by proper statistics:
- Effect sizes with 95% confidence intervals (non-central t-distribution, Wilson score, bootstrap)
- Multiple hypothesis correction via Benjamini-Hochberg FDR
- Calibrated scoring — sigmoid mapping tuned to avoid false alarms and missed detections
Report Formats
| Format | Use Case | Command |
|---|---|---|
| HTML | Interactive exploration (Plotly charts) | -o report.html |
| JSON | CI/CD pipelines, programmatic access | -o report.json |
| Markdown | Documentation, model cards | -o report.md |
| Sharing, archiving | -o report.pdf |
Optional Extras
# NLI-enhanced sycophancy detection (recommended)
pip install afterburn[nli]
# PDF export support
pip install afterburn[pdf]
# Semantic diversity analysis (SBERT)
pip install afterburn[semantic]
CLI Commands
# Full diagnostic — weights + behaviour + reward hacking
afterburn diagnose --base <model> --trained <model> --method <method> -o report.html
# Reward hacking check only (fastest way to get a risk score)
afterburn hack-check --base <model> --trained <model> --method <method>
# Weight analysis only (no inference needed)
afterburn weight-diff --base <model> --trained <model> --top-n 10
# Behavioral analysis only
afterburn behaviour --base <model> --trained <model> --suites math code safety
Supported training methods: sft, dpo, rlhf, rlvr, grpo, lora, qlora
Models: Any HuggingFace model ID or local path with safetensors weights.
Use Cases
After RLHF/DPO/GRPO training — Did your reward model exploit get baked in?
afterburn hack-check --base meta-llama/Llama-3.1-8B --trained my-rlvr-model --method rlvr
In CI/CD — Gate deployments on reward hacking risk:
afterburn hack-check --base $BASE --trained $TRAINED -o report.json
score=$(python -c "import json; print(json.load(open('report.json'))['hack_score'])")
[ $(echo "$score > 50" | bc -l) -eq 1 ] && echo "BLOCKED" && exit 1
Comparing training methods — SFT vs DPO vs GRPO, same base:
afterburn diagnose --base llama-8b --trained llama-sft --method sft -o sft.html
afterburn diagnose --base llama-8b --trained llama-dpo --method dpo -o dpo.html
Releasing model weights — Include a diagnostic report in your model card:
afterburn diagnose --base base-model --trained your-finetune -o afterburn-report.html
Configuration
Optional .afterburn.yaml in your project root:
device: auto # cuda, mps, cpu, or auto
behaviour:
suites: [math, code, reasoning, safety]
max_new_tokens: 512
batch_size: 4
reward_hack:
weights:
length_bias: 0.25
format_gaming: 0.30
strategy_collapse: 0.20
sycophancy: 0.25
Requirements
- Python 3.10+
- PyTorch 2.0+
- Works on CUDA, MPS (Apple Silicon), and CPU
Links
License
MIT
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file afterburn-0.6.2.tar.gz.
File metadata
- Download URL: afterburn-0.6.2.tar.gz
- Upload date:
- Size: 178.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
413fc252f06708a3a0a3a6cdbc105e99ecba2d59f913659ba69be3c6b6d56f40
|
|
| MD5 |
02795ece10ebbe263197e5baf44e28f1
|
|
| BLAKE2b-256 |
fc1f7daba1bcfeba717cc853869bc8883d09179de7bf38728e513ee26dc9a44e
|
File details
Details for the file afterburn-0.6.2-py3-none-any.whl.
File metadata
- Download URL: afterburn-0.6.2-py3-none-any.whl
- Upload date:
- Size: 126.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f008445c2fd85eb719fc7620f291e33d7e6e1a9140bfc09ac296e3d19b8f4bd0
|
|
| MD5 |
977fa8f2131a6cae25569b9a865c17df
|
|
| BLAKE2b-256 |
2335bab214566afbab3d8c12ed568bc9c803eda29cc6dc09aa134e1d144959db
|