Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
597c1e3
[ref][one_hot]: Added support for negative indicies. Fixed tests.
pkowalc1 Jul 31, 2025
04e718e
[ref][one_hot]: Fixed code style.
pkowalc1 Jul 31, 2025
972560b
[onnx]: Disabled onehot test.
pkowalc1 Aug 1, 2025
7304114
[gpu][one_hot]: Added support for negative indicies, added unittests.
pkowalc1 Aug 1, 2025
2f937d5
[cpu]: [one_hot]: Added support for negative indicies and and added t…
pkowalc1 Aug 4, 2025
deb076b
[doc]:[one_hot]: Added info about supporting negative indicies.
pkowalc1 Aug 4, 2025
5e61894
Merge branch 'master' into fix_one_hot_negative_indicies
pkowalc1 Aug 4, 2025
0ea1888
[TEMP][CI]: Add printing input to failing tests.
pkowalc1 Aug 5, 2025
b76c367
[ref]: Added NegativeIndicesMode to OneHot. Fixed ref and onnx tests.
pkowalc1 Aug 7, 2025
33459d7
[onnx]: Fixed doc check.
pkowalc1 Aug 7, 2025
c0c8d45
[one_hot]: Fixed code style.
pkowalc1 Aug 7, 2025
2d6e42c
[cpu][onehot]: Added support for oh mode. Fixed tests.
pkowalc1 Aug 8, 2025
f8ce920
[gpu][one_hot]: Added support for indicies mode with tests.
pkowalc1 Aug 8, 2025
fd4c4d8
Fixed clang-format.
pkowalc1 Aug 8, 2025
77fffc3
Merge branch 'master' into fix_one_hot_negative_indicies
pkowalc1 Aug 8, 2025
889ed07
[doc][onehot]: Added description of negative indices mode.
pkowalc1 Aug 11, 2025
3ff9d3d
Merge branch 'fix_one_hot_negative_indicies' of https://github.com/pk…
pkowalc1 Aug 11, 2025
42580f2
[gpu][cpu][ref]: Added OneHot v16 WIP
pkowalc1 Aug 28, 2025
28ad97c
[core]: Enabled shape infer for v16 One Hot.
pkowalc1 Aug 29, 2025
c275abe
[cpu]: Added tests for v16 shape infer.
pkowalc1 Aug 29, 2025
6727743
[onnx]: Fixed frontend tests.
pkowalc1 Aug 29, 2025
b11a989
[core]: Added shape inference tests for one hot v16.
pkowalc1 Aug 29, 2025
cc8c572
[core]: Add constant folding tests for OneHot v16.
pkowalc1 Aug 29, 2025
dcf4e91
[core]: Added attributes tests for one hot v16.
pkowalc1 Aug 29, 2025
28bd066
[template]: added onehot v16 tests
pkowalc1 Sep 2, 2025
5b416dd
Merge branch 'master' into fix_one_hot_negative_indicies_with_new_op_ver
pkowalc1 Sep 2, 2025
967dfb2
Fixed clang/build issues.
pkowalc1 Sep 2, 2025
681f0e1
[one_hot]: Fixes.
pkowalc1 Sep 2, 2025
4f56458
[one_hot]: Fixes.
pkowalc1 Sep 2, 2025
b7cd22f
[one_hot]: Fixed compilation.
pkowalc1 Sep 2, 2025
6afde05
[one_hot]: Fixed code style.
pkowalc1 Sep 2, 2025
e72fd40
[one_hot]: Fixes.
pkowalc1 Sep 3, 2025
8d42dea
[one_hot]: Conformance test
pkowalc1 Sep 3, 2025
ab3168f
[one_hot]: Removed typo.
pkowalc1 Sep 3, 2025
84f6b64
[one_hot]: Fixed cput shape inference tests.
pkowalc1 Sep 3, 2025
f523520
[one_hot]: Fixed tests.
pkowalc1 Sep 3, 2025
29f42a4
[one_hot]: Added functional tests
pkowalc1 Sep 3, 2025
e2e0a0a
[OneHot]: added new spec.
pkowalc1 Sep 3, 2025
2c921aa
[OneHotv1]: Restored spec.
pkowalc1 Sep 3, 2025
ad1654e
[OneHot1]: Restored spec.
pkowalc1 Sep 3, 2025
d8c1432
[OneHot1]: restored.
pkowalc1 Sep 3, 2025
6bbe914
[onehot]: Added transformation from v16 to v1
pkowalc1 Sep 4, 2025
e26471a
[onehot]: Fxied code style
pkowalc1 Sep 4, 2025
e99ce09
Update src/common/transformations/src/transformations/op_conversions/…
pkowalc1 Sep 15, 2025
1570297
Update src/core/shape_inference/include/one_hot_shape_inference.hpp
pkowalc1 Sep 15, 2025
90c900d
Update src/common/transformations/src/transformations/op_conversions/…
pkowalc1 Sep 15, 2025
dd498d8
[onehot]: Removed transformation v16 to v1.
pkowalc1 Sep 15, 2025
29908e4
[one_hote]: Removed transformation v16 to v1.
pkowalc1 Sep 15, 2025
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
OneHot
======


.. meta::
:description: Learn about OneHot-16 - a sequence processing operation, which
can be performed on four required input tensors.

**Versioned name**: *OneHot-16*

**Category**: *Sequence processing*

**Short description**: *OneHot* sets the elements in the output tensor with specified indices to ``on_value`` and fills all other locations with ``off_value``.

**Detailed description**

Taking a tensor with rank ``N`` as the first input ``indices``, OneHot produces a tensor with rank ``N+1`` extending the original
tensor with a new dimension at the ``axis`` position. The output tensor is populated with two scalar values: ``on_value``
that comes from the 3rd input and ``off_value`` that comes from the 4nd input. The population is made in the following way:

.. code-block:: cpp

output[:, ... ,:, i, :, ... ,:] = on_value if (indices[:, ..., :, :, ..., :] == i) else off_value

where ``i`` is at the ``axis`` position in the ``output`` shape and has values from the range ``[0, ..., depth-1]``.

When some elements from the ``indices`` are greater or equal to the ``depth``, it is a well-formed operation. The corresponding output rows are populated with ``off_value`` in this case.

The types of input scalars ``on_value`` and ``off_value`` should match and be equal to any supported type. The output tensor type is derived from the ``on_value`` or the ``off_value``, they all have the same type.

**Attributes**:

* *axis*

* **Description**: *axis* is a new axis position in the output shape to fill with one-hot values.
* **Range of values**: an integer. Negative value means counting dimension from the end.
* **Type**: ``int``
* **Required**: *yes*

* *negative_indices_mode*

* **Description**: controls how negative indices in indices tensor are handled.
* **Range of values**:

* ``ignore-negative``: negative indices are ignored, and the corresponding output rows are filled with ``off_value``.
* ``normalize``: negative indices in the range ``[-depth, -1]`` are normalized by ``depth + index``; which effectively maps the range ``[-depth, depth-1]`` to ``[0, depth-1]``.

* **Type**: ``string``
* **Default value**: ignore-negative
* **Required**: *no*

.. note::
OneHot-16 with negative_indices_mode set to ignore-negative mode behaves exactly as OneHot-1.

**Inputs**:

* **1**: ``indices``: input tensor of type *T1* with indices. Can be 0D. **Required.**
* **2**: ``depth``: positive scalar (0D tensor) of type *T1* that specifies the number of classes and thus the size of the one-hot dimension. **Required.**
* **3**: ``on_value``: scalar (0D tensor) of type *T2* that fills the locations in output tensor specified in ``indices``. **Required.**
* **4**: ``off_value``: scalar (0D tensor) of type *T2* that fills the locations not represented in ``indices``. **Required.**

**Outputs**:

* **1**: An ``N+1`` rank tensor of type *T2*, where ``N`` is a rank of the input tensor ``indices``. A new axis of the size ``depth`` is inserted at the dimension ``axis``.

**Types**

* *T1*: ``int32`` or ``int64``.

* *T2*: any supported data type.

**Examples**

.. code-block:: xml
:force:

<layer ... type="OneHot" ...>
<data axis="-1" negative_indices_mode="normalize"/>
<input>
<port id="0"> <!-- indices value: [0, -5, -2, 2] -->
<dim>4</dim>
</port>
<port id="1"> <!-- depth value: 3 -->
</port>
<port id="2"> <!-- on_value 1 -->
</port>
<port id="3"> <!-- off_value 2 -->
</port>
</input>
<output>
<port id="0"> <!-- output value # [[1, 2, 2], [2, 2, 2], [2, 1, 2], [2, 2, 1]] -->
<dim>4</dim>
<dim>3</dim>
</port>
</output>
</layer>



.. code-block:: xml
:force:

<layer ... type="OneHot" ...>
<data axis="1"/>
<input>
<port id="0"> <!-- indices value: [[0, 3, 1], [1, 2, 4]] -->
<dim>2</dim>
<dim>3</dim>
</port>
<port id="1"> <!-- depth value: 3 -->
</port>
<port id="2"> <!-- on_value 1 -->
</port>
<port id="3"> <!-- off_value 0 -->
</port>
</input>
<output>
<port id="0"> <!-- output value: [[[1, 0, 0], [0, 0, 1], [0, 0, 0]], -->
<dim>2</dim> <!-- [[0, 0, 0], [1, 0, 0], [0, 1, 0]]] -->
<dim>3</dim>
<dim>3</dim>
</port>
</output>
</layer>



76 changes: 65 additions & 11 deletions src/core/include/openvino/op/one_hot.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@

#pragma once

#include "openvino/op/op.hpp"
#include "openvino/op/util/one_hot_base.hpp"

namespace ov {
namespace op {
namespace v1 {
/// \brief OneHot operation.
///
/// \ingroup ov_ops_cpp_api
class OPENVINO_API OneHot : public Op {
class OPENVINO_API OneHot : public util::OneHotBase {
public:
OPENVINO_OP("OneHot", "opset1", op::Op);

Expand Down Expand Up @@ -40,19 +40,73 @@ class OPENVINO_API OneHot : public Op {

bool evaluate(TensorVector& outputs, const TensorVector& inputs) const override;
bool has_evaluate() const override;
};
} // namespace v1
namespace v16 {
/// \brief OneHot operation.
///
/// \ingroup ov_ops_cpp_api
class OPENVINO_API OneHot : public util::OneHotBase {
public:
OPENVINO_OP("OneHot", "opset16", op::Op);

/// \brief Lists the supported negative indices modes for this version of the operator.
/// See the specification for the description of how negative indices are handled.
enum class NegativeIndicesMode { IGNORE_NEGATIVE, NORMALIZE };

/// \brief Constructs a one-hot operation.
OneHot() = default;
/// \brief Constructs a one-hot operation.
///
/// \param indices Input tensor containing indices.
/// \param depth Specifies number of classes and the size of one-hot dimension.
/// \param on_value Specifies value that the locations in output tensor represented
/// by indices in input take.
/// \param off_value Specifies value that the locations in output tensor not
/// represented
/// by indices in input take.
/// \param axis Axis along which one-hot representation in added.
OneHot(const Output<Node>& indices,
const Output<Node>& depth,
const Output<Node>& on_value,
const Output<Node>& off_value,
int64_t axis,
NegativeIndicesMode mode = NegativeIndicesMode::IGNORE_NEGATIVE);

bool visit_attributes(AttributeVisitor& visitor) override;
std::shared_ptr<Node> clone_with_new_inputs(const OutputVector& new_args) const override;
void validate_and_infer_types() override;

bool evaluate(TensorVector& outputs, const TensorVector& inputs) const override;
bool has_evaluate() const override;

/// \return The index of the one-hot axis.
const int64_t& get_axis() const {
return m_axis;
/// \brief Sets the negative indices mode.
void set_negative_indices_mode(NegativeIndicesMode mode) {
m_negative_indices_mode = mode;
}
/// \return The negative indices mode.
NegativeIndicesMode get_negative_indices_mode() const {
return m_negative_indices_mode;
}
void set_axis(int64_t axis);

protected:
int64_t m_axis;

private:
friend void inline resolve_axis(OneHot* op);
NegativeIndicesMode m_negative_indices_mode;
};
} // namespace v1
} // namespace v16
} // namespace op

OPENVINO_API
std::ostream& operator<<(std::ostream& s, const op::v16::OneHot::NegativeIndicesMode& mode);

template <>
class OPENVINO_API AttributeAdapter<op::v16::OneHot::NegativeIndicesMode>
: public EnumAttributeAdapterBase<op::v16::OneHot::NegativeIndicesMode> {
public:
AttributeAdapter(op::v16::OneHot::NegativeIndicesMode& value)
: EnumAttributeAdapterBase<op::v16::OneHot::NegativeIndicesMode>(value) {}

OPENVINO_RTTI("AttributeAdapter<ov::op::v16::OneHot::NegativeIndicesMode>");
~AttributeAdapter() override;
};

} // namespace ov
57 changes: 57 additions & 0 deletions src/core/include/openvino/op/util/one_hot_base.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright (C) 2018-2025 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//

#pragma once

#include "openvino/op/op.hpp"
#include "openvino/op/util/attr_types.hpp"

namespace ov {
namespace op {
namespace util {
Comment on lines +10 to +12
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AS new file added:

Suggested change
namespace ov {
namespace op {
namespace util {
namespace ov::op::util {

class OPENVINO_API OneHotBase : public Op {
public:
OPENVINO_OP("OneHot", "util");

/// \brief Constructs a one-hot operation.
OneHotBase() = default;

/// \brief Constructs a one-hot operation.
///
/// \param indices Input tensor containing indices.
/// \param depth Specifies number of classes and the size of one-hot dimension.
/// \param on_value Specifies value that the locations in output tensor represented
/// by indices in input take.
/// \param off_value Specifies value that the locations in output tensor not
/// represented
/// by indices in input take.
/// \param axis Axis along which one-hot representation in added.
OneHotBase(const Output<Node>& indices,
const Output<Node>& depth,
const Output<Node>& on_value,
const Output<Node>& off_value,
int64_t axis);

bool visit_attributes(AttributeVisitor& visitor) override;
void validate_and_infer_types() override;
std::shared_ptr<Node> clone_with_new_inputs(const OutputVector& new_args) const override;

/// \return The index of the one-hot axis.
const int64_t& get_axis() const {
return m_axis;
}

/// @brief Sets the index of the one-hot axis.
/// @param axis The index of the one-hot axis.
void set_axis(int64_t axis);

protected:
int64_t m_axis;

private:
friend void inline resolve_axis(OneHotBase* op);
Comment on lines +52 to +53
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general friends has been removed in ops (looks like missed for this op). It can be removed also as we got get_axis and it can be used in shape inference functions.

};
} // namespace util
} // namespace op
} // namespace ov
1 change: 1 addition & 0 deletions src/core/include/openvino/opsets/opset16_tbl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ _OPENVINO_OP_REG(ISTFT, ov::op::v16)
_OPENVINO_OP_REG(SegmentMax, ov::op::v16)
_OPENVINO_OP_REG(SparseFillEmptyRows, ov::op::v16)
_OPENVINO_OP_REG(AvgPool, ov::op::v16)
_OPENVINO_OP_REG(OneHot, ov::op::v16)
18 changes: 12 additions & 6 deletions src/core/reference/include/openvino/reference/one_hot.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#pragma once

#include "openvino/core/shape.hpp"
#include "openvino/op/one_hot.hpp"

namespace ov {
namespace reference {
Expand All @@ -16,7 +17,9 @@ void one_hot(const INPUT_TYPE* indices,
const size_t depth,
const int64_t one_hot_axis,
const char* on_value,
const char* off_value) {
const char* off_value,
const op::v16::OneHot::NegativeIndicesMode mode) {
const bool is_mode_normalize = mode == op::v16::OneHot::NegativeIndicesMode::NORMALIZE;
const size_t num_ind = shape_size(indices_shape);
// Step 1: Set off_value to the output.
for (auto p = out; p < out + num_ind * depth * out_elem_size; p += out_elem_size)
Expand All @@ -31,11 +34,14 @@ void one_hot(const INPUT_TYPE* indices,
// Step 2: Write on_value at needed positions
for (size_t outer_i = 0; outer_i < num_ind; outer_i += inner_block) {
for (size_t inner_i = 0; inner_i < inner_block; inner_i++) {
auto input_val = indices[outer_i + inner_i];
// Negative indices are ignored
if ((input_val >= 0) && (static_cast<size_t>(input_val) < depth)) {
auto oh_index = static_cast<size_t>(input_val);
size_t output_offset = out_elem_size * (outer_i * depth + inner_i + oh_index * inner_block);
const int64_t input_val = static_cast<int64_t>(indices[outer_i + inner_i]);
const int64_t depth_i64 = static_cast<int64_t>(depth);
const int64_t actual_index = (input_val < 0 && is_mode_normalize) ? depth_i64 + input_val : input_val;
const int64_t max_valid = depth_i64 - 1;

if (actual_index >= 0 && actual_index <= max_valid) {
const size_t output_offset =
out_elem_size * (outer_i * depth + inner_i + static_cast<size_t>(actual_index) * inner_block);
std::copy(on_value, on_value + out_elem_size, out + output_offset);
}
}
Expand Down
35 changes: 26 additions & 9 deletions src/core/shape_inference/include/one_hot_shape_inference.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
namespace ov {
namespace op {
namespace util {

template <class T>
struct GetNotNegative {
const Node* m_op;
Expand All @@ -23,22 +22,21 @@ struct GetNotNegative {
return static_cast<T>(v);
}
};
} // namespace util
namespace v1 {
void inline resolve_axis(OneHot* op) {

void inline resolve_axis(OneHotBase* op) {
if (op->get_input_size() < 1) {
return;
}
const auto& indices_shape = op->get_input_partial_shape(0);
if (indices_shape.rank().is_static()) {
op->m_axis = ov::util::try_normalize_axis(op->m_axis, indices_shape.rank() + 1, *op);
op->m_axis = ov::util::try_normalize_axis(op->get_axis(), indices_shape.rank() + 1, *op);
}
}
} // namespace util

template <class T, class TRShape = result_shape_t<T>>
std::vector<TRShape> shape_infer(const OneHot* op,
const std::vector<T>& input_shapes,
const ITensorAccessor& ta = make_tensor_accessor()) {
std::vector<TRShape> shape_infer_base(const OneHotBase* op,
const std::vector<T>& input_shapes,
const ITensorAccessor& ta = make_tensor_accessor()) {
NODE_VALIDATION_CHECK(op, input_shapes.size() == 4);
using DimType = typename T::value_type;
const auto& indices_shape = input_shapes[0];
Expand Down Expand Up @@ -77,6 +75,25 @@ std::vector<TRShape> shape_infer(const OneHot* op,
}
return output_shapes;
}
} // namespace util

namespace v1 {
template <class TShape, class TRShape = result_shape_t<TShape>>
std::vector<TRShape> shape_infer(const OneHot* op,
const std::vector<TShape>& input_shapes,
const ITensorAccessor& ta = make_tensor_accessor()) {
return util::shape_infer_base(op, input_shapes, ta);
}
} // namespace v1

namespace v16 {
template <class TShape, class TRShape = result_shape_t<TShape>>
std::vector<TRShape> shape_infer(const OneHot* op,
const std::vector<TShape>& input_shapes,
const ITensorAccessor& ta = make_tensor_accessor()) {
return util::shape_infer_base(op, input_shapes, ta);
}
} // namespace v16

} // namespace op
} // namespace ov
Loading
Loading