Paper · 2024-12-18 · cs.SE, cs.RO
SimADFuzz: Simulation-Feedback Fuzz Testing for Autonomous Driving Systems
Genetic fuzzer for autonomous driving in CARLA. A Transformer over simulation feedback scores violation likelihood; NSGA-II selects scenarios by that score, SDC-Scissor, minimum distance and unique violations. Author-reported: 35 unique violations in 6 h on InterFuser, versus 26 (TM-Fuzzer), 18 (DriveFuzz) and 3 (AV-Fuzzer).
Fuzz testingMetaheuristic optimizationSelf-attentionSurrogate modelingautonomous-drivingfuzz-testingsimulation-testinggenetic-algorithmtransformer
arXivPDFCodeMarkdown11 min read
AI-compiled by claude-haiku-5-5 on 2026-10-25, not yet reviewed by a human. Every claim cites its source; check it when a detail matters.
In plain words
Self-driving software is tested by putting it into a driving simulator and throwing many traffic situations at it, looking for crashes, lane violations and other unsafe behaviour. The number of possible situations is huge, so the question is which ones to try next. This paper's tool, SimADFuzz, keeps a population of situations, scores them, and breeds new ones by mixing and changing the best. Two ideas make it different from earlier tools. First, the score comes from a learned model that reads how the cars moved during the simulation, not only from a simple summary such as the closest distance. Second, cars that are stuck or driving away from the test car are swapped out, because they are unlikely to cause trouble, while cars that might meet the test car are kept. The authors report that this finds more distinct failures than three earlier tools on one driving system, but the test is limited to one system and one map.
TL;DR
- SimADFuzz is a genetic-algorithm fuzzer for autonomous driving systems (ADS) in CARLA §4.
- A Transformer encoder reads per-frame vehicle states and outputs a violation score used as a fitness term §4.2.1 fig. 3.
- Selection uses NSGA-II over four objectives: the Transformer score, an SDC-Scissor score, minimum distance and unique violations §4.2.1.
- Distance-guided mutation removes NPC vehicles that stay still or move away from the ego vehicle, then adds new ones §4.2.3 alg. 1.
- Only one ADS (InterFuser) and one map (Town03) are evaluated; all numbers are author-reported §5.1 §5.3.
Problem
Simulation-based fuzzing needs scenarios that expose unsafe behaviour. Existing genetic fuzzers score a scenario with aggregate values such as a minimum or a count over the whole run, which can hide an interaction that is risky at one moment §3 fig. 2. They also mutate vehicles and pedestrians at random, so many offspring contain vehicles that never interact with the ego vehicle §3. The paper states that these limits are the reason for its two changes §1 §3.
Method
Overview. SimADFuzz has three modules: a simulation test engine that runs scenarios and records feedback, a simulation-feedback genetic algorithm that selects, crosses and mutates scenarios, and a violation detector §4 fig. 3. The test engine uses CARLA, which the authors prefer to LGSVL because LGSVL stopped being maintained in 2022 §4.1.
Feedback. For every vehicle, the simulator returns coordinates (loc_x, loc_y), speed (speed_x, speed_y), acceleration (acc_x, acc_y) and heading §4.1 tab. 2. Each scenario is a sequence of T scenes with seven features per vehicle, so with three vehicles the Transformer input is T × 21 §4.2.1.
Chromosome. A scenario has four parts: the ego route, the NPC routes, the pedestrian routes and the weather §4.2 fig. 4. Weather is sampled from predefined ranges, such as rain from 0 to 100 and sun altitude from −90° to 90° §4.2.3.
Fitness and selection §4.2.1:
- Violation prediction model (VPM). A Transformer encoder embeds the scene sequence; a single fully connected output gives a scalar that the paper describes as a violation probability.
- SDC-Scissor. A classifier on static road features of the driving path gives a safe/unsafe score. The paper's Table 3 lists the features tab. 3.
- Minimum distance between the ego vehicle and any other vehicle over the run.
- Number of unique violations found in the run.
These four objectives are combined with NSGA-II, which keeps the Pareto-optimal set §4.2.1.
Crossover §4.2.2. Two parents exchange routes. The ego route and weather are kept unchanged. For NPCs, the trajectory of an NPC in one parent is tested against the ego trajectory of the other; if they intersect, an NPC is swapped with a randomly chosen NPC of the other parent. For pedestrians, the paper says half of them are swapped at random.
Mutation §4.2.3 alg. 1. An NPC is removed if its total path length is below a threshold w (stuck), or if its distance to the ego vehicle has not shrunk over any window of length u (leaving). The ego and remaining NPC routes are re-drawn on the same road, and removed NPCs are replaced by vehicles with random start and end points. Pedestrians are spawned near the ego vehicle, and weather is re-sampled §4.2.3. The distance matrix used by the algorithm is defined in §4.2.3 (unnumbered equation).
# Distance-guided mutation [alg. 1] [§4.2.3]
# Input: npcs (NPC routes), ego (route), dist (T, |V|, |V|) distance matrix
# stuck_w (path length threshold), window_u (window, in seconds)
# Output: NPC routes for the offspring
def mutate_npcs(npcs, ego, dist, stuck_w, window_u):
# Mark NPCs whose total path length is below the threshold [alg. 1]
removed = set()
for npc in npcs:
if path_length(npc) < stuck_w:
removed.add(npc)
continue
# Mark NPCs whose distance to the ego never shrinks in a window
# [alg. 1] [§4.2.3]
if never_closing(npc, ego, dist, window_u):
removed.add(npc)
# Keep the other NPCs on their road, re-route the ego [alg. 1]
kept = [reroute_same_road(npc) for npc in npcs if npc not in removed]
ego = reroute_same_road(ego)
# Replace each removed NPC with one on a random route [alg. 1]
new_npcs = [random_npc() for _ in removed]
return kept + new_npcsFeedback features into the model (code path, see Paper vs code). Positions are shifted so that the ego's first position is the origin, duplicate frames are dropped, and the sequence is passed to the model without padding [code: fuzz.py#L368-L378].
Violations §4.3. Five types are detected: collision and lane invasion (CARLA sensors), speeding (ego speed above the limit for a duration T_speeding), running a red light, and stuck (ego stationary for a duration T_stuck). Each violation is saved with its scenario and a CARLA recording so it can be replayed §4.3.
Loop. Seeds are random ego routes in Town03 §5.1.2. Offspring are created with crossover and mutation probability 0.5 each, evaluated, and merged into the population by NSGA-II §5.1.2 §4.2.1 fuzz.py. The paper does not give the loop's stopping rule beyond the time budgets in §5.2.
Training of the VPM and SDC-Scissor §5.1.2. The authors generate 1,000 short scenarios of 2 minutes each, and train the VPM with Adam, learning rate 0.001, binary cross-entropy and early stopping (patience 10 epochs). SDC-Scissor is trained with logistic regression.
Hyperparameters
| Name | Value | Where | Notes |
|---|---|---|---|
| Population size | 20 | §5.1.2 | Paper value. Repo default is 10 fuzz.py |
| Crossover probability | 0.5 | §5.1.2 | Code uses the same value fuzz.py |
| Mutation probability | 0.5 | §5.1.2 | Code uses the same value fuzz.py |
| Simulator frame rate | 20 Hz | §5.1.2 | Code: fixed step 1/20 s sim_executor.py |
| Maximum simulation length | 10 min | §5.1.2 | Code: 60 × 10 s loop sim_executor.py |
| Map | Town03 | §5.1.2 | Code default fuzz.py |
| Scenario composition | 1 ego, 2 NPC vehicles, 10 pedestrians | §5.1.2 | Code fuzz.py |
| VPM embedding dimension | 128 | tab. 4 | Code: model width is 21 (3 × 7); 128 is the feed-forward width models.py models.py |
| VPM heads | 3 | tab. 4 | Code: heads = car number = 3 fuzz.py models.py |
| VPM encoder layers | 3 | tab. 4 | Code default is 2 and the fuzzer does not override it models.py models.py |
| VPM dropout | not stated | §5.1.2 | Code: 0.2 models.py |
| VPM optimiser | Adam, lr 0.001 | §5.1.2 | Training code not in repo |
| VPM loss | binary cross-entropy | §5.1.2 | Training code not in repo |
| VPM early stopping | patience 10 epochs | §5.1.2 | Training code not in repo |
| VPM training data | 1,000 scenarios, 2 min each | §5.1.2 | Not in repo |
| Stuck-vehicle threshold w | 10 m | tab. 4 | Code uses 5 m for NPCs fuzz.py; 10 m for ego route fuzz.py |
| Leaving-vehicle window u | 10 s | tab. 4 | Code uses 60 frames (3 s at 20 Hz) fuzz.py |
| Pedestrian distance bound | 20 m | tab. 4 | Code spawns in a ±30 m box, minimum 10 m fuzz.py |
| Pedestrian speed | not stated | — | Code: uniform 0 to 10 fuzz.py |
| SDC-Scissor model | logistic regression | §5.1.2 | Code loads a joblib model with predict_proba; type not checked fuzz.py fuzz.py |
| Speeding grace period T | not stated | §4.3 | Code: 3 s sim_executor.py |
| Stuck duration T_stuck | not stated | §4.3 | Code: speed under 1 km/h for 60 s sim_executor.py |
| Unique-violation match | ±10 s, ±30 m | §5.1.3 | Dedup in the fuzzer uses 20 s and 5 m fuzz.py |
| Run length | 3 h ablation, 6 h comparison | §5.2.1 §5.2.2 | Code loop stops at 6 h fuzz.py |
Results
Author-reported. Setup: InterFuser as the ADS under test, CARLA, Town03, 20 Hz, 10-minute simulations, one seed set shared by all fuzzers §5.1. The paper does not state hardware; the repository README lists an RTX 3090 GPU and CARLA 0.9.13 README.md.
| Setting | Metric | Baseline | This paper | Source |
|---|---|---|---|---|
| Ablation, 3 h: R+R vs VS+D | Unique violations | 14 | 24 | §5.2.1 fig. 7 |
| 6 h vs AV-Fuzzer | Unique violations | 3 | 35 | §5.2.2 fig. 8 |
| 6 h vs DriveFuzz | Unique violations | 18 | 35 | §5.2.2 fig. 8 |
| 6 h vs TM-Fuzzer | Unique violations | 26 | 35 | §5.2.2 fig. 8 |
| First collision | Time | 21 min (TM-Fuzzer) | 17 min | §5.2.2 |
| Composition of the 35 | Collisions / lane invasions / stuck | — | 4 / 20 / 11 | §5.2.2 |
| Speeding or red-light violations | Count | — | 0 for all fuzzers | §5.2.2 |
| Ego trajectory coverage, Town03 | Share of waypoints | AV-Fuzzer 3.04%, DriveFuzz 13.85%, TM-Fuzzer 24.88%, R+R 19.65% | 61.25% (VS+D) | §5.2.3 fig. 13 |
| NPCs within 50 m of ego, 3 h | Count | VS+R 23 | VS+D 35 | tab. 5 |
Margins quoted in the text: 32 over AV-Fuzzer, 27 over DriveFuzz and 9 over TM-Fuzzer §5.2.2 §7. The 6-hour counts above give 32 and 9 but 17 for DriveFuzz (see Pitfalls).
Violation types reported in tab. 6: four collisions (one with a pedestrian, three with vehicles), two lane invasions and two stuck cases. All eight reproduced §5.2.2.
Paper vs code
Official repository: yagol2020/SimADFuzz (Apache-2.0), cloned at
a4930f58c28797b16aa51e77e3d93a14e093cdd1. The paper does not print the URL;
the link was found through a GitHub search on the title. The owner is
"Yagol" at NUAA, the university of the first two authors, and the handle matches
the first author's e-mail in the paper header. This is the basis for treating
the repository as the authors' own; the paper itself does not link it. The repository README gives a
figshare DOI, 10.6084/m9.figshare.28769768 README.md.
- Transformer size. Paper: embedding 128, 3 heads, 3 layers tab. 4. Code: input width 21, 3 heads, 2 layers, feed-forward width 128 models.py fuzz.py. The released checkpoint's layer count was not checked.
- Output nonlinearity. Paper: the output node gives a probability §4.2.1. Code: a raw linear output, no sigmoid; the fitness uses this raw value models.py fuzz.py.
- Sequence model. Paper: no positional encoding is mentioned §4.2.1. Code: none is added; the last time step of the encoder is used as the feature models.py.
- Population size. Paper: 20 §5.1.2. Code: 10 fuzz.py and README README.md.
- Pedestrian swap. Paper: half of the pedestrians are swapped at random §4.2.2.
Code:
random.choicesdraws indices with replacement, five draws fuzz.py; repeated indices swap twice and cancel out. - Weather in crossover. Paper: weather is unchanged by crossover §4.2.2. Code: each weather value is swapped with probability 0.5 fuzz.py.
- Mutation with restart. Paper: mutation always changes the parent's NPCs and pedestrians §4.2.3. Code: with probability 0.5, or when the ego route is shorter than 10 m, the parent is discarded and a new random scenario is made fuzz.py.
- Stuck NPC threshold. Paper: 10 m tab. 4. Code: 5 m fuzz.py.
- Leaving window. Paper: 10 s tab. 4. Code: 60 frames, 3 s at 20 Hz fuzz.py sim_executor.py.
- Pedestrian placement. Paper: spawned within 20 m of the ego tab. 4. Code: a ±30 m box fuzz.py; the coordinates drawn after the 10 m check are drawn again without it fuzz.py.
- SDC-Scissor input. Paper: SDC-Scissor classifies the scenario §4.2.1. Code: a probability is computed for every vehicle, but only the ego value is used as fitness fuzz.py fuzz.py. Features come from a separate service on port 12555 models.py README.md.
- Unique-violation rule. Paper: ±10 s and ±30 m §5.1.3. Code: two violations are the same if they are within 20 s and either axis is within 5 m fuzz.py. The evaluation script that produced the paper's counts is not in the repository.
- Training code. Paper gives Adam, BCE, early stopping and the 1,000-scenario
dataset §5.1.2. The repository has no training script; it ships only the
checkpoints
Transformer.ck.pthandsdc.ck.pth.
No discrepancies were found for the 20 Hz rate, the 10-minute length, the 0.5 probabilities, the 6-hour loop, the seven vehicle features or the four fitness objectives.
Pitfalls
- Inconsistent counts. The 6-hour DriveFuzz count is 18 §5.2.2, so 35 − 18 = 17, but the text and conclusion say 27 more §5.2.2 §7. Check the source before quoting the 27.
- Raw score. The fitness uses the VPM's unbounded linear output models.py although the paper calls it a probability. Any reimplementation must choose; matching the code means no sigmoid.
- Variable length. Duplicate frames are removed before the model fuzz.py, so T differs per run. The model takes no padding or mask.
- No positional encoding is used, so frame order enters only through the attention pattern and the position of the last time step.
- Checkpoint vs paper. The architecture in code differs from tab. 4. Use the checkpoint's own shapes if you need the exact model, and check them.
- Missing training pipeline. The dataset, labels and optimiser code are not published; the VPM cannot be retrained from the repo.
- Hard-coded CUDA. The model is moved to the GPU at import fuzz.py fuzz.py. Without a GPU the fuzzer will not start as written.
- Cost. Each candidate is one simulation of up to 10 minutes [code: sim_executor.py#L472], and the evaluation loop runs them one after another fuzz.py fuzz.py. The number of simulations per hour is not stated.
- Environment. Python 3.7 for the fuzzer, Python 3.10 for SDC-Scissor, CARLA
0.9.13 in Docker, and InterFuser weights are needed; the README asks the user to
set
res_pathto a real directory README.md. - Early stops. A simulation that fails returns a sentinel and is dropped fuzz.py. Scenarios that end early (collision, goal reached, stuck) are scored on a shorter run sim_executor.py.
- Only one ADS, one map. The authors list this as a threat to external validity §5.3; InterFuser's conservative settings (5 m/s limit, traffic-light confidence 0.3) explain why no speeding or red-light violation was found §5.2.2.
- Baselines. The three baselines are described in one paragraph each §5.1.3; the paper gives no versions or settings for them.
Lineage
- Builds on: genetic fuzzing with scenario selection, crossover and mutation (AV-Fuzzer, DriveFuzz, Doppel) §2 tab. 1; the Transformer encoder §4.2.1; NSGA-II selection §4.2.1; SDC-Scissor for road-feature classification §4.2.1.
- Compared against: AV-Fuzzer, DriveFuzz and TM-Fuzzer §5.1.3. Doppel is discussed as prior work §3.
- Superseded by: not known from content already in this wiki.
Source and license
Adapted from “SimADFuzz: Simulation-Feedback Fuzz Testing for Autonomous Driving Systems” by Huiwen Yang, Yu Zhou, Taolue Chen (arXiv:2412.13802), used under CC BY 4.0. Changes: condensed and restructured for implementation, with tables, equations and algorithms taken from the paper and its code, each cited to its source. Not affiliated with or endorsed by the authors. Code citations refer to https://github.com/yagol2020/SimADFuzz at commit a4930f58c287 (Apache-2.0). Any quoted code is shown under that license.