
Code de recherche implémentant T-Backdoor, des attaques par porte dérobée à déclencheur temporel sur les réseaux de neurones impulsionnels utilisant des déclencheurs de taux, de latence et de gigue sans perturbation spatiale.
Les attaques par porte dérobée constituent une menace sérieuse pour la sécurité des réseaux de neurones profonds (DNN) et restent largement sous-explorées pour les réseaux de neurones impulsionnels (SNN). Les attaques existantes introduisent principalement des déclencheurs spatio-temporels qui induisent des déviations dans la distribution des spikes des échantillons empoisonnés par rapport à leurs homologues propres. Pour remédier à cette limitation, ce travail propose une nouvelle attaque par porte dérobée sur les SNN, appelée \textbf{T-Backdoor}, qui opère à l'aide de déclencheurs purement temporels tels que \textit{Rate}, \textit{Latency} et \textit{Jitter} sans introduire aucune perturbation spatiale, rendant le décalage dans les distributions de spikes nettement plus difficile à détecter. Grâce à des expériences approfondies sur trois jeux de données neuromorphiques de référence : N-MNIST, CIFAR10-DVS et N-Caltech101, et à une évaluation face à sept méthodes de défense par porte dérobée de référence, nous démontrons que T-Backdoor atteint un taux de réussite d'attaque (ASR) quasi parfait de 100 % dans les configurations à cible unique et à cibles multiples, avec seulement une dégradation mineure de la précision sur données propres, tout en restant robuste face aux techniques existantes de détection et d'atténuation des portes dérobées.
├── models.py # Architectures for all datasets (shared)
├── datasets.py # Neuromorphic dataset loading (shared)
│
├── main_single.py # 1. Single-target entry point
├── single_poisoned_dataset.py # Trigger implementations + loaders
├── single_utils.py # Train/eval loop, saving, plots
├── single_target.sh # Paper runs
│
├── main_multi_target.py # 2. Multi-target entry point
├── multi_target_poisoned_dataset.py # Per-target parameter assignment
├── multi_target_utils.py # Per-target ASR tracking, saving
├── multi_target.sh # Paper runs
│
├── main_mtmt.py # 3. Multi-trigger multi-target entry point
├── mtmt_poisoned_dataset.py # Per-target trigger-type config
├── mtmt_utils.py # Per-target ASR tracking, saving
└── mtmt.sh # Paper runs
python -m venv venv
source venv/bin/activate
pip install torch torchvision # CUDA build matching your driver
pip install spikingjelly
pip install numpy scipy matplotlib seaborn tqdm
Environnement de référence utilisé pour les résultats rapportés :
Téléchargez les jeux de données neuromorphiques bruts et placez chacun dans son propre sous-répertoire de
data/, nommé exactement comme la valeur de --dataset :
data/
├── mnist/ # N-MNIST
├── cifar10/ # CIFAR10-DVS
├── caltech/ # N-Caltech101
└── gesture/ # DVS128-Gesture
data/ doit être un répertoire littéral dans votre répertoire de travailmain_single.py)Un déclencheur, une classe cible.
python main_single.py --dataset cifar10 --type latency --delay_frames 1 \
--T 10 --epochs 100 --epsilon 0.1 --data_dir 'data/'
Arguments principaux
Arguments spécifiques aux déclencheurs
Définir --epsilon 0.0 entraîne un modèle de référence propre.
main_multi_target.py)Un type de déclencheur, N classes cibles séparées par la valeur du paramètre du déclencheur.
# Latency: delay 1 -> class 0, delay 3 -> class 1, delay 5 -> class 2
python main_multi_target.py --dataset mnist --type latency --n_targets 3 \
--trigger_labels 0 1 2 --delay_params 1 3 5 \
--epsilon 0.2 --T 10 --epochs 10 --data_dir 'data/'
Paramètres par cible. Fournissez-les explicitement, ou laissez-les être auto-attribués par
np.linspace sur une plage. Les listes explicites doivent avoir une longueur de --n_targets et remplacent
les arguments de plage.
Les paramètres entiers auto-attribués (latency, jitter_fixed) sont dédupliqués en
incrémentant les collisions, de sorte que deux cibles ne partagent jamais une valeur.
Pour static, les cibles sont séparées par quelles trames portent le patch — l'axe temporel
les distingue plutôt que l'apparence du patch.
L'ASR par cible est affiché à chaque époque, aux côtés de la précision sur données propres.
main_mtmt.py)Un type de déclencheur différent par cible.
python main_mtmt.py --dataset mnist --T 10 --n_targets 5 \
--target_types latency latency rate rate jitter_fixed \
--trigger_labels 0 1 2 3 4 \
--latency_delays 1 2 --rate_scales 0.5 2.0 --jitter_fixed_shifts 3 \
--epsilon 0.3 --epochs 100 --data_dir 'data/'
Listes de paramètres par type. Chaque liste a une entrée par cible de ce type — avec
--target_types latency latency rate rate jitter_fixed vous passez deux retards, deux taux
et un décalage :
Omettre une liste auto-attribue à partir de la plage *_min / *_max correspondante.
Préréglages intégrés (utilisés lorsque --target_types n'est pas fourni) :
--n_targets 3 — static (trames 0..T/3), latency (--delay), rate (--scale_factor)--n_targets 5 — deux static (groupes de trames et positions différents), deux latency
(--delay, --delay_2), un rateToute autre valeur de --n_targets nécessite --target_types.
Chaque exécution écrit une ligne dans un CSV partagé ainsi qu'un répertoire d'expérience autonome.
Les paramètres des déclencheurs sont encodés dans le nom du répertoire (df1 = retard 1, sf0.1 = taux
0.1, ns3 = 3 échanges), de sorte que les exécutions qui ne diffèrent que par un paramètre de déclencheur ne s'écrasent pas
mutuellement.
Certaines parties de cette base de code sont adaptées du dépôt Sneaky Spikes de Gorka Abad et al., accompagnant l'article « Sneaky Spikes: Uncovering Stealthy Backdoor Attacks in Spiking Neural Networks with Neuromorphic Data » (NDSS 2024). Nous remercions les auteurs d'avoir rendu leur code publiquement disponible.
Si vous trouvez ce travail utile dans vos recherches, veuillez envisager de le citer :
@article{miah2026tbackdoor,
title = {T-Backdoor: Exploiting Temporal Redundancy in Neuromorphic Data for Spike-preserving Backdoor Attacks on SNNs},
author = {Miah, Abdullah Arafat and Vu, Kevin and Bi, Yu},
journal = {arXiv},
year = {2026}
}
Pour toute question ou problème concernant le code, veuillez ouvrir une issue GitHub ou contacter :
| Paquet | Version |
|---|
| Python | 3.11.10 |
| torch | 2.11.0+cu128 |
| torchvision | 0.26.0+cu128 |
| numpy | 2.2.6 |
| scipy | 1.16.0 |
| matplotlib | 3.8.4 |
| seaborn | 0.13.2 |
| spikingjelly | latest from source |
| Argument | Défaut | Description |
|---|
--dataset | gesture | mnist, cifar10, caltech, gesture |
--type | static | static, moving, smart, latency, rate, jitter, jitter_fixed |
--epsilon | 0.1 | Fraction de l'ensemble d'entraînement à empoisonner |
--trigger_label | 0 | Classe cible |
--T | 10 | Pas de temps de simulation |
--epochs | 10 | Époques d'entraînement |
--batch_size | 16 | Taille du lot |
--lr | 0.001 | Taux d'apprentissage |
--loss | mse | mse ou cross |
--optim | adam | adam ou sgd |
--amp | désactivé | Activer la précision mixte automatique |
--seed | 42 | Graine aléatoire |
--data_dir | data/ | Racine des jeux de données |
--save_path | experiments_single | Racine de sortie |
--model_path | None | Démarrer à partir d'un point de contrôle pré-entraîné |
| Argument | Défaut | S'applique à |
|---|
--delay_frames | 2 | latency — trames de retard |
--scale_factor | 0.5 | rate — <1 plus lent, >1 plus rapide |
--n_shift | 3 | jitter_fixed — nombre de paires de trames échangées |
--trigger_size | 0.1 | static/moving/smart — taille du patch en fraction de la largeur |
--pos | top-left | static — top-left, top-right, bottom-left, bottom-right, middle, random |
--polarity | 3 | static/moving/smart — 0=noir, 1=bleu foncé, 2=vert, 3=bleu clair |
--n_masks | 2 | smart — nombre de régions candidates |
--least | désactivé | smart — cibler la région la moins active au lieu de la plus active |
--most_polarity | désactivé | smart — utiliser la polarité la plus active dans la région |
| Argument | Défaut | Description |
|---|
--type | rate | static, latency, rate, jitter, jitter_fixed |
--n_targets | 3 | Nombre de classes cibles |
--trigger_labels | [0..n-1] | Étiquettes cibles explicites ; la longueur doit être égale à --n_targets |
--epsilon | 0.1 | Budget total, réparti uniformément entre les cibles |
| Déclencheur | Explicite | Plage auto | Défaut auto |
|---|
latency | --delay_params 1 3 5 | --delay_min, --delay_max | 1 … T//2 |
rate | --rate_params 0.3 0.6 0.9 | --rate_min, --rate_max | 0.1 … 6.0 |
jitter | --jitter_params 0.05 0.15 0.25 | --jitter_std_min, --jitter_std_max | 0.05 … 0.3 |
jitter_fixed | --nshift_params 1 3 5 | --n_shift_min, --n_shift_max | 1 … max(n_shift_min+1, T//4) |
static | — | — | T divisé en n_targets groupes de trames |
| Argument | Défaut | Description |
|---|
--n_targets | 3 | Nombre de cibles ; 3 et 5 ont des préréglages intégrés |
--target_types | None | Type de déclencheur par cible — static, latency, rate, jitter, jitter_fixed. La longueur doit être égale à --n_targets. Remplace les préréglages |
--trigger_labels | [0..n-1] | Étiquettes cibles |
--epsilon | 0.2 | Budget total, réparti uniformément entre les cibles |
| Argument | S'applique à |
|---|
--latency_delays 1 2 | chaque cible latency |
--rate_scales 0.5 2.0 | chaque cible rate |
--jitter_fixed_shifts 3 | chaque cible jitter_fixed |
--jitter_stds 0.1 0.3 | chaque cible jitter |
--static_positions top-left bottom-right | chaque cible static |
--static_polarities 3 1 | chaque cible static |
| Configuration | CSV récapitulatif | Répertoire d'expérience |
|---|
| Unique | <save_path>/results.csv | <dataset>_<type>_<eps>_<size>_<param>_<seed>/ |
| Cibles multiples | <save_path>/multi_target_results.csv | multi_<type>_<dataset>_<n>targets_<labels>_eps<eps>_<params>_seed<seed>/ |
| MTMT | <save_path>/mtmt_results.csv | mtmt_<dataset>_<n>t_<params>_eps<eps>_seed<seed>/ |