Run a learned MLP policy forward without copying its parameters - #340
Run a learned MLP policy forward without copying its parameters#340Thiago316316 wants to merge 5 commits into
Conversation
A trained policy reaches a robot as one flat block of numbers. Two hidden layers 64 units wide over a 22-component observation come to about 5,900 of them, some 23 KB as `f32`, against the 64 KB of RAM a small Cortex-M has in total. Owning those weights would copy the block onto the stack every control cycle. `Layer` holds a `MatrixView` of its weights and a `VectorView` of its biases instead, so the coefficients are read where they were stored. `forward` writes only the activations, `OUTPUT` of them rather than `OUTPUT`x`INPUT`. `Activation` carries the scalar nonlinearity as an enum rather than a `fn` pointer, so the choice is inlinable and a layer stays inspectable; it is `#[non_exhaustive]`, leaving room for more. Widths are const parameters, so chaining a layer that produces three values into one that expects four fails to build rather than at runtime. Nothing allocates and nothing panics, so it runs under `no_std`. Inference only. Training belongs on a machine with room for it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The overview ran three long paragraphs before the example, restating in prose what the example shows. Cut to what a reader cannot get from the code: what the layers do, why the parameters are borrowed, and what the const widths buy. The links go with it. `cargo doc` denies warnings in CI, and rustdoc counts a link whose label already names a path in scope as a redundant explicit target. Both view types are imported here, so the bare labels resolve to the same pages the spelled-out paths did. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
a38ddda to
6a32e97
Compare
|
@Thiago316316 please resolve conflicts and update to main |
|
hi @kmolan one of the CI checks got stuck, please can you help me? |
| - [Kinematics](https://github.com/kmolan/multicalc-rust/blob/main/crates/multicalc/tutorials/kinematics.md): `KinematicTree` for revolute/prismatic/continuous/fixed/floating chains and forward and inverse kinematics, generic over the scalar with autodiff, built by hand or read from an MJCF or URDF file; a damped-least-squares SE(3) pose solver with joint limits and null-space redundancy resolution. | ||
| - [Collision checking](https://github.com/kmolan/multicalc-rust/blob/main/crates/multicalc/tutorials/kinematics.md#collision-checking): `CollisionQuery` for sphere/capsule proximity — primitives on tree frames against each other and against world-fixed obstacles, with pair exclusions and fixed capacities. | ||
| - [Motion](https://github.com/kmolan/multicalc-rust/blob/main/crates/multicalc/tutorials/motion.md): `PolylinePath` for waypoint paths with arc-length, closest-point, and lookahead queries, `MinimumSnapPlanner` for the smoothest trajectory through them, and `MotionProfilePlanner` for jerk-limited point-to-point moves with multi-axis synchronization. | ||
| - [Mapping](https://github.com/kmolan/multicalc-rust/blob/main/crates/multicalc/tutorials/mapping.md): 2D `OccupancyGrid` and `ScanGeometry` |
There was a problem hiding this comment.
There are two "mapping" entries here. Likely a mistake during merge.
edit: I am seeing similar in other readme in this PR with same mistake
There was a problem hiding this comment.
removed and checked properly.
| /// assert_eq!(output.forward(hidden.view()).unwrap().into_array(), [4.0]); | ||
| /// ``` | ||
| #[inline] | ||
| pub fn forward( |
There was a problem hiding this comment.
is it even possible for this to return an Error? Looks like it always succeeds.
There was a problem hiding this comment.
edit: Here and in other functions in the Pr, consider applying #[must_use] wherever possible.
There was a problem hiding this comment.
Result<Vector<OUTPUT, T>, LinalgError> now is just Vector<OUTPUT, T>: the approuch was to use conditional iterators methods with a branch that leads to zero but is never used, then the compiler will remove it.
applying #[must_use] : these function alredy has derived must_use and clippy warns about the redundance, then the flag -D warnings turns into CI failure, so it will stay the same.
| pub fn apply<T: Numeric>(self, value: T) -> T { | ||
| match self { | ||
| Activation::Relu => { | ||
| if value > T::ZERO { |
There was a problem hiding this comment.
what happens if value is NaN? Can it ever be NaN? What is our NaN handling strategy for this module?
There was a problem hiding this comment.
did some alterations on its handled:
/// assert_eq!(layer.forward_checked(spoiled.view()), Err(LinalgError::NonFinite));
/// // Unchecked, the rectifier turns that NaN into an ordinary 0.0.
/// assert_eq!(layer.forward(spoiled.view()).into_array(), [0.0]);
| - [Collision checking](https://github.com/kmolan/multicalc-rust/blob/main/crates/multicalc/tutorials/kinematics.md#collision-checking): `CollisionQuery` for sphere/capsule proximity — primitives on tree frames against each other and against world-fixed obstacles, with pair exclusions and fixed capacities. | ||
| - [Motion](https://github.com/kmolan/multicalc-rust/blob/main/crates/multicalc/tutorials/motion.md): `PolylinePath` for waypoint paths with arc-length, closest-point, and lookahead queries, `MinimumSnapPlanner` for the smoothest trajectory through them, and `MotionProfilePlanner` for jerk-limited point-to-point moves with multi-axis synchronization. | ||
| - [Mapping](https://github.com/kmolan/multicalc-rust/blob/main/crates/multicalc/tutorials/mapping.md): 2D `OccupancyGrid` and `ScanGeometry` | ||
| - [MLP inference](https://github.com/kmolan/multicalc-rust/blob/main/crates/multicalc/tutorials/mlp-inference.md): `Layer` and `Activation` run a trained multi-layer-perceptron policy forward on the robot — the weights and biases stay in flash behind a `MatrixView` / `VectorView` and are never copied onto the stack, and layer widths are const parameters, so a mismatched chain is a build error. |
There was a problem hiding this comment.
`Layer` and `Activation` run a trained MLP policy forward over borrowed `MatrixView`/`VectorView` parameters, in a const no-copy no-alloc environment.There was a problem hiding this comment.
make sure to also change the other readme
…behaviour, handling NaN following kmolan#338 pattern
|
Also: test (1.85) is required by branch protection, but no job produces that name any more, #339 renamed the matrix entry to test (1.92) along with the MSRV. It sits at "Expected — waiting for status to be reported" indefinitely, on every PR into main. Fix is Settings → Branches → main → required status checks: drop test (1.85), add test (1.92). |
What & why
A trained policy reaches a robot as one flat block of numbers. Two hidden layers 64 units wide over a 22-component observation come to about 5,900 of them, some 23 KB as
f32, against the 64 KB of RAM a small Cortex-M has in total.Layerholds aMatrixViewof its weights and aVectorViewof its biases instead, so the coefficients are read where they were stored.forwardwrites only the activations,OUTPUTof them rather thanOUTPUTxINPUT.Activationcarries the scalar nonlinearity as an enum rather than afnpointer, so the choice is inlinable and a layer stays inspectable; it is#[non_exhaustive], leaving room for more.Widths are const parameters, so chaining a layer that produces three values into one that expects four fails to build rather than at runtime. Nothing allocates and nothing panics, so it runs under
no_std.issue #83
Checklist
cargo test+cargo clippy --all-targetsclean locallyunwrap/expect/panicon library paths (typed errors instead)