Log1p¶
Log1p - 29¶
Version¶
name: Log1p (GitHub)
domain:
mainsince_version:
29function:
Falsesupport_level:
SupportType.COMMONshape inference:
True
This version of the operator has been available since version 29.
Summary¶
Computes y = ln(1 + x) element-wise, where ln is the natural logarithm.
The output has the same shape and element type as the input, including for
scalar and empty inputs.
For finite x > -1, the result is a floating-point approximation of ln(1 + x),
with 1 + x evaluated as an exact real sum. Small nonzero results representable
in the output type must be preserved even when floating-point addition would
round 1 + x to 1. For example, a FLOAT input of 1e-8 produces approximately
1e-8.
Special values are defined element-wise as follows:
Input |
Output |
|---|---|
Positive zero |
Positive zero |
Negative zero |
Negative zero |
|
Negative infinity |
Finite |
NaN |
Negative infinity |
NaN |
Positive infinity |
Positive infinity |
NaN |
NaN |
The sign and payload of an output NaN are unspecified.
Inputs¶
input (heterogeneous) - T:
Input tensor
Outputs¶
output (heterogeneous) - T:
The natural logarithm of one plus the input, computed element-wise
Type Constraints¶
T in (
tensor(bfloat16),tensor(double),tensor(float),tensor(float16)):Constrain input and output types to float tensors.
Examples¶
_log1p¶
import numpy as np
import onnx
node = onnx.helper.make_node("Log1p", ["x"], ["y"])
for dtype in [np.float16, ml_dtypes.bfloat16, np.float32, np.float64]:
x = np.array(
[[-0.75, -0.5, 0.0, 0.25], [0.5, 1.0, 3.0, 1000.0]], dtype=dtype
)
y = np.array([math.log1p(float(v)) for v in x.flat], dtype=dtype).reshape(
x.shape
)
expect(
node,
inputs=[x],
outputs=[y],
name=f"test_log1p_{np.dtype(dtype).name}",
rtol=1e-2 if dtype == ml_dtypes.bfloat16 else 1e-3,
)
_log1p_small_inputs¶
import numpy as np
import onnx
node = onnx.helper.make_node("Log1p", ["x"], ["y"])
for dtype, tiny in [
(np.float16, 2.0**-14),
(ml_dtypes.bfloat16, 2.0**-10),
(np.float32, 1e-8),
(np.float64, 1e-20),
]:
x = np.array([-tiny, -0.0, 0.0, tiny], dtype=dtype)
y = np.array([math.log1p(float(v)) for v in x], dtype=dtype)
# Relative error allows backend variation, while atol=0 catches
# an incorrect zero caused by rounding the intermediate 1 + x.
expect(
node,
inputs=[x],
outputs=[y],
name=f"test_log1p_small_inputs_{np.dtype(dtype).name}",
rtol=1e-2 if dtype == ml_dtypes.bfloat16 else 1e-3,
atol=0,
)
_log1p_near_negative_one¶
import numpy as np
import onnx
node = onnx.helper.make_node("Log1p", ["x"], ["y"])
for dtype in [np.float16, ml_dtypes.bfloat16, np.float32, np.float64]:
x = np.nextafter(
np.array([-1.0], dtype=dtype), np.array([0.0], dtype=dtype)
)
y = np.array([math.log1p(float(x[0]))], dtype=dtype)
expect(
node,
inputs=[x],
outputs=[y],
name=f"test_log1p_near_negative_one_{np.dtype(dtype).name}",
rtol=1e-2 if dtype == ml_dtypes.bfloat16 else 1e-3,
)
_log1p_special_values¶
import numpy as np
import onnx
node = onnx.helper.make_node("Log1p", ["x"], ["y"])
for dtype in [np.float16, ml_dtypes.bfloat16, np.float32, np.float64]:
x = np.array([-0.0, 0.0, -1.0, -2.0, -np.inf, np.inf, np.nan], dtype=dtype)
y = np.array(
[-0.0, 0.0, -np.inf, np.nan, np.nan, np.inf, np.nan], dtype=dtype
)
expect(
node,
inputs=[x],
outputs=[y],
name=f"test_log1p_special_values_{np.dtype(dtype).name}",
)
_log1p_scalar_and_empty¶
import numpy as np
import onnx
node = onnx.helper.make_node("Log1p", ["x"], ["y"])
expect(
node,
inputs=[np.array(1.0, dtype=np.float32)],
outputs=[np.array(math.log(2), dtype=np.float32)],
name="test_log1p_scalar",
)
x = np.empty((0, 3), dtype=np.float32)
expect(node, inputs=[x], outputs=[x], name="test_log1p_empty")