Function arm_hard_swish_f32¶
Defined in File arm_nnfunctions_flt.h
Function Documentation¶
-
arm_cmsis_nn_status arm_hard_swish_f32(const float32_t *input, float32_t *output, int32_t size)¶
Hard swish activation for float32 data.
Computes output[i] = input[i] * min(max(input[i] + 3, 0), 6) / 6 elementwise, evaluated as x * clamp(fma(x, 1/6, 0.5), 0, 1) so the saturated regions are exact: x >= 3 returns x bit-exactly and x <= -3 returns zero exactly (a negative zero, as IEEE negative * +0.0). In the curved region -3 < x < 3 the gate is a correctly rounded fused multiply-add on both build paths, so the scalar and MVE (cortex-m55) legs agree bit-exactly on every numeric normal input. Two carve-outs, both rooted in Armv8.1-M MVE floating-point arithmetic using the architecture’s Standard FPSCR value — DN=1 and FZ=1 hard-wired, FZ16 passed through (Arm v8-M ARM, DDI 0553B.l, StandardFPSCRValue(), selected by the MVE FP pseudocode’s fpscr_controlled=FALSE): NaN lanes agree in NaN-ness but not necessarily in payload (forced DN makes the MVE leg canonicalize payloads the scalar leg preserves), and the MVE leg flushes f32 subnormal operands and results to a signed zero regardless of FPSCR.FZ, where the scalar leg with FZ clear keeps them. Both reference models (FVP Corstone-300 and QEMU mps3-an547) exhibit the flush identically; it has not been executed on silicon, where the same architectural behavior is required. Near the lower knot the absolute contract is the meaningful one: for x just above -3 the output error is dominated by the gate constant’s representation error, bounded by |x^2 * (1/6f - 1/6)| ~ 4.5e-08 near x = -3 (e.g. nextafterf(-3, 0) returns -7.45e-08 against a float64 -1.19e-07 — millions of ulps of the tiny result, well inside the 1e-6 absolute contract), and where the gate underflows to exactly zero the kernel returns -0.0 with unbounded relative error. In-place operation (output == input) is supported on both legs; each element is read before it is written.
Note
NaN propagates (TensorFlow Lite semantics): a NaN input element yields NaN at that output element at every optimization level, on the toolchains this project gates (see the Testing & Verification guide, docs/guides/verification.md), including the shipped -Ofast: propagation rides the final multiply x * gate — a NaN x makes the product NaN whatever the gate resolved to — rather than a compare-and-select that -ffinite-math-only could fold. Only the NaN-ness of the element is guaranteed, not a particular NaN payload. +Inf returns +Inf (the gate is 1). -Inf returns NaN, not the mathematical limit 0: the gate is 0 there and (-Inf) * 0 is NaN by IEEE 754, the same result TFLite’s float hard-swish reference produces; special-casing -Inf would put a per-element select in the hot loop for an input no finite model produces. The scalar and MVE legs agree on the NaN-ness and on +/-Inf; NaN payload bits may differ between legs.
- Parameters:
input – [in] Pointer to the input samples.
output – [out] Pointer to the output samples.
size – [in] Number of elements to process. Must be at least 1.
- Returns:
ARM_CMSIS_NN_SUCCESSon success orARM_CMSIS_NN_ARG_ERRORon invalid arguments.