Project report. Full code, artifacts, and the append-only experiment log are in the project repository.
Can you tell, by looking inside a model, when it is being fooled?
I started this project expecting the answer to be yes. The plan was to build an internal-representation monitor for adversarial audio and show that internals were more trustworthy than the model's own confidence.
That headline did not survive contact with the experiments.
The project ended up testing nine hypotheses across two related audio anti-spoofing models, two corpora, clean and adversarial conditions, and several kinds of interpretability tools. The result I care about most is not that one particular monitor failed. It is that only three of nine interpretability findings transferred cleanly between the two models. Three inverted, one held only conditionally, and two stopped being meaningful on the second model.
That is a demonstration, not a population estimate. Two models are still two models. But the pair is unusually favorable for transfer: they share the same graph-attention back-end implementation and labelled training corpus while using very different front-ends. If an interpretability result can fail there, I think that should lower our confidence in single-model mechanistic claims more generally.
A few other results survived the audit:
The project also changed its own conclusions several times. I kept an append-only experiment log, so those reversals are still visible rather than cleaned away. In retrospect, that was probably the most useful methodological decision in the whole project.
Audio anti-spoofing models are binary classifiers. They take a few seconds of waveform and decide whether it is:
These models rarely sit alone. A deployment usually wraps them in a policy:
That third branch is often treated as the safety valve. The whole policy assumes the model's own confidence or some internal signal is trustworthy precisely when the model is under stress.
I wanted to test that assumption directly.
The models are AASIST and SSL-AASIST.
Both take roughly four seconds of audio and eventually feed a 160-dimensional embedding into a Linear(160,2) readout. Both use the same graph-attention back-end design, with spectral and temporal branches that exchange information before being pooled into the final embedding.
The major difference is the front-end:
| AASIST | SSL-AASIST | |
|---|---|---|
| front-end | SincConv, 70 fixed mel-spaced filters | wav2vec 2.0 XLS-R 300M |
| total parameters | 297,866 | 317,837,834 |
| spectral representation | 23 nodes with an exact node→Hz interpretation | 42 abstract projected dimensions |
| augmentation | none | RawBoost |
AASIST reports 0.83% EER on ASVspoof2019 LA. SSL-AASIST replaces the tiny fixed front-end with a large pretrained speech encoder, while leaving the graph-attention back-end implementation and final readout structure closely matched.
This is a strong portability test, but not a perfect one-variable experiment: SSL-AASIST also uses RawBoost augmentation. I therefore do not treat every difference downstream as causally attributable to the front-end alone. The narrower claim is that the back-end is held unusually stable while the representation entering it changes dramatically.
That representational change matters for interpretability itself. In AASIST, the spectral nodes correspond to actual frequency bands. In SSL-AASIST, the corresponding dimensions are abstract projections. So a question like which frequencies carry spoof evidence? is meaningful in one model and literally has no referent in the other.
This started as a BlueDot Impact Technical AI Safety project sprint, following their Technical AI Safety course.
I chose audio deepfake detection because it sits in an unusually useful middle ground for interpretability work: the models are small enough to inspect end-to-end, open enough to patch and attack directly, and tied to a real deployment problem rather than a toy benchmark. AASIST has only about 298K parameters, so I could run probes, causal interventions, adversarial attacks, and whole-model audits on the actual checkpoint rather than on a simplified proxy.
The original plan was narrower: build an internal-representation monitor that detects adversarial audio. That plan did not turn into a defence. After correcting how I evaluated the monitor, the best AASIST tap still catches only about 61% of attacks at a 5% false-alarm budget, and that is against processed studio audio rather than real recordings. The two models also behave differently enough that one model's monitoring conclusion does not predict the other's.
At that point the project changed from building a defence to auditing the assumptions behind the defence: which signals are trustworthy, which interpretability tools actually track mechanism, which failures are cheap to repair, and which conclusions survive a model change.
That reframing is why the post is organized around things I initially watched in the wrong way — confidence, internal monitors, probe directions, and finally the assumption that a mechanistic finding from one model will transfer to another.
Most numbers below live in one of four cells:
| in-domain — ASVspoof2019 | cross-corpus — ASVspoof5 | |
|---|---|---|
| clean | natural errors, branch attribution, probe directions | domain shift, confidence failure, representation-vs-readout diagnosis |
| attacked | white-box PGD, attack monitors, adaptive monitor evasion | attack transfer, adversarial-real attacks, depth-wise evidence retention |
This distinction matters because several of the strongest findings have no adversary involved at all. All three of the transfer inversions I discuss later are clean-data results.
For the adversarial experiments, every headline attack result is paired with an energy-matched benign control. On AASIST, white-box PGD successfully flips the model’s prediction on 91.9% of the clips it attacks at the ~40 dB perturbation setting. As a control, I add random Gaussian noise with exactly the same perturbation energy; that changes the model’s prediction on only 0.09% of clips — about 1 in 1,100. So the result is not simply that AASIST is sensitive to perturbations of this size. The perturbation becomes effective when it is optimized in an adversarial direction.
My original hypothesis was that the model's own confidence would be uninformative about its errors, and that internal representations would do better.
I was wrong.
The first reason is almost embarrassingly simple: attack success is defined by pushing the model confidently across the decision boundary. If you evaluate confidence only on successful attacks, you have built the answer into the subset you chose.
Once I split the analysis into natural errors, adversarial errors, and pooled errors, the result reversed. On AASIST's natural in-domain errors, confidence predicts failure at AUROC 0.954, while the best internal tap reaches only 0.659.
So the first lesson was not “confidence is bad.” It was:
Do not evaluate a metric on a subset selected using that same metric.
In my original analysis, I evaluated confidence only on successful attacks. But an attack counts as successful only after it has pushed the model across its decision boundary — exactly the behavior confidence is supposed to summarize. That makes the evaluation circular: I first use the model's score to help define which examples enter the subset, then ask whether that same score distinguishes the examples in it.
Once I separated natural errors from adversarially selected errors, the conclusion reversed: on natural in-domain errors, confidence actually outperformed every internal monitor I built.
The more worrying failure needs no attack.
Train on ASVspoof2019, evaluate on ASVspoof5, and the aggregate error-prediction AUROC for AASIST confidence is 0.656. Mediocre, but not obviously disastrous.
The problem is that the errors are almost all one class.
For AASIST, there are 702 false rejects of bonafide speech against 64 false accepts. On SSL-AASIST, the clean cross-corpus errors are even more one-sided: 576 of 576 are bonafide clips being rejected.
If errors concentrate in one class, an “error prediction” AUROC can get credit for doing the original classification task. So I recomputed the metric within the class where the errors occur.
Here, “within class” means: among bonafide clips only, can confidence distinguish the false rejects from the correctly accepted bonafide clips?
| errors | erroring class | all rows | within class | |
|---|---|---|---|---|
| AASIST — in-domain | 102 | spoof (99%) | 0.947 | 0.893 |
| SSL-AASIST — in-domain | 7 | spoof | 0.916 | 0.841 (too few errors to measure well) |
| AASIST — cross-corpus | 766 | bonafide (92%) | 0.656 | 0.339 |
| SSL-AASIST — cross-corpus | 576 | bonafide (100%) | 0.866 | 0.582 |
The in-domain row is an important control: confidence genuinely works there. The collapse is specific to domain shift.
For AASIST, 0.339 is below chance. The bonafide clips that the model wrongly rejects are, on average, held at higher confidence than the bonafide clips it accepts correctly.
Measured directly:
p(bonafide) is 0.013So AASIST does not merely reject about 70% of bonafide speech out of domain. It rejects it confidently.
A policy that escalates only low-confidence inputs would escalate almost none of these failures.
The mechanism is simple: domain shift can move an entire class across the decision threshold. Once the errors are confidently wrong rather than borderline, confidence cannot help.
If the output cannot be trusted, the next move is obvious: monitor the internals.
I fitted class-conditional Mahalanobis monitors at multiple internal “taps” — points where I read intermediate activations. AASIST has 12 taps in this analysis; SSL-AASIST has 36.
The central issue is that monitor quality depends on which negative distribution you compare against, and false-alarm rate at one inherited threshold is not the same thing as separability.
A useful attack monitor should not merely distinguish modified audio from untouched audio. It should distinguish an adversarial modification from an innocuous modification.
So the relevant benign set is not pristine speech. It contains 13,685 legitimate clips that have all been perturbed or re-encoded:
Scoring only against untouched clips would make the monitors look better while answering an easier question.
And even these controls are friendlier than deployment: they are software transforms of studio-clean ASVspoof audio, not phone calls, microphones, rooms, packet loss, or background environments. I return to that limitation below.
Here is the same AASIST monitor reported three ways:
| AASIST tap | AUROC vs clean | AUROC vs perturbed benign | FAR at a clean-fitted threshold |
|---|---|---|---|
embedding |
0.987 | 0.851 | 73% |
gat_T |
0.983 | 0.830 | 74% |
gat_S |
0.886 | 0.804 | 23% |
pool_T |
0.979 | 0.652 | 84% |
enc1 |
0.532 | 0.501 | 6.6% |
These columns answer different questions.
AUROC vs clean asks whether the monitor can separate adversarial audio from untouched audio. It is the easiest comparison, and the one that makes embedding look nearly perfect at 0.987.
AUROC vs perturbed benign asks the harder question: can the monitor distinguish adversarial perturbations from innocuous perturbations? The numbers fall, but embedding still reaches 0.851. That means the representation contains real attack-specific signal; it is not merely responding to the presence of any perturbation.
FAR at a clean-fitted threshold asks yet another question: what happens if I choose a threshold on pristine audio and then apply it to processed audio? For embedding, 73% of processed benign clips cross that threshold.
That 73% is real, but it is mostly a calibration result, not evidence that the representation contains no useful attack signal. The threshold was placed on one distribution and used on another.
This distinction matters because a single false-alarm number can make a capable-but-miscalibrated monitor look incapable.
A cleaner comparison is to fix the false-alarm budget and ask how many attacks the monitor catches.
| tap | perturbed benign negatives | detection @ 5% FAR | detection @ 10% FAR |
|---|---|---|---|
embedding |
MP3 | 60.8% | 69.2% |
embedding |
resampled | 60.1% | 68.1% |
embedding |
Gaussian noise | 54.8% | 63.4% |
gat_T |
MP3 | 52.4% | 64.6% |
gat_S |
MP3 | 47.1% | 57.0% |
pool_T |
MP3 | 30.7% | 37.9% |
So the AASIST conclusion is:
At a 5% false-alarm budget, the best monitor catches about 61% of attacks.
The 73% false-alarm figure and the 0.851 perturbed-negative AUROC are not contradictory: the first measures calibration at one particular threshold, while the second measures separability across all thresholds.
But it is still not a convincing defence. Missing roughly two attacks in five on the model and attack family used to build the experiment is a long way from where I would want a deployment monitor to be — especially because the negatives here are still cleaner than real deployment audio.
One concern is that the benign pool is dominated by Gaussian noise, which is a deliberately synthetic control.
I split the false alarms by processing type at the same clean-fitted threshold. For the AASIST embedding, the rates are:
The realistic software transforms are slightly worse, not better.
At a fixed 5% FAR the pattern also survives: embedding catches 60.8% of attacks against MP3 negatives versus 54.8% against matched Gaussian noise. So the Gaussian control was not chosen to manufacture the failure; if anything, it is the harder negative in Mahalanobis space.
There is one useful oddity: the fixed SincConv front-end behaves differently, firing on 90.3% of MP3 but only 3.0% of Gaussian at the inherited threshold. That is a reminder that “benign perturbation” is not one distribution, and different layers can be sensitive to very different processing artifacts.
The two-model comparison becomes especially informative when the metrics are separated.
AASIST embedding |
SSL-AASIST pool_T |
|
|---|---|---|
| AUROC vs clean | 0.987 | 0.823 |
| AUROC vs perturbed benign | 0.851 | 0.920 |
| benign FAR at clean-fitted threshold | 73% | 2.5% |
If I report only the conventional clean-negative AUROC, AASIST wins.
If I ask the more deployment-relevant question — adversarial versus already-processed benign audio — SSL-AASIST wins.
Reporting the easy metric alone ranks the models backwards.
SSL's perturbed-negative separability is also unusually stable: 0.920 in-domain and 0.919 cross-corpus, even though its clean-negative AUROC drops under corpus shift.
So the updated lesson is not “AASIST has no monitor and SSL does.” It is:
Separability, calibration, and operating point are three different things. Report which one you measured.
There is still a striking architectural contrast inside SSL-AASIST:
| SSL-AASIST tap (1 seed) | attack detection | false alarms on perturbed benign audio |
|---|---|---|
ssl_L09 — front-end |
0.967 | 100% |
embedding |
0.867 | 6.3% |
pool_T |
0.823 | 2.5% |
All 24 XLS-R transformer taps false-alarm on 100% of the perturbed-benign pool at this threshold. For those taps, “detects perturbation rather than attack” really is the right description.
The useful monitoring signal appears later, in the roughly 447K-parameter graph back-end — around 0.1% of SSL-AASIST's parameters.
The 300M front-end buys a lot elsewhere:
But it does not itself provide the useful monitoring site.
And the compute increase is smaller than the parameter count suggests: in this setup, 1,067× more parameters costs about 1.6× the forward pass.
What I have not tested is whether a much smaller learned front-end would get the same benefits. The experiment compares essentially 0 learned front-end parameters against 300M, with nothing in between.
Before the next result, it helps to distinguish three tools that are easy to conflate:
| tool | what you do | what it tells you |
|---|---|---|
| linear probe | train a classifier on activations | is the property decodable here? |
| cross-class patching | replace one clip's activation tensor with another class's tensor | does this site causally matter? |
| direction patching | add or subtract one controlled direction | does this axis causally matter? |
These form a hierarchy.
A probe can say the information is present nearly everywhere. Cross-class patching can show only a few sites actually affect the verdict. Direction patching can then show that even at a causally important site, the probe's own preferred axis is not the axis the model responds to.
The controls also differ:
| instrument | control |
|---|---|
| probe | shuffled labels |
| cross-class patching | random tensor matched to donor mean/std |
| direction patching | random unit vector at matched norm |
Every one of these controls changed at least one conclusion in the project.
This result is on clean, in-domain audio. No attack is involved.
At AASIST's gat_S tap, define a simple class-mean direction:
d = μ_spoof − μ_bonafide
No training. Just average the activations for spoof clips, average the activations for bonafide clips, and subtract.
Now intervene on the model.
Take a bonafide clip and add d.
p(bonafide): 0.997 → 0.015
The model flips to “spoof.”
Take a spoof clip and subtract d.
p(bonafide): 0.107 → 0.885
The model flips to “bonafide.”
A same-norm random direction barely moves either result.
So d is not merely correlated with the class. It is causally effective in both directions.
Now train a logistic regression probe on the same activations and take its weight vector w.
The probe is excellent:
By the usual standards, this is a very strong probe.
Because logistic regression scores σ(w·z + b), w is the direction in activation space along which the probe's confidence rises fastest. If probe weights describe the model's own mechanism, pushing the model along w should matter.
It does not.
| bonafide clip pushed to α=3 | p(bonafide) |
|---|---|
along class-mean direction d |
0.033 |
along probe direction w |
0.997 |
| along random direction | 0.999 |
In this cell, the probe direction is causally inert.
The probe was not wrong about prediction. Prediction was the part that worked.
It was wrong as a description of the model's own computation.
A natural response is: perhaps w and d simply point in different directions, so compute their cosine.
For AASIST gat_S:
cos(w, d) = 0.391
Against a random-direction null of roughly 0.090 ± 0.069, this is z ≈ 4.4 and even exceeds the maximum of 200 random draws.
So the cosine test would tell you the two directions genuinely align.
The intervention still says the probe direction does nothing.
Across taps the cosine is unreliable in two threshold-independent ways:
gat_S and gat_T branches in the wrong causal order;gat_T, the same cosine corresponds to opposite answers depending on whether the intervention is sufficiency or necessity.A single geometric statistic cannot encode a variable it never sees.
The headline cell was too neat, so I ran the same intervention battery across both models, three admissible taps, and both arms where possible.
| model · tap · arm | d flips at |
w flips at |
random | verdict |
|---|---|---|---|---|
AASIST gat_S sufficiency |
2.12 | never | never | probe inert |
AASIST gat_T sufficiency |
1.05 | 2.66 | never | probe ~2.5× weaker |
AASIST embedding sufficiency |
0.68 | 1.31 | never | probe ~1.9× weaker |
SSL gat_T sufficiency |
1.26 | 2.29 | never | probe ~1.8× weaker |
SSL gat_T necessity |
0.80 | never | never | probe inert |
SSL gat_S |
never | never | never | no direction here |
SSL embedding |
0.66 / 0.33 | 1.58 / 1.23 | 2.26 / 1.70 | invalid: random flips too |
Every probe here is 98.8–99.8% accurate, with AUROC 0.9987–1.0000.
The conclusion I would publish now is weaker than my first one:
d beats w;That weaker result is also not new. Marks & Tegmark (2023) report that difference-in-means directions are more causally implicated than logistic-probe directions for truth representations in LLMs, and derive the relation between the two.
The mechanism is roughly:
w ≈ Σ⁻¹(μ₁ − μ₀)
The probe whitens the class-mean difference by feature covariance. That can improve classification while rotating the direction away from the axis the downstream computation actually uses.
What this project adds is a different regime — audio, graph attention, a 297K-parameter model — and a case where the probe is not merely weaker but indistinguishable from random under intervention.
My current rule is:
Use probes as detectors. Do not read probe weights as causal directions without an intervention.
So far this sounds mostly negative:
The next question is whether looking inside the model buys anything a benchmark number cannot.
Here it does.
Both models degrade when moved to a corpus they were not trained on. From the outside, the failures look similar: high error rates and lots of bonafide speech being rejected.
But “the model fails out of domain” is not yet a diagnosis. The failure can live in three different places, and those places have very different repair costs.
The model can fail at three different stages:
raw audio → [ representation ] → embedding(160) → [ Linear(160,2) → softmax ]
③ retrain ② refit readout
297 K / 318 M 161 effective params
→ p(bonafide) → threshold → verdict
① move threshold
1 number
The three repairs change progressively more of the system:
| failure site | what went wrong | repair | cost |
|---|---|---|---|
| ① threshold | the score still ranks the classes usefully, but the cut is misplaced | move the threshold | 1 number |
| ② readout weights | the embedding still contains useful class information, but the final linear layer weights it poorly for the new corpus | refit Linear(160,2) with the representation frozen |
161 effective parameters |
| ③ representation | class information has already degraded by the time it reaches the embedding | retrain the representation | 297 K / 318 M parameters |
All three can produce the same visible symptom: a bad error rate.
That is why EER or accuracy alone cannot tell you what to repair. A system that needs one threshold changed and a system whose representation has collapsed can both look like “the model fails cross-corpus.”
The two tests answer different questions.
Test 1 diagnoses where the information is lost. Test 2 measures what can actually be repaired cheaply.
They are complementary rather than redundant.
| Test 1: probe the embedding | Test 2: apply the cheap repairs | |
|---|---|---|
| question | did the class information survive the representation? | which downstream fix actually removes the errors? |
| what changes? | nothing in the model | threshold and then readout weights |
| type of evidence | diagnostic / interpretability | direct repair experiment |
| can distinguish | representation failure vs downstream failure | threshold vs readout-weight failure, and how much remains |
| cannot tell alone | threshold vs stale readout weights | why a residual failure is upstream unless we know what information reached the embedding |
The distinction matters.
Suppose the embedding still separates bonafide from spoof almost perfectly, but the deployed model performs badly. Then the representation has done its job: the information reached the boundary between the representation and the readout. The failure must be downstream.
But Test 1 alone cannot tell whether downstream means:
Both failures can coexist with a perfectly informative embedding.
That is what Test 2 resolves. First move only the threshold. Then refit only the linear readout. Because each intervention changes a different part of the pipeline, the amount of error recovered tells us which downstream component was actually broken.
Conversely, if Test 1 already shows that the embedding no longer separates the classes well, then no threshold or linear readout can fully recover information that never reached them. Test 2 can still recover whatever signal remains, but any substantial residual error points back upstream to the representation.
So the logic is:
Test 1: Is the information still present at the embedding?
│
├─ yes → failure is downstream
│ │
│ └─ Test 2 separates threshold vs readout weights
│
└─ no → representation has degraded
│
└─ Test 2 measures how much of the remaining error is still cheaply recoverable
I probe the 160-dimensional embedding, because it is exactly what the released classifier's final Linear(160,2) layer receives.
This tap is important. An earlier layer could contain useful information that the network later throws away. Probing the embedding gives the strictest possible question:
Given exactly the information available to the shipped readout, are bonafide and spoof still linearly separable?
Cross-corpus:
| AASIST | SSL-AASIST | |
|---|---|---|
| EER | 29.60% | 4.20% |
| bonafide called spoof | 70.2% | 57.6% |
| error at threshold 0.5 | 38.3% | 28.8% |
| embedding probe — in-domain | 1.000 | 0.999 |
| embedding probe — cross-corpus | 0.859 | 0.996 |
The in-domain probes are essentially perfect in both models, so the protocol itself is not the source of the gap.
Cross-corpus, the models are very different:
That immediately changes the diagnosis.
For SSL-AASIST, a full retrain should be suspicious: the information is still there. Something downstream is using it badly.
For AASIST, some retraining pressure is real: the downstream layers cannot recover information that the representation no longer provides.
But Test 1 still does not tell me whether SSL-AASIST's downstream problem is the threshold or the readout weights, nor how much of AASIST's remaining error is still cheap to fix.
That is Test 2.
Now I intervene on the two downstream components separately.
The first repair — move the threshold — is not a new anti-spoofing technique. Threshold-swept evaluation is already standard in this field. In particular, EER (equal error rate) evaluates the detector at the threshold where the false-accept and false-reject rates are equal, and EER is a standard metric reported for ASVspoof systems.
So the point of moving the threshold here is mainly diagnostic:
If choosing an appropriate threshold makes most of the errors disappear, then the model's score still ranks the two classes well; the deployed cut was simply in the wrong place.
I use calibration data to choose the threshold and then evaluate it on held-out test data. This avoids choosing a threshold on the same examples used to report its performance.
One terminology caveat: I do not mean that the EER threshold is universally the “best” deployment threshold. A real system may choose a different operating point depending on the relative costs of false accepts and false rejects. Here, the EER-style threshold sweep is useful because it demonstrates how much performance is available without changing the representation or readout weights.
The second repair asks a different question. Refitting the readout changes the scoring function itself — it changes how the 160 embedding dimensions are weighted. That can recover failures that no threshold move can fix.
Everything below is fitted on calibration data and scored on held-out test data.
| fix | what changes | AASIST | SSL-AASIST |
|---|---|---|---|
| deployed | nothing | 37.4% error | 28.7% error |
| ① move threshold | only where the final score is cut | 28.9% — 23% of errors removed | 4.2% — 85% removed |
| ② refit readout | how the 160 embedding dimensions are weighted | 23.0% — 39% removed | 3.0% — 90% removed |
These two interventions tell us different things.
A threshold cannot change the ordering of examples. It can only move the cut.
This is why threshold sweeping is such a useful diagnostic. If a model has poor accuracy at the shipped threshold but a low EER, the score ordering may still be good: the classes are largely in the right order, but the chosen cut no longer matches the shifted score distribution.
So when SSL-AASIST drops from 28.7% error to 4.2% after choosing the threshold on calibration data, that says the model was already ranking bonafide and spoof very well; its operating threshold was simply in the wrong place for the new corpus.
That removes 85% of its errors without touching a model weight. In this section I use that result to demonstrate the diagnosis — threshold placement rather than representation failure — rather than to propose a new way of choosing thresholds for deployment.
Changing the threshold still uses exactly the same scalar score. It cannot change how the 160 embedding dimensions contribute to that score.
Refitting Linear(160,2) can.
On AASIST:
The extra improvement means some information survived into the embedding but the shipped readout was weighting it poorly under the new corpus.
So AASIST has two downstream problems on top of its representation loss:
That remaining error is consistent with what Test 1 already told us: the embedding itself has degraded.
The distinction between the two repairs is therefore simple:
If the threshold fixes almost everything, the representation and ranking largely survived. If refitting the readout adds substantial recovery, the information survived but the old weights use it poorly. If large error remains after both, the missing information is upstream in the representation.
This is the diagnosis:
| Test 1: embedding information | Test 2: cheap repair | diagnosis | |
|---|---|---|---|
| SSL-AASIST | 0.996 AUROC — essentially intact | threshold alone removes 85% of errors; full readout only adds ~4% more | mostly a threshold problem |
| AASIST | 0.859 AUROC — degraded | threshold removes 23%; readout refit removes 39% total; 23.0% error remains | representation loss + stale readout + threshold shift |
This is why I need both tests.
Test 1 tells me where the information survives. Test 2 tells me what repair actually pays off.
Without Test 1, I could see that a threshold or readout refit helps, but I would not know whether the residual failure reflects a deeper representation problem.
Without Test 2, I could see that SSL-AASIST's embedding is healthy, but I could not tell whether the problem is one misplaced threshold or 161 stale readout parameters.
A benchmark number would have told me only that both models degraded.
The internal diagnosis says something much more actionable:
That is the point in this project where interpretability stops being descriptive and changes what I would actually do to the model.
EER is threshold-free in the sense that it assumes the operating threshold is placed appropriately. A released checkpoint using softmax argmax effectively uses 0.5.
So SSL-AASIST can have:
without contradiction.
The ranking is still excellent; the cut is in the wrong place.
On cross-corpus SSL-AASIST, the class distributions remain separated but both collapse toward zero. Moving the threshold to about 0.0003 lands back in the gap.
AASIST's distributions overlap, so no threshold can repair the representation.
AASIST cross-corpus has an upstream gat_S probe at 0.881 AUROC, higher than the embedding's 0.859.
It is tempting to probe the strongest tap and say the representation is better than it looks.
But the readout never sees gat_S.
The signal degrades:
gat_S 0.881 → embedding 0.859 → shipped readout 0.776
Those are two different failures:
0.881 → 0.859: information lost inside the representation;0.859 → 0.776: information reaches the readout but the readout uses it poorly.Probing gat_S would have suggested 48% of errors were cheaply recoverable. Probing the embedding — the only layer a cheap readout refit can actually access — gives the real answer: 39%.
So another rule:
Probe the layer your intervention or repair can actually reach, not the layer with the prettiest score.
One caveat: I did not run full retraining as rung ③. It is listed as the expensive next step after the cheap fixes, not as a measured recovery number.
Now the main methodological result.
I ran the same battery of nine questions on both models.
Each finding falls into one of four outcomes:
| verdict | meaning |
|---|---|
| ✅ transfers | same answer on both models |
| ◑ conditional | agrees in one condition, differs in another |
| ❌ inverts | opposite answers |
| ⊘ not askable | the question stops being meaningful |
Here is the final table:
| question | AASIST | SSL-AASIST | verdict | |
|---|---|---|---|---|
| H1 | does confidence know when the model is wrong? | yes in-domain | same | ✅ transfers |
| H2 | after attack flips the output, does class evidence remain inside? | yes in-domain, breaks cross-corpus | same pattern | ✅ transfers |
| H6 | is spoofness represented along a linear causal direction? | yes | yes | ✅ transfers |
| H7 | is bonafide speech fragile under attack? | fragile | fixed in-domain, fragile cross-corpus | ◑ conditional |
| H3 | which branch carries the verdict? | no strong preference | strongly temporal | ❌ inverts |
| H8 | how does the readout split its evidence? | averages + master dominate | maxima dominate | ❌ inverts |
| H9 | why does cross-corpus failure happen? | representation degraded | threshold misplaced | ❌ inverts |
| H4 | can an attacker route around the causal bottleneck? | askable | detector and causal tap coincide | ⊘ not askable |
| H5 | which frequencies carry spoof evidence? | answerable, hypothesis refuted | no frequency axis | ⊘ not askable |
Tally: 3 transfer · 1 conditional · 3 invert · 2 not askable.
The important point is not that the exact tally is low. Again, 3/9 is not a transfer rate.
The important point is that transfer fails in several qualitatively different ways:
And all three inversions are clean-data findings. This is not a story about adversarial examples making interpretability brittle.
After a successful attack flips the model's verdict to bonafide, a probe trained on clean activations can still identify the underlying spoof evidence:
enc4Cross-corpus, that retention decays with depth. On AASIST it falls from roughly 82% at the front-end to 9% at the embedding.
The pattern transfers even though the raw numbers differ.
“Adversarial-real” attacks push genuine bonafide speech into the spoof class.
In-domain, SSL-AASIST is much less fragile than AASIST.
Cross-corpus, both collapse to roughly 100% attack success.
So “SSL fixes bonafide fragility” is true only in-domain. The model improvement is real, but conditional.
Cross-class activation patching asks which site carries class evidence.
On clean in-domain audio:
gat_S |
gat_T |
|
|---|---|---|
| AASIST | 0.312 | 0.306 |
| SSL-AASIST | 0.008 | 0.250 |
AASIST has essentially no spectral/temporal preference. SSL-AASIST is strongly temporal.
These are control-adjusted effects. That control matters: on SSL gat_T, the raw patching effect is 0.895, but a matched random tensor already causes 0.645. Most of the raw effect is magnitude, not class structure.
Applying the matched-random-tensor control reduces the raw branch contrast from 128× to 31×.
The qualitative inversion survived.
I also re-paired every AASIST bonafide clip with a different spoof donor. The control-adjusted branch comparison barely moved, which supports interpreting this as class-level rather than donor-specific evidence.
This is the case I trust most because it does not depend on a probe or approximate causal estimator.
Both models feed a 160-dimensional embedding into the same-shaped linear readout. That embedding is five 32-dimensional blocks:
Because the readout is linear, the contribution of each block to the bonafide-vs-spoof logit gap decomposes exactly.
AASIST:
SSL-AASIST:
The absolute contributions move too, so this is not just a percentage reshuffle:
| block | AASIST | SSL-AASIST |
|---|---|---|
| total class gap | 20.46 | 18.60 |
| master contribution | 5.92 | 1.27 |
T_max contribution |
0.36 | 6.42 |
Within-model seed variation is tiny compared with the between-model shift.
Had I stopped at AASIST, I would have published something like:
“The master node carries 29% of the decision using 0.04% of the model's parameters.”
That sounds like an architectural insight.
On SSL-AASIST the same block contributes only 6.8%.
It was a fact about one trained model.
Both models reject large amounts of bonafide speech cross-corpus.
But AASIST's representation degrades while SSL-AASIST's ranking remains almost intact and its threshold is misplaced.
Same failure from outside. Opposite repair.
This is exactly the kind of conclusion that a single benchmark metric hides.
These are stronger than ordinary non-transfer.
H4 — can an attacker route around the causal site?
On AASIST, the monitor tap and causal tap are distinct, so an attacker can try to fool one while preserving the other.
On SSL-AASIST, the best detector and causal tap coincide at pool_T. There is nothing to route around. The question dissolves.
H5 — which frequencies carry spoof evidence?
AASIST has a real node→Hz mapping. The hypothesis was refuted: the best single frequency node recovers only about +0.038 against a full-tensor effect around 0.60–0.72.
SSL-AASIST has no frequency axis at all.
So there is no cross-model transfer verdict to assign.
One of the more surprising results came from attacking the monitor itself.
I jointly optimized the attack against the classifier and the monitor.
At the adaptive endpoint in the project summary:
So the monitor loses badly if you judge it by detection AUROC.
But forcing the attacker to hide from it costs 86% of the attack's success rate.
That suggests a different success criterion:
A monitor need not catch the attacker to be useful. It can be useful if evading it is expensive.
For adversarial oversight, I now care about both:
On SSL-AASIST, this exact routing opportunity is not available because the best detector and causal tap coincide. Again, the principle may generalize while the architectural opportunity does not.
Several conclusions in this project depend less on adding a new interpretability method than on asking whether the measurement itself is well-posed.
Four checks were especially important:
gat_T, not gat_S.These checks are mundane compared with activation patching or adversarial optimization, but they determine whether the more sophisticated measurements mean what they appear to mean.
Do not gate review purely on softmax confidence. It can be excellent in-domain and fail under shift by becoming confidently wrong.
Do not assume one monitor number tells you whether the monitor works. On AASIST, embedding scores 0.987 AUROC against pristine negatives, 0.851 against perturbed benign negatives, and 73% FAR if I reuse a threshold fitted on clean audio. At a fixed 5% FAR, it catches about 61% of attacks. Those are three different claims: separability, calibration, and operating point. Measure the one your deployment actually cares about.
Calibrate against audio processed the way your inputs will be processed. My MP3/resampling controls are already harsher than pristine audio, but they are still software transforms of studio recordings. A real phone call is a harder negative distribution than anything in this project.
Judge monitors by evasion cost as well as detection. My adaptive monitor's AUROC collapsed below chance, but hiding from it destroyed most of the attack's success.
Before retraining, test the cheap repairs. A threshold, stale readout weights, and representation loss all look like “high error” from outside.
Choose instrumentation points by causal relevance, not probe score.
Give causal claims matched random controls. Mine changed conclusions twice.
Run both sufficiency and necessity when possible. SSL gat_T gave different answers for the probe direction depending on the arm.
Do not read probe weights as causal directions. A probe can be nearly perfect and still point somewhere the model does not use.
Then run the battery again on another model.
Put attack success next to the perturbation control.
Do not fit a threshold on the rows you then score it on. Fit the threshold on calibration data and report its performance on held-out test data; otherwise the estimated repair can be optimistic by construction.
State the model and condition on every number. Four conditions × two models is enough to accidentally quote across cells.
Keep an append-only experiment log. It makes it possible to trace each headline number back to the experiment, control, and condition that produced it.
Several tempting claims would overstate the evidence.
Every attack here is white-box: full access to weights and gradients.
That is an upper bound on attacker capability, not a deployment prediction. Black-box transfer is the obvious missing experiment.
Audio anti-spoofing models being attackable is already known.
The contributions here are the energy-matched controls, the two-model transfer audit, the probe-vs-causal comparison, and the representation-vs-readout diagnosis.
XLS-R was pretrained on 436k hours including MLS, and ASVspoof5 bonafide speech is drawn from MLS English.
So SSL-AASIST's cross-corpus advantage may partly reflect pretraining overlap rather than clean generalization.
A better test is In-the-Wild, which uses found celebrity audio and avoids that overlap.
SSL-AASIST resists FGSM much better than AASIST while iterative PGD still reaches roughly 82–100% success.
That pattern is consistent with gradient masking, not genuine robustness.
Every clip in this project is studio-quality ASVspoof audio. Even the more realistic benign controls are software MP3 compression and resampling applied to studio recordings.
There is no telephony codec, microphone response, room acoustics, environmental noise, or packet loss.
So the monitor operating point — roughly 61% detection at 5% FAR for the best AASIST tap — should be treated as an upper bound on what I have established. Real deployment negatives are likely harder; this project does not measure by how much.
This limitation matters most for the monitoring results, somewhat for end-to-end detection performance, and less directly for the clean mechanistic findings in the probe and transfer sections.
“3 of 9 transferred” shows that transfer can fail under an unusually favorable comparison.
It does not estimate how often interpretability findings transfer in general.
AASIST's core results use three seeds. Several SSL causal analyses are still single-seed.
The effects are large, but effect size is not a substitute for actually running the seeds.
In rough order of how much each could change the conclusions:
pool_T is SSL-AASIST's best monitoring tap and also one of the most interesting causal sites, but its top-k node selection changes per clip, which blocks the current direction test.The specific numbers belong to two audio models.
The methodological lessons feel broader:
The result that changed my mind most was not that an attack worked or that one monitor metric looked bad.
It was that I could produce what looked like a crisp mechanistic explanation on one model, repeat the analysis on a closely related model, and watch the explanation invert.
That is the result I would most like other interpretability work to stress-test.
The experiments are complete for the two-model, two-corpus matrix used in this project.
The repository includes:
The AASIST arm runs in the main Python environment. SSL-AASIST depends on an older fairseq stack, so its feature extraction runs under Python 3.7 / Torch 1.8 and dumps a shared artifact schema for later analysis under the main environment.
On an RTX 3090, the measured forward cost is roughly:
Despite having about 1,067× more parameters, SSL-AASIST is only about 1.6× slower in the forward pass in this setup because XLS-R compresses the waveform to a much shorter frame sequence before the dense operations.
The attacks are standard white-box PGD against public academic checkpoints.
The repository ships code and aggregate results, but does not distribute the generated adversarial audio. Roughly 32 GB of attack waveforms are deliberately gitignored.
The actionable outputs are mostly defender-side: where monitoring fails, how much adaptive evasion costs, which internal diagnoses distinguish cheap fixes from retraining, and which interpretability claims fail to transfer.
Full code, artifacts, and append-only experiment log:
github.com/gavin-keli/deepfake-detector-audit
Thanks to BlueDot Impact and my sprint cohort.