Skip to content

Add GELU, SiLU and Mish activations - #9

Merged
SomeB1oody merged 1 commit into
masterfrom
feat/preactivation-activations
Oct 7, 2026
Merged

SomeB1oody merged 1 commit into
masterfrom
feat/preactivation-activations

Conversation

@SomeB1oody

@SomeB1oody SomeB1oody commented Oct 7, 2026 •

Copy link
Copy Markdown
Owner

Summary

This PR adds 3 activations: GELU, SiLU (also named Swish), and Mish. Each one is an Activation variant and a standalone layer. Dense, all 10 convolution layers, SimpleRNN, LSTM, and GRU accept them.

Why the activation contract changes

Before this PR, Activation::backward read the activated output a alone. The derivative of GELU, SiLU, and Mish has no closed form in a, because these functions have the shape a = z * g(z). They need the pre-activation z.

  • Activation::saves() returns an ActivationInput, which names the tensor that the backward pass reads. It is PreActivation for the 3 new variants and Output for the 12 others.
  • Activation::forward_train(z) returns the output and an ActivationCache. The cache holds a copy of the output, or z itself.
  • Activation::backward(&cache, &grad) returns Error::InvalidInput for a cache that holds the other tensor. A wrong tensor therefore gives an error, not a wrong gradient.
  • A host layer still caches 1 activation tensor. An inference pass makes no cache and no copy.

Changes

  • Activations.
    • Activation::GELU { approximate }: the exact form uses erfcf from libm, so the negative tail keeps its precision. The tanh approximation uses x * sigmoid(2u), which does not cancel in the negative tail.
    • Activation::SiLU and Activation::Mish.
  • Standalone layers. GELU::new() gives the exact form, and with_approximate(true) selects the tanh approximation. The other 2 layers are SiLU::new() and Mish::new().
  • Host layers. Each host layer caches an ActivationCache in place of the activated output. The fused ReLU path of Dense and SimpleRNN stays.
  • Recurrent layers. RnnCell::RECORD_SLOTS is now the method record_slots(). SimpleRNN records z for each timestep with the 3 new activations. LSTM and GRU record the candidate pre-activation in place of the candidate.
  • Docs. The guide (chapters 1.5, 3.2, 3.7, and 6.2, in English and Chinese) and the CHANGELOG are updated.

Example

use rustyml::neural_network::layers::activation::GELU;
use rustyml::neural_network::layers::{Activation, Dense};

let exact = Dense::new(64, Activation::GELU { approximate: false }).unwrap();
let tanh = Dense::new(64, GELU::new().with_approximate(true)).unwrap();
let silu = Dense::new(64, Activation::SiLU).unwrap();

Breaking changes

  • Activation::backward takes &ActivationCache in place of the activated output tensor. Get the cache from Activation::forward_train(z).
  • Activation::backward returns Error::ShapeMismatch for a gradient of another shape. Before, most variants panicked.
  • Dense applies the activation to the output at its restored rank, not to the folded rank-2 matrix. The result is the same, because an embedded Softmax accepts only axis -1.

The derivative of GELU, SiLU and Mish has no closed form in the
activated output. The backward pass of an activation now reads an
ActivationCache. The cache holds the output or the pre-activation, as
Activation::saves names. Activation::forward_train makes the cache, and
Activation::backward refuses a cache of the other kind. A host layer
still caches 1 tensor.

Dense, all convolution layers, SimpleRNN, LSTM and GRU accept the 3
new activations. GELU, SiLU and Mish are also standalone layers. Exact
GELU uses erfc from libm, which keeps the precision of the negative
tail.

Breaking: Activation::backward takes &ActivationCache in place of the
activated output.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@SomeB1oody
SomeB1oody merged commit f0e56e8 into master Oct 7, 2026
4 checks passed
@SomeB1oody
SomeB1oody deleted the feat/preactivation-activations branch October 7, 2026 17:39
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