Optimizations for precision conversion operations in nGraph reference implementations (#3974)

* FP16->FP32 conversion vectorization

* int8->FP16 conversion vectorization in nGraph
This commit is contained in:
Vladislav Volkov 2021-02-08 16:21:45 +03:00 committed by GitHub
parent fc30d6e551
commit 2ad7db7b25
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 699 additions and 178 deletions

6
.gitmodules vendored
View File

@ -13,4 +13,8 @@
[submodule "inference-engine/samples/thirdparty/gflags"]
path = inference-engine/samples/thirdparty/gflags
url = https://github.com/gflags/gflags.git
ignore = dirty
ignore = dirty
[submodule "thirdparty/xbyak"]
path = thirdparty/xbyak
url = https://github.com/herumi/xbyak.git
ignore = dirty

View File

@ -108,6 +108,7 @@ function(build_ngraph)
set(NGRAPH_COMPONENT_PREFIX "deployment_tools/ngraph/")
add_subdirectory(ngraph)
set(NGRAPH_LIBRARIES ngraph PARENT_SCOPE)
set(NGRAPH_REF_LIBRARIES ngraph_reference PARENT_SCOPE)
endfunction()
function(openvino_developer_export_targets)
@ -156,6 +157,7 @@ add_subdirectory(docs)
ie_shellcheck_process(DIRECTORY "${OpenVINO_MAIN_SOURCE_DIR}"
SKIP "${OpenVINO_MAIN_SOURCE_DIR}/bin"
"${OpenVINO_MAIN_SOURCE_DIR}/build"
"${OpenVINO_MAIN_SOURCE_DIR}/thirdparty"
"${IE_MAIN_SOURCE_DIR}/tests/ie_test_utils/common_test_utils/gtest"
"${IE_MAIN_SOURCE_DIR}/samples/thirdparty"
"${IE_MAIN_SOURCE_DIR}/thirdparty"

View File

@ -109,7 +109,8 @@ target_compile_definitions(${TARGET_NAME}_obj PRIVATE IMPLEMENT_INFERENCE_ENGINE
$<TARGET_PROPERTY:ngraph::ngraph,INTERFACE_COMPILE_DEFINITIONS>)
target_include_directories(${TARGET_NAME}_obj SYSTEM PRIVATE $<TARGET_PROPERTY:ngraph::ngraph,INTERFACE_INCLUDE_DIRECTORIES>
$<TARGET_PROPERTY:pugixml,INTERFACE_INCLUDE_DIRECTORIES>)
$<TARGET_PROPERTY:pugixml,INTERFACE_INCLUDE_DIRECTORIES>
$<TARGET_PROPERTY:xbyak,INTERFACE_INCLUDE_DIRECTORIES>)
target_include_directories(${TARGET_NAME}_obj PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}"
"${IE_MAIN_SOURCE_DIR}/src/readers/ir_reader" # for ie_ir_version.hpp
@ -119,10 +120,6 @@ target_include_directories(${TARGET_NAME}_obj PRIVATE "${CMAKE_CURRENT_SOURCE_DI
target_link_libraries(${TARGET_NAME}_obj PRIVATE ${TARGET_NAME}_reader_api)
if(ENABLE_MKL_DNN)
target_include_directories(${TARGET_NAME}_obj SYSTEM PRIVATE "${IE_MAIN_SOURCE_DIR}/thirdparty/mkl-dnn/src/cpu/x64/xbyak")
endif()
set_ie_threading_interface_for(${TARGET_NAME}_obj)
add_cpplint_target(${TARGET_NAME}_cpplint FOR_TARGETS ${TARGET_NAME}_obj)
@ -215,10 +212,6 @@ configure_file("${IE_MAIN_SOURCE_DIR}/cmake/templates/InferenceEngineConfig-vers
# Export for developer package
add_library(xbyak INTERFACE)
target_include_directories(xbyak INTERFACE ${IE_MAIN_SOURCE_DIR}/thirdparty/mkl-dnn/src/cpu/xbyak)
openvino_developer_export_targets(COMPONENT openvino_common TARGETS xbyak)
ie_developer_export_targets(${TARGET_NAME} ${TARGET_NAME}_plugin_api)
# install TBB

View File

@ -9,89 +9,41 @@
#include <iostream>
#include <vector>
#ifdef ENABLE_MKL_DNN
# define XBYAK_NO_OP_NAMES
# define XBYAK_UNDEF_JNL
# include <xbyak_util.h>
#endif
# include <xbyak/xbyak_util.h>
namespace InferenceEngine {
#ifdef ENABLE_MKL_DNN
static Xbyak::util::Cpu& get_cpu_info() {
static Xbyak::util::Cpu cpu;
return cpu;
}
#endif
bool with_cpu_x86_sse42() {
#ifdef ENABLE_MKL_DNN
return get_cpu_info().has(Xbyak::util::Cpu::tSSE42);
#else
#if defined(HAVE_SSE)
return true;
#else
return false;
#endif
#endif
}
bool with_cpu_x86_avx() {
#ifdef ENABLE_MKL_DNN
return get_cpu_info().has(Xbyak::util::Cpu::tAVX);
#else
#if defined(HAVE_AVX)
return true;
#else
return false;
#endif
#endif
}
bool with_cpu_x86_avx2() {
#ifdef ENABLE_MKL_DNN
return get_cpu_info().has(Xbyak::util::Cpu::tAVX2);
#else
#if defined(HAVE_AVX2)
return true;
#else
return false;
#endif
#endif
}
bool with_cpu_x86_avx512f() {
#ifdef ENABLE_MKL_DNN
return get_cpu_info().has(Xbyak::util::Cpu::tAVX512F);
#else
#if defined(HAVE_AVX512)
return true;
#else
return false;
#endif
#endif
}
bool with_cpu_x86_avx512_core() {
#ifdef ENABLE_MKL_DNN
return get_cpu_info().has(Xbyak::util::Cpu::tAVX512F |
Xbyak::util::Cpu::tAVX512DQ |
Xbyak::util::Cpu::tAVX512BW);
#else
#if defined(HAVE_AVX512)
return true;
#else
return false;
#endif
#endif
}
bool with_cpu_x86_bfloat16() {
#ifdef ENABLE_MKL_DNN
return get_cpu_info().has(Xbyak::util::Cpu::tAVX512_BF16);
#else
return false;
#endif
}
bool checkOpenMpEnvVars(bool includeOMPNumThreads) {

View File

@ -28,7 +28,7 @@ ie_add_vs_version_file(NAME ${TARGET_NAME}
FILEDESCRIPTION "Inference Engine Transformations library")
target_link_libraries(${TARGET_NAME} PUBLIC ${NGRAPH_LIBRARIES}
PRIVATE openvino::conditional_compilation openvino::itt ngraph::builder pugixml)
PRIVATE ${NGRAPH_REF_LIBRARIES} openvino::conditional_compilation openvino::itt ngraph::builder pugixml)
target_include_directories(${TARGET_NAME} PUBLIC ${PUBLIC_HEADERS_DIR}
PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src")

View File

@ -14,6 +14,8 @@
#include <ngraph/opsets/opset1.hpp>
#include <ngraph_ops/type_relaxed.hpp>
#include <ngraph/runtime/reference/convert.hpp>
using namespace ngraph;
bool fuse_type_to_constant(std::shared_ptr<ngraph::Node> & node, ngraph::element::Type to, const std::vector<ngraph::Input<ngraph::Node>> & consumers);
@ -341,25 +343,44 @@ inline int32_t convert_value<uint32_t, int32_t>(uint32_t val) {
return static_cast<int32_t>(val);
}
template <element::Type_t PREC_FROM, element::Type_t PREC_TO>
static std::shared_ptr<Node> change_constant_precision(std::shared_ptr<opset4::Constant>& constant) {
using src_type = typename element_type_traits<PREC_FROM>::value_type;
using dst_type = typename element_type_traits<PREC_TO>::value_type;
namespace {
template <element::Type_t PREC_FROM, element::Type_t PREC_TO>
std::shared_ptr<Node> change_constant_precision(std::shared_ptr<opset4::Constant>& constant) {
using src_type = typename element_type_traits<PREC_FROM>::value_type;
using dst_type = typename element_type_traits<PREC_TO>::value_type;
const auto * src_data = constant->get_data_ptr<src_type>();
const auto size = shape_size(constant->get_shape());
const auto * src_data = constant->get_data_ptr<src_type>();
const auto size = shape_size(constant->get_shape());
auto new_constant = std::make_shared<ngraph::opset4::Constant>(PREC_TO, constant->get_shape());
auto * dst_data = const_cast<dst_type *>(reinterpret_cast<const dst_type *>(new_constant->get_data_ptr()));
if (dst_data == nullptr)
throw ngraph_error("Can't get destination data pointer");
auto new_constant = std::make_shared<ngraph::opset4::Constant>(PREC_TO, constant->get_shape());
auto * dst_data = const_cast<dst_type *>(reinterpret_cast<const dst_type *>(new_constant->get_data_ptr()));
if (dst_data == nullptr)
throw ngraph_error("Can't get destination data pointer");
std::vector<dst_type> final_data;
for (size_t i = 0; i < size; ++i) {
dst_data[i] = convert_value<src_type, dst_type>(src_data[i]);
for (size_t i = 0; i < size; ++i) {
dst_data[i] = convert_value<src_type, dst_type>(src_data[i]);
}
return new_constant;
}
return new_constant;
}
template <>
std::shared_ptr<Node> change_constant_precision<element::Type_t::f16, element::Type_t::f32>(std::shared_ptr<opset4::Constant>& constant) {
using src_type = typename element_type_traits<element::Type_t::f16>::value_type;
using dst_type = typename element_type_traits<element::Type_t::f32>::value_type;
const auto * src_data = constant->get_data_ptr<src_type>();
const auto size = shape_size(constant->get_shape());
auto new_constant = std::make_shared<ngraph::opset4::Constant>(element::Type_t::f32, constant->get_shape());
auto * dst_data = const_cast<dst_type *>(reinterpret_cast<const dst_type *>(new_constant->get_data_ptr()));
if (dst_data == nullptr)
throw ngraph_error("Can't get destination data pointer");
ngraph::runtime::reference::convert<src_type, dst_type>(src_data, dst_data, size);
return new_constant;
}
} // namespace
bool fuse_type_to_constant(std::shared_ptr<Node> & node, element::Type to, const std::vector<Input<Node>> & consumers) {
if (auto constant = as_type_ptr<opset4::Constant>(node)) {

View File

@ -37,9 +37,13 @@ if(COMMAND ie_faster_build)
)
endif()
target_compile_definitions(${TARGET_NAME} PRIVATE XBYAK_NO_OP_NAMES XBYAK64)
# Defines macro in C++ to load backend plugin
target_include_directories(${TARGET_NAME} PUBLIC ${REF_IMPL_INCLUDE_DIR} ${NGRAPH_INCLUDE_PATH})
target_link_libraries(${TARGET_NAME} PRIVATE xbyak)
# Add an alias so that library can be used inside the build tree, e.g. when testing
add_library(ngraph::reference ALIAS ${TARGET_NAME})

View File

@ -18,6 +18,8 @@
#include <cstddef>
#include "ngraph/type/float16.hpp"
namespace ngraph
{
namespace runtime
@ -34,6 +36,11 @@ namespace ngraph
}
}
template <>
void convert<uint8_t, float16>(const uint8_t* arg, float16* out, size_t count);
template <>
void convert<float16, float>(const float16* arg, float* out, size_t count);
template <typename TI, typename TO>
typename std::enable_if<std::is_same<TO, char>::value>::type
convert(const TI* arg, TO* out, size_t count)

View File

@ -0,0 +1,201 @@
//*****************************************************************************
// Copyright 2021 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//*****************************************************************************
#include "ngraph/runtime/reference/convert.hpp"
#include "jit_generator.hpp"
namespace ngraph
{
namespace runtime
{
namespace reference
{
namespace
{
template <typename src_t, typename dst_t>
void jit_convert_vec(jit::Generator&, const Xbyak::RegExp&, const Xbyak::RegExp&);
template <>
void jit_convert_vec<uint8_t, float16>(jit::Generator& gen,
const Xbyak::RegExp& src,
const Xbyak::RegExp& dst)
{
auto u8vec = gen.xmm1;
auto i32vec = gen.ymm2;
auto f16vec = gen.xmm3;
auto fvec = gen.ymm4;
gen.movq(u8vec, gen.qword[src]);
gen.vpmovzxbd(i32vec, u8vec);
gen.vcvtdq2ps(fvec, i32vec);
gen.vcvtps2ph(f16vec, fvec, 0);
gen.movdqu(gen.xword[dst], f16vec);
}
template <>
void jit_convert_vec<float16, float>(jit::Generator& gen,
const Xbyak::RegExp& src,
const Xbyak::RegExp& dst)
{
auto f16vec = gen.xmm3;
auto f32vec = gen.ymm4;
gen.movdqu(f16vec, gen.xword[src]);
gen.vcvtph2ps(f32vec, f16vec);
gen.vmovups(gen.yword[dst], f32vec);
}
class jit_convert_array : public jit::Generator
{
typedef struct context
{
struct
{
size_t type_size;
void (jit::Generator::*copy)(const Xbyak::Reg64& dst,
const Xbyak::Reg64& src,
const Xbyak::Reg64& size);
} src, dst;
void (*convert_vec)(jit::Generator&,
const Xbyak::RegExp&,
const Xbyak::RegExp&);
} context_t;
jit_convert_array(const context_t& ctx)
{
using namespace Xbyak;
const uint32_t vlen = 8u;
auto reg_src = rax;
auto reg_dst = rbx;
auto reg_sz = rdx;
Label tail, exit;
preamble();
mov(reg_src, ptr[param + offsetof(args_t, src)]);
mov(reg_dst, ptr[param + offsetof(args_t, out)]);
mov(reg_sz, ptr[param + offsetof(args_t, count)]);
xor_(rsi, rsi);
mov(r8, reg_sz);
shr(r8, 3);
foreach (rsi, 1, r8, [&, this](const Xbyak::Reg64& idx) {
ctx.convert_vec(*this, reg_src, reg_dst);
add(reg_src, ctx.src.type_size * vlen);
add(reg_dst, ctx.dst.type_size * vlen);
})
;
L(tail);
shl(rsi, 3);
sub(reg_sz, rsi);
test(reg_sz, reg_sz);
jz(exit);
// allocate array for 8 floats on stack
sub(rsp, vlen * sizeof(float));
mov(r8, rsp);
vpxor(ymm4, ymm4, ymm4);
vmovups(yword[r8], ymm4);
// Tail conversion
(this->*ctx.src.copy)(r8, reg_src, reg_sz);
ctx.convert_vec(*this, r8, r8);
(this->*ctx.dst.copy)(reg_dst, r8, reg_sz);
// Free the array on stack
add(rsp, vlen * sizeof(float));
L(exit);
postamble();
}
public:
typedef struct
{
const void* src;
void* out;
const size_t count;
} args_t;
typedef void (*fn_t)(const args_t*);
template <typename src_t, typename dst_t>
static fn_t get()
{
if (is_x64() && mayiuse(avx) && mayiuse(avx2) && mayiuse(fp16))
{
static const jit_convert_array::context_t context{
{sizeof(src_t), &jit::Generator::copy<src_t>},
{sizeof(dst_t), &jit::Generator::copy<dst_t>},
jit_convert_vec<src_t, dst_t>};
static jit_convert_array generator(context);
return (fn_t)generator.getCode();
}
return nullptr;
}
};
} // namespace
template <>
void convert<uint8_t, float16>(const uint8_t* arg, float16* out, size_t count)
{
auto converter = jit_convert_array::get<uint8_t, float16>();
if (converter)
{
jit_convert_array::args_t args = {arg, out, count};
converter(&args);
}
else
{
for (size_t i = 0; i < count; ++i)
{
out[i] = static_cast<float16>(arg[i]);
}
}
}
template <>
void convert<float16, float>(const float16* arg, float* out, size_t count)
{
auto converter = jit_convert_array::get<float16, float>();
if (converter)
{
jit_convert_array::args_t args = {arg, out, count};
converter(&args);
}
else
{
for (size_t i = 0; i < count; ++i)
{
out[i] = static_cast<float>(arg[i]);
}
}
}
}
}
}

View File

@ -0,0 +1,229 @@
//*****************************************************************************
// Copyright 2017-2021 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//*****************************************************************************
#include "jit_generator.hpp"
#include "ngraph/type/float16.hpp"
#include <xbyak/xbyak_util.h>
namespace ngraph
{
namespace runtime
{
namespace jit
{
using namespace Xbyak;
#ifdef XBYAK64
static const Xbyak::Operand::Code abi_save_gpr_regs[] = {
Xbyak::Operand::RBX,
Xbyak::Operand::RBP,
Xbyak::Operand::R12,
Xbyak::Operand::R13,
Xbyak::Operand::R14,
Xbyak::Operand::R15,
#ifdef _WIN32
Xbyak::Operand::RDI,
Xbyak::Operand::RSI,
#endif
};
#ifdef _WIN32
static const Xbyak::Reg64 abi_param1(Xbyak::Operand::RCX),
abi_param2(Xbyak::Operand::RDX), abi_param3(Xbyak::Operand::R8),
abi_param4(Xbyak::Operand::R9), abi_not_param1(Xbyak::Operand::RDI);
#else
static const Xbyak::Reg64 abi_param1(Xbyak::Operand::RDI),
abi_param2(Xbyak::Operand::RSI), abi_param3(Xbyak::Operand::RDX),
abi_param4(Xbyak::Operand::RCX), abi_param5(Xbyak::Operand::R8),
abi_param6(Xbyak::Operand::R9), abi_not_param1(Xbyak::Operand::RCX);
#endif
#endif
const size_t Generator::num_abi_save_gpr_regs =
sizeof(abi_save_gpr_regs) / sizeof(abi_save_gpr_regs[0]);
const Xbyak::Reg64 Generator::param = abi_param1;
bool Generator::mayiuse(const cpu_isa_t cpu_isa)
{
static Xbyak::util::Cpu cpu;
using namespace Xbyak::util;
switch (cpu_isa)
{
case sse42: return cpu.has(Cpu::tSSE42);
case avx: return cpu.has(Cpu::tAVX);
case avx2: return cpu.has(Cpu::tAVX2);
case avx512_common: return cpu.has(Cpu::tAVX512F);
case avx512_core:
return cpu.has(Cpu::tAVX512F) && cpu.has(Cpu::tAVX512BW) &&
cpu.has(Cpu::tAVX512VL) && cpu.has(Cpu::tAVX512DQ);
case avx512_core_vnni:
return cpu.has(Cpu::tAVX512F) && cpu.has(Cpu::tAVX512BW) &&
cpu.has(Cpu::tAVX512VL) && cpu.has(Cpu::tAVX512DQ) &&
cpu.has(Cpu::tAVX512_VNNI);
case avx512_mic:
return cpu.has(Cpu::tAVX512F) && cpu.has(Cpu::tAVX512CD) &&
cpu.has(Cpu::tAVX512ER) && cpu.has(Cpu::tAVX512PF);
case avx512_mic_4ops:
return mayiuse(avx512_mic) && cpu.has(Cpu::tAVX512_4FMAPS) &&
cpu.has(Cpu::tAVX512_4VNNIW);
case avx512_core_bf16:
return mayiuse(avx512_core_vnni) && cpu.has(Cpu::tAVX512_BF16);
case avx512_vpopcnt: return true && cpu.has(Cpu::tAVX512_VPOPCNTDQ);
case fp16: return cpu.has(Cpu::tF16C);
case isa_any: return true;
}
return false;
}
bool Generator::is_x64() { return sizeof(void*) == 8; }
Generator::Generator(void* code_ptr, size_t code_size)
: Xbyak::CodeGenerator(code_size, code_ptr)
, size_of_abi_save_regs(num_abi_save_gpr_regs * rax.getBit() / 8 +
xmm_to_preserve * xmm_len)
, reg_EVEX_max_8b_offt(rbp)
{
}
void Generator::preamble()
{
if (xmm_to_preserve)
{
sub(rsp, xmm_to_preserve * xmm_len);
for (size_t i = 0; i < xmm_to_preserve; ++i)
movdqu(ptr[rsp + i * xmm_len], Xbyak::Xmm(xmm_to_preserve_start + i));
}
for (size_t i = 0; i < num_abi_save_gpr_regs; ++i)
push(Xbyak::Reg64(abi_save_gpr_regs[i]));
if (mayiuse(avx512_common))
{
mov(reg_EVEX_max_8b_offt, 2 * EVEX_max_8b_offt);
}
}
void Generator::postamble()
{
for (size_t i = 0; i < num_abi_save_gpr_regs; ++i)
pop(Xbyak::Reg64(abi_save_gpr_regs[num_abi_save_gpr_regs - 1 - i]));
if (xmm_to_preserve)
{
for (size_t i = 0; i < xmm_to_preserve; ++i)
movdqu(Xbyak::Xmm(xmm_to_preserve_start + i), ptr[rsp + i * xmm_len]);
add(rsp, xmm_to_preserve * xmm_len);
}
if (mayiuse(avx) && !mayiuse(avx512_mic))
vzeroupper();
ret();
}
void Generator::foreach (const Xbyak::Reg64& idx,
size_t step,
const Xbyak::Reg64& end,
std::function<void(const Xbyak::Reg64&)> && fn)
{
Label loop, exit;
L(loop);
cmp(idx, end);
jge(exit);
fn(idx);
add(idx, step);
jmp(loop);
L(exit);
}
template <>
void Generator::copy<uint8_t>(const Xbyak::Reg64& dst,
const Xbyak::Reg64& src,
const Xbyak::Reg64& size)
{
push(rsi);
push(r15);
xor_(rsi, rsi);
foreach (rsi, 1, size, [&, this](const Xbyak::Reg64& idx) {
mov(r15b, byte[src + idx * sizeof(uint8_t)]);
mov(byte[dst + idx * sizeof(uint8_t)], r15b);
})
;
pop(r15);
pop(rsi);
}
template <>
void Generator::copy<uint16_t>(const Xbyak::Reg64& dst,
const Xbyak::Reg64& src,
const Xbyak::Reg64& size)
{
push(rsi);
push(r15);
xor_(rsi, rsi);
foreach (rsi, 1, size, [&, this](const Xbyak::Reg64& idx) {
mov(r15w, word[src + idx * sizeof(uint16_t)]);
mov(word[dst + idx * sizeof(uint16_t)], r15w);
})
;
pop(r15);
pop(rsi);
}
template <>
void Generator::copy<uint32_t>(const Xbyak::Reg64& dst,
const Xbyak::Reg64& src,
const Xbyak::Reg64& size)
{
push(rsi);
push(r15);
xor_(rsi, rsi);
foreach (rsi, 1, size, [&, this](const Xbyak::Reg64& idx) {
mov(r15d, dword[src + idx * sizeof(uint32_t)]);
mov(dword[dst + idx * sizeof(uint32_t)], r15d);
})
;
pop(r15);
pop(rsi);
}
template <>
void Generator::copy<float16>(const Xbyak::Reg64& dst,
const Xbyak::Reg64& src,
const Xbyak::Reg64& size)
{
copy<uint16_t>(dst, src, size);
}
template <>
void Generator::copy<float>(const Xbyak::Reg64& dst,
const Xbyak::Reg64& src,
const Xbyak::Reg64& size)
{
copy<uint32_t>(dst, src, size);
}
}
}
}

View File

@ -0,0 +1,82 @@
//*****************************************************************************
// Copyright 2017-2021 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//*****************************************************************************
#pragma once
#include <functional>
#include <xbyak/xbyak.h>
namespace ngraph
{
namespace runtime
{
namespace jit
{
class Generator : public Xbyak::CodeGenerator
{
static constexpr size_t xmm_len = 16;
#ifdef _WIN32
static constexpr size_t xmm_to_preserve_start = 6;
static constexpr size_t xmm_to_preserve = 10;
#else
static constexpr size_t xmm_to_preserve_start = 0;
static constexpr size_t xmm_to_preserve = 0;
#endif
static const size_t num_abi_save_gpr_regs;
const size_t size_of_abi_save_regs;
const Xbyak::Reg64 reg_EVEX_max_8b_offt;
static constexpr int EVEX_max_8b_offt = 0x200;
public:
static const Xbyak::Reg64 param;
typedef enum {
isa_any,
sse42,
avx,
avx2,
avx512_common,
avx512_core,
avx512_core_vnni,
avx512_mic,
avx512_mic_4ops,
avx512_core_bf16,
avx512_vpopcnt,
fp16
} cpu_isa_t;
static bool mayiuse(const cpu_isa_t cpu_isa);
static bool is_x64();
Generator(void* code_ptr = nullptr, size_t code_size = 16 * 1024);
void preamble();
void postamble();
void foreach (const Xbyak::Reg64& idx,
size_t step,
const Xbyak::Reg64& end,
std::function<void(const Xbyak::Reg64&)> && fn);
template <typename T>
void copy(const Xbyak::Reg64& dst,
const Xbyak::Reg64& src,
const Xbyak::Reg64& size);
};
}
}
}

View File

@ -25,115 +25,118 @@
using namespace ngraph;
using namespace ngraph::runtime::reference;
struct Rectangle
{
Rectangle(float y_left, float x_left, float y_right, float x_right)
: y1{y_left}
, x1{x_left}
, y2{y_right}
, x2{x_right}
{
}
Rectangle() = default;
float y1 = 0.0f;
float x1 = 0.0f;
float y2 = 0.f;
float x2 = 0.0f;
};
static float intersectionOverUnion(const Rectangle& boxI, const Rectangle& boxJ)
{
float areaI = (boxI.y2 - boxI.y1) * (boxI.x2 - boxI.x1);
float areaJ = (boxJ.y2 - boxJ.y1) * (boxJ.x2 - boxJ.x1);
if (areaI <= 0.0f || areaJ <= 0.0f)
{
return 0.0f;
}
float intersection_ymin = std::max(boxI.y1, boxJ.y1);
float intersection_xmin = std::max(boxI.x1, boxJ.x1);
float intersection_ymax = std::min(boxI.y2, boxJ.y2);
float intersection_xmax = std::min(boxI.x2, boxJ.x2);
float intersection_area = std::max(intersection_ymax - intersection_ymin, 0.0f) *
std::max(intersection_xmax - intersection_xmin, 0.0f);
return intersection_area / (areaI + areaJ - intersection_area);
}
struct SelectedIndex
{
SelectedIndex(int64_t batch_idx, int64_t class_idx, int64_t box_idx)
: batch_index(batch_idx)
, class_index(class_idx)
, box_index(box_idx)
{
}
SelectedIndex() = default;
int64_t batch_index = 0;
int64_t class_index = 0;
int64_t box_index = 0;
};
struct SelectedScore
{
SelectedScore(float batch_idx, float class_idx, float score)
: batch_index{batch_idx}
, class_index{class_idx}
, box_score{score}
{
}
SelectedScore() = default;
float batch_index = 0.0f;
float class_index = 0.0f;
float box_score = 0.0f;
};
struct BoxInfo
{
BoxInfo(const Rectangle& r,
int64_t idx,
float sc,
int64_t suppress_idx,
int64_t batch_idx,
int64_t class_idx)
: box{r}
, index{idx}
, suppress_begin_index{suppress_idx}
, batch_index{batch_idx}
, class_index{class_idx}
, score{sc}
{
}
BoxInfo() = default;
inline bool operator<(const BoxInfo& rhs) const
{
return score < rhs.score || (score == rhs.score && index > rhs.index);
}
Rectangle box;
int64_t index = 0;
int64_t suppress_begin_index = 0;
int64_t batch_index = 0;
int64_t class_index = 0;
float score = 0.0f;
};
namespace ngraph
{
namespace runtime
{
namespace reference
{
namespace
{
struct Rectangle
{
Rectangle(float y_left, float x_left, float y_right, float x_right)
: y1{y_left}
, x1{x_left}
, y2{y_right}
, x2{x_right}
{
}
Rectangle() = default;
float y1 = 0.0f;
float x1 = 0.0f;
float y2 = 0.f;
float x2 = 0.0f;
};
static float intersectionOverUnion(const Rectangle& boxI, const Rectangle& boxJ)
{
float areaI = (boxI.y2 - boxI.y1) * (boxI.x2 - boxI.x1);
float areaJ = (boxJ.y2 - boxJ.y1) * (boxJ.x2 - boxJ.x1);
if (areaI <= 0.0f || areaJ <= 0.0f)
{
return 0.0f;
}
float intersection_ymin = std::max(boxI.y1, boxJ.y1);
float intersection_xmin = std::max(boxI.x1, boxJ.x1);
float intersection_ymax = std::min(boxI.y2, boxJ.y2);
float intersection_xmax = std::min(boxI.x2, boxJ.x2);
float intersection_area =
std::max(intersection_ymax - intersection_ymin, 0.0f) *
std::max(intersection_xmax - intersection_xmin, 0.0f);
return intersection_area / (areaI + areaJ - intersection_area);
}
struct SelectedIndex
{
SelectedIndex(int64_t batch_idx, int64_t class_idx, int64_t box_idx)
: batch_index(batch_idx)
, class_index(class_idx)
, box_index(box_idx)
{
}
SelectedIndex() = default;
int64_t batch_index = 0;
int64_t class_index = 0;
int64_t box_index = 0;
};
struct SelectedScore
{
SelectedScore(float batch_idx, float class_idx, float score)
: batch_index{batch_idx}
, class_index{class_idx}
, box_score{score}
{
}
SelectedScore() = default;
float batch_index = 0.0f;
float class_index = 0.0f;
float box_score = 0.0f;
};
struct BoxInfo
{
BoxInfo(const Rectangle& r,
int64_t idx,
float sc,
int64_t suppress_idx,
int64_t batch_idx,
int64_t class_idx)
: box{r}
, index{idx}
, suppress_begin_index{suppress_idx}
, batch_index{batch_idx}
, class_index{class_idx}
, score{sc}
{
}
BoxInfo() = default;
inline bool operator<(const BoxInfo& rhs) const
{
return score < rhs.score || (score == rhs.score && index > rhs.index);
}
Rectangle box;
int64_t index = 0;
int64_t suppress_begin_index = 0;
int64_t batch_index = 0;
int64_t class_index = 0;
float score = 0.0f;
};
}
void non_max_suppression(const float* boxes_data,
const Shape& boxes_data_shape,
const float* scores_data,

View File

@ -16,6 +16,7 @@
#include "gtest/gtest.h"
#include "ngraph/ngraph.hpp"
#include "ngraph/runtime/reference/convert.hpp"
#include "ngraph/runtime/tensor.hpp"
#include "runtime/backend.hpp"
#include "util/all_close.hpp"
@ -171,3 +172,21 @@ NGRAPH_TEST(${BACKEND_NAME}, convert_bf16_float32)
1.5f}),
read_vector<float>(result));
}
NGRAPH_TEST(${BACKEND_NAME}, convert_fp16_float32)
{
std::vector<float> f32vec = {-20.5, -15, -10.5, -0.5, 0, 0.5, 10.5, 15, 20.5};
std::vector<float16> f16vec(std::begin(f32vec), std::end(f32vec));
std::vector<float> result(f32vec.size());
runtime::reference::convert(f16vec.data(), result.data(), f32vec.size());
EXPECT_EQ(result, f32vec);
}
NGRAPH_TEST(${BACKEND_NAME}, convert_uint8_fp16)
{
std::vector<uint8_t> u8vec = {0, 10, 15, 20, 43, 56, 78, 99, 102, 130, 142};
std::vector<float16> f16vec(std::begin(u8vec), std::end(u8vec));
std::vector<float16> result(u8vec.size());
runtime::reference::convert(u8vec.data(), result.data(), u8vec.size());
EXPECT_EQ(result, f16vec);
}

View File

@ -16,3 +16,6 @@
add_subdirectory(ittapi)
add_subdirectory(itt_collector)
add_subdirectory(xbyak)
openvino_developer_export_targets(COMPONENT openvino_common TARGETS xbyak)

1
thirdparty/xbyak vendored Submodule

@ -0,0 +1 @@
Subproject commit 8d1e41b650890080fb77548372b6236bbd4079f9