The classifier is a linear (single-layer) neural network: 4 output classes, each with a weight vector wk pointing to a vertex of a regular tetrahedron in the 3D input space. The score for class k at input x is
f_k(x) = w_k · x
predicted class ĉ(x) = argmax_k f_k(x)
140 points are sampled in 4 gaussian clusters around each wk direction, so almost all start correctly classified. This models Universal Adversarial Perturbations (Moosavi-Dezfooli et al., 2017): a single shared vector v, built once, that misclassifies most inputs when added to any of them -- unlike a per-example attack (FGSM/PGD) crafted separately for one input.
Per-sample step (DeepFool, exact for a linear classifier). For a point x currently classified as c, the minimum-norm push that ties class k's score with class c's is closed-form:
a = w_k − w_c
r_{c→k}(x) = [ (f_c(x) − f_k(x)) / ‖a‖² ] · a
The algorithm scans the dataset; whenever v does not yet fool the current point, it adds that point's minimum-norm boundary-crossing vector (over the best k) to v, then projects v back onto the ε-ball: v ← v · min(1, ε / ‖v‖). Repeating this over many points makes v generalize far beyond the sample it was last computed from.
- ε slider — the L2 budget the shared perturbation is not allowed to exceed; a larger ball reaches a higher fooling rate.
- Run accumulation — steps through the shuffled dataset, growing v exactly as the algorithm above prescribes.
- Reset v — snaps v back to 0 without touching the data, so you can re-run the same clusters at a different ε.
Real-world relevance: universal perturbations transfer across images and even across independently trained models, which is why input sanitization and adversarial training target the whole ε-ball around a decision boundary, not single known attacks.