From 11bac852da5700077a0416459ae12f3748b304d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20S=C5=82uszniak?= Date: Sun, 30 Aug 2026 11:17:31 +0200 Subject: [PATCH] [ET-VK] Clamp the tanh argument in the gelu shader The gelu shader evaluates the tanh approximation with an unclamped argument. For an input of x the argument is sqrt(2/pi) * (x + 0.044715 * x^3) which grows cubically, so x = -13.24 already yields -93.4. A driver that evaluates tanh as (e^y - e^-y) / (e^y + e^-y) overflows fp32 at |y| > ~88 and returns inf/inf = NaN. On a Mali-G76 this makes the Whisper encoder emit NaN from conv2 for exactly the two activations below -13, and the first LayerNorm then propagates them across the whole tensor. The tanh op in this same file already clamps to +/-15 for this reason; gelu now does the same. The clamp is numerically free: 1 - tanh(15) is 1.9e-13, well below fp32 epsilon, so the result is bit-identical for every input that gets clamped. --- backends/vulkan/runtime/graph/ops/glsl/unary_op.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/vulkan/runtime/graph/ops/glsl/unary_op.yaml b/backends/vulkan/runtime/graph/ops/glsl/unary_op.yaml index 46d12806149..e5e71b43694 100644 --- a/backends/vulkan/runtime/graph/ops/glsl/unary_op.yaml +++ b/backends/vulkan/runtime/graph/ops/glsl/unary_op.yaml @@ -23,7 +23,7 @@ unary_op: - NAME: exp OPERATOR: exp(X) - NAME: gelu - OPERATOR: 0.5 * X * (1 + tanh(sqrt(2 / 3.141593) * (X + 0.044715 * X * X * X))) + OPERATOR: 0.5 * X * (1 + tanh(clamp(sqrt(2 / 3.141593) * (X + 0.044715 * X * X * X), -15.0, 15.0))) - NAME: neg OPERATOR: -X - NAME: sigmoid