Skip to content

Check the MLP layers against numpy goldens end to end - #355

Open
Thiago316316 wants to merge 1 commit into
kmolan:mainfrom
Thiago316316:fix/83-mlp-qa-fixture
Open

Thiago316316 wants to merge 1 commit into
kmolan:mainfrom
Thiago316316:fix/83-mlp-qa-fixture

Conversation

@Thiago316316

Copy link
Copy Markdown
Contributor

What & why

Adds a numpy generator and two fixtures. policy_22x64x64x4 is a quadrotor controller's shape (22 observations in, two 64-wide rectified hidden layers, 4 rotor thrusts out ) with its 5,892 parameters sampled from a fixed seed, its eight observations, and the goldens for both hidden layers as well as the action. Storing the hidden activations turns "the actions are wrong" into "layer 2 is wrong, layer 1 was fine". Eight observations rather than one so the batch drives several distinct activation patterns instead of a single path through the rectifiers.

issue #83

Checklist

  • cargo test + cargo clippy --all-targets clean locally
  • New public APIs have a doc example
  • No unwrap/expect/panic on library paths (typed errors instead)

The layer and cursor types landed with unit tests that check their own
arithmetic. Nothing yet ran a whole policy and compared the answer with an
independent implementation, so a shape or ordering mistake that is consistent
across the crate would pass.

Adds a numpy generator and two fixtures. `policy_22x64x64x4` is a quadrotor
controller's shape — 22 observations in, two 64-wide rectified hidden layers,
4 rotor thrusts out — with its 5,892 parameters sampled from a fixed seed, its
eight observations, and the goldens for both hidden layers as well as the
action. Storing the hidden activations turns "the actions are wrong" into
"layer 2 is wrong, layer 1 was fine". Eight observations rather than one so the
batch drives several distinct activation patterns instead of a single path
through the rectifiers.

`activations` pins each nonlinearity at zero, at an ordinary value, and where
`Tanh` saturates, which is where a hand-rolled approximation would drift.

The test walks the flat export with `ParameterCursor` and asserts the buffer
ends empty: each layer reads correctly on its own even when a width is
mis-declared, so only the total catches it. It runs generic over the scalar,
so the f32 pass walks the same source rather than a transcription that could
drift, and narrows once on load the way an embedded caller would. The f32 band
is 1e-5 rather than the crate's usual 1e-3: a forward pass is only multiplies
and adds, so single precision sits within about 1e-6 of the f64 golden, and a
looser bound would pass a regression a thousand times larger than anything the
arithmetic can produce.

@Thiago316316 (kmolan#83)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant