Repository navigation
Add GELU, SiLU and Mish activations - #9
Merged
Merged
Conversation
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR adds 3 activations: GELU, SiLU (also named Swish), and Mish. Each one is an
Activationvariant and a standalone layer.Dense, all 10 convolution layers,SimpleRNN,LSTM, andGRUaccept them.Why the activation contract changes
Before this PR,
Activation::backwardread the activated outputaalone. The derivative of GELU, SiLU, and Mish has no closed form ina, because these functions have the shapea = z * g(z). They need the pre-activationz.Activation::saves()returns anActivationInput, which names the tensor that the backward pass reads. It isPreActivationfor the 3 new variants andOutputfor the 12 others.Activation::forward_train(z)returns the output and anActivationCache. The cache holds a copy of the output, orzitself.Activation::backward(&cache, &grad)returnsError::InvalidInputfor a cache that holds the other tensor. A wrong tensor therefore gives an error, not a wrong gradient.Changes
Activation::GELU { approximate }: the exact form useserfcffromlibm, so the negative tail keeps its precision. The tanh approximation usesx * sigmoid(2u), which does not cancel in the negative tail.Activation::SiLUandActivation::Mish.GELU::new()gives the exact form, andwith_approximate(true)selects the tanh approximation. The other 2 layers areSiLU::new()andMish::new().ActivationCachein place of the activated output. The fused ReLU path ofDenseandSimpleRNNstays.RnnCell::RECORD_SLOTSis now the methodrecord_slots().SimpleRNNrecordszfor each timestep with the 3 new activations.LSTMandGRUrecord the candidate pre-activation in place of the candidate.Example
Breaking changes
Activation::backwardtakes&ActivationCachein place of the activated output tensor. Get the cache fromActivation::forward_train(z).Activation::backwardreturnsError::ShapeMismatchfor a gradient of another shape. Before, most variants panicked.Denseapplies 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.