Skip to content

[Bug]: OpenVINO CPU saturates uint8 Sub instead of wrapping #35639

@ALinrunrun

Description

@ALinrunrun

OpenVINO Version

2026.1.0

Operating System

Other (Please specify in description)

Device used for inference

CPU

Framework

ONNX

Model used

Minimal ONNX model generated by the reproducer script.

Issue description

OpenVINO CPU appears to apply saturation semantics for uint8 ONNX Sub.

For A=[5, 200, 250, 0] and B=[10, 100, 10, 50], the expected unsigned wraparound result is [251, 100, 240, 206], but OpenVINO returns [0, 100, 240, 0], which matches saturated subtraction.

OS: Ubuntu 24.04.2 LTS / Linux x86_64

Step-by-step reproduction

#!/usr/bin/env python3
import sys
import numpy as np
import onnx
import openvino as ov
from onnx import TensorProto, helper

a = np.array([5, 200, 250, 0], dtype=np.uint8)
b = np.array([10, 100, 10, 50], dtype=np.uint8)

expected = ((a.astype(np.int32) - b.astype(np.int32)) % 256).astype(np.uint8)
saturated = np.clip(a.astype(np.int32) - b.astype(np.int32), 0, 255).astype(np.uint8)

A = helper.make_tensor_value_info("A", TensorProto.UINT8, [4])
B = helper.make_tensor_value_info("B", TensorProto.UINT8, [4])
Y = helper.make_tensor_value_info("Y", TensorProto.UINT8, [4])

node = helper.make_node("Sub", ["A", "B"], ["Y"])
graph = helper.make_graph([node], "uint8_sub", [A, B], [Y])
model = helper.make_model(graph, opset_imports=[helper.make_opsetid("", 14)])
model.ir_version = 8
onnx.checker.check_model(model)

core = ov.Core()
compiled = core.compile_model(core.read_model(model.SerializeToString(), b""), "CPU")
out = compiled({"A": a, "B": b})[compiled.output(0)]

print("A        :", a)
print("B        :", b)
print("OpenVINO :", out)
print("Expected :", expected)
print("Saturated:", saturated)

if np.array_equal(out, saturated) and not np.array_equal(out, expected):
    print("BUG REPRODUCED: OpenVINO uint8 Sub saturates instead of wrapping")
    sys.exit(0)

print("NOT REPRODUCED")
sys.exit(1)

Relevant log output

Expected:
OpenVINO should return the unsigned wraparound result:
[251 100 240 206]

Actual:
A        : [  5 200 250   0]
B        : [ 10 100  10  50]
OpenVINO : [  0 100 240   0]
Expected : [251 100 240 206]
Saturated: [  0 100 240   0]
BUG REPRODUCED: OpenVINO uint8 Sub saturates instead of wrapping

Issue submission checklist

  • I'm reporting an issue. It's not a question.
  • I checked the problem with the documentation, FAQ, open issues, Stack Overflow, etc., and have not found a solution.
  • There is reproducer code and related data files such as images, videos, models, etc.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions