Attacks¶
All methods return a CPU NumPy array with the same layout as the input
waveform, clipped to [-1, 1].
Shared arguments:
| Argument | Meaning |
|---|---|
audio |
One utterance: tensor or ndarray, (samples,) or (1, samples) |
target |
Transcript for targeted attacks |
targeted |
Minimize CTC toward target, or maximize away from the clean decode / label |
label |
Ground-truth transcript for untargeted attacks (default: clean greedy decode) |
epsilon |
Perturbation budget in the chosen norm (FGSM: single step) |
norm |
"inf" (default), 2, or 1 — FGSM, BIM, and PGD |
nested |
True if you wrap this call in another tqdm loop |
early_stop |
Stop when the greedy transcript succeeds |
verbose |
Show progress bars and early-stop messages; False is fully silent |
Every attack supports targeted and untargeted modes (untargeted: model
prediction or label=). Untargeted Imperceptible is a package extension.
Untargeted attacks freeze the reference transcript at the start. They do not re-decode a moving target each step.
Target length
CTC needs one logit frame per target token, plus one extra frame between
two identical neighbouring tokens (for example LL in HELLO). A target
that cannot fit in the model's output frames has no valid alignment, so the
attack raises a ValueError that names the frame count it needs. Use longer
audio or a shorter target.
FGSM¶
One normalized gradient step of size epsilon.
adv = attacker.fgsm(waveform, epsilon=0.01, targeted=False)
adv = attacker.fgsm(waveform, epsilon=0.01, label="THE CAT", targeted=False)
adv = attacker.fgsm(waveform, epsilon=0.01, norm=2, targeted=False)
adv = attacker.fgsm(waveform, target="THE CAT", epsilon=0.01, targeted=True)
BIM¶
Iterative FGSM. Each iterate is projected onto the L-norm ball of radius
epsilon, then [-1, 1]. Defaults: alpha = epsilon / 10; num_iter follows
the Kurakin paper rule when left as None.
adv = attacker.bim(
waveform,
target="THE CAT",
epsilon=0.03,
alpha=0.005,
num_iter=40,
targeted=True,
early_stop=True,
nested=False,
)
adv = attacker.bim(waveform, epsilon=0.03, norm=2, label="THE CAT", nested=False)
PGD¶
Same loop as BIM with a norm-matched random start. Default
alpha = 2.5 * epsilon / num_iter. Pass restarts= for multiple random
starts; random_start=False for BIM-style init.
adv = attacker.pgd(waveform, epsilon=0.03, num_iter=40, targeted=False)
adv = attacker.pgd(waveform, epsilon=0.03, norm=2, restarts=3, nested=False)
adv = attacker.pgd(waveform, epsilon=0.03, random_start=False, targeted=False)
CW (audio)¶
Audio Carlini & Wagner (arXiv:1801.01944):
||delta||_2^2 + c * CTC inside an L-inf box, Adam, optional bound shrinking.
loss="margin" is Sec. III-C (targeted); target="" is Sec. III-F silence.
early_stop and search_eps cannot both be true.
adv = attacker.cw(
waveform,
target="THE CAT",
epsilon=0.05,
c=1.0,
optimizer="adam",
num_iter=200,
targeted=True,
nested=False,
)
adv = attacker.cw(waveform, label="THE CAT", targeted=False, num_iter=200, nested=False)
Imperceptible¶
Qin et al. (arXiv:1903.10346). Default
mode="imperceptible" is offline (Sec. 4). mode="robust" /
"imperceptible_robust" need a RoomSimulator via rooms=. Untargeted mode
is a package extension. Defaults are long; start smaller when experimenting.
adv = attacker.imperceptible(
waveform,
target="THE CAT",
num_iter1=200,
num_iter2=100,
sample_rate=16000,
nested=False,
)
# Robust modes need rooms:
# from asr_attacks.rooms import RoomSimulator
# rooms = RoomSimulator.from_rirs([...]) # or RoomSimulator(num_rooms=...)
# adv = attacker.imperceptible(waveform, target="THE CAT", mode="robust", rooms=rooms, ...)
See algorithms for paper fidelity and extensions.