
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 :
| 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 |
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
| 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é |
Arguments spécifiques aux déclencheurs
| 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 |
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/'
| 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 |
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.
| 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 |
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.