[CPU] FQ shape agnostic kernel (#16585)

This commit is contained in:
Anton Voronov 2023-04-03 09:55:49 +04:00 committed by GitHub
parent d7f70b647b
commit b64cbff10b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 749 additions and 181 deletions

View File

@ -23,6 +23,7 @@
#include "memory_desc/dnnl_blocked_memory_desc.h"
#include "common/cpu_memcpy.h"
#include <common/primitive_hashing_utils.hpp>
#include <utils/shape_inference/shape_inference_pass_through.hpp>
#include <ngraph/opsets/opset1.hpp>
#include "utils/ngraph_utils.hpp"
@ -295,6 +296,45 @@ private:
bool do_rounding = true;
bool do_dequantization = true;
inline void load_broadcasted_vectors_only(size_t idx) {
const auto &broadcasted = jqp_.broadcasted;
if (broadcasted[static_cast<size_t>(FQ_add_input_type::CROP_LOW)]) uni_vbroadcastss(vmm_crop_low(idx), ptr[reg_crop_low]);
if (broadcasted[static_cast<size_t>(FQ_add_input_type::CROP_HIGH)]) uni_vbroadcastss(vmm_crop_high(idx), ptr[reg_crop_high]);
if (broadcasted[static_cast<size_t>(FQ_add_input_type::INPUT_SCALE)]) uni_vbroadcastss(vmm_input_scale(idx), ptr[reg_input_scale]);
if (broadcasted[static_cast<size_t>(FQ_add_input_type::INPUT_SHIFT)]) uni_vbroadcastss(vmm_input_shift(idx), ptr[reg_input_shift]);
if (do_dequantization) {
if (broadcasted[static_cast<size_t>(FQ_add_input_type::OUTPUT_SCALE)]) uni_vbroadcastss(vmm_output_scale(idx), ptr[reg_output_scale]);
if (broadcasted[static_cast<size_t>(FQ_add_input_type::OUTPUT_SHIFT)]) uni_vbroadcastss(vmm_output_shift(idx), ptr[reg_output_shift]);
}
}
template <typename T>
inline void load_not_broadcasted_vectors_only(size_t idx, size_t offset) {
const auto &broadcasted = jqp_.broadcasted;
if (!broadcasted[static_cast<size_t>(FQ_add_input_type::CROP_LOW)]) uni_vmovups(T(vmm_crop_low(idx).getIdx()), ptr[reg_crop_low + offset]);
if (!broadcasted[static_cast<size_t>(FQ_add_input_type::CROP_HIGH)]) uni_vmovups(T(vmm_crop_high(idx).getIdx()), ptr[reg_crop_high + offset]);
if (!broadcasted[static_cast<size_t>(FQ_add_input_type::INPUT_SCALE)]) uni_vmovups(T(vmm_input_scale(idx).getIdx()), ptr[reg_input_scale + offset]);
if (!broadcasted[static_cast<size_t>(FQ_add_input_type::INPUT_SHIFT)]) uni_vmovups(T(vmm_input_shift(idx).getIdx()), ptr[reg_input_shift + offset]);
if (do_dequantization) {
if (!broadcasted[static_cast<size_t>(FQ_add_input_type::OUTPUT_SCALE)])
uni_vmovups(T(vmm_output_scale(idx).getIdx()), ptr[reg_output_scale + offset]);
if (!broadcasted[static_cast<size_t>(FQ_add_input_type::OUTPUT_SHIFT)])
uni_vmovups(T(vmm_output_shift(idx).getIdx()), ptr[reg_output_shift + offset]);
}
}
inline void increase_ptrs_if_not_broadcasted(size_t offset) {
const auto &broadcasted = jqp_.broadcasted;
if (!broadcasted[static_cast<size_t>(FQ_add_input_type::CROP_LOW)]) add(reg_crop_low, offset);
if (!broadcasted[static_cast<size_t>(FQ_add_input_type::CROP_HIGH)]) add(reg_crop_high, offset);
if (!broadcasted[static_cast<size_t>(FQ_add_input_type::INPUT_SCALE)]) add(reg_input_scale, offset);
if (!broadcasted[static_cast<size_t>(FQ_add_input_type::INPUT_SHIFT)]) add(reg_input_shift, offset);
if (do_dequantization) {
if (!broadcasted[static_cast<size_t>(FQ_add_input_type::OUTPUT_SCALE)]) add(reg_output_scale, offset);
if (!broadcasted[static_cast<size_t>(FQ_add_input_type::OUTPUT_SHIFT)]) add(reg_output_shift, offset);
}
}
inline void compute_planar() {
int src_type_size = jqp_.src_prc.size();
int dst_type_size = jqp_.dst_prc.size();
@ -430,10 +470,10 @@ private:
if (isa == cpu::x64::avx512_core)
uni_vpxor(vmm_zero, vmm_zero, vmm_zero);
int simd_w = isa == cpu::x64::avx512_core ? 16 : 8;
int tail8_simd_w = 8;
int tail4_simd_w = 4;
int repeats = isa == cpu::x64::sse41 ? 2 : 1;
constexpr unsigned simd_w = isa == cpu::x64::avx512_core ? 16 : 8;
constexpr unsigned tail8_simd_w = 8;
constexpr unsigned tail4_simd_w = 4;
constexpr unsigned repeats = isa == cpu::x64::sse41 ? 2 : 1;
Label main_loop_label;
Label tail_blk8_label;
@ -446,18 +486,15 @@ private:
Label tail_loop_label;
Label exit_label;
for (int i = 0; i < repeats; i++) {
load_broadcasted_vectors_only(i);
}
cmp(reg_block_size, simd_w);
jl(simd_w == 16 ? tail_blk8_label : tail_blk4_label, T_NEAR);
for (int i = 0; i < repeats; i++) {
uni_vmovups(vmm_crop_low(i), ptr[reg_crop_low + i * (simd_w / 2) * sizeof(float)]);
uni_vmovups(vmm_crop_high(i), ptr[reg_crop_high + i * (simd_w / 2) * sizeof(float)]);
uni_vmovups(vmm_input_scale(i), ptr[reg_input_scale + i * (simd_w / 2) * sizeof(float)]);
uni_vmovups(vmm_input_shift(i), ptr[reg_input_shift + i * (simd_w / 2) * sizeof(float)]);
if (do_dequantization) {
uni_vmovups(vmm_output_scale(i), ptr[reg_output_scale + i * (simd_w / 2) * sizeof(float)]);
uni_vmovups(vmm_output_shift(i), ptr[reg_output_shift + i * (simd_w / 2) * sizeof(float)]);
}
load_not_broadcasted_vectors_only<Vmm>(i, i * (simd_w / 2) * sizeof(float));
}
L(main_loop_label); {
@ -493,14 +530,7 @@ private:
mov(aux_reg_from, reg_from);
mov(reg_work_amount, ptr[param + GET_OFF(work_amount)]);
uni_vmovups(ymm_crop_low(0), ptr[reg_crop_low]);
uni_vmovups(ymm_crop_high(0), ptr[reg_crop_high]);
uni_vmovups(ymm_input_scale(0), ptr[reg_input_scale]);
uni_vmovups(ymm_input_shift(0), ptr[reg_input_shift]);
if (do_dequantization) {
uni_vmovups(ymm_output_scale(0), ptr[reg_output_scale]);
uni_vmovups(ymm_output_shift(0), ptr[reg_output_shift]);
}
load_not_broadcasted_vectors_only<Ymm>(0, 0);
L(tail_blk8_loop_label); {
cmp(reg_work_amount, 0);
@ -527,14 +557,7 @@ private:
add(reg_from, tail8_simd_w * src_type_size);
add(reg_to, tail8_simd_w * dst_type_size);
add(reg_crop_low, tail8_simd_w * wei_type_size);
add(reg_crop_high, tail8_simd_w * wei_type_size);
add(reg_input_scale, tail8_simd_w * wei_type_size);
add(reg_input_shift, tail8_simd_w * wei_type_size);
if (do_dequantization) {
add(reg_output_scale, tail8_simd_w * wei_type_size);
add(reg_output_shift, tail8_simd_w * wei_type_size);
}
increase_ptrs_if_not_broadcasted(tail8_simd_w * wei_type_size);
sub(reg_block_size, tail8_simd_w);
}
@ -547,14 +570,7 @@ private:
mov(aux_reg_from, reg_from);
mov(reg_work_amount, ptr[param + GET_OFF(work_amount)]);
uni_vmovups(xmm_crop_low(0), ptr[reg_crop_low]);
uni_vmovups(xmm_crop_high(0), ptr[reg_crop_high]);
uni_vmovups(xmm_input_scale(0), ptr[reg_input_scale]);
uni_vmovups(xmm_input_shift(0), ptr[reg_input_shift]);
if (do_dequantization) {
uni_vmovups(xmm_output_scale(0), ptr[reg_output_scale]);
uni_vmovups(xmm_output_shift(0), ptr[reg_output_shift]);
}
load_not_broadcasted_vectors_only<Xmm>(0, 0);
L(tail_blk4_loop_label); {
cmp(reg_work_amount, 0);
@ -581,14 +597,8 @@ private:
add(reg_from, tail4_simd_w * src_type_size);
add(reg_to, tail4_simd_w * dst_type_size);
add(reg_crop_low, tail4_simd_w * wei_type_size);
add(reg_crop_high, tail4_simd_w * wei_type_size);
add(reg_input_scale, tail4_simd_w * wei_type_size);
add(reg_input_shift, tail4_simd_w * wei_type_size);
if (do_dequantization) {
add(reg_output_scale, tail4_simd_w * wei_type_size);
add(reg_output_shift, tail4_simd_w * wei_type_size);
}
increase_ptrs_if_not_broadcasted(tail4_simd_w * wei_type_size);
sub(reg_block_size, tail4_simd_w);
L(tail_label);
@ -602,28 +612,52 @@ private:
L(tail_loop_label); {
cmp(reg_work_amount, 0);
jle(exit_label, T_NEAR);
Label end_unroll;
for (int i = 0; i < jqp_.c % tail4_simd_w; i++) {
uni_vmovss(xmm_crop_low(0), ptr[reg_crop_low + i * wei_type_size]);
uni_vmovss(xmm_crop_high(0), ptr[reg_crop_high + i * wei_type_size]);
uni_vmovss(xmm_input_scale(0), ptr[reg_input_scale + i * wei_type_size]);
uni_vmovss(xmm_input_shift(0), ptr[reg_input_shift + i * wei_type_size]);
if (do_dequantization) {
uni_vmovss(xmm_output_scale(0), ptr[reg_output_scale + i * wei_type_size]);
uni_vmovss(xmm_output_shift(0), ptr[reg_output_shift + i * wei_type_size]);
auto tail_unroll = [&](size_t iter) {
const auto &broadcasted = jqp_.broadcasted;
for (int i = 0; i < iter; i++) {
if (!broadcasted[static_cast<size_t>(FQ_add_input_type::CROP_LOW)])
uni_vmovss(xmm_crop_low(0), ptr[reg_crop_low + i * wei_type_size]);
if (!broadcasted[static_cast<size_t>(FQ_add_input_type::CROP_HIGH)])
uni_vmovss(xmm_crop_high(0), ptr[reg_crop_high + i * wei_type_size]);
if (!broadcasted[static_cast<size_t>(FQ_add_input_type::INPUT_SCALE)])
uni_vmovss(xmm_input_scale(0), ptr[reg_input_scale + i * wei_type_size]);
if (!broadcasted[static_cast<size_t>(FQ_add_input_type::INPUT_SHIFT)])
uni_vmovss(xmm_input_shift(0), ptr[reg_input_shift + i * wei_type_size]);
if (do_dequantization) {
if (!broadcasted[static_cast<size_t>(FQ_add_input_type::OUTPUT_SCALE)])
uni_vmovss(xmm_output_scale(0), ptr[reg_output_scale + i * wei_type_size]);
if (!broadcasted[static_cast<size_t>(FQ_add_input_type::OUTPUT_SHIFT)])
uni_vmovss(xmm_output_shift(0), ptr[reg_output_shift + i * wei_type_size]);
}
load_scalar(xmm_val(0), ptr[aux_reg_from + i * src_type_size], jqp_.src_prc);
uni_vminps(xmm_val(0), xmm_val(0), xmm_crop_high(0));
uni_vmaxps(xmm_val(0), xmm_val(0), xmm_crop_low(0));
uni_vfmadd213ps(xmm_val(0), xmm_input_scale(0), xmm_input_shift(0));
if (do_rounding) uni_vroundps(xmm_val(0), xmm_val(0), 0);
if (do_dequantization) uni_vfmadd213ps(xmm_val(0), xmm_output_scale(0), xmm_output_shift(0));
store_scalar(ptr[aux_reg_to + i * dst_type_size], xmm_val(0), jqp_.dst_prc);
}
jmp(end_unroll, T_NEAR);
};
load_scalar(xmm_val(0), ptr[aux_reg_from + i * src_type_size], jqp_.src_prc);
uni_vminps(xmm_val(0), xmm_val(0), xmm_crop_high(0));
uni_vmaxps(xmm_val(0), xmm_val(0), xmm_crop_low(0));
uni_vfmadd213ps(xmm_val(0), xmm_input_scale(0), xmm_input_shift(0));
if (do_rounding) uni_vroundps(xmm_val(0), xmm_val(0), 0);
if (do_dequantization) uni_vfmadd213ps(xmm_val(0), xmm_output_scale(0), xmm_output_shift(0));
store_scalar(ptr[aux_reg_to + i * dst_type_size], xmm_val(0), jqp_.dst_prc);
std::array<Label, tail4_simd_w> unroll_labels;
for (size_t i = 1; i < tail4_simd_w; ++i) {
cmp(reg_block_size, i);
je(unroll_labels[i], T_NEAR);
}
for (size_t i = 1; i < tail4_simd_w; ++i) {
L(unroll_labels[i]);
tail_unroll(i);
}
L(end_unroll);
dec(reg_work_amount);
add(aux_reg_from, reg_src_step);
add(aux_reg_to, reg_dst_step);
@ -895,29 +929,39 @@ namespace {
struct FakeQuantKey {
jit_quantize_params jqp;
size_t hash() const {
using namespace dnnl::impl::primitive_hashing;
size_t seed = 0;
seed = hash_combine(seed, jqp.c);
seed = hash_combine(seed, jqp.is_planar);
seed = hash_combine(seed, jqp.src_prc.getPrecVal());
seed = hash_combine(seed, jqp.wei_prc.getPrecVal());
seed = hash_combine(seed, jqp.dst_prc.getPrecVal());
seed = dnnl::impl::primitive_hashing::get_vector_hash(seed, jqp.s_str);
seed = dnnl::impl::primitive_hashing::get_vector_hash(seed, jqp.d_str);
seed = hash_combine(seed, jqp.op_type);
if (jqp.op_type == Algorithm::FQBinarization) {
seed = hash_combine(seed, jqp.c);
} else {
seed = hash_combine(seed, jqp.broadcasted);
}
return seed;
}
bool operator==(const FakeQuantKey& rhs) const {
bool result = jqp.c == rhs.jqp.c && jqp.is_planar == rhs.jqp.is_planar && jqp.src_prc == rhs.jqp.src_prc &&
bool result = jqp.is_planar == rhs.jqp.is_planar && jqp.src_prc == rhs.jqp.src_prc &&
jqp.wei_prc == rhs.jqp.wei_prc && jqp.dst_prc == rhs.jqp.dst_prc &&
jqp.op_type == rhs.jqp.op_type && jqp.s_str == rhs.jqp.s_str && jqp.d_str == rhs.jqp.d_str;
jqp.op_type == rhs.jqp.op_type;
if (result) {
if (jqp.op_type == Algorithm::FQBinarization) {
result = result && jqp.c == rhs.jqp.c;
} else {
result = result && jqp.broadcasted == rhs.jqp.broadcasted;
}
}
return result;
}
};
} // namespace
FakeQuantize::FakeQuantize(const std::shared_ptr<ngraph::Node>& op, const GraphContext::CPtr context) :
Node(op, context, NgraphShapeInferFactory(op, EMPTY_PORT_MASK)) {
Node(op, context, PassThroughShapeInferFactory()) {
std::string errorMessage;
if (isSupportedOperation(op, errorMessage)) {
algorithm = Algorithm::FQCommon;
@ -1096,6 +1140,13 @@ FakeQuantize::FakeQuantize(const std::shared_ptr<ngraph::Node>& op, const GraphC
outputScaleSize = outputScale.size();
outputShiftSize = outputShift.size();
broadcasted[static_cast<size_t>(FQ_add_input_type::CROP_LOW)] = cropLowSize == 1;
broadcasted[static_cast<size_t>(FQ_add_input_type::CROP_HIGH)] = cropHighSize == 1;
broadcasted[static_cast<size_t>(FQ_add_input_type::INPUT_SCALE)] = inputScaleSize == 1;
broadcasted[static_cast<size_t>(FQ_add_input_type::INPUT_SHIFT)] = inputShiftSize == 1;
broadcasted[static_cast<size_t>(FQ_add_input_type::OUTPUT_SCALE)] = outputScaleSize == 1;
broadcasted[static_cast<size_t>(FQ_add_input_type::OUTPUT_SHIFT)] = outputShiftSize == 1;
if (everyone_is(1u, cropLowSize, cropHighSize, inputScaleSize, inputShiftSize, outputScaleSize, outputShiftSize))
broadcastingPolicy = PerTensor;
else if (one_of(1u, cropLowSize, cropHighSize, inputScaleSize, inputShiftSize, outputScaleSize, outputShiftSize))
@ -1285,7 +1336,15 @@ void FakeQuantize::initSupportedPrimitiveDescriptors() {
}
}
for (auto& fmt : getDataFormats()) {
std::vector<LayoutType> dataFormats;
// reference implementation supports only planar format
if (impl_type == impl_desc_type::ref) {
dataFormats.push_back(LayoutType::ncsp);
} else {
dataFormats = getDataFormats();
}
for (auto& fmt : dataFormats) {
NodeConfig config;
config.dynBatchSupport = true;
for (size_t i = 0; i < getParentEdges().size(); i++) {
@ -1315,32 +1374,33 @@ void FakeQuantize::initSupportedPrimitiveDescriptors() {
}
bool FakeQuantize::needPrepareParams() const {
auto selectedPrimitiveDescriptor = getSelectedPrimitiveDescriptor();
if (!selectedPrimitiveDescriptor)
IE_THROW() << "CPU quantize node with name '" << getName() << "' doesn't have primitive descriptors.";
if (isBinarization()) {
auto selectedPrimitiveDescriptor = getSelectedPrimitiveDescriptor();
if (!selectedPrimitiveDescriptor)
IE_THROW() << "CPU quantize node with name '" << getName() << "' doesn't have primitive descriptors.";
if (internalBlobMemory.empty() || (selectedPrimitiveDescriptor->getImplementationType() != impl_desc_type::ref && inputShapesModified())) {
return true;
if (internalBlobMemory.empty() || (selectedPrimitiveDescriptor->getImplementationType() != impl_desc_type::ref && inputShapesModified())) {
return true;
}
const auto axisSize = getParentEdgesAtPort(0)[0]->getMemory().getStaticDims()[getAxis()];
const auto newPaddedSize = rnd_up(axisSize, 16);
const auto currPaddedSize = rnd_up(currentAxisSize, 16);
return newPaddedSize != currPaddedSize || ((isInputLowBroadcasted || isOutputHighBroadcasted) && axisSize != currentAxisSize);
}
const auto axisSize = getParentEdgesAtPort(0)[0]->getMemory().getStaticDims()[getAxis()];
const auto newPaddedSize = rnd_up(axisSize, 16);
const auto currPaddedSize = rnd_up(currentAxisSize, 16);
return newPaddedSize != currPaddedSize || (isBinarization() && (isInputLowBroadcasted || isOutputHighBroadcasted) &&
axisSize != currentAxisSize);
return false;
}
void FakeQuantize::prepareParams() {
const size_t axisSize = getParentEdgesAtPort(0)[0]->getMemory().GetShape().getStaticDims()[getAxis()];
const size_t newPaddedSize = rnd_up(axisSize, 16);
IE_ASSERT(newPaddedSize != 0);
if (isBinarization()) {
const size_t axisSize = getParentEdgeAt(0)->getMemory().GetShape().getStaticDims()[getAxis()];
const size_t newPaddedSize = rnd_up(axisSize, 16);
IE_ASSERT(newPaddedSize != 0);
if (internalBlobMemory.empty() || newPaddedSize != rnd_up(currentAxisSize, 16) ||
(isBinarization() && (isInputLowBroadcasted || isOutputHighBroadcasted) && axisSize != currentAxisSize)) {
DnnlBlockedMemoryDesc weightsDataDesc(Shape(VectorDims{newPaddedSize}), memory::data_type::f32, memory::format_tag::x);
if (isBinarization()) {
if (internalBlobMemory.empty() || newPaddedSize != rnd_up(currentAxisSize, 16) ||
((isInputLowBroadcasted || isOutputHighBroadcasted) && axisSize != currentAxisSize)) {
DnnlBlockedMemoryDesc weightsDataDesc(Shape(VectorDims{newPaddedSize}), memory::data_type::f32, memory::format_tag::x);
constexpr size_t numBinFqIntBlob = 2;
bool needUpdThr = false, needUpdMask = false;
if (isInputLowBroadcasted && axisSize != currentAxisSize) {
@ -1376,65 +1436,49 @@ void FakeQuantize::prepareParams() {
internalBlobMemory[1] = binarizationMaskDataMem;
}
}
} else if (levels != 2) {
constexpr size_t numFqIntBlob = 6;
auto pushInternalBlob = [&](std::vector<float>& data, size_t idx) {
auto memory = std::make_shared<Memory>(getEngine());
bool needOverwrite = getInputShapeAtPort(0).getDims()[getAxis()] == Shape::UNDEFINED_DIM && data.size() == 1;
if (needOverwrite) {
memory->Create(weightsDataDesc);
float *ptr = reinterpret_cast<float *>(memory->GetPtr());
std::fill(ptr, ptr + newPaddedSize, data[0]);
} else {
if (data.size() == 1) {
data.resize(newPaddedSize, data[0]);
} else {
data.resize(newPaddedSize);
}
memory->Create(weightsDataDesc, &data[0]);
}
if (internalBlobMemory.size() != numFqIntBlob) {
internalBlobMemory.push_back(memory);
} else if (needOverwrite) {
internalBlobMemory[idx] = memory;
}
};
pushInternalBlob(cropLow, 0);
pushInternalBlob(cropHigh, 1);
pushInternalBlob(inputScale, 2);
pushInternalBlob(inputShift, 3);
pushInternalBlob(outputScale, 4);
pushInternalBlob(outputShift, 5);
} else {
IE_THROW() << "Can't fill internal blob for FakeQuantize node with name: " << getName();
}
currentAxisSize = axisSize;
}
currentAxisSize = axisSize;
}
void FakeQuantize::createPrimitive() {
Node::createPrimitive();
auto selectedPrimitiveDescriptor = getSelectedPrimitiveDescriptor();
if (!selectedPrimitiveDescriptor)
IE_THROW() << "CPU quantize node with name '" << getName() << "' doesn't have primitive descriptors.";
if (selectedPrimitiveDescriptor->getImplementationType() != impl_desc_type::ref) {
const auto& config = getSelectedPrimitiveDescriptor()->getConfig();
const auto& inDims = getParentEdgesAtPort(0)[0]->getMemory().getStaticDims();
//Form FakeQuanKey
FakeQuantKey key = {};
key.jqp.c = inDims.size() > 1 ? inDims[1] : 1;
key.jqp.src_prc = config.inConfs[0].getMemDesc()->getPrecision();
key.jqp.wei_prc = Precision::FP32;
key.jqp.dst_prc = config.outConfs[0].getMemDesc()->getPrecision();
auto srcDesc = getParentEdgeAt(0)->getMemory().GetDescWithType<BlockedMemoryDesc>();
key.jqp.s_str = srcDesc->getStrides();
auto dstDesc = getChildEdgeAt(0)->getMemory().GetDescWithType<BlockedMemoryDesc>();
const auto &srcMemory = getParentEdgeAt(0)->getMemory();
const auto &srcDesc = srcMemory.getDesc();
key.jqp.d_str = dstDesc->getStrides();
key.jqp.is_planar = srcDesc->hasLayoutType(LayoutType::ncsp) && one_of(srcDesc->getShape().getRank(), 3u, 4u, 5u);
key.jqp.is_planar = srcDesc.hasLayoutType(LayoutType::ncsp) && one_of(srcDesc.getShape().getRank(), 3, 4, 5);
key.jqp.op_type = getAlgorithm();
if (isBinarization()) {
const auto &inDims = srcMemory.getStaticDims();
key.jqp.c = inDims.size() > 1 ? inDims[1] : 1;
} else {
// in case of blocked layout we need to extend vectors to prevent read from unallocated memory
size_t paddedSize = srcDesc.hasLayoutType(LayoutType::nCsp16c) ? 16 : srcDesc.hasLayoutType(LayoutType::nCsp8c) ? 8 : 1;
if (paddedSize != 1) {
if (!broadcasted[static_cast<size_t>(FQ_add_input_type::CROP_LOW)]) cropLow.resize(rnd_up(cropLow.size(), paddedSize));
if (!broadcasted[static_cast<size_t>(FQ_add_input_type::CROP_HIGH)]) cropHigh.resize(rnd_up(cropHigh.size(), paddedSize));
if (!broadcasted[static_cast<size_t>(FQ_add_input_type::INPUT_SCALE)]) inputScale.resize(rnd_up(inputScale.size(), paddedSize));
if (!broadcasted[static_cast<size_t>(FQ_add_input_type::INPUT_SHIFT)]) inputShift.resize(rnd_up(inputShift.size(), paddedSize));
if (!broadcasted[static_cast<size_t>(FQ_add_input_type::OUTPUT_SCALE)]) outputScale.resize(rnd_up(outputScale.size(), paddedSize));
if (!broadcasted[static_cast<size_t>(FQ_add_input_type::OUTPUT_SHIFT)]) outputShift.resize(rnd_up(outputShift.size(), paddedSize));
}
key.jqp.broadcasted = broadcasted;
}
auto cache = context->getParamsCache();
auto buildExecutor = [](const FakeQuantKey& key) {
return std::make_shared<FakeQuantizeJitExecutor>(key.jqp);
@ -1513,13 +1557,6 @@ void FakeQuantize::executeReference() {
} else {
auto dst = reinterpret_cast<float *>(dstMemory->GetPtr());
auto crop_low = reinterpret_cast<const float*>(internalBlobMemory[0]->GetData());
auto crop_high = reinterpret_cast<const float*>(internalBlobMemory[1]->GetData());
auto input_scale = reinterpret_cast<const float*>(internalBlobMemory[2]->GetData());
auto input_shift = reinterpret_cast<const float*>(internalBlobMemory[3]->GetData());
auto output_scale = reinterpret_cast<const float*>(internalBlobMemory[4]->GetData());
auto output_shift = reinterpret_cast<const float*>(internalBlobMemory[5]->GetData());
parallel_nd(N, C, D, H, W, [&](dim_t n, dim_t c, dim_t d, dim_t h, dim_t w) {
size_t src_off = srcDims.size() == 5 ?
n * s_str[0] + c * s_str[1] + d * s_str[2] + h * s_str[3] + w * s_str[4] :
@ -1534,12 +1571,12 @@ void FakeQuantize::executeReference() {
float src_val = src[src_off];
int wei_idx = getAxis() == 0 ? n : c;
float cl = crop_low[wei_idx];
float ch = crop_high[wei_idx];
float isc = input_scale[wei_idx];
float ish = input_shift[wei_idx];
float osc = output_scale[wei_idx];
float osh = output_shift[wei_idx];
float cl = broadcasted[static_cast<size_t>(FQ_add_input_type::CROP_LOW)] ? cropLow[0] : cropLow[wei_idx];
float ch = broadcasted[static_cast<size_t>(FQ_add_input_type::CROP_HIGH)] ? cropHigh[0] : cropHigh[wei_idx];
float isc = broadcasted[static_cast<size_t>(FQ_add_input_type::INPUT_SCALE)] ? inputScale[0] : inputScale[wei_idx];
float ish = broadcasted[static_cast<size_t>(FQ_add_input_type::INPUT_SHIFT)] ? inputShift[0] : inputShift[wei_idx];
float osc = broadcasted[static_cast<size_t>(FQ_add_input_type::OUTPUT_SCALE)] ? outputScale[0] : outputScale[wei_idx];
float osh = broadcasted[static_cast<size_t>(FQ_add_input_type::OUTPUT_SHIFT)] ? outputShift[0] : outputShift[wei_idx];
float dst_val = nstl::min(ch, nstl::max(cl, src_val));
dst_val = dst_val * isc + ish;
@ -1562,7 +1599,7 @@ void FakeQuantize::executeReference() {
}
void FakeQuantize::executeBinarization(const std::unique_ptr<jit_uni_quantize_kernel> &pKernel) const {
auto &srcMemory = getParentEdgeAt(0)->getMemoryPtr();
const auto &srcMemory = getParentEdgeAt(0)->getMemoryPtr();
auto &dstMemory = getChildEdgeAt(0)->getMemoryPtr();
auto src = reinterpret_cast<const uint8_t *>(srcMemory->GetPtr());
@ -1573,8 +1610,8 @@ void FakeQuantize::executeBinarization(const std::unique_ptr<jit_uni_quantize_ke
auto src_dims = srcMemory->getStaticDims();
const auto &jqp = pKernel->jqp_;
std::vector<size_t> s_str = jqp.s_str;
auto srcMemDesc = srcMemory->GetDescWithType<BlockedMemoryDesc>();
std::vector<size_t> s_str = srcMemDesc->getStrides();
size_t tmp = s_str[s_str.size() - 1];
for (int i = s_str.size() - 1; i > 1; i--) {
s_str[i] = s_str[i - 1];
@ -1608,13 +1645,6 @@ void FakeQuantize::executeQuantization(const std::unique_ptr<jit_uni_quantize_ke
auto src = reinterpret_cast<const uint8_t *>(srcMemory->GetPtr());
auto dst = reinterpret_cast<uint8_t *>(dstMemory->GetPtr());
auto crop_low = reinterpret_cast<const float*>(internalBlobMemory[0]->GetData());
auto crop_high = reinterpret_cast<const float*>(internalBlobMemory[1]->GetData());
auto input_scale = reinterpret_cast<const float*>(internalBlobMemory[2]->GetData());
auto input_shift = reinterpret_cast<const float*>(internalBlobMemory[3]->GetData());
auto output_scale = reinterpret_cast<const float*>(internalBlobMemory[4]->GetData());
auto output_shift = reinterpret_cast<const float*>(internalBlobMemory[5]->GetData());
auto& srcDesc = srcMemory->getDesc();
auto srcDims = srcDesc.getShape().getStaticDims();
@ -1626,7 +1656,8 @@ void FakeQuantize::executeQuantization(const std::unique_ptr<jit_uni_quantize_ke
auto src_type_size = jqp.src_prc.size();
auto dst_type_size = jqp.dst_prc.size();
auto s_str = jqp.s_str;
auto srcMemDesc = srcMemory->GetDescWithType<BlockedMemoryDesc>();
auto s_str = srcMemDesc->getStrides();
if (is_blk_format) {
s_str[1] /= blk_size;
@ -1657,12 +1688,12 @@ void FakeQuantize::executeQuantization(const std::unique_ptr<jit_uni_quantize_ke
arg.from = &src[data_off * src_type_size];
arg.to = &dst[data_off * dst_type_size];
arg.crop_low = &crop_low[c];
arg.crop_high = &crop_high[c];
arg.input_scale = &input_scale[c];
arg.input_shift = &input_shift[c];
arg.output_scale = &output_scale[c];
arg.output_shift = &output_shift[c];
arg.crop_low = broadcasted[static_cast<size_t>(FQ_add_input_type::CROP_LOW)] ? &cropLow[0] : &cropLow[c];
arg.crop_high = broadcasted[static_cast<size_t>(FQ_add_input_type::CROP_HIGH)] ? &cropHigh[0] : &cropHigh[c];
arg.input_scale = broadcasted[static_cast<size_t>(FQ_add_input_type::INPUT_SCALE)] ? &inputScale[0] : &inputScale[c];
arg.input_shift = broadcasted[static_cast<size_t>(FQ_add_input_type::INPUT_SHIFT)] ? &inputShift[0] : &inputShift[c];
arg.output_scale = broadcasted[static_cast<size_t>(FQ_add_input_type::OUTPUT_SCALE)] ? &outputScale[0] : &outputScale[c];
arg.output_shift = broadcasted[static_cast<size_t>(FQ_add_input_type::OUTPUT_SHIFT)] ? &outputShift[0] : &outputShift[c];
arg.src_step = (size_t) blk_size * src_type_size;
arg.dst_step = (size_t) blk_size * dst_type_size;
@ -1687,12 +1718,12 @@ void FakeQuantize::executeQuantization(const std::unique_ptr<jit_uni_quantize_ke
arg.from = &src[data_off * src_type_size];
arg.to = &dst[data_off * dst_type_size];
arg.crop_low = &crop_low[c];
arg.crop_high = &crop_high[c];
arg.input_scale = &input_scale[c];
arg.input_shift = &input_shift[c];
arg.output_scale = &output_scale[c];
arg.output_shift = &output_shift[c];
arg.crop_low = broadcasted[static_cast<size_t>(FQ_add_input_type::CROP_LOW)] ? &cropLow[0] : &cropLow[c];
arg.crop_high = broadcasted[static_cast<size_t>(FQ_add_input_type::CROP_HIGH)] ? &cropHigh[0] : &cropHigh[c];
arg.input_scale = broadcasted[static_cast<size_t>(FQ_add_input_type::INPUT_SCALE)] ? &inputScale[0] : &inputScale[c];
arg.input_shift = broadcasted[static_cast<size_t>(FQ_add_input_type::INPUT_SHIFT)] ? &inputShift[0] : &inputShift[c];
arg.output_scale = broadcasted[static_cast<size_t>(FQ_add_input_type::OUTPUT_SCALE)] ? &outputScale[0] : &outputScale[c];
arg.output_shift = broadcasted[static_cast<size_t>(FQ_add_input_type::OUTPUT_SHIFT)] ? &outputShift[0] : &outputShift[c];
arg.src_step = is_blk_format ? (size_t) blk_size * src_type_size : (size_t) C * src_type_size;
arg.dst_step = is_blk_format ? (size_t) blk_size * dst_type_size : (size_t) C * dst_type_size;
@ -1715,12 +1746,12 @@ void FakeQuantize::executeQuantization(const std::unique_ptr<jit_uni_quantize_ke
arg.from = &src[data_off * src_type_size];
arg.to = &dst[data_off * dst_type_size];
arg.crop_low = &crop_low[c];
arg.crop_high = &crop_high[c];
arg.input_scale = &input_scale[c];
arg.input_shift = &input_shift[c];
arg.output_scale = &output_scale[c];
arg.output_shift = &output_shift[c];
arg.crop_low = broadcasted[static_cast<size_t>(FQ_add_input_type::CROP_LOW)] ? &cropLow[0] : &cropLow[c];
arg.crop_high = broadcasted[static_cast<size_t>(FQ_add_input_type::CROP_HIGH)] ? &cropHigh[0] : &cropHigh[c];
arg.input_scale = broadcasted[static_cast<size_t>(FQ_add_input_type::INPUT_SCALE)] ? &inputScale[0] : &inputScale[c];
arg.input_shift = broadcasted[static_cast<size_t>(FQ_add_input_type::INPUT_SHIFT)] ? &inputShift[0] : &inputShift[c];
arg.output_scale = broadcasted[static_cast<size_t>(FQ_add_input_type::OUTPUT_SCALE)] ? &outputScale[0] : &outputScale[c];
arg.output_shift = broadcasted[static_cast<size_t>(FQ_add_input_type::OUTPUT_SHIFT)] ? &outputShift[0] : &outputShift[c];
arg.src_step = is_blk_format ? (size_t) blk_size * src_type_size : (size_t) C * src_type_size;
arg.dst_step = is_blk_format ? (size_t) blk_size * dst_type_size : (size_t) C * dst_type_size;
@ -1737,11 +1768,7 @@ void FakeQuantize::executeDynamicImpl(dnnl::stream strm) {
}
void FakeQuantize::execute(dnnl::stream strm) {
auto selectedPrimitiveDescriptor = getSelectedPrimitiveDescriptor();
if (!selectedPrimitiveDescriptor)
IE_THROW() << "CPU quantize node with name '" << getName() << "' doesn't have primitive descriptors.";
if (selectedPrimitiveDescriptor->getImplementationType() != impl_desc_type::ref) {
if (getSelectedPrimitiveDescriptor()->getImplementationType() != impl_desc_type::ref) {
execPtr->exec(*this);
} else {
executeReference();

View File

@ -17,18 +17,27 @@ namespace ov {
namespace intel_cpu {
namespace node {
enum class FQ_add_input_type {
CROP_LOW,
CROP_HIGH,
INPUT_SCALE,
INPUT_SHIFT,
OUTPUT_SCALE,
OUTPUT_SHIFT,
INPUTS_SIZE
};
struct jit_quantize_params {
int c;
bool is_planar;
InferenceEngine::Precision src_prc;
InferenceEngine::Precision wei_prc;
InferenceEngine::Precision dst_prc;
std::vector<size_t> s_str;
std::vector<size_t> d_str;
Algorithm op_type;
int c; // need only for binarization
std::bitset<static_cast<size_t>(FQ_add_input_type::INPUTS_SIZE)> broadcasted; // need only for quantization
};
struct jit_quantize_call_args {
@ -82,6 +91,7 @@ public:
bool needPrepareParams() const override;
void prepareParams() override;
void createPrimitive() override;
const float* getBinarizationTresholdsPtr() const { return &binarizationThresholds[0]; }
const float* getBinarizationOutputMaskPtr() const { return reinterpret_cast<const float*>(&binarizationOutputMask[0]); }
@ -240,6 +250,8 @@ private:
size_t outputScaleSize;
size_t outputShiftSize;
std::bitset<static_cast<size_t>(FQ_add_input_type::INPUTS_SIZE)> broadcasted;
std::vector<float> fqScales;
// version based lazy evaluation, any parameter change increases parameterVersion

View File

@ -0,0 +1,529 @@
// Copyright (C) 2023 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
// Motivation:
// In a dynamic scenario, depending on the input shapes for the current node, we can either generate a new jit kernel or get an existing one from the cache.
// But the current single layer tests do not allow checking the case when the same kernel can be used for different nodes.
// This subgraph test contains 2 FQ nodes and allows us to check this case.
// ------------------------------------ ------------------------------------
// | Input 0 | | Input 1 |
// ------------------------------------ ------------------------------------
// | |
// ------------------------------------ ------------------------------------
// | FakeQuantize 0 | | FakeQuantize 1 |
// ------------------------------------ ------------------------------------
// | |
// | ------------------------------------
// | |Reshape (if !reshapeShape.empty())|
// | ------------------------------------
// | |
// ----------------------------------------------------------------------------
// | Concat |
// ----------------------------------------------------------------------------
// |
// --------
// |Output|
// --------
#include <shared_test_classes/base/ov_subgraph.hpp>
#include <ngraph_functions/builders.hpp>
#include <common_test_utils/ov_tensor_utils.hpp>
#include "test_utils/cpu_test_utils.hpp"
#include "cpp_interfaces/interface/ie_internal_plugin_config.hpp"
using namespace CPUTestUtils;
using namespace ov::test;
using namespace InferenceEngine;
using namespace ngraph;
namespace CPUSubgraphTestsDefinitions {
using InputShapesTuple = std::tuple<
std::vector<InputShape>, // fq dynamic data shapes
std::vector<std::vector<SizeVector>>, // fq range input shapes
std::vector<int32_t> // reshape shape
>;
using FqSpecificParams = std::tuple<int64_t, // 'data' input low bounds
int64_t, // 'data' input high bounds
std::vector<float>, // output low
std::vector<float>, // output high
size_t>; // levels
typedef std::tuple<
InputShapesTuple, // fq input shapes and reshape shape
FqSpecificParams, // fq specific params
std::pair<std::vector<float>, std::vector<float>>, // il and ih values
CPUSpecificParams,
std::map<std::string, std::string> // Additional config (disable snippets or no)
> FakeQuantizeCacheTestParams;
class FakeQuantizeCacheTest : public testing::WithParamInterface<FakeQuantizeCacheTestParams>,
virtual public SubgraphBaseTest, public CPUTestsBase {
public:
static std::string getTestCaseName(const testing::TestParamInfo<FakeQuantizeCacheTestParams> &obj) {
InputShapesTuple inputShapesTuple;
FqSpecificParams fqParams;
std::pair<std::vector<float>, std::vector<float>> inputRangesValues;
CPUSpecificParams cpuParams;
std::map<std::string, std::string> additionalConfig;
std::tie(inputShapesTuple, fqParams, inputRangesValues, cpuParams, additionalConfig) = obj.param;
std::vector<InputShape> shapes;
std::vector<std::vector<SizeVector>> ranges;
std::vector<int32_t> reshapeShape;
std::tie(shapes, ranges, reshapeShape) = inputShapesTuple;
int64_t inDataLowBounds, inDataHighBounds;
std::vector<float> inputLow, inputHigh, outputLow, outputHigh;
size_t levels;
inputLow = inputRangesValues.first;
inputHigh = inputRangesValues.second;
std::tie(inDataLowBounds, inDataHighBounds, outputLow, outputHigh, levels) = fqParams;
std::ostringstream results;
for (int i = 0; i < shapes.size(); i++) {
results << "FQ" << i << "_IS=(" << CommonTestUtils::partialShape2str({shapes[i].first}) << ")_";
results << "TS=";
for (const auto& shape : shapes[i].second) {
results << "(" << CommonTestUtils::vec2str(shape) << ")_";
}
results << "RS=";
for (const auto& range : ranges[i]) {
results << "(" << CommonTestUtils::vec2str(range) << ")_";
}
}
if (!reshapeShape.empty()) {
results << "ReshapeShape=(" << CommonTestUtils::vec2str(reshapeShape) << ")_";
}
results << "LOW_BOUNDS=" << inDataLowBounds << "_";
results << "HIGH_BOUNDS=" << inDataHighBounds << "_";
results << "IL=" << CommonTestUtils::vec2str(inputLow) << "_";
results << "IH=" << CommonTestUtils::vec2str(inputHigh) << "_";
results << "OL=" << CommonTestUtils::vec2str(outputLow) << "_";
results << "OH=" << CommonTestUtils::vec2str(outputHigh) << "_";
results << "LEVELS=" << levels;
results << CPUTestsBase::getTestCaseName(cpuParams);
if (!additionalConfig.empty()) {
results << "_PluginConf";
for (auto& item : additionalConfig) {
results << "_" << item.first << "=" << item.second;
}
}
return results.str();
}
protected:
void SetUp() override {
abs_threshold = 0.01f;
InputShapesTuple inputShapesTuple;
FqSpecificParams fqParams;
std::pair<std::vector<float>, std::vector<float>> inputRangesValues;
CPUSpecificParams cpuParams;
std::map<std::string, std::string> additionalConfig;
std::tie(inputShapesTuple, fqParams, inputRangesValues,
cpuParams, additionalConfig) = this->GetParam();
std::vector<InputShape> shapesVec;
std::vector<std::vector<SizeVector>> rangesVec;
std::vector<int32_t> reshapeShape;
std::tie(shapesVec, rangesVec, reshapeShape) = inputShapesTuple;
std::tie(inFmts, outFmts, priority, selectedType) = cpuParams;
configuration.insert(additionalConfig.begin(), additionalConfig.end());
targetDevice = CommonTestUtils::DEVICE_CPU;
init_input_shapes(shapesVec);
size_t levels;
std::vector<std::vector<float>> rangesBounds(RANGES_INPUT_NUMBER);
rangesBounds[0] = inputRangesValues.first;
rangesBounds[1] = inputRangesValues.second;
std::tie(inDataLowBounds, inDataHighBounds, rangesBounds[2], rangesBounds[3], levels) = fqParams;
ParameterVector ngraphParam;
std::vector<std::shared_ptr<Node>> ngraphInputs;
auto ngInPrec = element::Type_t::f32;
for (size_t i = 0; i < inputDynamicShapes.size(); i++) {
ngraphParam.push_back(std::make_shared<opset1::Parameter>(ngInPrec, inputDynamicShapes[i]));
ngraphInputs.push_back(ngraphParam.back());
}
auto makeFQ = [&](int i) {
auto extendData = [](const std::vector<float> &data, size_t newSize) {
std::vector<float> extendedData(newSize);
size_t oldSize = data.size();
for (size_t i = 0; i < newSize; i++) {
extendedData[i] = data[i % oldSize];
}
return extendedData;
};
auto ranges = rangesVec[i];
auto il = builder::makeConstant(ngInPrec, ranges[0], extendData(rangesBounds[0],
std::accumulate(ranges[0].begin(), ranges[0].end(), 1, std::multiplies<size_t>())));
auto ih = builder::makeConstant(ngInPrec, ranges[1], extendData(rangesBounds[1],
std::accumulate(ranges[1].begin(), ranges[1].end(), 1, std::multiplies<size_t>())));
auto ol = builder::makeConstant(ngInPrec, ranges[2], extendData(rangesBounds[2],
std::accumulate(ranges[2].begin(), ranges[2].end(), 1, std::multiplies<size_t>())));
auto oh = builder::makeConstant(ngInPrec, ranges[3], extendData(rangesBounds[3],
std::accumulate(ranges[3].begin(), ranges[3].end(), 1, std::multiplies<size_t>())));
auto fqNode = std::make_shared<opset5::FakeQuantize>(ngraphParam[i], il, ih, ol, oh, levels);
fqNode->get_rt_info() = getCPUInfo();
return fqNode;
};
std::shared_ptr<Node> lastNode0 = makeFQ(0);
std::shared_ptr<Node> lastNode1 = makeFQ(1);
if (!reshapeShape.empty()) {
auto reshapeConstNode = builder::makeConstant(::element::Type(::element::Type_t::i32),
{reshapeShape.size()}, reshapeShape);
lastNode1 = std::make_shared<opset5::Reshape>(lastNode1, reshapeConstNode, false);
}
auto concat = builder::makeConcat({lastNode0, lastNode1}, 0);
if (selectedType.empty()) {
selectedType = getPrimitiveType() + "_FP32";
}
function = std::make_shared<Function>(concat, ngraphParam, "fq_cache");
}
void generate_inputs(const std::vector<ov::Shape>& targetInputStaticShapes) override {
inputs.clear();
const auto& funcInputs = function->inputs();
for (int i = 0; i < funcInputs.size(); ++i) {
const auto& funcInput = funcInputs[i];
ov::Tensor tensor;
tensor = ov::test::utils::create_and_fill_tensor(funcInput.get_element_type(),
targetInputStaticShapes[i],
inDataHighBounds - inDataLowBounds,
inDataLowBounds);
inputs.insert({funcInput.get_node_shared_ptr(), tensor});
}
}
private:
const size_t RANGES_INPUT_NUMBER = 4;
int64_t inDataLowBounds, inDataHighBounds;
};
TEST_P(FakeQuantizeCacheTest, CompareWithRefs) {
run();
CheckPluginRelatedResults(compiledModel, "FakeQuantize");
}
namespace {
const std::vector<size_t> levels = {256};
int64_t dataLowBounds{-10}, dataHighBounds{10};
const std::vector<std::pair<std::vector<float>, std::vector<float>>> inputRanges = {
{{0.0f, 1.0f}, {5.0f, 6.0f}},
};
const std::vector<float> outputLow{5.0f, 6.0f}, outputHigh{25.0f, 31.0f};
const auto specificParams = ::testing::Combine(::testing::Values(dataLowBounds),
::testing::Values(dataHighBounds),
::testing::Values(outputLow),
::testing::Values(outputHigh),
::testing::ValuesIn(levels));
const std::map<std::string, std::string> emptyConfig = {};
const std::map<std::string, std::string> disableSnippets = {
{PluginConfigInternalParams::KEY_SNIPPETS_MODE, PluginConfigInternalParams::DISABLE}};
// 3D
std::vector<CPUSpecificParams> cpuParams_3D = {
CPUSpecificParams({ncw}, {ncw}, {}, {}),
};
std::vector<InputShapesTuple> inputShapes_3D = {
{
// fq dynamic data shapes
{
// input0
{{-1, -1, 43}, {{1, 10, 43}, {1, 20, 43}, {1, 10, 43}, {1, 20, 43}}},
// input1
{{-1, -1, 43}, {{1, 10, 43}, {1, 20, 43}, {1, 10, 43}, {1, 20, 43}}},
},
// fq range input shapes
{
// input0
{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, // miss
// input1
{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, // hit
},
// reshape shape
{},
},
{
// fq dynamic data shapes
{
// input0
{{-1, 10, -1}, {{1, 10, 22}, {1, 10, 44}, {1, 10, 22}, {1, 10, 44}}},
// input1
{{-1, 10, -1}, {{1, 10, 22}, {1, 10, 44}, {1, 10, 22}, {1, 10, 44}}},
},
// fq range input shapes
{
// input0
{{1, 10, 1}, {1, 10, 1}, {1, 10, 1}, {1, 10, 1}}, // miss
// input1
{{1, 10, 1}, {1, 10, 1}, {1, 10, 1}, {1, 10, 1}}, // hit
},
// reshape shape
{},
},
{
// fq dynamic data shapes
{
// input0
{{-1, 10, -1}, {{1, 10, 22}, {1, 10, 44}, {1, 10, 22}, {1, 10, 44}}},
// input1
{{-1, 10, -1}, {{1, 10, 22}, {1, 10, 44}, {1, 10, 22}, {1, 10, 44}}},
},
// fq range input shapes
{
// input0
{{1, 10, 1}, {1, 10, 1}, {1, 10, 1}, {1, 10, 1}}, // miss
// input1
{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, // miss
},
// reshape shape
{},
},
{
// fq dynamic data shapes
{
// input0
{{-1, 10, -1}, {{1, 10, 22}, {1, 10, 22}}},
// input1
{{-1, 20, -1}, {{1, 20, 22}, {1, 20, 22}}},
},
// fq range input shapes
{
// input0
{{1, 10, 1}, {1, 10, 1}, {1, 10, 1}, {1, 10, 1}}, // miss
// input1
{{1, 20, 1}, {1, 20, 1}, {1, 20, 1}, {1, 20, 1}}, // hit
},
// reshape shape
{-1, 10, 22},
},
};
INSTANTIATE_TEST_SUITE_P(smoke_FakeQuantizeCache_3D, FakeQuantizeCacheTest,
::testing::Combine(
::testing::ValuesIn(inputShapes_3D),
specificParams,
::testing::ValuesIn(inputRanges),
::testing::ValuesIn(filterCPUSpecificParams(cpuParams_3D)),
::testing::Values(disableSnippets)),
FakeQuantizeCacheTest::getTestCaseName);
// 4D
std::vector<CPUSpecificParams> cpuParams_4D = {
CPUSpecificParams({nchw}, {nchw}, {}, {}),
CPUSpecificParams({nhwc}, {nhwc}, {}, {}),
CPUSpecificParams({nChw16c}, {nChw16c}, {}, {}),
};
std::vector<InputShapesTuple> inputShapes_4D = {
{
// fq dynamic data shapes
{
// input0
{{-1, -1, -1, 43}, {{1, 17, 3, 43}, {1, 34, 3, 43}, {1, 17, 3, 43}, {1, 34, 3, 43}}},
// input1
{{-1, -1, -1, 43}, {{1, 17, 3, 43}, {1, 34, 3, 43}, {1, 17, 3, 43}, {1, 34, 3, 43}}},
},
// fq range input shapes
{
// input0
{{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}}, // miss
// input1
{{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}}, // hit
},
// reshape shape
{},
},
{
// fq dynamic data shapes
{
// input0
{{-1, 47, -1, -1}, {{1, 47, 2, 22}, {1, 47, 3, 33}, {1, 47, 2, 22}, {1, 47, 3, 33}}},
// input1
{{-1, 47, -1, -1}, {{1, 47, 2, 22}, {1, 47, 3, 33}, {1, 47, 2, 22}, {1, 47, 3, 33}}},
},
// fq range input shapes
{
// input0
{{1, 47, 1, 1}, {1, 47, 1, 1}, {1, 47, 1, 1}, {1, 47, 1, 1}}, // miss
// input1
{{1, 47, 1, 1}, {1, 47, 1, 1}, {1, 47, 1, 1}, {1, 47, 1, 1}}, // hit
},
// reshape shape
{},
},
{
// fq dynamic data shapes
{
// input0
{{-1, 47, -1, -1}, {{1, 47, 2, 22}, {1, 47, 3, 33}, {1, 47, 2, 22}, {1, 47, 3, 33}}},
// input1
{{-1, 47, -1, -1}, {{1, 47, 2, 22}, {1, 47, 3, 33}, {1, 47, 2, 22}, {1, 47, 3, 33}}},
},
// fq range input shapes
{
// input0
{{1, 47, 1, 1}, {1, 47, 1, 1}, {1, 47, 1, 1}, {1, 47, 1, 1}}, // miss
// input1
{{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}}, // miss
},
// reshape shape
{},
},
{
// fq dynamic data shapes
{
// input0
{{-1, 17, -1, -1}, {{1, 17, 2, 22}, {1, 17, 2, 22}}},
// input1
{{-1, 34, -1, -1}, {{1, 34, 2, 22}, {1, 34, 2, 22}}},
},
// fq range input shapes
{
// input0
{{1, 17, 1, 1}, {1, 17, 1, 1}, {1, 17, 1, 1}, {1, 17, 1, 1}}, // miss
// input1
{{1, 34, 1, 1}, {1, 34, 1, 1}, {1, 34, 1, 1}, {1, 34, 1, 1}}, // hit
},
// reshape shape
{-1, 17, 2, 22},
},
};
INSTANTIATE_TEST_SUITE_P(smoke_FakeQuantizeCache_4D, FakeQuantizeCacheTest,
::testing::Combine(
::testing::ValuesIn(inputShapes_4D),
specificParams,
::testing::ValuesIn(inputRanges),
::testing::ValuesIn(filterCPUSpecificParams(cpuParams_4D)),
::testing::Values(disableSnippets)),
FakeQuantizeCacheTest::getTestCaseName);
// 5D
std::vector<CPUSpecificParams> cpuParams_5D = {
CPUSpecificParams({ncdhw}, {ncdhw}, {}, {}),
CPUSpecificParams({ndhwc}, {ndhwc}, {}, {}),
CPUSpecificParams({nCdhw16c}, {nCdhw16c}, {}, {}),
};
std::vector<InputShapesTuple> inputShapes_5D = {
{
// fq dynamic data shapes
{
// input0
{{-1, -1, -1, -1, 43}, {{1, 17, 2, 3, 43}, {1, 34, 2, 3, 43}, {1, 17, 2, 3, 43}, {1, 34, 2, 3, 43}}},
// input1
{{-1, -1, -1, -1, 43}, {{1, 17, 2, 3, 43}, {1, 34, 2, 3, 43}, {1, 17, 2, 3, 43}, {1, 34, 2, 3, 43}}},
},
// fq range input shapes
{
// input0
{{1, 1, 1, 1, 1}, {1, 1, 1, 1, 1}, {1, 1, 1, 1, 1}, {1, 1, 1, 1, 1}}, // miss
// input1
{{1, 1, 1, 1, 1}, {1, 1, 1, 1, 1}, {1, 1, 1, 1, 1}, {1, 1, 1, 1, 1}}, // hit
},
// reshape shape
{},
},
{
// fq dynamic data shapes
{
// input0
{{-1, 47, -1, -1, -1}, {{1, 47, 2, 3, 22}, {1, 47, 3, 2, 33}, {1, 47, 2, 3, 22}, {1, 47, 3, 2, 33}}},
// input1
{{-1, 47, -1, -1, -1}, {{1, 47, 2, 3, 22}, {1, 47, 3, 2, 33}, {1, 47, 2, 3, 22}, {1, 47, 3, 2, 33}}},
},
// fq range input shapes
{
// input0
{{1, 47, 1, 1, 1}, {1, 47, 1, 1, 1}, {1, 47, 1, 1, 1}, {1, 47, 1, 1, 1}}, // miss
// input1
{{1, 47, 1, 1, 1}, {1, 47, 1, 1, 1}, {1, 47, 1, 1, 1}, {1, 47, 1, 1, 1}}, // hit
},
// reshape shape
{},
},
{
// fq dynamic data shapes
{
// input0
{{-1, 47, -1, -1, -1}, {{1, 47, 2, 3, 22}, {1, 47, 3, 2, 33}, {1, 47, 2, 3, 22}, {1, 47, 3, 2, 33}}},
// input1
{{-1, 47, -1, -1, -1}, {{1, 47, 2, 3, 22}, {1, 47, 3, 2, 33}, {1, 47, 2, 3, 22}, {1, 47, 3, 2, 33}}},
},
// fq range input shapes
{
// input0
{{1, 47, 1, 1, 1}, {1, 47, 1, 1, 1}, {1, 47, 1, 1, 1}, {1, 47, 1, 1, 1}}, // miss
// input1
{{1, 1, 1, 1, 1}, {1, 1, 1, 1, 1}, {1, 1, 1, 1, 1}, {1, 1, 1, 1, 1}}, // miss
},
// reshape shape
{},
},
{
// fq dynamic data shapes
{
// input0
{{-1, 17, -1, -1, -1}, {{1, 17, 2, 3, 22}, {1, 17, 2, 3, 22}}},
// input1
{{-1, 34, -1, -1, -1}, {{1, 34, 2, 3, 22}, {1, 34, 2, 3, 22}}},
},
// fq range input shapes
{
// input0
{{1, 17, 1, 1, 1}, {1, 17, 1, 1, 1}, {1, 17, 1, 1, 1}, {1, 17, 1, 1, 1}}, // miss
// input1
{{1, 34, 1, 1, 1}, {1, 34, 1, 1, 1}, {1, 34, 1, 1, 1}, {1, 34, 1, 1, 1}}, // hit
},
// reshape shape
{-1, 17, 2, 3, 22},
},
};
INSTANTIATE_TEST_SUITE_P(smoke_FakeQuantizeCache_5D, FakeQuantizeCacheTest,
::testing::Combine(
::testing::ValuesIn(inputShapes_5D),
specificParams,
::testing::ValuesIn(inputRanges),
::testing::ValuesIn(filterCPUSpecificParams(cpuParams_5D)),
::testing::Values(disableSnippets)),
FakeQuantizeCacheTest::getTestCaseName);
} // namespace
} // namespace CPUSubgraphTestsDefinitions