[FP8] Implementation of FP8 element types (ov::element::f8e4m3 and ov::element::f8e5m2) (#21608)
* FP8 element types init * Remove redundant union * Replace using ov * Update fundamental types * Update class name check * Update tests * Remove redundant sign * Expose f8 types in Python * Add to py to dtype map * Style alignment * Align python style * Update test values * Remove constexpr from_bits to fix warning * Add trivially construcitble asserts and common constrexpr * Align python tests opset * Update f8e4m3 <-> float conversion * f8e5m2 class update * Add f8e5m2 unit test * Add to string conversion tests * Rename class f8e4m3 -> float8_e4m3 * Rename f8e5m2 -> float8_e5m2 * Remove size() and to_string from float8 - size() can be replaced by compile time sizeof - to_string can be replaced by std::to_string() * float8 E5M2 remove unused constexpr value * Fix union initialization and ncc style rules * Fix test issues * Use NaN from std::numeric_limits instead macro - minor refactor of float8_e4m3 * Update nf4 usage in element_type.cpp * Sync openvino.style with master * Update f8e5m2 test --------- Co-authored-by: Raasz, Pawel <pawel.raasz@intel.com>
This commit is contained in:
parent
0ad801a184
commit
b3c2c386dc
|
|
@ -1,6 +1,6 @@
|
|||
# custom OpenVINO values
|
||||
CppMethod: '^(operator\W+|[a-z_\d]+|signaling_NaN|quiet_NaN|OPENVINO_OP)$'
|
||||
ClassName: '^([A-Z][\w]+|b?float16|numeric_limits|ngraph_error|stopwatch|unsupported_op)$'
|
||||
ClassName: '^([A-Z][\w]+|b?float16|float8_e4m3|float8_e5m2|numeric_limits|ngraph_error|stopwatch|unsupported_op)$'
|
||||
StructName: '^([A-Z][\w]+|element_type_traits|hash|oi_pair|stat)$'
|
||||
FunctionName: '^(operator\W+|[a-z_\d]+)|PrintTo$'
|
||||
Namespace: '^([a-z\d_]*|InferenceEngine)$'
|
||||
|
|
@ -18,7 +18,7 @@ VariableReference: '^\w+$'
|
|||
|
||||
EnumName: '^[A-Z][\w]+$'
|
||||
# excepts element_type
|
||||
EnumConstantName: '^([A-Z\d_]+|undefined|dynamic|boolean|bf16|f16|f32|f64|i4|i8|i16|i32|i64|u1|u4|u8|u16|u32|u64|nf4|string|asymmetric|align_corners|round_prefer_floor|round_prefer_ceil|floor|ceil|simple|nearest|linear|linear_onnx|cubic|area|scales|sizes|half_pixel|tf_half_pixel_for_nn|pytorch_half_pixel|asymetric)$'
|
||||
EnumConstantName: '^([A-Z\d_]+|undefined|dynamic|boolean|bf16|f16|f32|f64|i4|i8|i16|i32|i64|u1|u4|u8|u16|u32|u64|nf4|f8e4m3|f8e5m2|string|asymmetric|align_corners|round_prefer_floor|round_prefer_ceil|floor|ceil|simple|nearest|linear|linear_onnx|cubic|area|scales|sizes|half_pixel|tf_half_pixel_for_nn|pytorch_half_pixel|asymetric)$'
|
||||
# TODO: align
|
||||
UsingDeclaration: '^.*$'
|
||||
TypedefName: '^.*$'
|
||||
|
|
|
|||
|
|
@ -187,6 +187,8 @@ typedef enum {
|
|||
U32, //!< u32 element type
|
||||
U64, //!< u64 element type
|
||||
NF4, //!< nf4 element type
|
||||
F8E4M3, //!< f8e4m3 element type
|
||||
F8E5M3, //!< f8e5m2 element type
|
||||
} ov_element_type_e;
|
||||
|
||||
/**
|
||||
|
|
@ -210,4 +212,4 @@ ov_free(const char* content);
|
|||
* @ingroup ov_base_c_api
|
||||
*/
|
||||
OPENVINO_C_API(const char*)
|
||||
ov_get_last_err_msg();
|
||||
ov_get_last_err_msg();
|
||||
|
|
|
|||
|
|
@ -24,7 +24,9 @@ const std::map<ov_element_type_e, ov::element::Type> element_type_map = {
|
|||
{ov_element_type_e::U16, ov::element::u16},
|
||||
{ov_element_type_e::U32, ov::element::u32},
|
||||
{ov_element_type_e::U64, ov::element::u64},
|
||||
{ov_element_type_e::NF4, ov::element::nf4}};
|
||||
{ov_element_type_e::NF4, ov::element::nf4},
|
||||
{ov_element_type_e::F8E4M3, ov::element::f8e4m3},
|
||||
{ov_element_type_e::F8E5M3, ov::element::f8e5m2}};
|
||||
|
||||
inline ov_element_type_e find_ov_element_type_e(ov::element::Type type) {
|
||||
for (auto iter = element_type_map.begin(); iter != element_type_map.end(); iter++) {
|
||||
|
|
|
|||
|
|
@ -19,24 +19,16 @@ namespace type_helpers {
|
|||
|
||||
const std::map<ov::element::Type, py::dtype>& ov_type_to_dtype() {
|
||||
static const std::map<ov::element::Type, py::dtype> ov_type_to_dtype_mapping = {
|
||||
{ov::element::f16, py::dtype("float16")},
|
||||
{ov::element::bf16, py::dtype("float16")},
|
||||
{ov::element::f32, py::dtype("float32")},
|
||||
{ov::element::f64, py::dtype("float64")},
|
||||
{ov::element::i8, py::dtype("int8")},
|
||||
{ov::element::i16, py::dtype("int16")},
|
||||
{ov::element::i32, py::dtype("int32")},
|
||||
{ov::element::i64, py::dtype("int64")},
|
||||
{ov::element::u8, py::dtype("uint8")},
|
||||
{ov::element::u16, py::dtype("uint16")},
|
||||
{ov::element::u32, py::dtype("uint32")},
|
||||
{ov::element::u64, py::dtype("uint64")},
|
||||
{ov::element::boolean, py::dtype("bool")},
|
||||
{ov::element::u1, py::dtype("uint8")},
|
||||
{ov::element::u4, py::dtype("uint8")},
|
||||
{ov::element::nf4, py::dtype("uint8")},
|
||||
{ov::element::i4, py::dtype("int8")},
|
||||
{ov::element::string, py::dtype("bytes_")},
|
||||
{ov::element::f16, py::dtype("float16")}, {ov::element::bf16, py::dtype("float16")},
|
||||
{ov::element::f32, py::dtype("float32")}, {ov::element::f64, py::dtype("float64")},
|
||||
{ov::element::i8, py::dtype("int8")}, {ov::element::i16, py::dtype("int16")},
|
||||
{ov::element::i32, py::dtype("int32")}, {ov::element::i64, py::dtype("int64")},
|
||||
{ov::element::u8, py::dtype("uint8")}, {ov::element::u16, py::dtype("uint16")},
|
||||
{ov::element::u32, py::dtype("uint32")}, {ov::element::u64, py::dtype("uint64")},
|
||||
{ov::element::boolean, py::dtype("bool")}, {ov::element::u1, py::dtype("uint8")},
|
||||
{ov::element::u4, py::dtype("uint8")}, {ov::element::nf4, py::dtype("uint8")},
|
||||
{ov::element::i4, py::dtype("int8")}, {ov::element::f8e4m3, py::dtype("uint8")},
|
||||
{ov::element::f8e5m2, py::dtype("uint8")}, {ov::element::string, py::dtype("bytes_")},
|
||||
};
|
||||
return ov_type_to_dtype_mapping;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,6 +50,8 @@ void regclass_graph_Type(py::module m) {
|
|||
type.attr("u64") = ov::element::u64;
|
||||
type.attr("bf16") = ov::element::bf16;
|
||||
type.attr("nf4") = ov::element::nf4;
|
||||
type.attr("f8e4m3") = ov::element::f8e4m3;
|
||||
type.attr("f8e5m2") = ov::element::f8e5m2;
|
||||
type.attr("string") = ov::element::string;
|
||||
|
||||
type.def("__hash__", &ov::element::Type::hash);
|
||||
|
|
|
|||
|
|
@ -411,3 +411,125 @@ def test_memory_sharing(shared_flag):
|
|||
else:
|
||||
assert not np.array_equal(ov_const.data, arr)
|
||||
assert not np.shares_memory(arr, ov_const.data)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(("ov_type", "numpy_dtype"), [
|
||||
(Type.f32, np.float32),
|
||||
(Type.f16, np.float16),
|
||||
])
|
||||
def test_float_to_f8e5m2_constant(ov_type, numpy_dtype):
|
||||
from openvino.runtime import opset12 as opset
|
||||
import openvino as ov
|
||||
data = np.array([4.75, 4.5, -5.25, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5,
|
||||
0.6, 0.7, 0.8, 0.9, 1, -0.0, -0.1, -0.2, -0.3,
|
||||
-0.4, -0.5, -0.6, -0.7, -0.8, -0.9, -1.0, 0.0000152587890625, 448, 500, 512, 57344], dtype=numpy_dtype)
|
||||
|
||||
compressed_const = opset.constant(data, dtype=ov.Type.f8e5m2, name="f8e5m2_constant")
|
||||
convert = opset.convert(compressed_const, data.dtype)
|
||||
parameter = opset.parameter(ov.PartialShape([-1]), ov_type)
|
||||
add_op = opset.add(parameter, convert)
|
||||
model = ov.Model([add_op], [parameter])
|
||||
|
||||
compiled = ov.compile_model(model)
|
||||
tensor = np.zeros(data.shape, dtype=numpy_dtype)
|
||||
result = compiled(tensor)[0]
|
||||
|
||||
target = [5.0, 4.0, -5.0, 0.0, 0.09375, 0.1875, 0.3125, 0.375, 0.5, 0.625, 0.75,
|
||||
0.75, 0.875, 1.0, -0.0, -0.09375, -0.1875, -0.3125, -0.375,
|
||||
-0.5, -0.625, -0.75, -0.75, -0.875, -1.0, 0.0000152587890625,
|
||||
448, 512, 512, 57344]
|
||||
target = np.array(target, dtype=numpy_dtype)
|
||||
|
||||
assert np.allclose(result, target)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(("ov_type", "numpy_dtype"), [
|
||||
(Type.f32, np.float32),
|
||||
(Type.f16, np.float16),
|
||||
])
|
||||
def test_float_to_f8e4m3_constant(ov_type, numpy_dtype):
|
||||
from openvino.runtime import opset12 as opset
|
||||
import openvino as ov
|
||||
data = np.array([4.75, 4.5, -5.25, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5,
|
||||
0.6, 0.7, 0.8, 0.9, 1, -0.0, -0.1, -0.2, -0.3,
|
||||
-0.4, -0.5, -0.6, -0.7, -0.8, -0.9, -1, 448, 512], dtype=numpy_dtype)
|
||||
|
||||
compressed_const = opset.constant(data, dtype=ov.Type.f8e4m3, name="f8e4m3_constant")
|
||||
convert = opset.convert(compressed_const, data.dtype)
|
||||
parameter = opset.parameter(ov.PartialShape([-1]), ov_type)
|
||||
add_op = opset.add(parameter, convert)
|
||||
model = ov.Model([add_op], [parameter])
|
||||
|
||||
compiled = ov.compile_model(model)
|
||||
tensor = np.zeros(data.shape, dtype=numpy_dtype)
|
||||
result = compiled(tensor)[0]
|
||||
|
||||
target = [5.0, 4.5, -5.0, 0.0, 0.1015625, 0.203125, 0.3125,
|
||||
0.40625, 0.5, 0.625, 0.6875, 0.8125, 0.875, 1,
|
||||
-0, -0.1015625, -0.203125, -0.3125, -0.40625, -0.5, -0.625,
|
||||
-0.6875, -0.8125, -0.875, -1, 448, np.nan]
|
||||
target = np.array(target, dtype=numpy_dtype)
|
||||
|
||||
assert np.allclose(result, target, equal_nan=True)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(("ov_type", "numpy_dtype"), [
|
||||
(Type.f32, np.float32),
|
||||
(Type.f16, np.float16),
|
||||
])
|
||||
def test_float_to_f8e5m2_convert(ov_type, numpy_dtype):
|
||||
from openvino.runtime import opset12 as opset
|
||||
import openvino as ov
|
||||
data = np.array([4.75, 4.5, -5.25, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5,
|
||||
0.6, 0.7, 0.8, 0.9, 1, -0.0, -0.1, -0.2, -0.3,
|
||||
-0.4, -0.5, -0.6, -0.7, -0.8, -0.9, -1.0, 0.0000152587890625, 448, 500, 512, 57344], dtype=numpy_dtype)
|
||||
|
||||
compressed_const = opset.constant(data, dtype=ov_type, name="fx_constant")
|
||||
convert_to_fp8 = opset.convert(compressed_const, Type.f8e5m2)
|
||||
convert_back = opset.convert(convert_to_fp8, ov_type)
|
||||
parameter = opset.parameter(ov.PartialShape([-1]), ov_type)
|
||||
add_op = opset.add(parameter, convert_back)
|
||||
model = ov.Model([add_op], [parameter])
|
||||
|
||||
compiled = ov.compile_model(model)
|
||||
tensor = np.zeros(data.shape, dtype=numpy_dtype)
|
||||
result = compiled(tensor)[0]
|
||||
|
||||
target = [5.0, 4.0, -5.0, 0.0, 0.09375, 0.1875, 0.3125, 0.375, 0.5, 0.625, 0.75,
|
||||
0.75, 0.875, 1.0, -0.0, -0.09375, -0.1875, -0.3125, -0.375,
|
||||
-0.5, -0.625, -0.75, -0.75, -0.875, -1.0, 0.0000152587890625,
|
||||
448, 512, 512, 57344]
|
||||
target = np.array(target, dtype=numpy_dtype)
|
||||
|
||||
assert np.allclose(result, target)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(("ov_type", "numpy_dtype"), [
|
||||
(Type.f32, np.float32),
|
||||
(Type.f16, np.float16),
|
||||
])
|
||||
def test_float_to_f8e4m3_convert(ov_type, numpy_dtype):
|
||||
from openvino.runtime import opset12 as opset
|
||||
import openvino as ov
|
||||
data = np.array([4.75, 4.5, -5.25, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5,
|
||||
0.6, 0.7, 0.8, 0.9, 1, -0.0, -0.1, -0.2, -0.3,
|
||||
-0.4, -0.5, -0.6, -0.7, -0.8, -0.9, -1, 448, 512], dtype=numpy_dtype)
|
||||
|
||||
compressed_const = opset.constant(data, dtype=ov_type, name="fx_constant")
|
||||
convert_to_fp8 = opset.convert(compressed_const, Type.f8e4m3)
|
||||
convert_back = opset.convert(convert_to_fp8, ov_type)
|
||||
parameter = opset.parameter(ov.PartialShape([-1]), ov_type)
|
||||
add_op = opset.add(parameter, convert_back)
|
||||
model = ov.Model([add_op], [parameter])
|
||||
|
||||
compiled = ov.compile_model(model)
|
||||
tensor = np.zeros(data.shape, dtype=numpy_dtype)
|
||||
result = compiled(tensor)[0]
|
||||
|
||||
target = [5.0, 4.5, -5.0, 0.0, 0.1015625, 0.203125, 0.3125,
|
||||
0.40625, 0.5, 0.625, 0.6875, 0.8125, 0.875, 1,
|
||||
-0, -0.1015625, -0.203125, -0.3125, -0.40625, -0.5, -0.625,
|
||||
-0.6875, -0.8125, -0.875, -1, 448, np.nan]
|
||||
target = np.array(target, dtype=numpy_dtype)
|
||||
|
||||
assert np.allclose(result, target, equal_nan=True)
|
||||
|
|
|
|||
|
|
@ -35,6 +35,8 @@ using ov::element::dynamic;
|
|||
using ov::element::f16;
|
||||
using ov::element::f32;
|
||||
using ov::element::f64;
|
||||
using ov::element::f8e4m3;
|
||||
using ov::element::f8e5m2;
|
||||
using ov::element::i16;
|
||||
using ov::element::i32;
|
||||
using ov::element::i4;
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@
|
|||
#include "openvino/core/rtti.hpp"
|
||||
#include "openvino/core/type/bfloat16.hpp"
|
||||
#include "openvino/core/type/float16.hpp"
|
||||
#include "openvino/core/type/float8_e4m3.hpp"
|
||||
#include "openvino/core/type/float8_e5m2.hpp"
|
||||
|
||||
/**
|
||||
* @defgroup ov_element_cpp_api Element types
|
||||
|
|
@ -52,6 +54,8 @@ enum class Type_t {
|
|||
u32, //!< u32 element type
|
||||
u64, //!< u64 element type
|
||||
nf4, //!< nf4 element type
|
||||
f8e4m3, //!< f8e4m3 element type
|
||||
f8e5m2, //!< f8e5m2 element type
|
||||
string //!< string element type
|
||||
};
|
||||
|
||||
|
|
@ -182,6 +186,12 @@ constexpr Type u64(Type_t::u64);
|
|||
/// \brief nf4 element type
|
||||
/// \ingroup ov_element_cpp_api
|
||||
constexpr Type nf4(Type_t::nf4);
|
||||
/// \brief f8e4m3 element type
|
||||
/// \ingroup ov_element_cpp_api
|
||||
constexpr Type f8e4m3(Type_t::f8e4m3);
|
||||
/// \brief f8e4m3 element type
|
||||
/// \ingroup ov_element_cpp_api
|
||||
constexpr Type f8e5m2(Type_t::f8e5m2);
|
||||
/// \brief string element type
|
||||
/// \ingroup ov_element_cpp_api
|
||||
constexpr Type string(Type_t::string);
|
||||
|
|
@ -219,6 +229,10 @@ OPENVINO_API Type from<ov::bfloat16>();
|
|||
template <>
|
||||
OPENVINO_API Type from<ov::float16>();
|
||||
template <>
|
||||
OPENVINO_API Type from<ov::float8_e4m3>();
|
||||
template <>
|
||||
OPENVINO_API Type from<ov::float8_e5m2>();
|
||||
template <>
|
||||
OPENVINO_API Type from<std::string>();
|
||||
|
||||
OPENVINO_API Type fundamental_type_for(const Type& type);
|
||||
|
|
|
|||
|
|
@ -98,6 +98,16 @@ struct element_type_traits<element::Type_t::nf4> {
|
|||
using value_type = int8_t;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct element_type_traits<element::Type_t::f8e4m3> {
|
||||
using value_type = ov::float8_e4m3;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct element_type_traits<element::Type_t::f8e5m2> {
|
||||
using value_type = ov::float8_e5m2;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct element_type_traits<element::Type_t::string> {
|
||||
using value_type = std::string;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,157 @@
|
|||
// Copyright (C) 2018-2023 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "openvino/core/core_visibility.hpp"
|
||||
|
||||
namespace ov {
|
||||
|
||||
/**
|
||||
* @brief Class to represent the f8e4m3 type.
|
||||
*/
|
||||
class OPENVINO_API float8_e4m3 {
|
||||
public:
|
||||
float8_e4m3() = default;
|
||||
float8_e4m3(uint32_t sign, uint32_t biased_exponent, uint32_t fraction);
|
||||
float8_e4m3(float value);
|
||||
|
||||
template <typename I>
|
||||
explicit float8_e4m3(I value) : m_value{float8_e4m3{static_cast<float>(value)}.m_value} {}
|
||||
|
||||
template <typename T>
|
||||
bool operator==(const T& other) const;
|
||||
template <typename T>
|
||||
bool operator!=(const T& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool operator<(const T& other) const;
|
||||
template <typename T>
|
||||
bool operator<=(const T& other) const;
|
||||
template <typename T>
|
||||
bool operator>(const T& other) const;
|
||||
template <typename T>
|
||||
bool operator>=(const T& other) const;
|
||||
template <typename T>
|
||||
float8_e4m3 operator+(const T& other) const;
|
||||
template <typename T>
|
||||
float8_e4m3 operator+=(const T& other);
|
||||
template <typename T>
|
||||
float8_e4m3 operator-(const T& other) const;
|
||||
template <typename T>
|
||||
float8_e4m3 operator-=(const T& other);
|
||||
template <typename T>
|
||||
float8_e4m3 operator*(const T& other) const;
|
||||
template <typename T>
|
||||
float8_e4m3 operator*=(const T& other);
|
||||
template <typename T>
|
||||
float8_e4m3 operator/(const T& other) const;
|
||||
template <typename T>
|
||||
float8_e4m3 operator/=(const T& other);
|
||||
|
||||
operator float() const;
|
||||
|
||||
static constexpr float8_e4m3 from_bits(uint8_t bits) {
|
||||
return float8_e4m3(bits, true);
|
||||
}
|
||||
uint8_t to_bits() const;
|
||||
friend std::ostream& operator<<(std::ostream& out, const float8_e4m3& obj) {
|
||||
out << static_cast<float>(obj);
|
||||
return out;
|
||||
}
|
||||
|
||||
private:
|
||||
constexpr float8_e4m3(uint8_t x, bool) : m_value{x} {}
|
||||
|
||||
uint8_t m_value;
|
||||
};
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable : 4756)
|
||||
#endif
|
||||
template <typename T>
|
||||
bool float8_e4m3::operator==(const T& other) const {
|
||||
#if defined(__GNUC__)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||
#endif
|
||||
return (static_cast<float>(*this) == static_cast<float>(other));
|
||||
#if defined(__GNUC__)
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool float8_e4m3::operator<(const T& other) const {
|
||||
return (static_cast<float>(*this) < static_cast<float>(other));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool float8_e4m3::operator<=(const T& other) const {
|
||||
return (static_cast<float>(*this) <= static_cast<float>(other));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool float8_e4m3::operator>(const T& other) const {
|
||||
return (static_cast<float>(*this) > static_cast<float>(other));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool float8_e4m3::operator>=(const T& other) const {
|
||||
return (static_cast<float>(*this) >= static_cast<float>(other));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
float8_e4m3 float8_e4m3::operator+(const T& other) const {
|
||||
return {static_cast<float>(*this) + static_cast<float>(other)};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
float8_e4m3 float8_e4m3::operator+=(const T& other) {
|
||||
return *this = *this + other;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
float8_e4m3 float8_e4m3::operator-(const T& other) const {
|
||||
return {static_cast<float>(*this) - static_cast<float>(other)};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
float8_e4m3 float8_e4m3::operator-=(const T& other) {
|
||||
return *this = *this - other;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
float8_e4m3 float8_e4m3::operator*(const T& other) const {
|
||||
return {static_cast<float>(*this) * static_cast<float>(other)};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
float8_e4m3 float8_e4m3::operator*=(const T& other) {
|
||||
return *this = *this * other;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
float8_e4m3 float8_e4m3::operator/(const T& other) const {
|
||||
return {static_cast<float>(*this) / static_cast<float>(other)};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
float8_e4m3 float8_e4m3::operator/=(const T& other) {
|
||||
return *this = *this / other;
|
||||
}
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
} // namespace ov
|
||||
|
|
@ -0,0 +1,157 @@
|
|||
// Copyright (C) 2018-2023 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "openvino/core/core_visibility.hpp"
|
||||
|
||||
namespace ov {
|
||||
|
||||
/**
|
||||
* @brief Class to represent the f8e5m2 type.
|
||||
*/
|
||||
class OPENVINO_API float8_e5m2 {
|
||||
public:
|
||||
float8_e5m2() = default;
|
||||
float8_e5m2(uint32_t sign, uint32_t biased_exponent, uint32_t fraction);
|
||||
float8_e5m2(float value);
|
||||
|
||||
template <typename I>
|
||||
explicit float8_e5m2(I value) : m_value{float8_e5m2{static_cast<float>(value)}.m_value} {}
|
||||
|
||||
template <typename T>
|
||||
bool operator==(const T& other) const;
|
||||
template <typename T>
|
||||
bool operator!=(const T& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool operator<(const T& other) const;
|
||||
template <typename T>
|
||||
bool operator<=(const T& other) const;
|
||||
template <typename T>
|
||||
bool operator>(const T& other) const;
|
||||
template <typename T>
|
||||
bool operator>=(const T& other) const;
|
||||
template <typename T>
|
||||
float8_e5m2 operator+(const T& other) const;
|
||||
template <typename T>
|
||||
float8_e5m2 operator+=(const T& other);
|
||||
template <typename T>
|
||||
float8_e5m2 operator-(const T& other) const;
|
||||
template <typename T>
|
||||
float8_e5m2 operator-=(const T& other);
|
||||
template <typename T>
|
||||
float8_e5m2 operator*(const T& other) const;
|
||||
template <typename T>
|
||||
float8_e5m2 operator*=(const T& other);
|
||||
template <typename T>
|
||||
float8_e5m2 operator/(const T& other) const;
|
||||
template <typename T>
|
||||
float8_e5m2 operator/=(const T& other);
|
||||
|
||||
operator float() const;
|
||||
|
||||
static constexpr float8_e5m2 from_bits(uint8_t bits) {
|
||||
return float8_e5m2(bits, true);
|
||||
}
|
||||
uint8_t to_bits() const;
|
||||
friend std::ostream& operator<<(std::ostream& out, const float8_e5m2& obj) {
|
||||
out << static_cast<float>(obj);
|
||||
return out;
|
||||
}
|
||||
|
||||
private:
|
||||
constexpr float8_e5m2(uint8_t x, bool) : m_value{x} {}
|
||||
|
||||
uint8_t m_value;
|
||||
};
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable : 4756)
|
||||
#endif
|
||||
template <typename T>
|
||||
bool float8_e5m2::operator==(const T& other) const {
|
||||
#if defined(__GNUC__)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||
#endif
|
||||
return (static_cast<float>(*this) == static_cast<float>(other));
|
||||
#if defined(__GNUC__)
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool float8_e5m2::operator<(const T& other) const {
|
||||
return (static_cast<float>(*this) < static_cast<float>(other));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool float8_e5m2::operator<=(const T& other) const {
|
||||
return (static_cast<float>(*this) <= static_cast<float>(other));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool float8_e5m2::operator>(const T& other) const {
|
||||
return (static_cast<float>(*this) > static_cast<float>(other));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool float8_e5m2::operator>=(const T& other) const {
|
||||
return (static_cast<float>(*this) >= static_cast<float>(other));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
float8_e5m2 float8_e5m2::operator+(const T& other) const {
|
||||
return {static_cast<float>(*this) + static_cast<float>(other)};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
float8_e5m2 float8_e5m2::operator+=(const T& other) {
|
||||
return *this = *this + other;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
float8_e5m2 float8_e5m2::operator-(const T& other) const {
|
||||
return {static_cast<float>(*this) - static_cast<float>(other)};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
float8_e5m2 float8_e5m2::operator-=(const T& other) {
|
||||
return *this = *this - other;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
float8_e5m2 float8_e5m2::operator*(const T& other) const {
|
||||
return {static_cast<float>(*this) * static_cast<float>(other)};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
float8_e5m2 float8_e5m2::operator*=(const T& other) {
|
||||
return *this = *this * other;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
float8_e5m2 float8_e5m2::operator/(const T& other) const {
|
||||
return {static_cast<float>(*this) / static_cast<float>(other)};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
float8_e5m2 float8_e5m2::operator/=(const T& other) {
|
||||
return *this = *this / other;
|
||||
}
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
} // namespace ov
|
||||
|
|
@ -164,6 +164,12 @@ public:
|
|||
case Type_t::nf4:
|
||||
fill_data<Type_t::nf4>(value);
|
||||
break;
|
||||
case Type_t::f8e4m3:
|
||||
fill_data<Type_t::f8e4m3>(value);
|
||||
break;
|
||||
case Type_t::f8e5m2:
|
||||
fill_data<Type_t::f8e5m2>(value);
|
||||
break;
|
||||
case Type_t::string:
|
||||
fill_data<Type_t::string>(value);
|
||||
break;
|
||||
|
|
@ -882,6 +888,12 @@ private:
|
|||
case Type_t::nf4:
|
||||
write_buffer<Type_t::nf4>(source);
|
||||
break;
|
||||
case Type_t::f8e4m3:
|
||||
write_buffer<Type_t::f8e4m3>(source);
|
||||
break;
|
||||
case Type_t::f8e5m2:
|
||||
write_buffer<Type_t::f8e5m2>(source);
|
||||
break;
|
||||
case Type_t::string:
|
||||
write_buffer<Type_t::string>(source);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ namespace ov {
|
|||
template <class T>
|
||||
constexpr bool is_floating_point() {
|
||||
using U = typename std::decay<T>::type;
|
||||
return std::is_floating_point<U>::value || std::is_same<float16, U>::value || std::is_same<bfloat16, U>::value;
|
||||
return std::is_floating_point<U>::value || std::is_same<float16, U>::value || std::is_same<bfloat16, U>::value ||
|
||||
std::is_same<float8_e4m3, U>::value || std::is_same<float8_e5m2, U>::value;
|
||||
}
|
||||
} // namespace ov
|
||||
|
|
|
|||
|
|
@ -221,8 +221,26 @@ struct ValueToString : ov::element::NotSupported<std::string> {
|
|||
|
||||
std::string Constant::convert_value_to_string(size_t index) const {
|
||||
using namespace ov::element;
|
||||
return IfTypeOf<boolean, bf16, f16, f32, f64, i4, i8, i16, i32, i64, u1, u4, u8, u16, u32, u64, nf4, string>::apply<
|
||||
ValueToString>(get_element_type(), this, index);
|
||||
return IfTypeOf<boolean,
|
||||
bf16,
|
||||
f16,
|
||||
f32,
|
||||
f64,
|
||||
i4,
|
||||
i8,
|
||||
i16,
|
||||
i32,
|
||||
i64,
|
||||
u1,
|
||||
u4,
|
||||
u8,
|
||||
u16,
|
||||
u32,
|
||||
u64,
|
||||
nf4,
|
||||
f8e4m3,
|
||||
f8e5m2,
|
||||
string>::apply<ValueToString>(get_element_type(), this, index);
|
||||
}
|
||||
|
||||
size_t Constant::get_byte_size() const {
|
||||
|
|
|
|||
|
|
@ -19,7 +19,8 @@ constexpr bool is_lp_type(const element::Type_t et) {
|
|||
return (et == element::i4) || (et == element::u1) || (et == element::u4) || (et == element::nf4);
|
||||
}
|
||||
|
||||
#define CONVERT_ET_LIST boolean, bf16, f16, f32, f64, i4, i8, i16, i32, i64, u1, u4, u8, u16, u32, u64, nf4
|
||||
#define CONVERT_ET_LIST \
|
||||
boolean, bf16, f16, f32, f64, i4, i8, i16, i32, i64, u1, u4, u8, u16, u32, u64, nf4, f8e4m3, f8e5m2
|
||||
|
||||
struct Evaluate : public element::NoAction<bool> {
|
||||
using element::NoAction<bool>::visit;
|
||||
|
|
@ -173,6 +174,8 @@ bool Convert::has_evaluate() const {
|
|||
case element::u32:
|
||||
case element::u64:
|
||||
case element::nf4:
|
||||
case element::f8e4m3:
|
||||
case element::f8e5m2:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -376,6 +376,8 @@ static std::string get_value(const std::shared_ptr<ov::op::v0::Constant>& consta
|
|||
case ov::element::Type_t::u4:
|
||||
case ov::element::Type_t::nf4:
|
||||
case ov::element::Type_t::i4:
|
||||
case ov::element::Type_t::f8e4m3:
|
||||
case ov::element::Type_t::f8e5m2:
|
||||
ss << constant->get_output_element_type(0).get_type_name() << " value";
|
||||
break;
|
||||
case ov::element::Type_t::bf16:
|
||||
|
|
|
|||
|
|
@ -71,6 +71,10 @@ inline TypeInfo get_type_info(ov::element::Type_t type) {
|
|||
return {64, false, false, false, "uint64_t", "u64"};
|
||||
case ov::element::Type_t::nf4:
|
||||
return {4, false, false, true, "nfloat4", "nf4"};
|
||||
case ov::element::Type_t::f8e4m3:
|
||||
return {8, true, true, true, "f8e4m3", "f8e4m3"};
|
||||
case ov::element::Type_t::f8e5m2:
|
||||
return {8, true, true, true, "f8e5m2", "f8e5m2"};
|
||||
case ov::element::Type_t::string:
|
||||
return {8 * sizeof(std::string), false, false, false, "string", "string"};
|
||||
default:
|
||||
|
|
@ -119,6 +123,10 @@ ov::element::Type type_from_string(const std::string& type) {
|
|||
return ::ov::element::Type(::ov::element::Type_t::dynamic);
|
||||
} else if (type == "nf4" || type == "NF4") {
|
||||
return ::ov::element::Type(::ov::element::Type_t::nf4);
|
||||
} else if (type == "f8e4m3" || type == "F8E4M3") {
|
||||
return ::ov::element::Type(::ov::element::Type_t::f8e4m3);
|
||||
} else if (type == "f8e5m2" || type == "F8E5M2") {
|
||||
return ::ov::element::Type(::ov::element::Type_t::f8e5m2);
|
||||
} else {
|
||||
OPENVINO_THROW("Incorrect type: ", type);
|
||||
}
|
||||
|
|
@ -126,24 +134,12 @@ ov::element::Type type_from_string(const std::string& type) {
|
|||
} // namespace
|
||||
|
||||
std::vector<const ov::element::Type*> ov::element::Type::get_known_types() {
|
||||
std::vector<const ov::element::Type*> rc = {&ov::element::dynamic,
|
||||
&ov::element::boolean,
|
||||
&ov::element::bf16,
|
||||
&ov::element::f16,
|
||||
&ov::element::f32,
|
||||
&ov::element::f64,
|
||||
&ov::element::i4,
|
||||
&ov::element::i8,
|
||||
&ov::element::i16,
|
||||
&ov::element::i32,
|
||||
&ov::element::i64,
|
||||
&ov::element::u1,
|
||||
&ov::element::u4,
|
||||
&ov::element::u8,
|
||||
&ov::element::u16,
|
||||
&ov::element::u32,
|
||||
&ov::element::u64,
|
||||
&ov::element::string};
|
||||
std::vector<const ov::element::Type*> rc = {
|
||||
&ov::element::dynamic, &ov::element::boolean, &ov::element::bf16, &ov::element::f16, &ov::element::f32,
|
||||
&ov::element::f64, &ov::element::i4, &ov::element::i8, &ov::element::i16, &ov::element::i32,
|
||||
&ov::element::i64, &ov::element::u1, &ov::element::u4, &ov::element::u8, &ov::element::u16,
|
||||
&ov::element::u32, &ov::element::u64, &ov::element::nf4, &ov::element::f8e4m3, &ov::element::f8e5m2,
|
||||
&ov::element::string};
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
@ -172,7 +168,9 @@ ov::element::Type::Type(size_t bitwidth,
|
|||
{ov::element::Type_t::u16, {16, false, false, false, "uint16_t", "u16"}},
|
||||
{ov::element::Type_t::u32, {32, false, false, false, "uint32_t", "u32"}},
|
||||
{ov::element::Type_t::u64, {64, false, false, false, "uint64_t", "u64"}},
|
||||
{ov::element::Type_t::u4, {4, false, false, false, "uint4_t", "nf4"}},
|
||||
{ov::element::Type_t::nf4, {4, false, false, true, "nfloat4", "nf4"}},
|
||||
{ov::element::Type_t::f8e4m3, {8, true, true, true, "f8e4m3", "f8e4m3"}},
|
||||
{ov::element::Type_t::f8e5m2, {8, true, true, true, "f8e5m2", "f8e5m2"}},
|
||||
{ov::element::Type_t::string, {8 * sizeof(std::string), false, false, false, "string", "string"}},
|
||||
};
|
||||
for (const auto& t : elements_map) {
|
||||
|
|
@ -266,6 +264,14 @@ Type from<ov::bfloat16>() {
|
|||
return Type_t::bf16;
|
||||
}
|
||||
template <>
|
||||
Type from<ov::float8_e4m3>() {
|
||||
return Type_t::f8e4m3;
|
||||
}
|
||||
template <>
|
||||
Type from<ov::float8_e5m2>() {
|
||||
return Type_t::f8e5m2;
|
||||
}
|
||||
template <>
|
||||
Type from<std::string>() {
|
||||
return Type_t::string;
|
||||
}
|
||||
|
|
@ -282,6 +288,10 @@ Type fundamental_type_for(const Type& type) {
|
|||
return from<element_type_traits<Type_t::f32>::value_type>();
|
||||
case Type_t::f64:
|
||||
return from<element_type_traits<Type_t::f64>::value_type>();
|
||||
case Type_t::f8e4m3:
|
||||
return from<element_type_traits<Type_t::f8e4m3>::value_type>();
|
||||
case Type_t::f8e5m2:
|
||||
return from<element_type_traits<Type_t::f8e5m2>::value_type>();
|
||||
case Type_t::i4:
|
||||
return from<element_type_traits<Type_t::i4>::value_type>();
|
||||
case Type_t::i8:
|
||||
|
|
@ -304,6 +314,8 @@ Type fundamental_type_for(const Type& type) {
|
|||
return from<element_type_traits<Type_t::u32>::value_type>();
|
||||
case Type_t::u64:
|
||||
return from<element_type_traits<Type_t::u64>::value_type>();
|
||||
case Type_t::nf4:
|
||||
return from<element_type_traits<Type_t::nf4>::value_type>();
|
||||
case Type_t::string:
|
||||
return from<element_type_traits<Type_t::string>::value_type>();
|
||||
default:
|
||||
|
|
@ -320,24 +332,13 @@ std::ostream& ov::element::operator<<(std::ostream& out, const ov::element::Type
|
|||
|
||||
std::istream& ov::element::operator>>(std::istream& in, ov::element::Type& obj) {
|
||||
const std::unordered_map<std::string, ov::element::Type> legacy = {
|
||||
{"BOOL", ov::element::boolean},
|
||||
{"BF16", ov::element::bf16},
|
||||
{"I4", ov::element::i4},
|
||||
{"I8", ov::element::i8},
|
||||
{"I16", ov::element::i16},
|
||||
{"I32", ov::element::i32},
|
||||
{"I64", ov::element::i64},
|
||||
{"U4", ov::element::u4},
|
||||
{"U8", ov::element::u8},
|
||||
{"U16", ov::element::u16},
|
||||
{"U32", ov::element::u32},
|
||||
{"U64", ov::element::u64},
|
||||
{"FP32", ov::element::f32},
|
||||
{"FP64", ov::element::f64},
|
||||
{"FP16", ov::element::f16},
|
||||
{"BIN", ov::element::u1},
|
||||
{"NF4", ov::element::nf4},
|
||||
{"STRING", ov::element::string},
|
||||
{"BOOL", ov::element::boolean}, {"BF16", ov::element::bf16}, {"I4", ov::element::i4},
|
||||
{"I8", ov::element::i8}, {"I16", ov::element::i16}, {"I32", ov::element::i32},
|
||||
{"I64", ov::element::i64}, {"U4", ov::element::u4}, {"U8", ov::element::u8},
|
||||
{"U16", ov::element::u16}, {"U32", ov::element::u32}, {"U64", ov::element::u64},
|
||||
{"FP32", ov::element::f32}, {"FP64", ov::element::f64}, {"FP16", ov::element::f16},
|
||||
{"BIN", ov::element::u1}, {"NF4", ov::element::nf4}, {"F8E4M3", ov::element::f8e4m3},
|
||||
{"F8E5M2", ov::element::f8e5m2}, {"STRING", ov::element::string},
|
||||
};
|
||||
std::string str;
|
||||
in >> str;
|
||||
|
|
@ -420,6 +421,8 @@ inline size_t compiler_byte_size(ov::element::Type_t et) {
|
|||
ET_CASE(u32);
|
||||
ET_CASE(u64);
|
||||
ET_CASE(nf4);
|
||||
ET_CASE(f8e4m3);
|
||||
ET_CASE(f8e5m2);
|
||||
ET_CASE(string);
|
||||
#undef ET_CASE
|
||||
case ov::element::Type_t::undefined:
|
||||
|
|
@ -454,6 +457,8 @@ OPENVINO_API EnumNames<element::Type_t>& EnumNames<element::Type_t>::get() {
|
|||
{"u32", element::Type_t::u32},
|
||||
{"u64", element::Type_t::u64},
|
||||
{"nf4", element::Type_t::nf4},
|
||||
{"f8e4m3", element::Type_t::f8e4m3},
|
||||
{"f8e5m2", element::Type_t::f8e5m2},
|
||||
{"string", element::Type_t::string}});
|
||||
return enum_names;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,135 @@
|
|||
// Copyright (C) 2018-2023 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#include "openvino/core/type/float8_e4m3.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
|
||||
namespace ov {
|
||||
|
||||
static_assert(sizeof(float8_e4m3) == 1, "class f8e4m3 must be exactly 1 byte");
|
||||
static_assert(std::is_trivially_constructible<float8_e4m3, float8_e4m3>::value, "should be trivially constructible");
|
||||
static_assert(std::is_trivially_copyable<float8_e4m3>::value, "must be trivially copyable");
|
||||
static_assert(std::is_trivially_destructible<float8_e4m3>::value, "must be trivially destructible");
|
||||
|
||||
namespace {
|
||||
constexpr auto float_nan = std::numeric_limits<float>::quiet_NaN();
|
||||
// Lookup table for conversion f8 -> float. The f8 bit value without sign bit (masked 0x7f) is LUT offset.
|
||||
static constexpr std::array<float, 128> f8_to_float_lut{
|
||||
0.0f, 0.001953125f, 0.00390625f, 0.005859375f, 0.0078125f, 0.009765625f, 0.01171875f, 0.013671875f,
|
||||
0.015625f, 0.017578125f, 0.01953125f, 0.021484375f, 0.0234375f, 0.025390625f, 0.02734375f, 0.029296875f,
|
||||
0.03125f, 0.03515625f, 0.0390625f, 0.04296875f, 0.046875f, 0.05078125f, 0.0546875f, 0.05859375f,
|
||||
0.0625f, 0.0703125f, 0.078125f, 0.0859375f, 0.09375f, 0.1015625f, 0.109375f, 0.1171875f,
|
||||
0.125f, 0.140625f, 0.15625f, 0.171875f, 0.1875f, 0.203125f, 0.21875f, 0.234375f,
|
||||
0.25f, 0.28125f, 0.3125f, 0.34375f, 0.375f, 0.40625f, 0.4375f, 0.46875f,
|
||||
0.5f, 0.5625f, 0.625f, 0.6875f, 0.75f, 0.8125f, 0.875f, 0.9375f,
|
||||
1.0f, 1.125f, 1.25f, 1.375f, 1.5f, 1.625f, 1.75f, 1.875f,
|
||||
2.0f, 2.25f, 2.5f, 2.75f, 3.0f, 3.25f, 3.5f, 3.75f,
|
||||
4.0f, 4.5f, 5.0f, 5.5f, 6.0f, 6.5f, 7.0f, 7.5f,
|
||||
8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f,
|
||||
16.0f, 18.0f, 20.0f, 22.0f, 24.0f, 26.0f, 28.0f, 30.0f,
|
||||
32.0f, 36.0f, 40.0f, 44.0f, 48.0f, 52.0f, 56.0f, 60.0f,
|
||||
64.0f, 72.0f, 80.0f, 88.0f, 96.0f, 104.0f, 112.0f, 120.0f,
|
||||
128.0f, 144.0f, 160.0f, 176.0f, 192.0f, 208.0f, 224.0f, 240.0f,
|
||||
256.0f, 288.0f, 320.0f, 352.0f, 384.0f, 416.0f, 448.0f, float_nan};
|
||||
|
||||
constexpr uint32_t three_bytes_shift = 24;
|
||||
|
||||
constexpr uint8_t f8e4m3_s_mask = 0x80; // f8e4m3 sign bit mask
|
||||
constexpr uint8_t f8e4m3_e_size = 4; // f8e4m3 exponent bit size
|
||||
constexpr uint8_t f8e4m3_e_mask = 0x78; // f8e4m3 exponent bit mask
|
||||
constexpr uint8_t f8e4m3_e_bias = 7; // f8e4m3 exponent bias
|
||||
constexpr uint8_t f8e4m3_e_max = 0x0f; // f8e4m3 exponent max value
|
||||
constexpr uint8_t f8e4m3_m_size = 3; // f8e4m3 mantissa bits size
|
||||
constexpr uint8_t f8e4m3_m_mask = 0x07; // f8e4m3 mantissa bit mask
|
||||
|
||||
union f32_t {
|
||||
float value;
|
||||
uint32_t bits;
|
||||
};
|
||||
|
||||
uint8_t f32_to_f8e4m3_bits(const float value) {
|
||||
constexpr uint32_t f32_s_mask = 0x80000000; // f32 sign bit mask
|
||||
constexpr uint32_t f32_e_mask = 0x7F800000; // f32 exponent bits mask
|
||||
constexpr uint32_t f32_e_bias = 127; // f32 exponent bias
|
||||
constexpr uint32_t f32_e_size = 8; // f32 exponent bits size
|
||||
constexpr uint32_t f32_m_mask = 0x007fffff; // f32 mantissa bits mask
|
||||
constexpr uint32_t f32_m_size = 23; // f32 mantissa bits size
|
||||
|
||||
constexpr uint32_t f8_e_mask = f8e4m3_e_mask << three_bytes_shift; // f8 exponent bits mask (on u32)
|
||||
constexpr uint32_t f8_m_mask = f8e4m3_m_mask << three_bytes_shift; // f8 mantissa bits mask (on u32)
|
||||
constexpr uint32_t f8_m_hidden_one_mask = 0x08000000; // f8 mantissa hidden one bits mask (on u32)
|
||||
|
||||
constexpr uint32_t round_half = 0x01ffffff; // value for half to even round for f8
|
||||
constexpr uint32_t round_norm = 0x007fffff; // value for normal round for f8
|
||||
constexpr uint32_t round_even = 0x00800000; // value for half to even round for f8
|
||||
constexpr uint32_t round_odd = 0x01800000; // value for an non-half to even round for f8
|
||||
|
||||
const auto input = f32_t{value};
|
||||
auto f8_bits = static_cast<uint8_t>((input.bits & f32_s_mask) >> three_bytes_shift);
|
||||
|
||||
uint32_t f32_e_field = input.bits & f32_e_mask;
|
||||
|
||||
if (f32_e_field == f32_e_mask) {
|
||||
f8_bits |= (f8e4m3_e_mask | f8e4m3_m_mask);
|
||||
} else if (f32_e_field != 0) {
|
||||
int32_t f8_biased_exp = (f32_e_field >> f32_m_size) - (f32_e_bias - f8e4m3_e_bias);
|
||||
uint32_t fractional = (input.bits & f32_m_mask) << (f32_e_size - f8e4m3_e_size);
|
||||
|
||||
// for normalized values round apply rounding change f8 fractional and biased exponent
|
||||
if ((fractional & round_half) == round_odd || (fractional & round_norm) != 0) {
|
||||
fractional += round_even;
|
||||
if (0 != (fractional & f8_e_mask)) {
|
||||
fractional &= f8_e_mask;
|
||||
++f8_biased_exp;
|
||||
}
|
||||
}
|
||||
fractional &= f8_m_mask;
|
||||
|
||||
// set exponent and mantissa on f8 bits
|
||||
if (f8_biased_exp > f8e4m3_e_max) {
|
||||
// Use NAN as this type has no infinity
|
||||
f8_bits |= (f8e4m3_e_mask | f8e4m3_m_mask);
|
||||
} else if (f8_biased_exp > 0) {
|
||||
f8_bits |= (f8_biased_exp << f8e4m3_m_size) | (fractional >> three_bytes_shift);
|
||||
} else {
|
||||
// Restore the hidden 1 in f8 mantissa for subnormal calculation
|
||||
fractional = f8_m_hidden_one_mask | (input.bits & f32_m_mask) << (f32_e_size - f8e4m3_e_size);
|
||||
// Will any bits be shifted off?
|
||||
int32_t shift = f8_biased_exp < -(f8e4m3_e_max) ? 0 : (1U << (1 - f8_biased_exp));
|
||||
uint32_t sticky = (fractional & (shift - 1)) ? 1 : 0;
|
||||
|
||||
fractional = ((1 + f8_biased_exp) > f8e4m3_e_max) ? 0 : fractional >> (1 - f8_biased_exp);
|
||||
fractional |= sticky;
|
||||
// apply rounding
|
||||
if (((fractional & round_half) == round_odd) || ((fractional & round_norm) != 0)) {
|
||||
fractional += round_even;
|
||||
}
|
||||
|
||||
f8_bits |= fractional >> three_bytes_shift;
|
||||
}
|
||||
}
|
||||
|
||||
return f8_bits;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
float8_e4m3::float8_e4m3(const uint32_t sign, const uint32_t biased_exponent, const uint32_t fraction)
|
||||
: m_value(((sign & 0x01U) << (f8e4m3_e_size + f8e4m3_m_size)) |
|
||||
(biased_exponent & (f8e4m3_e_mask >> f8e4m3_m_size)) << f8e4m3_m_size | (fraction & f8e4m3_m_mask)) {}
|
||||
|
||||
float8_e4m3::float8_e4m3(const float value) : m_value{f32_to_f8e4m3_bits(value)} {}
|
||||
|
||||
float8_e4m3::operator float() const {
|
||||
auto converted = f32_t{f8_to_float_lut[m_value & (f8e4m3_e_mask | f8e4m3_m_mask)]};
|
||||
converted.bits |= (m_value & f8e4m3_s_mask) << three_bytes_shift;
|
||||
return converted.value;
|
||||
}
|
||||
|
||||
uint8_t float8_e4m3::to_bits() const {
|
||||
return m_value;
|
||||
}
|
||||
} // namespace ov
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
// Copyright (C) 2018-2023 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#include "openvino/core/type/float8_e5m2.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
|
||||
#include "openvino/reference/fake_convert.hpp"
|
||||
|
||||
namespace ov {
|
||||
static_assert(sizeof(float8_e5m2) == 1, "class f8e5m2 must be exactly 1 byte");
|
||||
static_assert(std::is_trivially_constructible<float8_e5m2, float8_e5m2>::value, "should be trivially constructible");
|
||||
static_assert(std::is_trivially_copyable<float8_e5m2>::value, "must be trivially copyable");
|
||||
static_assert(std::is_trivially_destructible<float8_e5m2>::value, "must be trivially destructible");
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr uint8_t byte_shift = 8;
|
||||
|
||||
constexpr uint8_t f8e5m2_e_size = 5; // f8e5m2 exponent bit size
|
||||
constexpr uint8_t f8e5m2_e_mask = 0x7c; // f8e5m2 exponent bit mask
|
||||
constexpr uint8_t f8e5m2_m_size = 2; // f8e5m2 mantissa bits size
|
||||
constexpr uint8_t f8e5m2_m_mask = 0x03; // f8e5m2 mantissa bit mask
|
||||
|
||||
uint8_t f32_to_f8e5m2_bits(const float value) {
|
||||
auto f16 = static_cast<float16>(value);
|
||||
reference::func::emulate_f8e5m2_on_fp16(&f16, &f16, 1);
|
||||
return static_cast<uint8_t>((f16.to_bits() >> byte_shift));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
float8_e5m2::float8_e5m2(uint32_t sign, uint32_t biased_exponent, uint32_t fraction)
|
||||
: m_value((sign & 0x01) << (f8e5m2_e_size + f8e5m2_m_size) |
|
||||
(biased_exponent & (f8e5m2_e_mask >> f8e5m2_m_size)) << f8e5m2_m_size | (fraction & f8e5m2_m_mask)) {}
|
||||
|
||||
float8_e5m2::float8_e5m2(const float value) : m_value(f32_to_f8e5m2_bits(value)){};
|
||||
|
||||
float8_e5m2::operator float() const {
|
||||
return static_cast<float>(float16::from_bits((static_cast<uint16_t>(m_value) << byte_shift)));
|
||||
}
|
||||
|
||||
uint8_t float8_e5m2::to_bits() const {
|
||||
return m_value;
|
||||
}
|
||||
} // namespace ov
|
||||
|
|
@ -67,6 +67,10 @@ TEST(element_type, from_string) {
|
|||
EXPECT_EQ(element::Type("U64"), element::u64);
|
||||
EXPECT_EQ(element::Type("nf4"), element::nf4);
|
||||
EXPECT_EQ(element::Type("NF4"), element::nf4);
|
||||
EXPECT_EQ(element::Type("f8e4m3"), element::f8e4m3);
|
||||
EXPECT_EQ(element::Type("F8E4M3"), element::f8e4m3);
|
||||
EXPECT_EQ(element::Type("f8e5m2"), element::f8e5m2);
|
||||
EXPECT_EQ(element::Type("F8E5M2"), element::f8e5m2);
|
||||
EXPECT_EQ(element::Type("string"), element::string);
|
||||
EXPECT_EQ(element::Type("STRING"), element::string);
|
||||
|
||||
|
|
|
|||
|
|
@ -2963,7 +2963,8 @@ TEST(eval, evaluate_fake_convert_f32_to_f8e4m3_no_scale_no_shift) {
|
|||
using namespace testing;
|
||||
constexpr auto et = element::f32;
|
||||
|
||||
std::vector<float> input_data{0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.f};
|
||||
std::vector<float> input_data{0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.f,
|
||||
-0.0f, -0.1f, -0.2f, -0.3f, -0.4f, -0.5f, -0.6f, -0.7f, -0.8f, -0.9f, -1.f};
|
||||
const auto data_shape = Shape{input_data.size()};
|
||||
|
||||
auto data = make_shared<ov::op::v0::Parameter>(et, data_shape);
|
||||
|
|
@ -2983,10 +2984,10 @@ TEST(eval, evaluate_fake_convert_f32_to_f8e4m3_no_scale_no_shift) {
|
|||
EXPECT_EQ(result.get_shape(), data_shape);
|
||||
EXPECT_THAT(
|
||||
read_vector<float>(result),
|
||||
Pointwise(
|
||||
FloatEq(),
|
||||
std::vector<
|
||||
float>{0.f, 0.1015625f, 0.203125f, 0.3125f, 0.40625f, 0.5f, 0.625f, 0.6875f, 0.8125f, 0.875f, 1.f}));
|
||||
Pointwise(FloatEq(), std::vector<float>{0.f, 0.1015625f, 0.203125f, 0.3125f, 0.40625f, 0.5f,
|
||||
0.625f, 0.6875f, 0.8125f, 0.875f, 1.f, -0.f,
|
||||
-0.1015625f, -0.203125f, -0.3125f, -0.40625f, -0.5f, -0.625f,
|
||||
-0.6875f, -0.8125f, -0.875f, -1.f}));
|
||||
}
|
||||
|
||||
TEST(eval, evaluate_fake_convert_f32_seq_to_f8e4m3_scale_1) {
|
||||
|
|
@ -3223,7 +3224,8 @@ TEST(eval, evaluate_fake_convert_f32_to_f8e5m2_scale_1) {
|
|||
using namespace testing;
|
||||
constexpr auto et = element::f32;
|
||||
|
||||
std::vector<float> input_data{0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.f};
|
||||
std::vector<float> input_data{0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.f,
|
||||
-0.0f, -0.1f, -0.2f, -0.3f, -0.4f, -0.5f, -0.6f, -0.7f, -0.8f, -0.9f, -1.f};
|
||||
|
||||
const auto data_shape = Shape{input_data.size()};
|
||||
|
||||
|
|
@ -3244,11 +3246,11 @@ TEST(eval, evaluate_fake_convert_f32_to_f8e5m2_scale_1) {
|
|||
|
||||
EXPECT_EQ(result.get_element_type(), et);
|
||||
EXPECT_EQ(result.get_shape(), data_shape);
|
||||
EXPECT_THAT(
|
||||
read_vector<float>(result),
|
||||
Pointwise(
|
||||
FloatEq(),
|
||||
std::vector<float>{0.f, 0.09375f, 0.1875f, 0.3125f, 0.375f, 0.5f, 0.625f, 0.75f, 0.75f, 0.875f, 1.f}));
|
||||
EXPECT_THAT(read_vector<float>(result),
|
||||
Pointwise(FloatEq(),
|
||||
std::vector<float>{0.f, 0.09375f, 0.1875f, 0.3125f, 0.375f, 0.5f, 0.625f, 0.75f,
|
||||
0.75f, 0.875f, 1.f, -0.f, -0.09375f, -0.1875f, -0.3125f, -0.375f,
|
||||
-0.5f, -0.625f, -0.75f, -0.75f, -0.875f, -1.f}));
|
||||
}
|
||||
|
||||
TEST(eval, evaluate_fake_convert_f16_to_f8e5m2_scale_1) {
|
||||
|
|
@ -3707,7 +3709,7 @@ TEST(eval, evaluate_fake_convert_bf16_matching_f8_to_f8e5m2_scale_1) {
|
|||
4096.f, 5120.f, 6144.f, 7168.f,
|
||||
8192.f, 10240.f, 12288.f, 14336.f,
|
||||
16384.f, 20480.f, 24576.f, 28672.f,
|
||||
32768.f, 40960.f, 49152.f, 57344.0
|
||||
32768.f, 40960.f, 49152.f, 57344.f
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
|
@ -3766,6 +3768,92 @@ TEST(eval, evaluate_fake_convert_f32_matching_f8e4m3_to_f8e5m2_scale_1) {
|
|||
EXPECT_THAT(read_vector<float>(result), Pointwise(FloatEq(), output_data));
|
||||
}
|
||||
|
||||
TEST(eval, evaluate_f8e5m2_const_from_f32) {
|
||||
using namespace testing;
|
||||
constexpr auto et = element::f8e5m2;
|
||||
|
||||
std::vector<float> input_data{
|
||||
0.017578125f, 0.021484375f, 0.025390625f, 0.029296875f, 0.03515625f, 0.0703125f, 0.140625f,
|
||||
0.28125f, 0.5625f, 1.125f, 1.625f, 1.875f, 2.25f, 3.75f,
|
||||
4.5f, 9.f, 18.f, 36.f, 72.f, 144.f, 288.f,
|
||||
};
|
||||
/* Rounded to f8e5m2 vals */
|
||||
std::vector<ov::float8_e5m2> output_data{0.015625f, 0.0234375f, 0.0234375f, 0.03125f, 0.03125f, 0.0625f, 0.125f,
|
||||
0.25f, 0.5f, 1.f, 1.5, 2.f, 2.f, 4.f,
|
||||
4.f, 8.f, 16.f, 32.f, 64.f, 128.f, 256.f};
|
||||
|
||||
const auto data_shape = Shape{input_data.size()};
|
||||
|
||||
auto op = make_shared<op::v0::Constant>(et, data_shape, input_data);
|
||||
auto model = make_shared<Model>(OutputVector{op}, ParameterVector{});
|
||||
|
||||
auto result = ov::Tensor();
|
||||
auto out_vector = ov::TensorVector{result};
|
||||
auto in_vector = ov::TensorVector{};
|
||||
ASSERT_TRUE(model->evaluate(out_vector, in_vector));
|
||||
result = out_vector.at(0);
|
||||
|
||||
EXPECT_EQ(result.get_element_type(), et);
|
||||
EXPECT_EQ(result.get_shape(), data_shape);
|
||||
EXPECT_THAT(read_vector<ov::float8_e5m2>(result), Pointwise(FloatEq(), output_data));
|
||||
}
|
||||
|
||||
TEST(eval, evaluate_f8e5m2_const_seq_from_f32) {
|
||||
using namespace testing;
|
||||
constexpr auto et = element::f8e5m2;
|
||||
|
||||
std::vector<float> input_data{0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.f,
|
||||
-0.0f, -0.1f, -0.2f, -0.3f, -0.4f, -0.5f, -0.6f, -0.7f, -0.8f, -0.9f, -1.f};
|
||||
|
||||
/* Rounded to f8e5m2 vals */
|
||||
std::vector<ov::float8_e5m2> output_data{0.f, 0.09375f, 0.1875f, 0.3125f, 0.375f, 0.5f, 0.625f, 0.75f,
|
||||
0.75f, 0.875f, 1.f, -0.f, -0.09375f, -0.1875f, -0.3125f, -0.375f,
|
||||
-0.5f, -0.625f, -0.75f, -0.75f, -0.875f, -1.f};
|
||||
|
||||
const auto data_shape = Shape{input_data.size()};
|
||||
|
||||
auto op = make_shared<op::v0::Constant>(et, data_shape, input_data);
|
||||
auto model = make_shared<Model>(OutputVector{op}, ParameterVector{});
|
||||
|
||||
auto result = ov::Tensor();
|
||||
auto out_vector = ov::TensorVector{result};
|
||||
auto in_vector = ov::TensorVector{};
|
||||
ASSERT_TRUE(model->evaluate(out_vector, in_vector));
|
||||
result = out_vector.at(0);
|
||||
|
||||
EXPECT_EQ(result.get_element_type(), et);
|
||||
EXPECT_EQ(result.get_shape(), data_shape);
|
||||
EXPECT_THAT(read_vector<ov::float8_e5m2>(result), Pointwise(FloatEq(), output_data));
|
||||
}
|
||||
|
||||
TEST(eval, evaluate_f8e4m3_const_seq_from_f32) {
|
||||
using namespace testing;
|
||||
constexpr auto et = element::f8e4m3;
|
||||
|
||||
std::vector<float> input_data{0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.f,
|
||||
-0.0f, -0.1f, -0.2f, -0.3f, -0.4f, -0.5f, -0.6f, -0.7f, -0.8f, -0.9f, -1.f};
|
||||
|
||||
/* Rounded to f8e4m3 vals */
|
||||
std::vector<ov::float8_e4m3> output_data{
|
||||
0.f, 0.1015625f, 0.203125f, 0.3125f, 0.40625f, 0.5f, 0.625f, 0.6875f, 0.8125f, 0.875f, 1.f,
|
||||
-0.f, -0.1015625f, -0.203125f, -0.3125f, -0.40625f, -0.5f, -0.625f, -0.6875f, -0.8125f, -0.875f, -1.f};
|
||||
|
||||
const auto data_shape = Shape{input_data.size()};
|
||||
|
||||
auto op = make_shared<op::v0::Constant>(et, data_shape, input_data);
|
||||
auto model = make_shared<Model>(OutputVector{op}, ParameterVector{});
|
||||
|
||||
auto result = ov::Tensor();
|
||||
auto out_vector = ov::TensorVector{result};
|
||||
auto in_vector = ov::TensorVector{};
|
||||
ASSERT_TRUE(model->evaluate(out_vector, in_vector));
|
||||
result = out_vector.at(0);
|
||||
|
||||
EXPECT_EQ(result.get_element_type(), et);
|
||||
EXPECT_EQ(result.get_shape(), data_shape);
|
||||
EXPECT_THAT(read_vector<ov::float8_e4m3>(result), Pointwise(FloatEq(), output_data));
|
||||
}
|
||||
|
||||
TEST(eval, evaluate_fake_convert_f32_seq_to_f8e5m2_scale_shift) {
|
||||
using namespace testing;
|
||||
constexpr auto et = element::f32;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,175 @@
|
|||
// Copyright (C) 2018-2023 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#include "openvino/core/type/float8_e4m3.hpp"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <climits>
|
||||
|
||||
#include "common_test_utils/float_util.hpp"
|
||||
namespace ov {
|
||||
namespace test {
|
||||
|
||||
template <class TContainer>
|
||||
std::vector<std::tuple<int, typename TContainer::value_type>> enumerate(const TContainer& values) {
|
||||
std::vector<std::tuple<int, typename TContainer::value_type>> enum_values;
|
||||
int i = 0;
|
||||
for (const auto& v : values) {
|
||||
enum_values.emplace_back(i, v);
|
||||
++i;
|
||||
}
|
||||
return enum_values;
|
||||
}
|
||||
|
||||
TEST(F8E4M3Test, f32_inf) {
|
||||
const auto f8 = ov::float8_e4m3(std::numeric_limits<float>::infinity());
|
||||
|
||||
EXPECT_EQ(f8.to_bits(), 0x7f);
|
||||
}
|
||||
|
||||
TEST(F8E4M3Test, f32_minus_inf) {
|
||||
const auto f8 = ov::float8_e4m3(-std::numeric_limits<float>::infinity());
|
||||
// f8 is NaN as there is no infinity
|
||||
EXPECT_EQ(f8.to_bits(), 0xff);
|
||||
}
|
||||
|
||||
TEST(F8E4M3Test, f32_nan) {
|
||||
const auto f8 = ov::float8_e4m3(std::numeric_limits<float>::quiet_NaN());
|
||||
|
||||
EXPECT_EQ(f8.to_bits(), 0x7f);
|
||||
}
|
||||
|
||||
TEST(F8E4M3Test, f32_gt_zero_le_f8_half_lowest_subnormal) {
|
||||
const auto f8 = ov::float8_e4m3(0.0009765625f);
|
||||
|
||||
EXPECT_EQ(f8.to_bits(), 0x00);
|
||||
}
|
||||
|
||||
TEST(F8E4M3Test, f32_gt_zero_gt_f8_half_lowest_subnormal) {
|
||||
const auto f8 = ov::float8_e4m3(0.00097656273283064365387f);
|
||||
|
||||
EXPECT_EQ(f8.to_bits(), 0x01);
|
||||
}
|
||||
|
||||
TEST(F8E4M3Test, f32_normal_fractional_rounding) {
|
||||
const auto f8 = ov::float8_e4m3(0.129f);
|
||||
|
||||
// Rounded to 0.140625f -> 0x21
|
||||
EXPECT_EQ(f8.to_bits(), 0x20);
|
||||
}
|
||||
|
||||
TEST(F8E4M3Test, f32_normal_negative_fractional_rounding) {
|
||||
const auto f8 = ov::float8_e4m3(-0.281f);
|
||||
|
||||
// Rounded to -0.28125f -> 0x21
|
||||
EXPECT_EQ(f8.to_bits(), 0xa9);
|
||||
}
|
||||
|
||||
TEST(F8E4M3Test, f32_ge_f8_max_within_round_to_max) {
|
||||
const auto f8 = ov::float8_e4m3(460.0f);
|
||||
|
||||
// Rounded to 448.0f -> 0x7e
|
||||
EXPECT_EQ(f8.to_bits(), 0x7e);
|
||||
}
|
||||
|
||||
TEST(F8E4M3Test, f32_ge_f8_max_not_within_round_to_max) {
|
||||
const auto f8 = ov::float8_e4m3(560.0f);
|
||||
|
||||
// f8 has no such value (NaN)
|
||||
EXPECT_EQ(f8.to_bits(), 0x7f);
|
||||
}
|
||||
|
||||
TEST(F8E4M3Test, f32_le_f8_lowest_within_round_to_lowest) {
|
||||
const auto f8 = ov::float8_e4m3(-460.0f);
|
||||
|
||||
// Rounded to -448.0f -> 0xfe
|
||||
EXPECT_EQ(f8.to_bits(), 0xfe);
|
||||
}
|
||||
|
||||
TEST(F8E4M3Test, f32_le_f8_lowest_not_within_round_to_lowest) {
|
||||
const auto f8 = ov::float8_e4m3(-760.0f);
|
||||
|
||||
// f8 has no such value (NaN)
|
||||
EXPECT_EQ(f8.to_bits(), 0xff);
|
||||
}
|
||||
|
||||
TEST(F8E4M3Test, stream_operator) {
|
||||
std::stringstream s;
|
||||
s << ov::float8_e4m3(2.5f);
|
||||
|
||||
EXPECT_EQ(s.str(), "2.5");
|
||||
}
|
||||
|
||||
TEST(F8E4M3Test, to_string) {
|
||||
const auto f8 = ov::float8_e4m3::from_bits(0b00111010);
|
||||
|
||||
EXPECT_EQ(std::to_string(f8), "1.250000");
|
||||
}
|
||||
constexpr auto f32_qnan = std::numeric_limits<float>::quiet_NaN();
|
||||
|
||||
const auto exp_floats = std::vector<float>{
|
||||
0.0f, 0.001953125f, 0.00390625f, 0.005859375f, 0.0078125f, 0.009765625f, 0.01171875f, 0.013671875f,
|
||||
0.015625f, 0.017578125f, 0.01953125f, 0.021484375f, 0.0234375f, 0.025390625f, 0.02734375f, 0.029296875f,
|
||||
0.03125f, 0.03515625f, 0.0390625f, 0.04296875f, 0.046875f, 0.05078125f, 0.0546875f, 0.05859375f,
|
||||
0.0625f, 0.0703125f, 0.078125f, 0.0859375f, 0.09375f, 0.1015625f, 0.109375f, 0.1171875f,
|
||||
0.125f, 0.140625f, 0.15625f, 0.171875f, 0.1875f, 0.203125f, 0.21875f, 0.234375f,
|
||||
0.25f, 0.28125f, 0.3125f, 0.34375f, 0.375f, 0.40625f, 0.4375f, 0.46875f,
|
||||
0.5f, 0.5625f, 0.625f, 0.6875f, 0.75f, 0.8125f, 0.875f, 0.9375f,
|
||||
1.0f, 1.125f, 1.25f, 1.375f, 1.5f, 1.625f, 1.75f, 1.875f,
|
||||
2.0f, 2.25f, 2.5f, 2.75f, 3.0f, 3.25f, 3.5f, 3.75f,
|
||||
4.0f, 4.5f, 5.0f, 5.5f, 6.0f, 6.5f, 7.0f, 7.5f,
|
||||
8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f,
|
||||
16.0f, 18.0f, 20.0f, 22.0f, 24.0f, 26.0f, 28.0f, 30.0f,
|
||||
32.0f, 36.0f, 40.0f, 44.0f, 48.0f, 52.0f, 56.0f, 60.0f,
|
||||
64.0f, 72.0f, 80.0f, 88.0f, 96.0f, 104.0f, 112.0f, 120.0f,
|
||||
128.0f, 144.0f, 160.0f, 176.0f, 192.0f, 208.0f, 224.0f, 240.0f,
|
||||
256.0f, 288.0f, 320.0f, 352.0f, 384.0f, 416.0f, 448.0f, f32_qnan,
|
||||
-0.0f, -0.001953125f, -0.00390625f, -0.005859375f, -0.0078125f, -0.009765625f, -0.01171875f, -0.013671875f,
|
||||
-0.015625f, -0.017578125f, -0.01953125f, -0.021484375f, -0.0234375f, -0.025390625f, -0.02734375f, -0.029296875f,
|
||||
-0.03125f, -0.03515625f, -0.0390625f, -0.04296875f, -0.046875f, -0.05078125f, -0.0546875f, -0.05859375f,
|
||||
-0.0625f, -0.0703125f, -0.078125f, -0.0859375f, -0.09375f, -0.1015625f, -0.109375f, -0.1171875f,
|
||||
-0.125f, -0.140625f, -0.15625f, -0.171875f, -0.1875f, -0.203125f, -0.21875f, -0.234375f,
|
||||
-0.25f, -0.28125f, -0.3125f, -0.34375f, -0.375f, -0.40625f, -0.4375f, -0.46875f,
|
||||
-0.5f, -0.5625f, -0.625f, -0.6875f, -0.75f, -0.8125f, -0.875f, -0.9375f,
|
||||
-1.0f, -1.125f, -1.25f, -1.375f, -1.5f, -1.625f, -1.75f, -1.875f,
|
||||
-2.0f, -2.25f, -2.5f, -2.75f, -3.0f, -3.25f, -3.5f, -3.75f,
|
||||
-4.0f, -4.5f, -5.0f, -5.5f, -6.0f, -6.5f, -7.0f, -7.5f,
|
||||
-8.0f, -9.0f, -10.0f, -11.0f, -12.0f, -13.0f, -14.0f, -15.0f,
|
||||
-16.0f, -18.0f, -20.0f, -22.0f, -24.0f, -26.0f, -28.0f, -30.0f,
|
||||
-32.0f, -36.0f, -40.0f, -44.0f, -48.0f, -52.0f, -56.0f, -60.0f,
|
||||
-64.0f, -72.0f, -80.0f, -88.0f, -96.0f, -104.0f, -112.0f, -120.0f,
|
||||
-128.0f, -144.0f, -160.0f, -176.0f, -192.0f, -208.0f, -224.0f, -240.0f,
|
||||
-256.0f, -288.0f, -320.0f, -352.0f, -384.0f, -416.0f, -448.0f, -f32_qnan};
|
||||
|
||||
using f8m4e3_params = std::tuple<int, float>;
|
||||
class F8E4M3PTest : public testing::TestWithParam<f8m4e3_params> {};
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(convert,
|
||||
F8E4M3PTest,
|
||||
testing::ValuesIn(enumerate(exp_floats)),
|
||||
testing::PrintToStringParamName());
|
||||
|
||||
TEST_P(F8E4M3PTest, f8_bits_to_f32) {
|
||||
const auto& params = GetParam();
|
||||
const auto& exp_value = std::get<1>(params);
|
||||
const auto f8 = ov::float8_e4m3::from_bits(std::get<0>(params));
|
||||
|
||||
if (std::isnan(exp_value)) {
|
||||
EXPECT_TRUE(std::isnan(static_cast<float>(f8)));
|
||||
} else {
|
||||
EXPECT_EQ(static_cast<float>(f8), exp_value);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(F8E4M3PTest, f32_to_f8_bits) {
|
||||
const auto& params = GetParam();
|
||||
const auto& exp_value = std::get<0>(params);
|
||||
const auto& value = std::get<1>(params);
|
||||
const auto f8 = ov::float8_e4m3(value);
|
||||
|
||||
EXPECT_EQ(f8.to_bits(), exp_value);
|
||||
}
|
||||
} // namespace test
|
||||
} // namespace ov
|
||||
|
|
@ -0,0 +1,176 @@
|
|||
// Copyright (C) 2018-2023 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#include "openvino/core/type/float8_e5m2.hpp"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <climits>
|
||||
|
||||
#include "common_test_utils/float_util.hpp"
|
||||
|
||||
namespace ov {
|
||||
namespace test {
|
||||
|
||||
TEST(F8E5M2Test, stream_operator) {
|
||||
std::stringstream s;
|
||||
s << ov::float8_e5m2(2.5f);
|
||||
|
||||
EXPECT_EQ(s.str(), "2.5");
|
||||
}
|
||||
|
||||
TEST(F8E5M2Test, to_string) {
|
||||
const auto f8 = ov::float8_e5m2::from_bits(0b00111010);
|
||||
|
||||
EXPECT_EQ(std::to_string(f8), "0.750000");
|
||||
}
|
||||
|
||||
TEST(F8E5M2Test, f32_inf) {
|
||||
const auto f8 = ov::float8_e5m2(std::numeric_limits<float>::infinity());
|
||||
|
||||
EXPECT_EQ(f8.to_bits(), 0b01111100);
|
||||
}
|
||||
|
||||
TEST(F8E5M2Test, f32_minus_inf) {
|
||||
const auto f8 = ov::float8_e5m2(-std::numeric_limits<float>::infinity());
|
||||
|
||||
EXPECT_EQ(f8.to_bits(), 0b11111100);
|
||||
}
|
||||
|
||||
TEST(F8E5M2Test, f32_ge_f8_max_round_to_inf) {
|
||||
const auto f8 = ov::float8_e5m2(65520.0f);
|
||||
|
||||
EXPECT_EQ(f8.to_bits(), 0b01111100);
|
||||
}
|
||||
|
||||
TEST(F8E5M2Test, f32_ge_f8_max_round_to_max) {
|
||||
const auto f8 = ov::float8_e5m2(65519.9f);
|
||||
|
||||
EXPECT_EQ(f8.to_bits(), 0b01111011);
|
||||
}
|
||||
|
||||
TEST(F8E5M2Test, f32_ge_f8_max_round_to_minus_inf) {
|
||||
const auto f8 = ov::float8_e5m2(-65520.0f);
|
||||
|
||||
EXPECT_EQ(f8.to_bits(), 0b11111100);
|
||||
}
|
||||
|
||||
TEST(F8E5M2Test, f32_ge_f8_max_round_to_lowest) {
|
||||
const auto f8 = ov::float8_e5m2(-65519.9f);
|
||||
|
||||
EXPECT_EQ(f8.to_bits(), 0b11111011);
|
||||
}
|
||||
|
||||
template <class TContainer>
|
||||
std::vector<std::tuple<int, typename TContainer::value_type>> enumerate(const TContainer& values) {
|
||||
std::vector<std::tuple<int, typename TContainer::value_type>> enum_values;
|
||||
int i = 0;
|
||||
for (const auto& v : values) {
|
||||
enum_values.emplace_back(i, v);
|
||||
++i;
|
||||
}
|
||||
return enum_values;
|
||||
}
|
||||
|
||||
constexpr auto f32_qnan = std::numeric_limits<float>::quiet_NaN();
|
||||
constexpr auto f32_inf = std::numeric_limits<float>::infinity();
|
||||
|
||||
// clang-format off
|
||||
const auto exp_floats = std::vector<float>{
|
||||
0.0f, 1.52587890625e-05f, 3.0517578125e-05f, 4.57763671875e-05f,
|
||||
6.103515625e-05f, 7.62939453125e-05f, 9.1552734375e-05f, 0.0001068115234375f,
|
||||
0.0001220703125f, 0.000152587890625f, 0.00018310546875f, 0.000213623046875f,
|
||||
0.000244140625f, 0.00030517578125f, 0.0003662109375f, 0.00042724609375f,
|
||||
0.00048828125f, 0.0006103515625f, 0.000732421875f, 0.0008544921875f,
|
||||
0.0009765625f, 0.001220703125f, 0.00146484375f, 0.001708984375f,
|
||||
0.001953125f, 0.00244140625f, 0.0029296875f, 0.00341796875f,
|
||||
0.00390625f, 0.0048828125f, 0.005859375f, 0.0068359375f,
|
||||
0.0078125f, 0.009765625f, 0.01171875f, 0.013671875f,
|
||||
0.015625f, 0.01953125f, 0.0234375f, 0.02734375f,
|
||||
0.03125f, 0.0390625f, 0.046875f, 0.0546875f,
|
||||
0.0625f, 0.078125f, 0.09375f, 0.109375f,
|
||||
0.125f, 0.15625f, 0.1875f, 0.21875f,
|
||||
0.25f, 0.3125f, 0.375f, 0.4375f,
|
||||
0.5f, 0.625f, 0.75f, 0.875f,
|
||||
1.0f, 1.25f, 1.5f, 1.75f,
|
||||
2.0f, 2.5f, 3.0f, 3.5f,
|
||||
4.0f, 5.0f, 6.0f, 7.0f,
|
||||
8.0f, 10.0f, 12.0f, 14.0f,
|
||||
16.0f, 20.0f, 24.0f, 28.0f,
|
||||
32.0f, 40.0f, 48.0f, 56.0f,
|
||||
64.0f, 80.0f, 96.0f, 112.0f,
|
||||
128.0f, 160.0f, 192.0f, 224.0f,
|
||||
256.0f, 320.0f, 384.0f, 448.0f,
|
||||
512.0f, 640.0f, 768.0f, 896.0f,
|
||||
1024.0f, 1280.0f, 1536.0f, 1792.0f,
|
||||
2048.0f, 2560.0f, 3072.0f, 3584.0f,
|
||||
4096.0f, 5120.0f, 6144.0f, 7168.0f,
|
||||
8192.0f, 10240.0f, 12288.0f, 14336.0f,
|
||||
16384.0f, 20480.0f, 24576.0f, 28672.0f,
|
||||
32768.0f, 40960.0f, 49152.0f, 57344.0f,
|
||||
f32_inf, f32_qnan, f32_qnan, f32_qnan,
|
||||
-0.0f, -1.52587890625e-05f, -3.0517578125e-05f, -4.57763671875e-05f,
|
||||
-6.103515625e-05f, -7.62939453125e-05f, -9.1552734375e-05f, -0.0001068115234375f,
|
||||
-0.0001220703125f, -0.000152587890625f, -0.00018310546875f, -0.000213623046875f,
|
||||
-0.000244140625f, -0.00030517578125f, -0.0003662109375f, -0.00042724609375f,
|
||||
-0.00048828125f, -0.0006103515625f, -0.000732421875f, -0.0008544921875f,
|
||||
-0.0009765625f, -0.001220703125f, -0.00146484375f, -0.001708984375f,
|
||||
-0.001953125f, -0.00244140625f, -0.0029296875f, -0.00341796875f,
|
||||
-0.00390625f, -0.0048828125f, -0.005859375f, -0.0068359375f,
|
||||
-0.0078125f, -0.009765625f, -0.01171875f, -0.013671875f,
|
||||
-0.015625f, -0.01953125f, -0.0234375f, -0.02734375f,
|
||||
-0.03125f, -0.0390625f, -0.046875f, -0.0546875f,
|
||||
-0.0625f, -0.078125f, -0.09375f, -0.109375f,
|
||||
-0.125f, -0.15625f, -0.1875f, -0.21875f,
|
||||
-0.25f, -0.3125f, -0.375f, -0.4375f,
|
||||
-0.5f, -0.625f, -0.75f, -0.875f,
|
||||
-1.0f, -1.25f, -1.5f, -1.75f,
|
||||
-2.0f, -2.5f, -3.0f, -3.5f,
|
||||
-4.0f, -5.0f, -6.0f, -7.0f,
|
||||
-8.0f, -10.0f, -12.0f, -14.0f,
|
||||
-16.0f, -20.0f, -24.0f, -28.0f,
|
||||
-32.0f, -40.0f, -48.0f, -56.0f,
|
||||
-64.0f, -80.0f, -96.0f, -112.0f,
|
||||
-128.0f, -160.0f, -192.0f, -224.0f,
|
||||
-256.0f, -320.0f, -384.0f, -448.0f,
|
||||
-512.0f, -640.0f, -768.0f, -896.0f,
|
||||
-1024.0f, -1280.0f, -1536.0f, -1792.0f,
|
||||
-2048.0f, -2560.0f, -3072.0f, -3584.0f,
|
||||
-4096.0f, -5120.0f, -6144.0f, -7168.0f,
|
||||
-8192.0f, -10240.0f, -12288.0f, -14336.0f,
|
||||
-16384.0f, -20480.0f, -24576.0f, -28672.0f,
|
||||
-32768.0f, -40960.0f, -49152.0f, -57344.0f,
|
||||
-f32_inf, -f32_qnan, -f32_qnan, -f32_qnan};
|
||||
// clang-format on
|
||||
|
||||
using f8m5e2_params = std::tuple<int, float>;
|
||||
class F8E5M2PTest : public testing::TestWithParam<f8m5e2_params> {};
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(convert,
|
||||
F8E5M2PTest,
|
||||
testing::ValuesIn(enumerate(exp_floats)),
|
||||
testing::PrintToStringParamName());
|
||||
|
||||
TEST_P(F8E5M2PTest, f8_bits_to_f32) {
|
||||
const auto& params = GetParam();
|
||||
const auto& exp_value = std::get<1>(params);
|
||||
const auto f8 = ov::float8_e5m2::from_bits(std::get<0>(params));
|
||||
|
||||
if (std::isnan(exp_value)) {
|
||||
EXPECT_TRUE(std::isnan(static_cast<float>(f8)));
|
||||
} else {
|
||||
EXPECT_EQ(static_cast<float>(f8), exp_value);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(F8E5M2PTest, f32_to_f8_bits) {
|
||||
const auto& params = GetParam();
|
||||
const auto& value = std::get<1>(params);
|
||||
const auto& exp_value = std::isnan(value) ? (std::signbit(value) ? 0xfe : 0x7e) : std::get<0>(params);
|
||||
const auto f8 = ov::float8_e5m2(value);
|
||||
|
||||
EXPECT_EQ(f8.to_bits(), exp_value);
|
||||
}
|
||||
} // namespace test
|
||||
} // namespace ov
|
||||
|
|
@ -105,6 +105,22 @@ void CommonReferenceTest::ValidateBlobs(const ov::Tensor& refBlob,
|
|||
threshold,
|
||||
abs_threshold);
|
||||
break;
|
||||
case ov::element::f8e4m3:
|
||||
LayerTestsUtils::LayerTestsCommon::Compare<ov::float8_e4m3, ov::float8_e4m3>(
|
||||
refBlob.data<const ov::float8_e4m3>(),
|
||||
outBlob.data<const ov::float8_e4m3>(),
|
||||
actual_comparision_size,
|
||||
threshold,
|
||||
abs_threshold);
|
||||
break;
|
||||
case ov::element::f8e5m2:
|
||||
LayerTestsUtils::LayerTestsCommon::Compare<ov::float8_e5m2, ov::float8_e5m2>(
|
||||
refBlob.data<const ov::float8_e5m2>(),
|
||||
outBlob.data<const ov::float8_e5m2>(),
|
||||
actual_comparision_size,
|
||||
threshold,
|
||||
abs_threshold);
|
||||
break;
|
||||
case ov::element::f32:
|
||||
LayerTestsUtils::LayerTestsCommon::Compare<float, float>(refBlob.data<const float>(),
|
||||
outBlob.data<const float>(),
|
||||
|
|
|
|||
|
|
@ -201,6 +201,50 @@ std::vector<ConstantParams> generateConstantDefinedTypeParams() {
|
|||
std::vector<int64_t>{0x4000000000000001, 0x4000000000000002},
|
||||
std::vector<int64_t>{0x4000000000000001, 0x4000000000000002},
|
||||
"tensor_constant_int64"),
|
||||
ConstantParams(
|
||||
{3, 9},
|
||||
element::Type_t::f8e4m3,
|
||||
element::Type_t::f8e4m3,
|
||||
std::vector<ov::float8_e4m3>{4.75f, 4.5f, -5.25f, 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f,
|
||||
0.6f, 0.7f, 0.8f, 0.9f, 1.f, -0.0f, -0.1f, -0.2f, -0.3f,
|
||||
-0.4f, -0.5f, -0.6f, -0.7f, -0.8f, -0.9f, -1.f, 0.001953125f, 448.f},
|
||||
std::vector<ov::float8_e4m3>{5.0f, 4.5f, -5.0f, 0.0f, 0.1015625f, 0.203125f, 0.3125f,
|
||||
0.40625f, 0.5f, 0.625f, 0.6875f, 0.8125f, 0.875f, 1.f,
|
||||
-0.f, -0.1015625f, -0.203125f, -0.3125f, -0.40625f, -0.5f, -0.625f,
|
||||
-0.6875f, -0.8125f, -0.875f, -1.f, 0.001953125f, 448.f},
|
||||
"tensor_constant_f8e4m3"),
|
||||
ConstantParams({3, 9},
|
||||
element::Type_t::f8e5m2,
|
||||
element::Type_t::f8e5m2,
|
||||
std::vector<ov::float8_e5m2>{4.75f, 4.5f,
|
||||
-5.25f, 0.0f,
|
||||
0.1f, 0.2f,
|
||||
0.3f, 0.4f,
|
||||
0.5f, 0.6f,
|
||||
0.7f, 0.8f,
|
||||
0.9f, 1.f,
|
||||
-0.0f, -0.1f,
|
||||
-0.2f, -0.3f,
|
||||
-0.4f, -0.5f,
|
||||
-0.6f, -0.7f,
|
||||
-0.8f, -0.9f,
|
||||
-1.f, 0.0000152587890625f,
|
||||
57344.f},
|
||||
std::vector<ov::float8_e5m2>{4.75f, 4.5f,
|
||||
-5.25f, 0.0f,
|
||||
0.09375f, 0.1875f,
|
||||
0.3125f, 0.375f,
|
||||
0.5f, 0.625f,
|
||||
0.75f, 0.75f,
|
||||
0.875f, 1.f,
|
||||
-0.f, -0.09375f,
|
||||
-0.1875f, -0.3125f,
|
||||
-0.375f, -0.5f,
|
||||
-0.625f, -0.75f,
|
||||
-0.75f, -0.875f,
|
||||
-1.f, 0.0000152587890625f,
|
||||
57344.f},
|
||||
"tensor_constant_f8e5m2"),
|
||||
};
|
||||
return constantParams;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,6 +57,163 @@ INSTANTIATE_TEST_SUITE_P(
|
|||
std::numeric_limits<float>::infinity(),
|
||||
-std::numeric_limits<float>::infinity()},
|
||||
std::vector<char>{0, 1, 1, 0, 1, 1, 1, 1, 1}),
|
||||
|
||||
ConvertParams(ConversionTypes::CONVERT,
|
||||
ov::PartialShape{1, 1, 3, 7},
|
||||
ov::element::f32,
|
||||
ov::element::f8e5m2,
|
||||
std::vector<float>{
|
||||
0.017578125f, 0.021484375f, 0.025390625f, 0.029296875f, 0.03515625f, 0.0703125f, 0.140625f,
|
||||
0.28125f, 0.5625f, 1.125f, 1.625f, 1.875f, 2.25f, 3.75f,
|
||||
4.5f, 9.f, 18.f, 36.f, 72.f, 144.f, 288.f},
|
||||
std::vector<ov::float8_e5m2>{0.015625f, 0.0234375f, 0.0234375f, 0.03125f, 0.03125f, 0.0625f,
|
||||
0.125f, 0.25f, 0.5f, 1.f, 1.5, 2.f,
|
||||
2.f, 4.f, 4.f, 8.f, 16.f, 32.f,
|
||||
64.f, 128.f, 256.f}),
|
||||
ConvertParams(ConversionTypes::CONVERT,
|
||||
ov::PartialShape{1, 1, 3, 7},
|
||||
ov::element::f8e5m2,
|
||||
ov::element::f32,
|
||||
std::vector<ov::float8_e5m2>{0.015625f, 0.0234375f, 0.0234375f, 0.03125f, 0.03125f, 0.0625f,
|
||||
0.125f, 0.25f, 0.5f, 1.f, 1.5, 2.f,
|
||||
2.f, 4.f, 4.f, 8.f, 16.f, 32.f,
|
||||
64.f, 128.f, 256.f},
|
||||
std::vector<float>{0.015625f, 0.0234375f, 0.0234375f, 0.03125f, 0.03125f, 0.0625f, 0.125f,
|
||||
0.25f, 0.5f, 1.f, 1.5, 2.f, 2.f, 4.f,
|
||||
4.f, 8.f, 16.f, 32.f, 64.f, 128.f, 256.f}),
|
||||
ConvertParams(ConversionTypes::CONVERT,
|
||||
ov::PartialShape{1, 1, 7},
|
||||
ov::element::f16,
|
||||
ov::element::f8e5m2,
|
||||
std::vector<ov::float16>{0.f, -0.f, 0.5f, 1.5f, 2.5f, 1.5f, 3.5f},
|
||||
std::vector<ov::float8_e5m2>{0.f, -0.f, 0.5f, 1.5f, 2.5f, 1.5f, 3.5f}),
|
||||
ConvertParams(ConversionTypes::CONVERT,
|
||||
ov::PartialShape{1, 1, 7},
|
||||
ov::element::f8e5m2,
|
||||
ov::element::f16,
|
||||
std::vector<ov::float8_e5m2>{0.f, -0.f, 0.5f, 1.5f, 2.5f, 1.5f, 3.5f},
|
||||
std::vector<ov::float16>{0.f, -0.f, 0.5f, 1.5f, 2.5f, 1.5f, 3.5f}),
|
||||
|
||||
ConvertParams(ConversionTypes::CONVERT,
|
||||
ov::PartialShape{1, 3, 5},
|
||||
ov::element::f16,
|
||||
ov::element::f8e4m3,
|
||||
std::vector<ov::float16>{0.0f,
|
||||
0.1f,
|
||||
0.2f,
|
||||
0.3f,
|
||||
0.4f,
|
||||
0.5f,
|
||||
0.6f,
|
||||
0.7f,
|
||||
0.8f,
|
||||
0.9f,
|
||||
1.f,
|
||||
1.5f,
|
||||
2.5f,
|
||||
1.5f,
|
||||
3.5f},
|
||||
std::vector<ov::float8_e4m3>{0.f,
|
||||
0.1015625f,
|
||||
0.203125f,
|
||||
0.3125f,
|
||||
0.40625f,
|
||||
0.5f,
|
||||
0.625f,
|
||||
0.6875f,
|
||||
0.8125f,
|
||||
0.875f,
|
||||
1.f,
|
||||
1.5f,
|
||||
2.5f,
|
||||
1.5f,
|
||||
3.5f}),
|
||||
|
||||
ConvertParams(ConversionTypes::CONVERT,
|
||||
ov::PartialShape{1, 1, 3},
|
||||
|
||||
ov::element::f8e4m3,
|
||||
ov::element::f16,
|
||||
std::vector<ov::float8_e4m3>{0.5f, 1.5f, 0.f},
|
||||
std::vector<ov::float16>{0.5f, 1.5f, 0.f}),
|
||||
|
||||
ConvertParams(ConversionTypes::CONVERT,
|
||||
ov::PartialShape{1, 1, 3},
|
||||
|
||||
ov::element::f8e4m3,
|
||||
ov::element::f8e4m3,
|
||||
std::vector<ov::float8_e4m3>{0.5f, 1.5f, 0.f},
|
||||
std::vector<ov::float8_e4m3>{0.5f, 1.5f, 0.f}),
|
||||
|
||||
ConvertParams(ConversionTypes::CONVERT,
|
||||
ov::PartialShape{1, 1, 2},
|
||||
|
||||
ov::element::f8e5m2,
|
||||
ov::element::f8e5m2,
|
||||
std::vector<ov::float8_e5m2>{0.5f, 1.5f},
|
||||
std::vector<ov::float8_e5m2>{0.5f, 1.5f}),
|
||||
|
||||
ConvertParams(ConversionTypes::CONVERT,
|
||||
ov::PartialShape{1, 1, 2},
|
||||
|
||||
ov::element::f32,
|
||||
ov::element::f32,
|
||||
std::vector<float>{0.5f, 1.5f},
|
||||
std::vector<float>{0.5f, 1.5f}),
|
||||
|
||||
ConvertParams(ConversionTypes::CONVERT,
|
||||
ov::PartialShape{1, 1, 2},
|
||||
|
||||
ov::element::f8e4m3,
|
||||
ov::element::f32,
|
||||
std::vector<ov::float8_e4m3>{0.5f, 1.5f},
|
||||
std::vector<float>{0.5f, 1.5f}),
|
||||
|
||||
ConvertParams(ConversionTypes::CONVERT,
|
||||
ov::PartialShape{1, 1, 2},
|
||||
|
||||
ov::element::f8e4m3,
|
||||
ov::element::f16,
|
||||
std::vector<ov::float8_e4m3>{0.5f, 1.5f},
|
||||
std::vector<ov::float16>{0.5f, 1.5f}),
|
||||
|
||||
ConvertParams(ConversionTypes::CONVERT,
|
||||
ov::PartialShape{1, 1, 3, 2},
|
||||
ov::element::f8e4m3,
|
||||
ov::element::f32,
|
||||
std::vector<ov::float8_e4m3>{
|
||||
0.5f,
|
||||
1.5f,
|
||||
0.5f,
|
||||
2.5f,
|
||||
1.5f,
|
||||
3.5f,
|
||||
},
|
||||
std::vector<float>{0.5f, 1.5f, 0.5f, 2.5f, 1.5f, 3.5f}),
|
||||
|
||||
ConvertParams(
|
||||
ConversionTypes::CONVERT,
|
||||
ov::PartialShape{1, 1, 3, 5},
|
||||
ov::element::f32,
|
||||
ov::element::f8e4m3,
|
||||
std::
|
||||
vector<float>{0.5f, 1.5f, 0.5f, 2.5f, 1.5f, 0.5f, 3.5f, 2.5f, 0.5f, 0.5f, 2.5f, 0.5f, 0.5f, 0.5f, 1.5f},
|
||||
std::vector<ov::float8_e4m3>{0.5f,
|
||||
1.5f,
|
||||
0.5f,
|
||||
2.5f,
|
||||
1.5f,
|
||||
0.5f,
|
||||
3.5f,
|
||||
2.5f,
|
||||
0.5f,
|
||||
0.5f,
|
||||
2.5f,
|
||||
0.5f,
|
||||
0.5f,
|
||||
0.5f,
|
||||
1.5f}),
|
||||
|
||||
// destination bf16
|
||||
ConvertParams(
|
||||
ConversionTypes::CONVERT,
|
||||
|
|
|
|||
|
|
@ -525,6 +525,14 @@ inline ov::float16 ie_abs(const ov::float16& val) {
|
|||
return ov::float16::from_bits(val.to_bits() & 0x7FFF);
|
||||
}
|
||||
|
||||
inline ov::float8_e4m3 ie_abs(const ov::float8_e4m3& val) {
|
||||
return ov::float8_e4m3::from_bits(val.to_bits() & 0x7F);
|
||||
}
|
||||
|
||||
inline ov::float8_e5m2 ie_abs(const ov::float8_e5m2& val) {
|
||||
return ov::float8_e5m2::from_bits(val.to_bits() & 0x7F);
|
||||
}
|
||||
|
||||
} // namespace utils
|
||||
} // namespace test
|
||||
} // namespace ov
|
||||
|
|
|
|||
Loading…
Reference in New Issue