1122cdce33e3e0a01a7f82645617317530aa571fbA. Unique TensorFlower/* Copyright 2015 The TensorFlow Authors. All Rights Reserved.
2ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden
3ca4e053aa52ab9a42467d4df814ca9272487dbdfPete WardenLicensed under the Apache License, Version 2.0 (the "License");
4ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Wardenyou may not use this file except in compliance with the License.
5ca4e053aa52ab9a42467d4df814ca9272487dbdfPete WardenYou may obtain a copy of the License at
6ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden
7ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden    http://www.apache.org/licenses/LICENSE-2.0
8ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden
9ca4e053aa52ab9a42467d4df814ca9272487dbdfPete WardenUnless required by applicable law or agreed to in writing, software
10ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Wardendistributed under the License is distributed on an "AS IS" BASIS,
11ca4e053aa52ab9a42467d4df814ca9272487dbdfPete WardenWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12ca4e053aa52ab9a42467d4df814ca9272487dbdfPete WardenSee the License for the specific language governing permissions and
13ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Wardenlimitations under the License.
14ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden==============================================================================*/
15ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden
1641997756c73532666d8531ba760b313c9f3e076fA. Unique TensorFlower#define EIGEN_USE_THREADS
1741997756c73532666d8531ba760b313c9f3e076fA. Unique TensorFlower
18ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden#include <functional>
19ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden
20ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden#include "tensorflow/core/framework/allocator.h"
21ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden#include "tensorflow/core/framework/fake_input.h"
22ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden#include "tensorflow/core/framework/node_def_builder.h"
23ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden#include "tensorflow/core/framework/op_kernel.h"
24ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden#include "tensorflow/core/framework/tensor.h"
25ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden#include "tensorflow/core/framework/tensor_testutil.h"
26ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden#include "tensorflow/core/framework/types.h"
27ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden#include "tensorflow/core/framework/types.pb.h"
28ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden#include "tensorflow/core/kernels/ops_testutil.h"
29ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden#include "tensorflow/core/kernels/ops_util.h"
3041997756c73532666d8531ba760b313c9f3e076fA. Unique TensorFlower#include "tensorflow/core/kernels/quantization_utils.h"
31ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden#include "tensorflow/core/lib/core/status_test_util.h"
32ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden#include "tensorflow/core/platform/test.h"
33ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden
34ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Wardennamespace tensorflow {
35ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden
36ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Wardenclass QuantizedBiasAddTest : public OpsTestBase {
37ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden protected:
38ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden};
39ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden
40ca4e053aa52ab9a42467d4df814ca9272487dbdfPete WardenTEST_F(QuantizedBiasAddTest, Small) {
41ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  TF_ASSERT_OK(NodeDefBuilder("quantized_bias_add_op", "QuantizedBiasAdd")
42ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden                   .Input(FakeInput(DT_QUINT8))
43ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden                   .Input(FakeInput(DT_QUINT8))
44ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden                   .Input(FakeInput(DT_FLOAT))
45ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden                   .Input(FakeInput(DT_FLOAT))
46ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden                   .Input(FakeInput(DT_FLOAT))
47ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden                   .Input(FakeInput(DT_FLOAT))
48ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden                   .Attr("out_type", DataTypeToEnum<qint32>::v())
49ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden                   .Finalize(node_def()));
50ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  TF_ASSERT_OK(InitOp());
51ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  const float input_min = 0.0f;
52ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  const float input_max = 60.0f;
53ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  const int input_height = 2;
54ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  const int input_width = 3;
55ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  Tensor input_float(DT_FLOAT, {input_height, input_width});
56ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  test::FillValues<float>(&input_float,
57ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden                          {10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f});
58ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  Tensor input_quantized =
59ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden      FloatTensorToQuantized<quint8>(input_float, input_min, input_max);
60ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden
61ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  const float bias_min = 0.0f;
62ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  const float bias_max = 3.0f;
63ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  const int bias_width = 3;
64ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  Tensor bias_float(DT_FLOAT, {bias_width});
65ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  test::FillValues<float>(&bias_float, {1.0f, 2.0f, 3.0f});
66ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  Tensor bias_quantized =
67ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden      FloatTensorToQuantized<quint8>(bias_float, bias_min, bias_max);
68ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden
69ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  Tensor expected_float(DT_FLOAT, {input_height, input_width});
70ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  test::FillValues<float>(&expected_float,
71ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden                          {11.0f, 22.0f, 33.0f, 41.0f, 52.0f, 63.0f});
72ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden
73ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  AddInputFromArray<quint8>(input_quantized.shape(),
74ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden                            input_quantized.flat<quint8>());
75ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  AddInputFromArray<quint8>(bias_quantized.shape(),
76ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden                            bias_quantized.flat<quint8>());
77ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  AddInputFromArray<float>(TensorShape({1}), {input_min});
78ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  AddInputFromArray<float>(TensorShape({1}), {input_max});
79ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  AddInputFromArray<float>(TensorShape({1}), {bias_min});
80ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  AddInputFromArray<float>(TensorShape({1}), {bias_max});
81ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  TF_ASSERT_OK(RunOpKernel());
82ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  const Tensor& output_quantized = *GetOutput(0);
83ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  const float output_min = GetOutput(1)->flat<float>()(0);
84ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  const float output_max = GetOutput(2)->flat<float>()(0);
85ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  Tensor output_float =
86ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden      QuantizedTensorToFloat<qint32>(output_quantized, output_min, output_max);
87ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  test::ExpectTensorNear<float>(expected_float, output_float, 0.2);
88ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden}
89ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden
90ca4e053aa52ab9a42467d4df814ca9272487dbdfPete WardenTEST_F(QuantizedBiasAddTest, RealData) {
91ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  TF_ASSERT_OK(NodeDefBuilder("quantized_bias_add_op", "QuantizedBiasAdd")
92ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden                   .Input(FakeInput(DT_QUINT8))
93ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden                   .Input(FakeInput(DT_QUINT8))
94ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden                   .Input(FakeInput(DT_FLOAT))
95ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden                   .Input(FakeInput(DT_FLOAT))
96ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden                   .Input(FakeInput(DT_FLOAT))
97ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden                   .Input(FakeInput(DT_FLOAT))
98ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden                   .Attr("out_type", DataTypeToEnum<qint32>::v())
99ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden                   .Finalize(node_def()));
100ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  TF_ASSERT_OK(InitOp());
101ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  const float input_min = -2164.25f;
102ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  const float input_max = 2006.27f;
103ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  const int input_height = 1;
104ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  const int input_width = 64;
105ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  Tensor input_float(DT_FLOAT, {input_height, input_width});
106ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  test::FillValues<float>(
107ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden      &input_float,
108ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden      {-1014.12, -157.382, -810.17,  1435.28,  1016.37,  219.684,  -316.054,
109ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden       -2164.25, 2006.27,  -547.444, 857.376,  404.376,  9.72115,  332.588,
110ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden       194.385,  -286.57,  26.062,   23.1125,  110.436,  247.055,  -127.683,
111ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden       -376.275, -124.81,  -846.826, -77.1507, 305.581,  -202.747, 12.9528,
112ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden       9.64886,  872.686,  40.9069,  197.816,  44.16,    -306.768, -1457.52,
113ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden       -368.939, -1049.42, -486.353, 1745.87,  95.7695,  395.773,  -254.333,
114ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden       -404.27,  787.16,   -2.44114, 199.37,   -1024.08, 784.901,  235.055,
115ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden       -42.7295, 241.498,  -245.365, 470.763,  186.159,  186.579,  -220.163,
116ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden       1304.58,  386.272,  -358.853, -755.996, 360.109,  -866.007, 55.2828,
117ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden       -508.801});
118ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  Tensor input_quantized =
119ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden      FloatTensorToQuantized<quint8>(input_float, input_min, input_max);
120ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden
121ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  const float bias_min = -0.739539f;
122ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  const float bias_max = 0.641057f;
123ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  const int bias_width = 64;
124ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  Tensor bias_float(DT_FLOAT, {bias_width});
125ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  test::FillValues<float>(
126ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden      &bias_float,
127ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden      {-0.294619, -0.0670519, 0.261507,   -0.126274, 0.127229,   -0.176945,
128ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden       -0.251223, 0.231086,   0.453694,   0.415666,  -0.288733,  0.508717,
129ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden       0.211551,  0.0435907,  -0.582383,  -0.308779, 0.0696883,  -0.438122,
130ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden       0.114,     0.433964,   0.109883,   0.284931,  -0.149661,  0.108657,
131ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden       0.458333,  -0.130231,  -0.35805,   -0.123206, -0.437968,  0.0282411,
132ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden       0.628818,  -0.0522173, -0.0233403, 0.124863,  0.217165,   0.262294,
133ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden       -0.171005, -0.254693,  -0.200433,  -0.287354, 0.488166,   -0.0354688,
134ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden       -0.118091, -0.590444,  0.491537,   -0.739539, 0.083117,   0.282482,
135ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden       0.275269,  -0.36574,   0.107476,   0.0511428, -0.136887,  -0.0149852,
136ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden       -0.259694, 0.641057,   0.264054,   -0.295126, -0.0218791, 0.361211,
137ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden       0.012448,  0.0709718,  -0.392394,  -0.434215});
138ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  Tensor bias_quantized =
139ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden      FloatTensorToQuantized<quint8>(bias_float, bias_min, bias_max);
140ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden
141ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  Tensor expected_float(DT_FLOAT, {input_height, input_width});
142ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  test::FillValues<float>(
143ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden      &expected_float,
144ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden      {-1014.42, -157.449, -809.908, 1435.16,  1016.5,  219.507,  -316.305,
145ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden       -2164.02, 2006.73,  -547.028, 857.088,  404.885, 9.9327,   332.632,
146ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden       193.803,  -286.878, 26.1317,  22.6744,  110.55,  247.489,  -127.573,
147ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden       -375.99,  -124.959, -846.717, -76.6923, 305.451, -203.105, 12.8296,
148ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden       9.21089,  872.714,  41.5357,  197.764,  44.1367, -306.643, -1457.3,
149ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden       -368.677, -1049.6,  -486.608, 1745.67,  95.4821, 396.261,  -254.368,
150ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden       -404.388, 786.57,   -1.94961, 198.63,   -1024.0, 785.183,  235.33,
151ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden       -43.0953, 241.605,  -245.314, 470.627,  186.144, 186.319,  -219.522,
152ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden       1304.84,  385.977,  -358.874, -755.635, 360.122, -865.936, 54.8904,
153ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden       -509.235});
154ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden
155ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  AddInputFromArray<quint8>(input_quantized.shape(),
156ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden                            input_quantized.flat<quint8>());
157ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  AddInputFromArray<quint8>(bias_quantized.shape(),
158ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden                            bias_quantized.flat<quint8>());
159ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  AddInputFromArray<float>(TensorShape({1}), {input_min});
160ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  AddInputFromArray<float>(TensorShape({1}), {input_max});
161ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  AddInputFromArray<float>(TensorShape({1}), {bias_min});
162ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  AddInputFromArray<float>(TensorShape({1}), {bias_max});
163ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  TF_ASSERT_OK(RunOpKernel());
164ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  const Tensor& output_quantized = *GetOutput(0);
165ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  const float output_min = GetOutput(1)->flat<float>()(0);
166ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  const float output_max = GetOutput(2)->flat<float>()(0);
167ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  Tensor output_float =
168ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden      QuantizedTensorToFloat<qint32>(output_quantized, output_min, output_max);
169ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden  test::ExpectTensorNear<float>(expected_float, output_float, 20.0);
170ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden}
171ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden
172ca4e053aa52ab9a42467d4df814ca9272487dbdfPete Warden}  // namespace tensorflow
173