Two publication-quality matplotlib figures are generated automatically after each experiment run, providedDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/Antisource/heronaisec/llms.txt
Use this file to discover all available pages before exploring further.
visualization.save_figures: true is set in the config. Both are written to the figures/ subdirectory of the run’s timestamped output directory and are ready for direct inclusion in papers or reports.
persistence_curve.png
persistence_curve.png is the main result figure. It visualizes how the backdoor degrades — and how task performance holds up — as progressively larger fractions of clean fine-tuning data are applied.
The plot uses a dual-axis layout:
- Primary y-axis (left): Attack Success Rate and Mean Trigger Confidence, both plotted against
clean_ratio - Secondary y-axis (right): Clean Accuracy, plotted against
clean_ratio - x-axis: Clean Fine-Tuning Ratio (0.0 to 1.0)
o); Mean Trigger Confidence uses a square marker (s); Clean Accuracy uses a dashed line on the secondary axis. All three share a unified legend positioned automatically by matplotlib.
The key observation this figure captures is that ASR decreases progressively as the clean fine-tuning ratio increases, while Clean Accuracy remains comparatively stable throughout — demonstrating that the inherited backdoor can be eroded without significantly degrading the model’s downstream utility.
reviewer_intervention.png
reviewer_intervention.png is a companion figure intended to highlight the specific point at which a reviewer would intervene.
It plots Attack Success Rate vs. clean_ratio using the same line as the persistence curve, and marks the reviewer’s intervention point with a star (*) scatter marker at the ratio specified by reviewer.checkpoint_ratio in the config (default: 0.4).
reviewer_intervention.png is only generated when reviewer.enabled: true is set in configs/baseline.yaml. If the reviewer block is disabled, plot_reviewer_intervention() is not called and no file is written.Plot Configuration
All figures are saved at 300 DPI using matplotlib’sconstrained_layout=True, which prevents axis labels and titles from overlapping without manual padding adjustments.
Global style settings are applied at module import time in src/visualization.py via plt.rcParams.update():
| Setting | Value |
|---|---|
figure.figsize | (8, 5) |
figure.dpi | 300 |
axes.grid | True |
axes.spines.top | False |
axes.spines.right | False |
font.size | 11 |
legend.frameon | False |
plot_backdoor_persistence() or plot_reviewer_intervention().
Regenerating Figures Manually
If you want to regenerate figures from a savedmetrics.csv — for example, to adjust a label or tweak the output path — import the plotting functions directly:
output_path without a file extension — the .png suffix is appended automatically.
Required Columns for plot_backdoor_persistence
plot_backdoor_persistence() validates its input before drawing anything. The DataFrame passed as results must contain all four of the following columns:
clean_ratioattack_success_rateclean_accuracymean_trigger_confidence
ValueError is raised immediately with a message listing the missing column names. The same validation check is also performed by plot_reviewer_intervention().
Figures are always saved as
.png regardless of whether output_path already has a suffix. The .with_suffix('.png') call inside visualization.py enforces this — passing "figures/persistence_curve.pdf" will still produce a .png file.