172 lines
5.4 KiB
C++
172 lines
5.4 KiB
C++
/*
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
* All rights reserved.
|
|
*
|
|
* This source code is licensed under the BSD-style license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
|
|
#include <algorithm>
|
|
#include <functional>
|
|
#include <iostream>
|
|
#include <random>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
#include "./TestUtils.h"
|
|
#include "bench/BenchUtils.h"
|
|
#include "fbgemm/Fbgemm.h"
|
|
|
|
using namespace std;
|
|
using namespace fbgemm;
|
|
|
|
vector<QuantizationGranularity> qGranularityVals{
|
|
QuantizationGranularity::TENSOR,
|
|
QuantizationGranularity::OUT_CHANNEL};
|
|
|
|
namespace {
|
|
|
|
// tuple represents #rows, #cols, fuse_relu, quantization_granularity, bias_type
|
|
class FloatRequantizeTest
|
|
: public testing::TestWithParam<
|
|
tuple<int, int, bool, QuantizationGranularity>> {};
|
|
|
|
}; // namespace
|
|
|
|
INSTANTIATE_TEST_CASE_P(
|
|
InstantiationName,
|
|
FloatRequantizeTest,
|
|
::testing::Combine(
|
|
::testing::ValuesIn({1, 2, 3, 4}), // number of rows
|
|
::testing::ValuesIn(
|
|
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 16, 20, 32}), // number of
|
|
// cols
|
|
::testing::Bool(), // fuse relu
|
|
::testing::ValuesIn(qGranularityVals))); // requantization granularity
|
|
|
|
/**
|
|
* Test for float bias
|
|
*/
|
|
TEST_P(FloatRequantizeTest, floatBiasTest) {
|
|
int rows, cols;
|
|
bool fuse_relu;
|
|
QuantizationGranularity q_gran;
|
|
tie(rows, cols, fuse_relu, q_gran) = GetParam();
|
|
|
|
int numElements = rows * cols;
|
|
|
|
aligned_vector<float> act_times_w_scale(cols);
|
|
randFill<float>(act_times_w_scale, -8, 8);
|
|
|
|
float out_scale = 2.0f;
|
|
|
|
aligned_vector<float> C_multiplier(cols);
|
|
transform(
|
|
act_times_w_scale.begin(),
|
|
act_times_w_scale.end(),
|
|
C_multiplier.begin(),
|
|
[&out_scale](float i) { return i / out_scale; });
|
|
|
|
aligned_vector<int32_t> Bint8_zero_point(cols);
|
|
randFill<int32_t>(Bint8_zero_point, -8, 8);
|
|
|
|
aligned_vector<int32_t> row_offset_buf(rows);
|
|
randFill<int32_t>(row_offset_buf, -8, 8);
|
|
|
|
aligned_vector<int32_t> col_offsets(cols);
|
|
randFill<int32_t>(col_offsets, -8, 8);
|
|
|
|
// quantized bias
|
|
aligned_vector<int32_t> bias_q(cols);
|
|
randFill<int32_t>(bias_q, -8, 8);
|
|
|
|
// floating point bias
|
|
aligned_vector<float> bias_f(cols);
|
|
if (q_gran == QuantizationGranularity::TENSOR) {
|
|
transform(
|
|
bias_q.begin(),
|
|
bias_q.end(),
|
|
bias_f.begin(),
|
|
[&act_times_w_scale](float i) { return i * act_times_w_scale[0]; });
|
|
} else if (q_gran == QuantizationGranularity::OUT_CHANNEL) {
|
|
transform(
|
|
act_times_w_scale.begin(),
|
|
act_times_w_scale.end(),
|
|
bias_q.begin(),
|
|
bias_f.begin(),
|
|
multiplies<float>());
|
|
|
|
} else {
|
|
FAIL();
|
|
}
|
|
|
|
aligned_vector<int32_t> input(numElements);
|
|
randFill<int32_t>(input, -8, 8);
|
|
|
|
aligned_vector<uint8_t> output_q_bias(numElements);
|
|
aligned_vector<uint8_t> output_f_bias(numElements);
|
|
|
|
int32_t C_zero_point = 3;
|
|
int32_t Aint8_zero_point = 3;
|
|
|
|
block_type_t block{0, rows, 0, cols};
|
|
|
|
DoNothing<> doNothingObj{};
|
|
|
|
#define TESTCODE(FUSE_RELU, Q_GRAN) \
|
|
ReQuantizeOutput<FUSE_RELU, Q_GRAN> reqObj_q( \
|
|
doNothingObj, \
|
|
C_multiplier.data(), \
|
|
C_zero_point, \
|
|
Aint8_zero_point, \
|
|
Bint8_zero_point.data(), \
|
|
row_offset_buf.data(), \
|
|
col_offsets.data(), \
|
|
bias_q.data(), \
|
|
cols); \
|
|
ReQuantizeOutput<FUSE_RELU, Q_GRAN, float> reqObj_f( \
|
|
doNothingObj, \
|
|
C_multiplier.data(), \
|
|
C_zero_point, \
|
|
Aint8_zero_point, \
|
|
Bint8_zero_point.data(), \
|
|
row_offset_buf.data(), \
|
|
col_offsets.data(), \
|
|
bias_f.data(), \
|
|
cols, \
|
|
1, \
|
|
act_times_w_scale.data()); \
|
|
reqObj_q.f<inst_set_t::avx2>( \
|
|
output_q_bias.data(), input.data(), block, cols, cols); \
|
|
reqObj_f.f<inst_set_t::avx2>( \
|
|
output_f_bias.data(), input.data(), block, cols, cols);
|
|
|
|
if (fuse_relu) {
|
|
if (q_gran == QuantizationGranularity::TENSOR) {
|
|
TESTCODE(true, QuantizationGranularity::TENSOR)
|
|
|
|
} else if (q_gran == QuantizationGranularity::OUT_CHANNEL) {
|
|
TESTCODE(true, QuantizationGranularity::OUT_CHANNEL)
|
|
|
|
} else {
|
|
FAIL();
|
|
}
|
|
|
|
} else {
|
|
if (q_gran == QuantizationGranularity::TENSOR) {
|
|
TESTCODE(false, QuantizationGranularity::TENSOR)
|
|
|
|
} else if (q_gran == QuantizationGranularity::OUT_CHANNEL) {
|
|
TESTCODE(false, QuantizationGranularity::OUT_CHANNEL)
|
|
|
|
} else {
|
|
FAIL();
|
|
}
|
|
}
|
|
#undef TESTCODE
|
|
ASSERT_EQ(output_q_bias, output_f_bias)
|
|
<< "Requantization with quantized bias and float bias differs";
|
|
}
|