Activation Function — Machine Learning/Neural Networks
Machine_Learning/Neural_Networks/Activation_Function · 1 input / 1 output port(s) at insert · exports to Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text
Description#
The block's own DESCRIPTION_HTML, rendered verbatim — the same text the config dialog's info panel and the library navigator show. Fix a wrong sentence in the block's .cpp (R-D9), never here.
Activation Function
Machine Learning / Neural Networks
Applies one elementwise nonlinearity to every entry of the input, with no change of shape. This is the activation as its own node, for a graph that places it between layers rather than inside them – a residual branch that adds before activating, layers exported unactivated from the framework, or simply a network you would rather read off the canvas.
The Dense Layer block carries four activations internally; use those when the activation belongs to the layer, and this block when it does not.
Ports
- u – the input, any size [r,c]. The function is applied to each entry independently.
- Output – y, the same [r,c]: an elementwise map never changes the signal's dimensions.
Parameters
- Activation – which function to apply:
- ReLU – max(0, x). The default, and the usual hidden-layer choice.
- LeakyReLU – x for x > 0, Leaky Slope·x otherwise; keeps a small gradient on the negative side.
- ELU – x for x > 0, ELU Alpha·(ex − 1) otherwise; saturates smoothly at −alpha instead of at 0.
- Tanh – squashes to (−1, 1).
- Sigmoid – 1 ÷ (1 + e−x), squashes to (0, 1).
- Softplus – ln(1 + ex), a smooth ReLU.
- SiLU – x · sigmoid(x), also called swish.
- GELU – 0.5·x·(1 + tanh(√(2/π)·(x + 0.044715·x³))). See the Notes: this is the tanh approximation, deliberately.
- Leaky Slope – the negative-side slope used by LeakyReLU
only, and ignored by every other setting. Default 0.01, PyTorch's
negative_slope. - ELU Alpha – the saturation level used by ELU only, and
ignored by every other setting. Default 1.0, PyTorch's
alpha. - Sampling Time (s) – zero or less inherits the solver's rate; a positive value runs the block at that period.
Code export
All ten targets: Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog and PLC Structured Text. The chosen activation is baked into the body at export time – it is structural, not something to retune on the target – and so are the two slope constants.
The three HDL targets are simulation-only: they carry the
function in real arithmetic and quantize only at the port boundary.
Six of the eight activations are transcendental and have no place in a Q16.16
datapath; ReLU and LeakyReLU alone would be synthesizable, and a block whose
synthesizability changed with a combo value would be worse than one that is
honest about the whole of itself.
PLC Structured Text has no TANH, so Tanh and GELU are emitted through
2 ÷ (1 + EXP(−2z)) − 1, which is the same
function written in terms of EXP alone.
Simulink bridge
None. Simulink has no single elementwise-activation block to map to:
its Deep Learning blocks take a trained network object, and the nearest
primitives (Saturation, Math Function,
Trigonometric Function) each cover one of these eight at best and
none of the others, so no ParamRule could carry the combo across.
The bridge reports the block rather than dropping it silently, and it has
no parity testbench, which is the documented consequence of
Support::None rather than a gap. Code export verification still
covers it across all ten languages.
Notes
- Algebraic and stateless: the output depends only on the current input, so the block cannot break an algebraic loop.
- Nonlinear, and deliberately carries no state space – every one of the eight is nonlinear, so no A/B/C/D describes it and model reduction correctly refuses the block.
- GELU is the tanh approximation
(
nn.GELU(approximate='tanh')), not the exact 0.5·x·(1 + erf(x/√2)). This is a portability decision:erfexists in none of VHDL, Verilog, SystemVerilog or IEC 61131-3, so the exact form could not be exported to four of the ten targets at all. The two differ by up to about 1e-3 of the output; if your trained network used the exact form and that matters, place the difference in your error budget rather than assuming these agree. - Every activation is written in an overflow-safe form – the exponent argument is never positive in ELU or Softplus – so a large input saturates rather than producing an infinity or a NaN.
Code facts#
| Fact | Value |
|---|---|
| registered type | Machine_Learning/Neural_Networks/Activation_Function |
| family | Machine_Learning/Neural_Networks |
| solver environment class | ICoreBlock_0_Machine_Learning_1_Neural_Networks_2_Activation_Function |
| source | src/ICoreSDK/ICoreBlockLibrary/Blocks/Machine_Learning/Neural_Networks/Activation_Function/ICoreBlock_0_Machine_Learning_1_Neural_Networks_2_Activation_Function.cpp |
| header | src/ICoreSDK/ICoreBlockLibrary/Blocks/Machine_Learning/Neural_Networks/Activation_Function/ICoreBlock_0_Machine_Learning_1_Neural_Networks_2_Activation_Function.h |
| default size on canvas | 110 × 80 px |
| ports at insert | 1 in, 1 out |
| code generators implemented | Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text |
Ports#
| # | Direction | Signal type | Description label |
|---|---|---|---|
| 1 | in | ICoreDouble | u |
| 2 | out | ICoreDouble | y |
Ports the constructor creates. A block whose port list changes with its configuration adds or removes ports at load time; the count above is the one a freshly inserted block has.
Configuration variables#
| Config variable | Default | Simulink parameter |
|---|---|---|
Activation | ReLU%~%LeakyReLU%~%ELU%~%Tanh%~%Sigmoid%~%Softplus%~%SiLU… | — |
Leaky Slope | 0.01 | — |
ELU Alpha | 1.0 | — |
Every block also carries Sampling Time (s) from ICoreBlockSolverEnvironment: zero or less inherits the solver's rate, a positive value runs the block at that period.
Simulink bridge#
| support | Support::None |
| Simulink path | — |
| port-count rule | PortsParam::None |
SampleTime parameter | yes |
Caveat (shown to the user): no Simulink equivalent: its Deep Learning blocks take a trained network OBJECT, and no primitive carries an eight-way elementwise activation -- Saturation, Math Function and Trigonometric Function each cover at most one of these and none of the rest, so there is no parameter this combo could map onto
Catalog contract: src/ICoreSDK/ICoreCoder/ICoreCommandSystem/SimulinkBridge/ICoreSimulinkBlockCatalog.h
Description vs code#
The lists agree. check_block_descriptions.py finds no disagreement between the description's Ports, Parameters, Code export and Simulink bridge lists and the code's.
The verdict above is
tools/docs/check_block_descriptions.py(P7.1), which compares LISTS. It cannot read a sentence: "stateless" on a block with a state, an initial-value semantic the recursion does not implement, a "not synthesizable" caveat the HDL banner contradicts. That is the agent audit (P7.3) on BLOCK_DESCRIPTION_AUDIT.md, and this tool's green is not a substitute for one.
File banner (developer view)#
The top comment of the block's .cpp — the maths, the realization and the export strategy, addressed to whoever changes it. It must not contradict the description above (P7.5).
Activation Function — one elementwise nonlinearity, eight of them, as its own block Every activation below is written in an OVERFLOW-SAFE, mostly branchless form, and the same form in all ten backends. That is worth stating because the obvious spellings are not safe:
- ELU as
x > 0 ? x : a*(exp(x)-1)is fine with a real branch, but the vectorizedspellings (numpy's where, MATLAB's masking) evaluate BOTH sides, and exp() of a large positive x is +Inf -- which multiplied by the zero mask is NaN, not the value it replaced. Written as
max(x,0) + a*(exp(min(x,0)) - 1)it is exact and can never overflow, because the exponent argument is never positive.
- Softplus as
log(1 + exp(x))overflows to +Inf for x beyond ~709 and returns Inf wherethe true answer is x.
max(x,0) + log(1 + exp(-|x|))is the standard stable identity and is what all ten emit.
- ReLU and LeakyReLU are written with abs() in the HDL bodies -- (x+|x|)/2 and its leaky
generalization -- because a VHDL-2008 conditional expression is NOT a primary and will not parse inside a block body's expression.
The three HDL targets are SIMULATION-ONLY
realarithmetic, as with the rest of this family: six of the eight activations are transcendental, and a block whose synthesizability depended on which combo value you picked would be worse than one that says so about the whole of itself.
Sample results#
| t | in ICoreDouble-Out-0 | out ICoreDouble-Out-0 |
|---|---|---|
| 0 | -2 | 0 |
| 0.4 | 0.5 | 0.5 |
| 0.8 | -2 | 0 |
| 1.2 | 0.5 | 0.5 |
| 1.6 | -2 | 0 |
| 2 | 0.5 | 0.5 |
| 2.4 | -2 | 0 |
| 2.8 | 0.5 | 0.5 |
| 3.2 | -2 | 0 |
| 3.6 | 0.5 | 0.5 |
| 4 | -2 | 0 |
| 4.4 | 0.5 | 0.5 |
| 4.8 | -2 | 0 |
| 5.2 | 0.5 | 0.5 |
Every 4th of 60 samples, from the table stimulus.
The same rig also ran:
| Stimulus | What it is | Output range |
|---|---|---|
impulse | Impulse: one sample of 1 at k = 5, 0 elsewhere (Repeating Sequence Stair) | 0 … 1 |
ramp | Ramp: slope 1 from t = 0 | 0 … 5.8 |
sine | Sine Wave: amplitude 1, 2 rad/s, no phase, no bias | 0 … 0.9996 |
step | Step: 0 -> 1 at t = 1 s | 0 … 1 |
Plotted: table — Repeating Sequence Stair: [-2 -1 -0.5 0 0.5 1 2 3], one entry per sample
Category static · sample time 0.1 · 60 steps · commit ccf005c8 · produced by docsSample --out <folder> --steps 60 · data docs/generated/samples/Machine_Learning__Neural_Networks__Activation_Function.json · the SVG is generated from those numbers by tools/docs/plot_svg.py, so it is a run and not a drawing (R-D10).