Add support for I2 element type#34956
Add support for I2 element type#34956anikulk wants to merge 2 commits intoopenvinotoolkit:masterfrom
Conversation
- Add i2 (signed 2-bit integer) element type to core registration
- Add Type_t::i2 to the enum in element_type.hpp
- Add inline constexpr Type i2(Type_t::i2) constant
- Add i2_aliases and type_info entry (2-bit, signed, quantized)
- Add i2 to the EnumNames string lookup map
- Add i2 element type iterator and template backend support
- element_type_traits.hpp: add element_type_traits<i2> with value_type int8_t
- element_iterator.hpp: add i2 to is_bit_type(), bit_width<i2>() = 2
specialization, sign-extension in operator value_type() for i2 alongside i4,
and exclude i2 from the unsigned raw-cast operator
- template backend convert.cpp: add i2 cases to evaluate_by_input_type and
evaluate_by_output_type dispatch switches
- template backend evaluate_node.hpp: add Type_t::i2 case to generic dispatch
- template backend subtract.cpp: add evaluate<i2> specialization (unpack i2->i8,
subtract, repack i8->i2) and dispatch case, matching u2 pattern
- Changes related to int2 unpacking in python bindings
- Add support for in tflite FE
- Updated schema.fbs for int2
Signed-off-by: Anisha Kulkarni <anisha.dattatraya.kulkarni@intel.com>
There was a problem hiding this comment.
Pull request overview
Adds a new signed 2-bit integer element type (i2) across OpenVINO core type registration and multiple integration points (template backend, CPU plugin conversion, Python/C bindings, and TFLite FE), enabling model import, conversion, and basic evaluation paths to recognize and operate on i2.
Changes:
- Register
ov::element::i2in core (Type_t, type info/aliases, string ↔ enum mapping, traits, iterator support, Constant/Convert handling). - Extend execution/evaluation support for
i2(template backend Convert/Subtract dispatch; CPU plugincpu_convert2-bit unpack path). - Wire
i2into external interfaces (Python helpers/bindings, C API mapping, TFLite schema + type mapping).
Reviewed changes
Copilot reviewed 20 out of 20 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/plugins/template/backend/ops/subtract.cpp | Adds i2 specialization and dispatch for Subtract evaluation via i8 intermediate conversion. |
| src/plugins/template/backend/ops/evaluate_node.hpp | Adds Type_t::i2 to generic evaluate dispatch. |
| src/plugins/template/backend/ops/convert.cpp | Adds i2 to Convert evaluation dispatch switches. |
| src/plugins/intel_cpu/src/nodes/common/cpu_convert.cpp | Extends 2-bit conversion path to handle i2 (signed unpack) alongside existing u2. |
| src/frontends/tensorflow_lite/src/utils.cpp | Maps TFLite INT2 tensor type to ov::element::i2. |
| src/frontends/tensorflow_lite/src/schema/schema.fbs | Extends TFLite schema with INT2 enum value. |
| src/frontends/tensorflow_lite/src/frontend.cpp | Adds new includes (context not shown indicating functional usage). |
| src/core/src/type/element_type.cpp | Registers i2 aliases/type_info and adds string-to-enum name mapping. |
| src/core/src/pass/visualize_tree.cpp | Includes i2 in Constant visualization handling set. |
| src/core/src/op/convert.cpp | Adds i2 to Convert op supported element type lists. |
| src/core/src/op/constant.cpp | Adds i2 to supported Constant types and range validation logic. |
| src/core/include/openvino/core/type/element_type_traits.hpp | Adds element_type_traits<i2> with int8_t value type. |
| src/core/include/openvino/core/type/element_type.hpp | Adds Type_t::i2 and inline constexpr Type i2. |
| src/core/dev_api/openvino/core/type/element_iterator.hpp | Extends bit-type iterator utilities and signed conversion proxy to support i2. |
| src/common/transformations/src/transformations/convert_precision.cpp | Allows low-precision integer conversion utilities to include i2. |
| src/bindings/python/src/pyopenvino/graph/types/element_type.cpp | Exposes Type.i2 in Python bindings. |
| src/bindings/python/src/pyopenvino/core/common.cpp | Maps i2 to NumPy dtype and updates packed-stride handling; retains a duplicate nf4 map entry. |
| src/bindings/python/src/openvino/helpers/packing.py | Adds i2 to Python pack/unpack helpers (signed handling). |
| src/bindings/c/src/ov_tensor.cpp | Adds C API enum → OpenVINO type mapping for I2. |
| src/bindings/c/include/openvino/c/ov_common.h | Adds I2 to C API element type enum. |
| #define INTEL_CPU_CVT_FROM_2BIT_LIST \ | ||
| INTEL_CPU_CVT(u2, f32), INTEL_CPU_CVT(u2, f16), INTEL_CPU_CVT(u2, bf16), INTEL_CPU_CVT(u2, i32), \ | ||
| INTEL_CPU_CVT(u2, u8), INTEL_CPU_CVT(u2, i8) | ||
| INTEL_CPU_CVT(u2, f32), INTEL_CPU_CVT(u2, f16), INTEL_CPU_CVT(u2, bf16), INTEL_CPU_CVT(u2, u8), INTEL_CPU_CVT(u2, i8), \ |
There was a problem hiding this comment.
[BLOCKER] INTEL_CPU_CVT_FROM_2BIT_LIST no longer includes a u2 -> i32 conversion entry, so cpu_convert() will hit OPENVINO_ASSERT(ctx.converted, ...) for that conversion path. Please restore the missing u2 conversion(s) (at least u2 -> i32, as previously supported) or otherwise ensure u2 can still be converted to i32 via the 2-bit dispatch.
| INTEL_CPU_CVT(u2, f32), INTEL_CPU_CVT(u2, f16), INTEL_CPU_CVT(u2, bf16), INTEL_CPU_CVT(u2, u8), INTEL_CPU_CVT(u2, i8), \ | |
| INTEL_CPU_CVT(u2, f32), INTEL_CPU_CVT(u2, f16), INTEL_CPU_CVT(u2, bf16), INTEL_CPU_CVT(u2, u8), INTEL_CPU_CVT(u2, i8), INTEL_CPU_CVT(u2, i32), \ |
| @@ -24,7 +24,7 @@ def pack_data(array: np.ndarray, type: Type) -> np.ndarray: | |||
|
|
|||
| :param array: numpy array with values to pack. | |||
| :type array: numpy array | |||
| :param type: Type to interpret the array values. Type must be u1, u2, u3, u4, u6, i4, nf4 or f4e2m1. | |||
| :param type: Type to interpret the array values. Type must be u1, u2, u3, u4, u6, i2, i4, nf4 or f4e2m1. | |||
| :type type: openvino.Type | |||
| """ | |||
| # Handle u3 and u6 with special transposed packing | |||
| @@ -33,9 +33,9 @@ def pack_data(array: np.ndarray, type: Type) -> np.ndarray: | |||
| elif type == Type.u6: | |||
| return _pack_u6(array) | |||
|
|
|||
| assert type in [Type.u1, Type.u2, Type.u4, Type.i4, Type.nf4, Type.f4e2m1], "Packing algorithm for the" "data types stored in 1, 2 or 4 bits" | |||
| assert type in [Type.u1, Type.u2, Type.u4, Type.i2, Type.i4, Type.nf4, Type.f4e2m1], "Packing algorithm for the" "data types stored in 1, 2 or 4 bits" | |||
|
|
|||
| minimum_regular_dtype = np.int8 if type == Type.i4 else np.uint8 | |||
| minimum_regular_dtype = np.int8 if type in (Type.i2, Type.i4) else np.uint8 | |||
| casted_to_regular_type = array.astype(dtype=minimum_regular_dtype, casting="unsafe") | |||
| if not np.array_equal(casted_to_regular_type, array): | |||
| raise RuntimeError(f'The conversion of array "{array}" to dtype' f' "{casted_to_regular_type}" results in rounding') | |||
There was a problem hiding this comment.
[HIGH] pack_data/unpack_data now support Type.i2, but the Python test suite doesn’t appear to cover i2 yet (existing parametrized packing/constant tests cover u1/u2/u3/u4/u6/i4/nf4). Please extend the relevant tests (e.g. test_constant_direct_packing and runtime tensor packing tests) to include Type.i2, including negative values to validate sign-extension and round-trip correctness against ops.constant(..., dtype=Type.i2) / Tensor(Type.i2, ...).
| {ov::element::boolean, py::dtype("bool")}, {ov::element::u1, py::dtype("uint8")}, | ||
| {ov::element::u2, py::dtype("uint8")}, {ov::element::u3, py::dtype("uint8")}, | ||
| {ov::element::u4, py::dtype("uint8")}, {ov::element::u6, py::dtype("uint8")}, | ||
| {ov::element::nf4, py::dtype("uint8")}, {ov::element::nf4, py::dtype("uint8")}, |
There was a problem hiding this comment.
The ov_type_to_dtype_mapping initializer contains ov::element::nf4 twice. This duplicate key is redundant (only one entry will be kept) and makes the mapping harder to audit; please remove the duplicate entry.
| {ov::element::nf4, py::dtype("uint8")}, {ov::element::nf4, py::dtype("uint8")}, | |
| {ov::element::nf4, py::dtype("uint8")}, |
| typedef enum { | ||
| DYNAMIC = 0U, //!< Dynamic element type | ||
| BOOLEAN, //!< boolean element type | ||
| BF16, //!< bf16 element type | ||
| F16, //!< f16 element type | ||
| F32, //!< f32 element type | ||
| F64, //!< f64 element type | ||
| I2, //!< i2 element type | ||
| I4, //!< i4 element type | ||
| I8, //!< i8 element type |
There was a problem hiding this comment.
[BLOCKER] ov_element_type_e is documented as being aligned with ov::element::Type_t, but inserting I2 in the middle changes the underlying numeric values of all subsequent enumerators (I4, I8, …). This is an ABI/API break for any C/C++ user code (or binaries) that persists/passes these enum values by integer. If numeric stability is required, please preserve existing values by appending I2 at the end or by explicitly assigning fixed values to all enumerators while keeping the old ones unchanged (and make the same adjustment in ov::element::Type_t).
Add i2 (signed 2-bit integer) element type to core registration
Add i2 element type iterator and template backend support
Changes related to int2 unpacking in python bindings
Add support for in tflite FE
Details:
Tickets:
AI Assistance: