Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions coremltools/converters/mil/mil/ops/defs/iOS15/activation.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,14 @@ class clamped_relu(activation_with_alpha_and_beta):

@precondition(allow=VALUE)
def value_inference(self):
x = np.minimum(np.maximum(self.x.val, 0), self.beta.val)
y = np.minimum(np.minimum(self.x.val, 0) * self.alpha.val, self.beta.val)
return x + y
# Splitting into a positive and a negative half and adding them back together
# only works when at most one half is non-zero, which stops being true once
# beta is negative and clamps both of them. Apply the documented formula
# directly instead.
return np.minimum(
np.where(self.x.val >= 0, self.x.val, self.x.val * self.alpha.val),
self.beta.val,
)


@register_op
Expand Down
14 changes: 14 additions & 0 deletions coremltools/converters/mil/mil/ops/tests/iOS14/test_activation.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,20 @@ def test_builder_eval(self):
y = np.minimum(np.minimum(x_val, 0) * 2.0, 1.0)
np.testing.assert_allclose(x + y, v.val, atol=1e-04, rtol=1e-05)

@ssa_fn
def test_builder_eval_negative_beta(self):
"""
Constant folding must agree with the runtime contract
``f(x) = min((x >= 0 ? x : alpha * x), beta)`` for a negative beta too.
The alpha / beta combinations here match the ones the neural network backend
test for this layer already covers (test_numpy_nn_layers.test_clamped_relu_cpu).
"""
x_val = np.arange(-20, 20, dtype=np.float32)
for alpha, beta in itertools.product([0.0, 2.0, -3.0], [7.0, -8.0]):
v = mb.clamped_relu(x=x_val, alpha=alpha, beta=beta)
expected = np.minimum(beta, np.where(x_val >= 0, x_val, x_val * alpha))
np.testing.assert_allclose(expected, v.val, atol=1e-04, rtol=1e-05)

@pytest.mark.parametrize(
"compute_unit, backend, dim, alpha, beta",
itertools.product(compute_units, backends, [2, 4, 8], [2.0, 3.0], [4.0, 5.0]),
Expand Down