An autoencoder has been trained on small black-and-white sketches. Encode a sketch of a circle and you get one code; encode a sketch of a square and you get another. The lesson's experiment is to mix those two codes by a sliding amount and decode every mixture, producing a strip of frames that morphs from one sketch into the other.
The decoder here is a single layer. It multiplies the code by a weight matrix, adds a bias, and replaces every negative result with :
Task: write latent_walk(code_a, code_b, weights, bias, points), returning the decoded frames along the walk as a list of lists, every value rounded to 4 decimal places.
points is the number of frames, at least . The mixing amounts are evenly spaced from to inclusive, so the first frame is the decoding of code_a and the last is the decoding of code_b.code_a and is code_b.weights has one row per output value and one column per code entry; bias has one entry per output value.Worked through, latent_walk([1.0], [3.0], [[1.0], [-1.0]], [0.0, 2.0], 3):
| code | before clipping | returned frame | ||
|---|---|---|---|---|
| 0 | [1.0, 1.0] | |||
| 1 | [2.0, 0.0] | |||
| 2 | [3.0, 0.0] |
so the function returns [[1.0, 1.0], [2.0, 0.0], [3.0, 0.0]].
Only the two end frames correspond to sketches anyone actually drew. Every frame in between comes from a code no training input was ever encoded to, which is exactly why a walk like this is the standard way to find out what a decoder learned.