Visual walkthrough — Concept-based explanations
Step 1 — What is "activation space"?
WHAT. Pick one hidden layer inside the network, call it layer (the Greek letter ell, just a name for "which layer"). When you push an image through the net and pause at that layer, the layer emits a list of numbers. If the layer has neurons, that list is numbers long. We write it as one arrow (a vector) and call it
Every image becomes one point in a -dimensional space. We cannot draw 2048 dimensions, so every figure on this page draws just 2 of those neurons as the two axes — the picture that fits on paper. The logic is identical in high dimensions.
When we have several images and need to talk about "the activation of image number ," we hang a little label on top: means the activation vector produced by the -th image at layer . Same object as , just tagged with which image it came from.
WHY a vector and not a picture of pixels? Because the model's own understanding lives here, not in the pixels. Two images that look different (a tiger, a striped shirt) can land near each other in activation space if the model "thinks about them" the same way.
PICTURE. Each dot is one image's activation.

Step 2 — Two clouds: concept vs. random
WHAT. Gather two sets of images:
- (positive) — images that contain the concept, e.g. striped things.
- (negative/random) — ordinary images with no particular concept.
Feed all of them through, stop at layer , and drop every activation (from Step 1) as a dot. We label each dot:
Here (read "y-sub-i") is just a tag on dot number saying which cloud it belongs to.
WHY. If the model has an internal notion of "stripes," the dots should huddle together, separate from the dots. We are about to measure that separation.
PICTURE. Orange = striped (), gray = random ().

Step 3 — Slice the two clouds with a straight cut
WHAT. Draw the flat surface (a hyperplane — in 2D just a straight line) that best separates orange from gray. A line is described by the direction pointing across it (perpendicular to it). We find the best by minimizing a training loss over the labelled dots from Step 2:
Term by term:
- — the dot product of the direction with dot (the -th activation from Step 1). It measures how far along the dot sits. (Why a dot product? Because it collapses a whole vector down to one number: "which side of the line, and how far.")
- — the loss. Concretely, the standard choice (as in the original TCAV) is logistic (cross-entropy) loss: , where is the score and the tag. Notice what it does: when has the same sign as (correct side), is small and the loss is near ; when the signs disagree (wrong side), is large and the loss grows. Any loss with this "small when right, large when wrong, smooth" property works (hinge loss, used by a linear SVM, is another common choice).
- — "the that makes this smallest." (Not the min value; the winning direction.)
- — a regularization penalty. (lambda) is a small positive number you choose (typical scale to ). Its job: keep the entries of from blowing up. Larger → shorter, smoother that ignores noisy neurons but may under-fit; → no penalty, easy to over-fit. Since we only ever use the direction of , mainly controls how much noise the boundary is allowed to chase.
The winning direction, once we shrink it to length 1, is the Concept Activation Vector .
WHY a straight cut and not a curvy one? Because we want a single, clean direction to call "the striped direction." A curve has no one direction; a line does. That direction is the whole payoff.
PICTURE. The line separates the clouds; the red arrow points from gray into orange — "more striped this way."

Step 4 — What direction increases the class score?
WHAT. Separately, the network has an output number for "zebra," the logit (score for class , before the final softmax). Ask: if I could nudge the activation a tiny bit, which way makes grow fastest? That fastest-uphill direction is the gradient:
Term by term:
- (read "nabla", the upside-down triangle) — "collect the slope of with respect to every neuron."
- — a partial derivative: "if only neuron wiggles up a hair, how much does the zebra score move?" Positive = pushing that neuron up helps zebra.
WHY a gradient? Because we need a direction of steepest increase of the class score, and the gradient is exactly that — it is the arrow that answers "which way is uphill for zebra?" We get it for free by backpropagation, the same machinery that trains the net.
PICTURE. Blue arrow = gradient of the zebra logit at one zebra's activation dot; contour lines show the score climbing.

Step 5 — The key move: does concept-direction agree with uphill?
WHAT. Now put the two arrows in the same space:
- — the "more striped" direction (Step 3, red).
- — the "more zebra" direction (Step 4, blue).
Compare them with a dot product:
The dot product of two arrows equals (length)(length)(cosine of the angle between them). So its sign is the sign of that cosine:
- angle → arrows agree → → becoming more striped also makes it more zebra.
- angle → arrows oppose → → stripes push zebra score down.
- angle → → stripes are irrelevant here (the degenerate, on-the-fence case).
WHY the dot product and not, say, distance? Because we don't care how big either arrow is — we care whether pushing toward the concept helps or hurts the class. Only the angle answers that, and the dot product's sign reads the angle directly.
PICTURE. Three panels: agree (green, sharp angle), oppose (red, obtuse angle), perpendicular (gray, the zero case).

Step 6 — From one example to a score: vote and average
WHAT. One zebra could be a fluke, so test many. Let be the set of test images that belong to class (e.g. a batch of held-out zebra photos — importantly not the images used to fit in Step 3). For each image , mark a vote:
is the indicator: it turns a yes/no question into a /. Then average the votes:
The result is just the fraction of green votes over — a number between and .
WHY average and not sum? So the score is comparable across concepts and classes regardless of how many test images held — it's always a fraction.
PICTURE. A row of zebra dots, each with a tiny green/red mark; the fraction green = TCAV.

Step 7 — The degenerate case: why is "nothing", not "half"
WHAT. Take a random direction instead of a real concept — a pointing nowhere meaningful. In a high-dimensional space, a random arrow lands on either side of the gradient with roughly equal chance, so its vote is basically a coin flip and TCAV .
WHY this matters. A raw score of looks "high" but could be pure noise. So we run many random CAVs, collect their scores, and ask: is the real score an outlier? The p-value
counts how many random directions matched or beat the real one. Term by term: the numerator's "" and denominator's "" are a safety padding so is never exactly ; the sum tallies random scores that reach the real score. Small (say ) = the concept genuinely stands out.
PICTURE. Histogram of random-CAV scores clustered at ; the real striped score at sits far in the right tail.

The one-picture summary
Everything above is one pipeline: two clouds → a cutting line → its normal () → compare its angle to the class gradient → vote → average → sanity-check against random.

Recall Feynman retelling (plain words)
Deep inside the network, every picture becomes a dot in a big space of numbers. I collect a pile of striped pictures and a pile of random ones, and I slice between the two piles with a straight cut. The arrow that points straight across that cut, from random into striped, I name the "striped direction."
Separately, for a zebra picture, I ask the network: "which way should I nudge your inner numbers to make you more sure it's a zebra?" That's another arrow — the uphill-for-zebra direction.
Then the whole trick is just comparing two arrows. If the striped direction and the more-zebra direction point roughly the same way (angle under 90°), then stripes help the zebra verdict — I score a green vote. I do this for a hundred fresh zebras (not the ones I built the striped direction from) and count the greens. Say 87 out of 100 → score 0.87.
But maybe any random arrow scores high by luck. So I repeat with a bunch of nonsense directions. They average around 0.5 — a coin flip. My real 0.87 is way out in the tail, so I trust it: the network really leans on stripes to call a zebra a zebra.
Recall Check yourself
Why do we take the sign of the dot product rather than its size? ::: Because we only care whether the concept helps or hurts the class score, which is the angle between the arrows; size (lengths of the arrows) is irrelevant to that yes/no. What does TCAV mean? ::: The concept behaves like a random direction — no consistent effect on the class. It is the "nothing happening" baseline, not "half important." Why must and the CAV-training set be disjoint? ::: Otherwise you fit and evaluate the concept direction on the same points, so a lucky over-fit boundary inflates the score; a held-out split keeps the test honest. What breaks if you skip the random-CAV test? ::: A noisy score like 0.65 could be pure high-dimensional chance; without the random baseline and p-value you cannot tell signal from noise.
Connections
- Feature Attribution Methods — attribution finds uphill directions in input space; TCAV finds them in concept space.
- Probing Classifiers — Step 3's linear cut is exactly a probe; TCAV then adds Steps 4–6 to test usage, not just encoding.
- Layer-wise Relevance Propagation — an alternative way to score influence, traced to inputs rather than concepts.
- Model Editing — once is known, you can ablate that direction to remove a concept's influence.
- Adversarial Examples — the same gradient of that TCAV uses is what adversarial attacks exploit.