Skip to content

Commit 8c4e8f2

Browse files
committed
Add support for I2 element type
- 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>
1 parent 6f57382 commit 8c4e8f2

File tree

20 files changed

+136
-49
lines changed

20 files changed

+136
-49
lines changed

src/bindings/c/include/openvino/c/ov_common.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ typedef enum {
175175
F16, //!< f16 element type
176176
F32, //!< f32 element type
177177
F64, //!< f64 element type
178+
I2, //!< i2 element type
178179
I4, //!< i4 element type
179180
I8, //!< i8 element type
180181
I16, //!< i16 element type

src/bindings/c/src/ov_tensor.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ const std::map<ov_element_type_e, ov::element::Type> element_type_map = {
1313
{ov_element_type_e::F16, ov::element::f16},
1414
{ov_element_type_e::F32, ov::element::f32},
1515
{ov_element_type_e::F64, ov::element::f64},
16+
{ov_element_type_e::I2, ov::element::i2},
1617
{ov_element_type_e::I4, ov::element::i4},
1718
{ov_element_type_e::I8, ov::element::i8},
1819
{ov_element_type_e::I16, ov::element::i16},

src/bindings/python/src/openvino/helpers/packing.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@
99

1010

1111
def pack_data(array: np.ndarray, type: Type) -> np.ndarray:
12-
"""Represent array values as u1, u2, u3, u4, u6 or i4 openvino element type and pack them into uint8 numpy array.
12+
"""Represent array values as u1, u2, u3, u4, u6, i2 or i4 openvino element type and pack them into uint8 numpy array.
1313
14-
For u1, u4, i4: Standard bit packing where 8 % bitwidth == 0
14+
For u1, u2, u4, i2, i4: Standard bit packing where 8 % bitwidth == 0
1515
For u3: Transposed packing - 8 values in 3 bytes
1616
For u6: Transposed packing - 4 values in 3 bytes
1717
@@ -24,7 +24,7 @@ def pack_data(array: np.ndarray, type: Type) -> np.ndarray:
2424
2525
:param array: numpy array with values to pack.
2626
:type array: numpy array
27-
:param type: Type to interpret the array values. Type must be u1, u2, u3, u4, u6, i4, nf4 or f4e2m1.
27+
:param type: Type to interpret the array values. Type must be u1, u2, u3, u4, u6, i2, i4, nf4 or f4e2m1.
2828
:type type: openvino.Type
2929
"""
3030
# Handle u3 and u6 with special transposed packing
@@ -33,9 +33,9 @@ def pack_data(array: np.ndarray, type: Type) -> np.ndarray:
3333
elif type == Type.u6:
3434
return _pack_u6(array)
3535

36-
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"
36+
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"
3737

38-
minimum_regular_dtype = np.int8 if type == Type.i4 else np.uint8
38+
minimum_regular_dtype = np.int8 if type in (Type.i2, Type.i4) else np.uint8
3939
casted_to_regular_type = array.astype(dtype=minimum_regular_dtype, casting="unsafe")
4040
if not np.array_equal(casted_to_regular_type, array):
4141
raise RuntimeError(f'The conversion of array "{array}" to dtype' f' "{casted_to_regular_type}" results in rounding')
@@ -61,7 +61,7 @@ def pack_data(array: np.ndarray, type: Type) -> np.ndarray:
6161
def unpack_data(array: np.ndarray, type: Type, shape: Union[list, Shape]) -> np.ndarray:
6262
"""Extract openvino element type values from array into new uint8/int8 array given shape.
6363
64-
For u1, u4, i4: Standard bit unpacking where 8 % bitwidth == 0
64+
For u1, u2, u4, i2, i4: Standard bit unpacking where 8 % bitwidth == 0
6565
For u3: Transposed unpacking - 8 values from 3 bytes
6666
For u6: Transposed unpacking - 4 values from 3 bytes
6767
@@ -71,7 +71,7 @@ def unpack_data(array: np.ndarray, type: Type, shape: Union[list, Shape]) -> np.
7171
7272
:param array: numpy array to unpack.
7373
:type array: numpy array
74-
:param type: Type to extract from array values. Type must be u1, u2, u3, u4, u6, i4, nf4 or f4e2m1.
74+
:param type: Type to extract from array values. Type must be u1, u2, u3, u4, u6, i2, i4, nf4 or f4e2m1.
7575
:type type: openvino.Type
7676
:param shape: the new shape for the unpacked array.
7777
:type shape: Union[list, openvino.Shape]
@@ -82,7 +82,7 @@ def unpack_data(array: np.ndarray, type: Type, shape: Union[list, Shape]) -> np.
8282
elif type == Type.u6:
8383
return _unpack_u6(array, shape)
8484

85-
assert type in [Type.u1, Type.u2, Type.u4, Type.i4, Type.nf4, Type.f4e2m1], "Unpacking algorithm for the" "data types stored in 1, 2 or 4 bits"
85+
assert type in [Type.u1, Type.u2, Type.u4, Type.i2, Type.i4, Type.nf4, Type.f4e2m1], "Unpacking algorithm for the" "data types stored in 1, 2 or 4 bits"
8686
unpacked = np.unpackbits(array.view(np.uint8))
8787
shape = list(shape)
8888
if type.bitwidth == 1:
@@ -91,7 +91,7 @@ def unpack_data(array: np.ndarray, type: Type, shape: Union[list, Shape]) -> np.
9191
unpacked = unpacked.reshape(-1, type.bitwidth)
9292
padding_shape = (unpacked.shape[0], 8 - type.bitwidth)
9393
padding = np.ndarray(padding_shape, np.uint8) # type: np.ndarray
94-
if type == Type.i4:
94+
if type in (Type.i2, Type.i4):
9595
for axis, bits in enumerate(unpacked):
9696
if bits[0] == 1:
9797
padding[axis] = np.ones((padding_shape[1],), np.uint8)
@@ -101,7 +101,7 @@ def unpack_data(array: np.ndarray, type: Type, shape: Union[list, Shape]) -> np.
101101
padding = np.zeros(padding_shape, np.uint8)
102102
padded = np.concatenate((padding, unpacked), 1) # type: ignore
103103
packed = np.packbits(padded, 1)
104-
if type == Type.i4:
104+
if type in (Type.i2, Type.i4):
105105
return np.resize(packed, shape).astype(dtype=np.int8)
106106
else:
107107
return np.resize(packed, shape)

src/bindings/python/src/pyopenvino/core/common.cpp

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,19 +20,20 @@ namespace type_helpers {
2020

2121
const std::map<ov::element::Type, py::dtype>& ov_type_to_dtype() {
2222
static const std::map<ov::element::Type, py::dtype> ov_type_to_dtype_mapping = {
23-
{ov::element::f16, py::dtype("float16")}, {ov::element::bf16, py::dtype("float16")},
24-
{ov::element::f32, py::dtype("float32")}, {ov::element::f64, py::dtype("float64")},
25-
{ov::element::i8, py::dtype("int8")}, {ov::element::i16, py::dtype("int16")},
26-
{ov::element::i32, py::dtype("int32")}, {ov::element::i64, py::dtype("int64")},
27-
{ov::element::u8, py::dtype("uint8")}, {ov::element::u16, py::dtype("uint16")},
28-
{ov::element::u32, py::dtype("uint32")}, {ov::element::u64, py::dtype("uint64")},
29-
{ov::element::boolean, py::dtype("bool")}, {ov::element::u1, py::dtype("uint8")},
30-
{ov::element::u2, py::dtype("uint8")}, {ov::element::u3, py::dtype("uint8")},
31-
{ov::element::u4, py::dtype("uint8")}, {ov::element::u6, py::dtype("uint8")},
32-
{ov::element::nf4, py::dtype("uint8")}, {ov::element::nf4, py::dtype("uint8")},
33-
{ov::element::i4, py::dtype("int8")}, {ov::element::f8e4m3, py::dtype("uint8")},
34-
{ov::element::f8e5m2, py::dtype("uint8")}, {ov::element::string, py::dtype("bytes_")},
35-
{ov::element::f4e2m1, py::dtype("uint8")}, {ov::element::f8e8m0, py::dtype("uint8")},
23+
{ov::element::f16, py::dtype("float16")}, {ov::element::bf16, py::dtype("float16")},
24+
{ov::element::f32, py::dtype("float32")}, {ov::element::f64, py::dtype("float64")},
25+
{ov::element::i8, py::dtype("int8")}, {ov::element::i16, py::dtype("int16")},
26+
{ov::element::i32, py::dtype("int32")}, {ov::element::i64, py::dtype("int64")},
27+
{ov::element::u8, py::dtype("uint8")}, {ov::element::u16, py::dtype("uint16")},
28+
{ov::element::u32, py::dtype("uint32")}, {ov::element::u64, py::dtype("uint64")},
29+
{ov::element::boolean, py::dtype("bool")}, {ov::element::u1, py::dtype("uint8")},
30+
{ov::element::u2, py::dtype("uint8")}, {ov::element::u3, py::dtype("uint8")},
31+
{ov::element::u4, py::dtype("uint8")}, {ov::element::u6, py::dtype("uint8")},
32+
{ov::element::nf4, py::dtype("uint8")}, {ov::element::nf4, py::dtype("uint8")},
33+
{ov::element::i2, py::dtype("int8")}, {ov::element::i4, py::dtype("int8")},
34+
{ov::element::f8e4m3, py::dtype("uint8")}, {ov::element::f8e5m2, py::dtype("uint8")},
35+
{ov::element::string, py::dtype("bytes_")}, {ov::element::f4e2m1, py::dtype("uint8")},
36+
{ov::element::f8e8m0, py::dtype("uint8")},
3637
};
3738
return ov_type_to_dtype_mapping;
3839
}
@@ -405,6 +406,7 @@ std::vector<size_t> _get_byte_strides(const ov::Shape& s, const size_t element_b
405406
std::vector<size_t> _get_strides(const ov::op::v0::Constant& self) {
406407
using namespace ov::element;
407408
switch (self.get_element_type()) {
409+
case i2:
408410
case i4:
409411
case u1:
410412
case u2:

src/bindings/python/src/pyopenvino/graph/types/element_type.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ void regclass_graph_Type(py::module m) {
3636
type.attr("f16") = ov::element::f16;
3737
type.attr("f32") = ov::element::f32;
3838
type.attr("f64") = ov::element::f64;
39+
type.attr("i2") = ov::element::i2;
3940
type.attr("i4") = ov::element::i4;
4041
type.attr("i8") = ov::element::i8;
4142
type.attr("i16") = ov::element::i16;

src/common/transformations/src/transformations/convert_precision.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1275,7 +1275,8 @@ void convert_lp_value(const SRC& src,
12751275

12761276
std::shared_ptr<Node> convert_low_precisions_int(std::shared_ptr<v0::Constant>& constant, ov::element::Type to) {
12771277
// Supported integer precisions
1278-
static const precisions_set_t supported_integer_precisions = {ov::element::i4,
1278+
static const precisions_set_t supported_integer_precisions = {ov::element::i2,
1279+
ov::element::i4,
12791280
ov::element::u4,
12801281
ov::element::u1,
12811282
ov::element::u2};

src/core/dev_api/openvino/core/type/element_iterator.hpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ namespace element {
3232
* @return True if element type is bit type otherwise false.
3333
*/
3434
constexpr bool is_bit_type(Type_t et) {
35-
return et == u1 || et == u2;
35+
return et == u1 || et == u2 || et == i2;
3636
}
3737

3838
/**
@@ -97,6 +97,11 @@ constexpr size_t bit_width<Type_t::u2>() {
9797
return 2;
9898
}
9999

100+
template <>
101+
constexpr size_t bit_width<Type_t::i2>() {
102+
return 2;
103+
}
104+
100105
template <>
101106
constexpr size_t bit_width<Type_t::u3>() {
102107
return 3;
@@ -207,7 +212,7 @@ class BitProxy<T, ET, std::enable_if_t<is_bit_type(ET) || is_nibble_type(ET)>> {
207212
*
208213
* @return Value of BitProxy.
209214
*/
210-
template <Type_t ETT = ET, std::enable_if_t<ETT != i4 && ETT != f4e2m1>* = nullptr>
215+
template <Type_t ETT = ET, std::enable_if_t<ETT != i2 && ETT != i4 && ETT != f4e2m1>* = nullptr>
211216
operator value_type() const {
212217
return static_cast<value_type>(get_bit_value());
213218
}
@@ -245,7 +250,7 @@ class BitProxy<T, ET, std::enable_if_t<is_bit_type(ET) || is_nibble_type(ET)>> {
245250
*
246251
* @return Value of BitProxy.
247252
*/
248-
template <Type_t ETT = ET, std::enable_if_t<ETT == i4>* = nullptr>
253+
template <Type_t ETT = ET, std::enable_if_t<ETT == i2 || ETT == i4>* = nullptr>
249254
operator value_type() const {
250255
constexpr auto value_mask = util::make_n_bit_mask(m_bits);
251256
constexpr auto value_msb_mask = (1U << (m_bits - 1U));

src/core/include/openvino/core/type/element_type.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ enum class Type_t {
4343
f16, //!< f16 element type
4444
f32, //!< f32 element type
4545
f64, //!< f64 element type
46+
i2, //!< i2 element type
4647
i4, //!< i4 element type
4748
i8, //!< i8 element type
4849
i16, //!< i16 element type
@@ -153,6 +154,9 @@ inline constexpr Type f32(Type_t::f32);
153154
/// \brief f64 element type
154155
/// \ingroup ov_element_cpp_api
155156
inline constexpr Type f64(Type_t::f64);
157+
/// \brief i2 element type
158+
/// \ingroup ov_element_cpp_api
159+
inline constexpr Type i2(Type_t::i2);
156160
/// \brief i4 element type
157161
/// \ingroup ov_element_cpp_api
158162
inline constexpr Type i4(Type_t::i4);

src/core/include/openvino/core/type/element_type_traits.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ struct element_type_traits<element::Type_t::f64> {
3838
using value_type = double;
3939
};
4040

41+
template <>
42+
struct element_type_traits<element::Type_t::i2> {
43+
using value_type = int8_t;
44+
};
45+
4146
template <>
4247
struct element_type_traits<element::Type_t::i4> {
4348
using value_type = int8_t;

src/core/src/op/constant.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
namespace ov::op {
2929

3030
#define SUPPORTED_ET \
31-
boolean, bf16, f16, f32, f64, i4, i8, i16, i32, i64, u1, u2, u3, u4, u6, u8, u16, u32, u64, nf4, f8e4m3, f8e5m2, \
31+
boolean, bf16, f16, f32, f64, i2, i4, i8, i16, i32, i64, u1, u2, u3, u4, u6, u8, u16, u32, u64, nf4, f8e4m3, f8e5m2, \
3232
f4e2m1, f8e8m0
3333

3434
template <class TContainer>
@@ -111,6 +111,9 @@ bool in_t_range(const U& v) {
111111
} else if constexpr (ET == element::u6) {
112112
const auto temp = static_cast<ConstantT>(v);
113113
return 0 <= temp && temp <= 63;
114+
} else if constexpr (ET == element::i2) {
115+
const auto temp = static_cast<ConstantT>(v);
116+
return -2 <= temp && temp <= 1;
114117
} else if constexpr (ET == element::i4) {
115118
const auto temp = static_cast<ConstantT>(v);
116119
return -8 <= temp && temp <= 7;

0 commit comments

Comments
 (0)