1) Why robustness metrics need to be different from “normal” ML metrics
Standard ML evaluation answers: “How accurate is the model on clean data?”
Adversarial robustness evaluation answers: “How does the model behave under worst-case, attacker-controlled inputs?”
A model can have 99% clean accuracy and 0–10% adversarial accuracy under a strong attack.
So robustness metrics must capture:
- performance under attack
- attacker success rate
- robustness–accuracy trade-offs
- stability and confidence behavior under perturbations
- (optionally) provable guarantees (certified metrics)
2) Always define the evaluation setup (or the metric is meaningless)
Before you report any robustness metric, log these parameters:
Threat Model
- Norm: L∞, L2, etc.
- Budget: ε
- Input constraints: valid ranges, feature constraints
Attack Details
- Attack type: FGSM / PGD / C&W / etc.
- Steps, step size, restarts
- Targeted vs untargeted
- White-box vs black-box
- Query budget (if black-box)
Model Context
- preprocessing pipeline (must match training/inference)
- stochastic transforms (require EOT-style evaluation)
- random seeds and averaging strategy
Rule: No robustness metric should be reported without its threat model + attack config.
3) Core robustness metrics (the essentials)
Metric A — Robust Accuracy (Empirical Robust Accuracy)
Definition: Accuracy on adversarially perturbed inputs generated by a specified attack under a specified ε.
Interpretation:
- higher is better
- compare across ε values (robustness curve)
Metric B — Attack Success Rate (ASR)
Definition (untargeted): fraction of inputs where attacker causes misclassification.
Relation:
ASR=1−RobustAcc(only if all samples are correctly classified cleanly and counted equally)Better practice: compute ASR over clean-correct samples only (see Metric C).
Metric C — Conditional Robust Accuracy (on Clean-Correct Subset)
Many robustness papers report robustness only for samples the model got right originally.
Let:
Why it’s important:
Otherwise, models with poor clean accuracy can look “robust” just because they’re already wrong.
Metric D — Robustness Degradation / Robustness Gap
Measures how much performance drops under attack:
Interpretation: smaller gap = better stability.
Metric E — Worst-Case Robust Accuracy (Attack Suite)
Instead of one attack, evaluate with a suite and take worst-case:
Why: prevents “robust to FGSM only” illusions.
4) Advanced but very useful metrics
Metric F — Minimum Perturbation Needed to Fool (Distortion / Margin Proxy)
For each sample, estimate smallest ε where attack succeeds (or approximation):
“How far must an attacker push input before it breaks?”
Report median/mean minimal distortion
Useful for comparing models when a single ε is too arbitrary.
Metric G — Robustness Curve + AUC
Evaluate robust accuracy at multiple ε values:
ε ∈ {0.0, 0.05, 0.1, 0.2, 0.3}
Plot RobustAcc(ε) and compute area under curve (AUC).
This summarizes robustness across budgets.
Metric H — Calibration Under Attack (Confidence Reliability)
Even if accuracy drops, a safe model should not be overconfident on adversarial inputs.
Track:
Expected Calibration Error (ECE) on clean vs adversarial data
average max softmax probability under attack
Metric I — Certified Metrics
For certified defenses:
Certified radius per sample
Certified accuracy at ε:
% of samples that are both correct and provably robust within ε
5) Recommended reporting template (ELMS-ready)
Robustness Report (minimum)
Clean Accuracy: __
Threat model: norm = __, ε = __
Attack: PGD (steps=, step size=, restarts=__)
Robust Accuracy (PGD): __
Robust Accuracy (FGSM): __
Worst-case Robust Accuracy (suite): __
Robustness Gap: __
Optional
Robustness curve AUC: __
Confidence metrics (ECE / avg confidence) under attack: __
Certified accuracy (if applicable): __
6) Code: Compute clean acc, robust acc, ASR, robustness gap (TF2 + CleverHans)
Assumes you already have:
model(logits output)x_test,y_test_oh
import numpy as np
import tensorflow as tf
from cleverhans.tf2.attacks.fast_gradient_method import fast_gradient_method
from cleverhans.tf2.attacks.projected_gradient_descent import projected_gradient_descent
def accuracy(model, x, y_onehot):
return float(model.evaluate(x, y_onehot, verbose=0)[1])
def evaluate_robustness(model, x, y_onehot,
fgsm_eps=0.2,
pgd_eps=0.3, pgd_eps_iter=0.03, pgd_steps=20):
# Clean accuracy
clean_acc = accuracy(model, x, y_onehot)
# FGSM adversarial accuracy
x_fgsm = fast_gradient_method(model_fn=model, x=x, eps=fgsm_eps, norm=np.inf)
fgsm_acc = accuracy(model, x_fgsm, y_onehot)
# PGD adversarial accuracy
x_pgd = projected_gradient_descent(model_fn=model, x=x,
eps=pgd_eps, eps_iter=pgd_eps_iter, nb_iter=pgd_steps,
norm=np.inf, targeted=False)
pgd_acc = accuracy(model, x_pgd, y_onehot)
# Robustness gap (using PGD as main attack)
gap = clean_acc - pgd_acc
# Attack Success Rate (ASR) (untargeted)
pgd_asr = 1.0 - pgd_acc
return {
"clean_acc": clean_acc,
"fgsm_acc": fgsm_acc,
"pgd_acc": pgd_acc,
"pgd_asr": pgd_asr,
"robustness_gap_clean_minus_pgd": gap,
"params": {
"fgsm_eps": fgsm_eps,
"pgd_eps": pgd_eps,
"pgd_eps_iter": pgd_eps_iter,
"pgd_steps": pgd_steps,
"norm": "Linf"
}
}
# Example:
# results = evaluate_robustness(model, x_test, y_test_oh)
# print(results)
7) Code: Conditional robust accuracy (only on clean-correct samples)
def conditional_robust_accuracy(model, x, y_onehot, attack_fn):
# clean predictions
logits = model(x, training=False)
y_true = tf.argmax(y_onehot, axis=1)
y_pred = tf.argmax(logits, axis=1)
mask = tf.equal(y_pred, y_true) # clean-correct subset
x_cc = tf.boolean_mask(x, mask)
y_cc = tf.boolean_mask(y_onehot, mask)
if x_cc.shape[0] == 0:
return 0.0
x_adv = attack_fn(x_cc)
return accuracy(model, x_adv, y_cc)
# Example usage:
# pgd_attack = lambda x_in: projected_gradient_descent(model, x_in, eps=0.3, eps_iter=0.03, nb_iter=20,
# norm=np.inf, targeted=False)
# cra = conditional_robust_accuracy(model, x_test, y_test_oh, pgd_attack)
# print("Conditional robust accuracy (PGD):", cra)








Comments are closed.