Your Network Is a List of Pictures. You Can Edit It.

· 17 min read

#ml#kernels#interpretability#prototypes#continual-learning#machine-unlearning#yat#deep-learning

Part 3 of 12The Prototype Network
  1. 1What a Finite Kernel Buys an MLP
  2. 2Your Neuron Is a Direction. It Should Be a Picture.
  3. 3Your Network Is a List of Pictures. You Can Edit It.you are here
  4. 4You Only Have to Train the Features
  5. 5You Don't Even Have to Train the Features
  6. 6How Far Down Can You Build?
  7. 7When 80% Should Mean 80%
  8. 8A Risk Model That Names Its Reasons
  9. 9The White-Box Survival Model on Trial
  10. 10Your Network Is a Stack of Layers. It Could Be a Fixed Point.
  11. 11Edit One Operator, Edit Every Depth
  12. 12One Kernel, Fitted Twice
Runnable JAX companionEditing a Network by Hand, in JAX/Flax NNXPrefer to read the code? This post has a hands-on JAX / Flax NNX implementation.Open the JAX companion

Someone asks you to make a trained model forget one person: a court ordered it, or a user invoked their right to be forgotten. So you go looking for the place in the network that holds them, and there is no such place. What a model knows is smeared across all of its weights at once, every number leaning on every other, with nothing you can point to and pull out. The only exact fix is to delete the data and train the whole network over from nothing. Of every artifact in software, a neural network is the one you cannot open and edit. You can only grow a new one.

Now picture a different kind of network, one where each neuron is not a sliver of some shared tangle but a single picture, one image per unit. Stack those and the whole network is a list of pictures, and a list is something you edit by hand. Tell it to forget a class and you delete that class’s pictures; tell it to learn a new one and you paste a few in. No gradient steps either way, and you can diff the weights afterward to prove nothing else moved.

So the two operations that are supposed to be brutal come down to a delete and a paste: adding a class without wrecking the rest, the problem called catastrophic forgetting, and making a model genuinely forget, the one called machine unlearning that courts have started to ask about. They are hard in an ordinary network because of how it stores a class, and easy here because of how this one does. The previous post is where that began: swap a neuron’s activation for the Yat kernel and it stops being a direction and becomes a prototype, a point in input space, and on an image a literal picture. Every number below is from a real run (scripts/yat_editable_fmnist.py).

A network you edit instead of train

Why can you not just open an ordinary network and rewrite a class by hand? The obstacle is the neuron itself. A standard neuron stores a direction ww, and a direction is nothing you can point at: you cannot hand-write a useful one, read meaning off one, or edit anything by retyping it. Training is the only way in, since the weights mean nothing until gradient descent puts meaning there.

A Yat unit stores a prototype WuW_u instead, and scores an input by a kernel against it, ϕu(x)=(Wux+b)2/(xWu2+ε)\phi_u(x) = (W_u^\top x + b)^2 / (\lVert x - W_u\rVert^2 + \varepsilon). The prototype sits in the same space as the data, so you can point at it: on Fashion-MNIST it is a 28x28 picture of a piece of clothing. A classifier is a bank of these prototypes and a readout that records which class each one speaks for. Built by hand from k-means centroids, with no gradient steps at all, it reaches 79% on Fashion-MNIST.

Write that as vectors; the edits later are one line each off it. Stack the KK activations into ϕ(x)=(ϕ1(x),,ϕK(x))R0K\phi(x) = (\phi_1(x), \dots, \phi_K(x)) \in \mathbb{R}^K_{\ge 0}, and let the readout be a matrix A{0,1}K×CA \in \{0,1\}^{K \times C} with row uu one-hot at unit uu‘s class. The class scores are the readout applied to the activations,

s(x)=Aϕ(x)RC,sc(x)=u:class(u)=cϕu(x),y^(x)=argmaxcsc(x).s(x) = A^\top \phi(x) \in \mathbb{R}^C, \qquad s_c(x) = \sum_{u\,:\,\text{class}(u)=c} \phi_u(x), \qquad \hat y(x) = \arg\max_c\, s_c(x).

One note before the sum does any work. The structure of that formula, each class scored from its own block of rows and no others, is what this whole post exploits; the quoted accuracies, though, come from a sharper decision rule inside the same blocks: score class cc by its best-matching prototype, sc(x)=maxucϕu(x)s_c(x) = \max_{u \in c} \phi_u(x), the nearest-prototype readout (mode='max' in the script). The previous post measured the gap: the linear sum-vote reaches 68%, the per-class max 79%. Everything below, teaching by appending rows, forgetting by deleting them, the invariance of every untouched class, holds under either rule, because both read a class from its own rows alone; the prototypes enter one term each, and teaching adds terms while forgetting removes them.

First, though, how it decides. Pick an image below and the kernel against all 200 prototypes runs in your browser. Each atom is a prototype, brightening with resemblance; the readout carries those resemblances to the ten class outputs, and the loudest wins. The prediction is that vote, with nothing behind it.

Each class is one vector

Move one class, and the other nine cannot feel it. That is the property every edit in this post rides on, and it is one line of kernel algebra away. The theory is in the previous post: ϕu(x)=k(x,Wu)\phi_u(x) = k(x, W_u) is a positive-definite kernel with an RKHS feature map Φ\Phi, so ϕu(x)=Φ(x),Φ(Wu)H\phi_u(x) = \langle\Phi(x),\Phi(W_u)\rangle_{\mathcal H}, and the centers sit in input space, which is what makes them pictures. The line we need is what happens when the sum over a class slides inside the inner product,

sc(x)=ucΦ(x),Φ(Wu)H=Φ(x),μcH,μc:=ucΦ(Wu).s_c(x)=\sum_{u\in c}\langle\Phi(x),\Phi(W_u)\rangle_{\mathcal H}=\langle\Phi(x),\,\mu_c\rangle_{\mathcal H},\qquad \mu_c:=\sum_{u\in c}\Phi(W_u).

A class is now one vector μcH\mu_c\in\mathcal H, the mean of its prototypes in feature space, and the sum-vote network picks the class whose vector matches best, y^(x)=argmaxcΦ(x),μc\hat y(x)=\arg\max_c\langle\Phi(x),\mu_c\rangle, a Parzen-window vote (the nearest-prototype rule reads the same picture, just crediting the single closest Φ(Wu)\Phi(W_u) in the bundle instead of the whole bundle). Ten classes, ten independent vectors, each built from its own prototypes and nothing else. Edit one μc\mu_c and the other nine do not change. The rest of the post is watching that sentence happen.

The network is a landscape of wells

Everything so far has lived in a space with 784 axes, which is to say you cannot picture any of it. Here is the move that rescues the intuition, and it is not a metaphor I am reaching for; it is sitting in the formula. Look at the denominator, 1/(xWu2+ε)1 / (\lVert x - W_u\rVert^2 + \varepsilon). That is a softened inverse-square law, the exact shape of gravity and of electrostatics, and the ε\varepsilon is its softening length, the same constant an N-body simulation adds so the force stays finite when two bodies meet. So a prototype is a mass. It digs a well into the input space, and no matter how many dimensions that space has, you can now hold the whole thing in your head as one picture: a landscape of wells that things fall into.

The correspondence is exact enough to write down, term for term, and it is worth having in front of you for the rest of the post:

in the networkin the physical picture
prototype WuW_ua mass sitting in the space
activation ϕu(x)\phi_u(x)the pull you feel from that mass
ε\varepsilonthe N-body softening length
class score sc(x)s_c(x)the field of class cc‘s masses
classifying xxfalling into the deepest basin
teaching a classdropping in new masses, a well opens
forgetting a classremoving them, the basin caves in

A bank of prototypes is then a landscape of wells, one cluster per class, and the class score is its field: sc(x)=ucϕu(x)s_c(x) = \sum_{u\in c} \phi_u(x) sums class cc‘s wells the way a gravitational field sums the potentials of its masses (the nearest-prototype rule reads the same landscape by its single deepest well, which is why both rules tell the same story here). A point is classified by the deepest basin it can feel, y^(x)=argmaxcsc(x)\hat y(x) = \arg\max_c s_c(x), and the boundary is the watershed where two fields come out even, {x:sc(x)=sc(x)}\{x : s_c(x) = s_{c'}(x)\}. Far from every prototype the field stays bounded instead of blowing up, so a point that looks like nothing settles nowhere and the network can hold back. Drag the marker below across a ridge and its class flips.

The two edits ahead are moves on this landscape. Teaching drops a new mass and opens a basin where there was none. Forgetting takes a mass away; its basin caves in and the neighbours spread into exactly the ground it held, no further, which is what makes the forgetting exact. Fields add, so the landscape is the sum of its wells no matter the order they arrived, and teaching one class at a time ends where building all ten at once does. Underneath the vote, the teaching, the forgetting, and the order-independence sits one inverse-square law.

Teach it a class, no training

Give the network a hole, then watch how cheaply it fills. This hand-built classifier has only ever seen eight of the ten classes, twenty prototypes each for classes 0 through 7, and it has never laid eyes on a Bag or a Boot; on the classes it does know, it scores 77.8%. So how do you teach it the two it is missing?

The answer is a paste. Take twenty example images of Bag and twenty of Boot, drop them in as new prototypes, and give each a readout row naming its class. Forty pictures placed, no optimizer, no backward pass, no epochs.

The model now recognizes Bag at 95% and Boot at 94%, classes it had never encountered a moment ago. And the classes it already knew barely flinch: accuracy on classes 0 through 7 moves from 77.8% to 75.6%, a two-point dip that comes only from the new prototypes occasionally sitting closer to an old test image, not from anything being overwritten. Overall, across all ten classes, it scores 79.4%.

A model built on all ten classes from the start scores 79.4% too. Adding the two after the fact cost nothing, because for a list there is no “after the fact”: a prototype placed last behaves exactly like one placed first.

Why did nothing old move? One line of algebra. Teaching class cc appends rows (Wc,ec)(W_c, e_c) to (W,A)(W, A), each new readout row one-hot at cc. For any other class ccc' \ne c, the new units contribute Au,cϕu(x)=0A_{u,c'}\,\phi_u(x) = 0, so

sc(x)  is unchanged, exactly,sc(x)    sc(x)+unewϕu(x).s_{c'}(x) \;\text{is unchanged, exactly,} \qquad s_c(x) \;\mapsto\; s_c(x) + \sum_{u \in \text{new}} \phi_u(x).

Only the taught class’s score moves (under the nearest-prototype rule, replace that added sum with a max over old and new rows; every other class’s score is identical either way). An old image gets relabelled only if the new scs_c now beats its previous winner, never because its own class was corrupted underneath it, which is the two-point dip and not a point more. And neither a sum nor a max remembers the order its terms arrived in, so teaching one class at a time and building all ten at once give the identical score function. Order-independence is just addition commuting, which was the fields superposing seen from the other side.

Try it above: start with an empty memory that gets everything wrong, then teach one class and watch its test images turn green the instant its pictures are placed, the others untouched.

Make it forget, exactly

Now run it backwards. Take the full ten-class model and ask it to forget Sandals: not to score them worse, but to lose the capability, as if those examples had never been part of it.

What edit could possibly amount to erasure? The obvious one. Find the twenty prototypes that vote for Sandal, delete them, delete their readout rows. That is the entire procedure.

Sandal recall goes from 64% to 0%. The class is gone; nothing in the network resembles a sandal anymore, so nothing can be classified as one. And the other nine classes go from 81.1% to 81.3%, untouched, in fact a hair better, because the deleted prototypes are no longer around to occasionally steal a test image that belonged to someone else. The forgetting is exact and surgical. You removed precisely one capability and left the rest of the network bit-for-bit identical.

The partition makes that provable. For any surviving class ccc' \ne c, the score is built from class cc'‘s own rows, sc(x)=ucϕu(x)s_{c'}(x) = \sum_{u \in c'} \phi_u(x), or their max under the nearest-prototype rule, and neither ever named one of class cc‘s rows, so deleting them does nothing to it: scs_{c'} is the function it was, term for term, while scs_c empties out. The other nine are not approximately preserved, the way a fine-tuned or gradient-scrubbed model leaves them. They are identical, and you can diff the weight matrices to see it; the companion does exactly that, asserting every surviving row bit-for-bit equal to what it was before the edit. That is the line between approximate and exact unlearning: not “we lowered its influence and hope,” but “the rows are gone, check.”

Delete any class above and only its line drops; the other nine hold flat. That is the claim, on screen.

Why this is supposed to be hard

If you train networks for a living, both results are the kind you double-check. In an ordinary network they are expensive, and the second one is barely possible at all.

Teaching a trained network a new class usually means fine-tuning, and fine-tuning on the new class degrades the old ones. The phenomenon has a name, catastrophic forgetting, and it is old enough to have been described in 1989. An entire subfield, continual learning, exists to fight it with rehearsal buffers, regularizers that pin important weights in place, and dynamically grown sub-networks. The reason the fight is necessary is structural: in a network of directions, knowledge is smeared across shared weights, so every new gradient step writes over a little of everything that came before. There is no row you can point to that is the old class, so there is no way to protect it except indirectly.

Unlearning is worse. “Make the model forget these training examples” is a live research problem, machine unlearning, driven by privacy law and the right to be forgotten, and the baseline for doing it correctly is to throw the model away and retrain from scratch on the data minus the part you want gone. Everything cheaper is an approximation that you then have to audit, because the forgotten data left its fingerprints distributed across all the weights and you can never quite prove you wiped them.

Write the ordinary classifier’s score the same way and the reason shows. Its logit for class cc is zc(x)=wch(x)z_c(x) = w_c^\top h(x), with h(x)h(x) a representation every class shares. Class cc lives a little in its head wcw_c and mostly, diffusely, in the weights that build hh, which the other classes read from too. You cannot move cc without moving hh, and moving hh tilts every zcz_{c'} at once. The entanglement is not a training artifact; it is the data path. Set that beside sc(x)=ucϕu(x)s_c(x) = \sum_{u \in c} \phi_u(x), where class cc reaches only its own units: a shared h(x)h(x) against a partitioned ϕ(x)\phi(x).

The Yat network sidesteps both problems, then, not by being cleverer, but by storing knowledge in a form you can address. A class is not smeared across the weights; it is a contiguous set of prototypes. So protecting it during an edit is trivial (do not touch those rows) and erasing it is exact (delete exactly those rows, and provably nothing else carries the class). Continual learning and unlearning stop being algorithms you run and become slices you take.

The boundary, and where this goes

None of this is free in general. It is free here, on raw pixels, because the input space is the feature space. A prototype can be a legible, placeable, deletable picture only because what the kernel compares against lives where the data lives. Put the Yat kernel on top of learned features and a prototype becomes an exemplar in feature space, and those features still cost a training run; “no training” narrows to “no training of the head, given features.”

The narrowing is not a retreat, it is the real question. How much of a network can you construct instead of optimize, and how far down does the construction reach before you have to learn? On pixels, the whole classifier. On learned features, the whole classifier on top of a trained backbone, which is where adding and forgetting matter most anyway. That part is for next time. The smaller claim holds on its own: a network whose neurons are pictures is not a black box you fill by training. It is a document you write, and revise, by hand.


The prototype-network idea (“this looks like that”) is from Chen et al. (2019); Fashion-MNIST from Xiao et al. (2017); the Yat kernel from Bouhsine (2026). This is a follow-up to Your Neuron Is a Direction. It Should Be a Picture.

Cite as

Bouhsine, T. (). Your Network Is a List of Pictures. You Can Edit It.. Records of the !mmortal Data Scientist. https://tahabouhsine.com/blog/edit-a-network-by-hand/

BibTeX
@misc{bouhsine2026editanetworkbyhand,
  author       = {Bouhsine, Taha},
  title        = {Your Network Is a List of Pictures. You Can Edit It.},
  year         = {2026},
  month        = {jun},
  howpublished = {\url{https://tahabouhsine.com/blog/edit-a-network-by-hand/}},
  note         = {Blog post, Records of the !mmortal Data Scientist}
}

References

  1. Chen, C., Li, O., Tao, D., Barnett, A., Su, J., Rudin, C. (2019). This Looks Like That: Deep Learning for Interpretable Image Recognition. NeurIPS 2019.arXiv:1806.10574
  2. McCloskey, M., Cohen, N. J. (1989). Catastrophic Interference in Connectionist Networks: The Sequential Learning Problem. Psychology of Learning and Motivation 24.
  3. Bourtoule, L., Chandrasekaran, V., Choquette-Choo, C. A., Jia, H., Travers, A., Zhang, B., Lie, D., Papernot, N. (2021). Machine Unlearning. IEEE S&P 2021.arXiv:1912.03817
  4. Xiao, H., Rasul, K., Vollgraf, R. (2017). Fashion-MNIST: a Novel Image Dataset for Benchmarking Machine Learning Algorithms. arXiv:1708.07747
  5. Bouhsine, T. (2026). A Universal Reproducing Kernel Hilbert Space from Polynomial Alignment and IMQ Distance. arXiv:2605.03262