#23638·keras

soft_shrink, sparse_plus and selu mangle integer inputs (numpy/tensorflow/openvino truncate, torch raises)

Author: Nanduu24Created Sep 15, 2026Updated Sep 16, 2026
Labelsbackend:torchbackend:tensorflowbackend:jaxbackend:OpenVino

Describe the bug

Several float activation ops do not promote integer (or bool) inputs to float, so their internal float constants get cast to the input's integer dtype and truncate. This is the same class of bug recently reported for leaky_relu (#23607) and hard_sigmoid (#23544), and already fixed for gelu.

Affected ops: keras.ops.soft_shrink, keras.ops.sparse_plus, keras.ops.selu.

  • numpy / tensorflow / openvino backends silently return wrong values (the output even keeps the integer dtype for soft_shrink/sparse_plus).
  • torch backend raises NotImplementedError ("not implemented for 'Int'") for soft_shrink/selu.

For example, selu's scale (1.0507...) is cast to the input's integer dtype, truncates to 1, and selu degenerates into a bare elu.

To Reproduce (numpy backend)

import numpy as np
from keras import ops

x = np.array([-2, -1, 0, 1, 2], dtype="int32")

print(ops.soft_shrink(x))  # [-1  0  0  0  1] int32   -> should be [-1.5 -0.5 0.  0.5  1.5]
print(ops.sparse_plus(x))  # [ 0  0  0  1  2] int32   -> should be [ 0.   0.   0.25 1.   2. ]
print(ops.selu(x))         # [-0.865 -0.632 0. 1. 2.] -> should be [-1.520 -1.111 0. 1.051 2.101]

Casting the same values to float32 gives the correct results, so the outputs differ only because the input was integer.

Expected behavior

Integer/bool inputs should be promoted to float and produce the same result as the equivalent float inputs, on every backend — matching the behavior already in place for leaky_relu, hard_sigmoid and gelu.

Would you accept a PR?

I've traced the cause (float constants cast to the integer dtype, exactly like #23607) and have a fix ready that promotes integer/bool inputs to float on all backends plus regression tests, mirroring the leaky_relu fix. Opening the PR alongside this issue.