mkldnn_quantizer_tester.cc 12.0 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
// Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
//
// 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 <gtest/gtest.h>
16

17 18
#include "paddle/fluid/framework/tensor.h"
#include "paddle/fluid/inference/api/analysis_predictor.h"
19
#include "paddle/fluid/inference/api/mkldnn_quantizer.h"
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
#include "paddle/fluid/inference/api/paddle_inference_api.h"

DEFINE_string(dirname, "", "dirname to tests.");

namespace paddle {

class MkldnnQuantizerTest : public testing::Test {
 public:
  MkldnnQuantizerTest() {
    AnalysisConfig config(FLAGS_dirname);
    predictor = std::move(CreatePaddlePredictor(config));
    auto* predictor_p = static_cast<AnalysisPredictor*>(predictor.get());

    auto qconfig = new MkldnnQuantizerConfig();

    mkldnn_quantizer.reset(
        new AnalysisPredictor::MkldnnQuantizer(*predictor_p, qconfig));
  }

  std::pair<std::vector<int>, float> Histogram(
40
      const phi::DenseTensor& var_tensor,
41 42
      float min_val,
      float max_val,
43 44 45 46
      int num_bins) const {
    return mkldnn_quantizer->Histogram(var_tensor, min_val, max_val, num_bins);
  }

47 48
  std::pair<bool, phi::DenseTensor> GetMaxScalingFactor(
      const phi::DenseTensor& var_tensor, bool is_unsigned) const {
49 50 51
    return mkldnn_quantizer->GetMaxScalingFactor(var_tensor, is_unsigned);
  }

52 53
  std::pair<bool, phi::DenseTensor> GetMaxChScalingFactor(
      const phi::DenseTensor& var_tensor, bool is_unsigned) const {
54 55 56
    return mkldnn_quantizer->GetMaxChScalingFactor(var_tensor, is_unsigned, 0);
  }

57 58
  std::pair<bool, phi::DenseTensor> GetKLScalingFactor(
      const phi::DenseTensor& var_tensor, bool is_unsigned) const {
59 60 61
    return mkldnn_quantizer->GetKLScalingFactor(var_tensor, is_unsigned);
  }

62 63 64
  std::pair<bool, phi::DenseTensor> GetMaxChGRUScalingFactor(
      const phi::DenseTensor& wx_tensor,
      const phi::DenseTensor& wh_tensor) const {
65 66 67
    return mkldnn_quantizer->GetMaxChGRUScalingFactor(wx_tensor, wh_tensor);
  }

68 69 70
  std::pair<bool, phi::DenseTensor> GetMaxChLSTMScalingFactor(
      const phi::DenseTensor& wx_tensor,
      const phi::DenseTensor& wh_tensor) const {
71 72 73
    return mkldnn_quantizer->GetMaxChLSTMScalingFactor(wx_tensor, wh_tensor);
  }

74 75 76 77 78 79 80 81 82
 protected:
  std::unique_ptr<PaddlePredictor> predictor;
  std::unique_ptr<AnalysisPredictor::MkldnnQuantizer> mkldnn_quantizer;
  float abs_error = 1e-6;
  static const std::array<float, 10> non_negative_values;
  static const std::array<float, 10> positive_and_negative_values;
};

const std::array<float, 10> MkldnnQuantizerTest::non_negative_values = {
83 84 85 86 87 88 89 90 91 92
    0.0158671,
    0.026459,
    0.0280772,
    0.00962479,
    0.0131628,
    0.016704,
    0.00118407,
    0.00765726,
    0.0123213,
    0.00944741};
93
const std::array<float, 10> MkldnnQuantizerTest::positive_and_negative_values =
94 95 96 97 98 99 100 101 102 103
    {-0.0482659,
     -0.0102493,
     -0.00794221,
     -0.00387115,
     -0.00674586,
     -0.0495346,
     0.0629528,
     -0.00531285,
     -0.0230353,
     0.0269089};
104 105 106 107 108 109

TEST_F(MkldnnQuantizerTest, histogram_inverted_min_max) {
  const auto& values = non_negative_values;
  auto min_val = *std::min_element(values.begin(), values.end());
  auto max_val = *std::max_element(values.begin(), values.end());

110
  phi::DenseTensor var_tensor;
111
  var_tensor.Resize(phi::make_dim(values.size()));
112 113
  std::copy(begin(values),
            end(values),
114
            var_tensor.mutable_data<float>(phi::CPUPlace()));
115 116 117 118 119 120 121 122 123 124 125

  ASSERT_THROW(Histogram(var_tensor, max_val, min_val, 3),
               platform::EnforceNotMet);
}

TEST_F(MkldnnQuantizerTest, histogram_non_negative_to_3) {
  // all non-negative values
  const auto& values = non_negative_values;
  auto min_val = *std::min_element(values.begin(), values.end());
  auto max_val = *std::max_element(values.begin(), values.end());

126
  phi::DenseTensor var_tensor;
127
  var_tensor.Resize(phi::make_dim(values.size()));
128 129
  std::copy(begin(values),
            end(values),
130
            var_tensor.mutable_data<float>(phi::CPUPlace()));
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149

  std::vector<int> histogram;
  float bin_width;

  std::tie(histogram, bin_width) = Histogram(var_tensor, min_val, max_val, 3);

  ASSERT_NEAR(bin_width, std::abs(max_val - min_val) / 3.f, abs_error)
      << "Improperly calculated bin_width.";

  ASSERT_EQ(histogram[0], 4);
  ASSERT_EQ(histogram[1], 4);
  ASSERT_EQ(histogram[2], 2);
}

TEST_F(MkldnnQuantizerTest, histogram_positive_and_negative_to_3) {
  const auto& values = positive_and_negative_values;
  auto min_val = *std::min_element(values.begin(), values.end());
  auto max_val = *std::max_element(values.begin(), values.end());

150
  phi::DenseTensor var_tensor;
151
  var_tensor.Resize(phi::make_dim(values.size()));
152 153
  std::copy(begin(values),
            end(values),
154
            var_tensor.mutable_data<float>(phi::CPUPlace()));
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173

  std::vector<int> histogram;
  float bin_width;

  std::tie(histogram, bin_width) = Histogram(var_tensor, min_val, max_val, 3);

  ASSERT_NEAR(bin_width, std::abs(max_val - min_val) / 3.0f, abs_error)
      << "Improperly calculated bin_width.";

  ASSERT_EQ(histogram[0], 3);
  ASSERT_EQ(histogram[1], 5);
  ASSERT_EQ(histogram[2], 2);
}

TEST_F(MkldnnQuantizerTest, histogram_zero_bins) {
  const auto& values = non_negative_values;
  auto min_val = *std::min_element(values.begin(), values.end());
  auto max_val = *std::max_element(values.begin(), values.end());

174
  phi::DenseTensor var_tensor;
175
  var_tensor.Resize(phi::make_dim(values.size()));
176 177
  std::copy(begin(values),
            end(values),
178
            var_tensor.mutable_data<float>(phi::CPUPlace()));
179 180 181 182 183 184 185 186 187 188

  ASSERT_THROW(Histogram(var_tensor, min_val, max_val, 0),
               platform::EnforceNotMet);
}

TEST_F(MkldnnQuantizerTest, histogram_empty) {
  // empty tensor
  ASSERT_THROW(Histogram({}, -1, 1, 1), platform::EnforceNotMet);

  // zero tensor
189
  phi::DenseTensor var_tensor;
190
  var_tensor.Resize({0});
191
  var_tensor.mutable_data<double>(phi::CPUPlace());
192 193 194 195 196 197 198

  ASSERT_THROW(Histogram(var_tensor, -1, 1, 1), platform::EnforceNotMet);
}

TEST_F(MkldnnQuantizerTest, kl_scaling_factor_signed) {
  const auto& values = positive_and_negative_values;

199
  phi::DenseTensor var_tensor;
200
  var_tensor.Resize(phi::make_dim(values.size()));
201 202
  std::copy(begin(values),
            end(values),
203
            var_tensor.mutable_data<float>(phi::CPUPlace()));
204 205

  bool is_unsigned;
206
  phi::DenseTensor lod_tensor;
207 208 209 210 211 212 213 214 215 216 217 218

  std::tie(is_unsigned, lod_tensor) = GetKLScalingFactor(var_tensor, false);

  ASSERT_EQ(is_unsigned, false);
  ASSERT_EQ(lod_tensor.numel(), 1);
  ASSERT_NEAR(lod_tensor.data<double>()[0], 1.0 / 0.0899106152344, abs_error);
}

TEST_F(MkldnnQuantizerTest, max_scaling_factor_signed) {
  const auto& values = positive_and_negative_values;
  auto max_val = *std::max_element(values.begin(), values.end());

219
  phi::DenseTensor var_tensor;
220
  var_tensor.Resize(phi::make_dim(values.size()));
221 222
  std::copy(begin(values),
            end(values),
223
            var_tensor.mutable_data<float>(phi::CPUPlace()));
224 225

  bool is_unsigned;
226
  phi::DenseTensor lod_tensor;
227 228 229 230 231 232 233 234 235 236 237 238

  std::tie(is_unsigned, lod_tensor) = GetMaxScalingFactor(var_tensor, false);

  ASSERT_EQ(is_unsigned, false);
  ASSERT_EQ(lod_tensor.numel(), 1);
  ASSERT_NEAR(lod_tensor.data<double>()[0], 1.0 / max_val, abs_error);
}

TEST_F(MkldnnQuantizerTest, max_scaling_factor_unsigned) {
  const auto& values = non_negative_values;
  auto max_val = *std::max_element(values.begin(), values.end());

239
  phi::DenseTensor var_tensor;
240
  var_tensor.Resize(phi::make_dim(values.size()));
241 242
  std::copy(begin(values),
            end(values),
243
            var_tensor.mutable_data<float>(phi::CPUPlace()));
244 245

  bool is_unsigned;
246
  phi::DenseTensor lod_tensor;
247 248 249 250 251 252 253 254 255 256 257 258 259

  std::tie(is_unsigned, lod_tensor) = GetMaxScalingFactor(var_tensor, true);

  ASSERT_EQ(is_unsigned, true);
  ASSERT_EQ(lod_tensor.numel(), 1);
  ASSERT_NEAR(lod_tensor.data<double>()[0], 1.0 / max_val, abs_error);
}

TEST_F(MkldnnQuantizerTest, max_scaling_factor_chwise_unsigned) {
  const auto& values = non_negative_values;
  auto max_val = *std::max_element(values.begin(), values.end());
  int channels = 3;

260
  phi::DenseTensor var_tensor;
261
  var_tensor.Resize(phi::make_dim(channels, 1, 1, values.size()));
262
  for (int i = 0; i < channels; i++)
263 264 265 266
    std::copy(
        begin(values),
        end(values),
        var_tensor.mutable_data<float>(phi::CPUPlace()) + i * values.size());
267 268

  bool is_unsigned;
269
  phi::DenseTensor lod_tensor;
270 271 272 273 274 275 276 277 278 279 280 281 282

  std::tie(is_unsigned, lod_tensor) = GetMaxChScalingFactor(var_tensor, true);

  ASSERT_EQ(is_unsigned, true);
  ASSERT_EQ(lod_tensor.numel(), channels);
  for (int i = 0; i < channels; i++) {
    ASSERT_NEAR(lod_tensor.data<double>()[i], 1.0 / max_val, abs_error);
  }
}

TEST_F(MkldnnQuantizerTest, kl_scaling_factor_unsigned) {
  const auto& values = non_negative_values;

283
  phi::DenseTensor var_tensor;
284
  var_tensor.Resize(phi::make_dim(values.size()));
285 286
  std::copy(begin(values),
            end(values),
287
            var_tensor.mutable_data<float>(phi::CPUPlace()));
288 289

  bool is_unsigned;
290
  phi::DenseTensor lod_tensor;
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307

  std::tie(is_unsigned, lod_tensor) = GetKLScalingFactor(var_tensor, true);

  ASSERT_EQ(is_unsigned, true);
  ASSERT_EQ(lod_tensor.numel(), 1);
  ASSERT_NEAR(lod_tensor.data<double>()[0], 1.0 / 0.0252845321362, abs_error);
}

const std::vector<std::vector<float>> wx = {
    {0.04347931, -0.5643393, 0.7551297, 0.26713502, 0.8055306, 0.91144973},
    {0.01707571, 0.12741385, 0.15419468, 0.66127586, 0.46821925, 0.9665961},
    {0.40393898, 0.884427, -0.5853097, 0.5840954, 0.9170512, 0.98245513}};
const std::vector<std::vector<float>> wh = {
    {0.42484227, -0.9025513, 0.17087583, 0.8403284, 0.03325734, 0.92331886},
    {0.32630175, 0.41691914, 0.99848574, 0.3504407, 0.06707559, 0.62239844}};

TEST_F(MkldnnQuantizerTest, max_ch_gru_scaling_factor) {
308
  phi::DenseTensor wx_tensor, wh_tensor, lod_tensor;
309

310
  wx_tensor.Resize(phi::make_dim(wx.size(), wx[0].size()));
311 312
  for (size_t i = 0; i < wx.size(); i++)
    std::copy(
313 314
        begin(wx[i]),
        end(wx[i]),
315
        wx_tensor.mutable_data<float>(phi::CPUPlace()) + i * wx[0].size());
316

317
  wh_tensor.Resize(phi::make_dim(wh.size(), wh[0].size()));
318 319
  for (size_t i = 0; i < wh.size(); i++)
    std::copy(
320 321
        begin(wh[i]),
        end(wh[i]),
322
        wh_tensor.mutable_data<float>(phi::CPUPlace()) + i * wh[0].size());
323 324 325 326 327

  bool is_unsigned;
  std::tie(is_unsigned, lod_tensor) =
      GetMaxChGRUScalingFactor(wx_tensor, wh_tensor);

328 329
  std::vector<double> scales = {
      2.35381475, 1.08304947, 1.32427582, 1.19001095, 1.00151656, 1.01785819};
330 331 332 333 334 335
  ASSERT_EQ(is_unsigned, false);
  ASSERT_EQ(lod_tensor.numel(), static_cast<int64_t>(scales.size()));
  for (int64_t i = 0; i < lod_tensor.numel(); i++) {
    ASSERT_NEAR(lod_tensor.data<double>()[i], scales[i], abs_error);
  }
}
336 337

TEST_F(MkldnnQuantizerTest, max_ch_lstm_scaling_factor) {
338
  phi::DenseTensor wx_tensor, wh_tensor, lod_tensor;
339

340
  wx_tensor.Resize(phi::make_dim(wx.size(), wx[0].size()));
341 342
  for (size_t i = 0; i < wx.size(); i++)
    std::copy(
343 344
        begin(wx[i]),
        end(wx[i]),
345
        wx_tensor.mutable_data<float>(phi::CPUPlace()) + i * wx[0].size());
346

347
  wh_tensor.Resize(phi::make_dim(wh.size(), wh[0].size()));
348 349
  for (size_t i = 0; i < wh.size(); i++)
    std::copy(
350 351
        begin(wh[i]),
        end(wh[i]),
352
        wh_tensor.mutable_data<float>(phi::CPUPlace()) + i * wh[0].size());
353 354 355 356 357

  bool is_unsigned;
  std::tie(is_unsigned, lod_tensor) =
      GetMaxChLSTMScalingFactor(wx_tensor, wh_tensor);

358 359
  std::vector<double> scales = {
      2.35381475, 1.10797026, 1.00151656, 1.19001095, 1.09045166, 1.01785819};
360 361 362 363 364 365 366
  ASSERT_EQ(is_unsigned, false);
  ASSERT_EQ(lod_tensor.numel(), static_cast<int64_t>(scales.size()));
  for (int64_t i = 0; i < lod_tensor.numel(); i++) {
    ASSERT_NEAR(lod_tensor.data<double>()[i], scales[i], abs_error);
  }
}

367
}  // namespace paddle