1 /* Copyright 2021 The TensorFlow Authors. All Rights Reserved.
2 
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6 
7     http://www.apache.org/licenses/LICENSE-2.0
8 
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15 
16 #include <memory>
17 #include <vector>
18 
19 #include "tensorflow/lite/delegates/gpu/common/operations.h"
20 #include "tensorflow/lite/delegates/gpu/common/status.h"
21 #include "tensorflow/lite/delegates/gpu/common/task/testing_util.h"
22 #include "tensorflow/lite/delegates/gpu/common/tasks/quantize_and_dequantize.h"
23 #include "tensorflow/lite/kernels/internal/quantization_util.h"
24 
25 namespace tflite {
26 namespace gpu {
27 
QuantAndDequant_Dim2Bits8Test(TestExecutionEnvironment * env)28 absl::Status QuantAndDequant_Dim2Bits8Test(TestExecutionEnvironment* env) {
29   TensorFloat32 src_tensor;
30   src_tensor.shape = BHWC(1, 3, 2, 1);
31   src_tensor.data = {0.0f, 1.0f, 0.25f, 0.50f, 0.4444444f, 0.00001f};
32 
33   // Unlike TFLite's FakeQuant kernel, we assume that the incoming values are
34   // pre-nudged, since this should be done during model conversion.
35   const int num_bits = 8;
36   const int quant_min = 0;
37   const int quant_max = (1 << num_bits) - 1;
38   QuantizeAndDequantizeAttributes attr;
39   NudgeQuantizationRange(/**original_min**/ 0.0, /**original_max**/ 1.0,
40                          quant_min, quant_max, &attr.min, &attr.max,
41                          &attr.scale);
42 
43   for (auto precision : env->GetSupportedPrecisions()) {
44     auto data_type = DeduceDataTypeFromPrecision(precision);
45     for (auto storage : env->GetSupportedStorages(data_type)) {
46       const float eps = precision == CalculationsPrecision::F32 ? 1e-6f : 1e-2f;
47       OperationDef op_def;
48       op_def.precision = precision;
49       op_def.src_tensors.push_back({data_type, storage, Layout::HWC});
50       op_def.dst_tensors.push_back({data_type, storage, Layout::HWC});
51       TensorFloat32 dst_tensor;
52       GPUOperation operation = CreateQuantizeAndDequantize(op_def, attr);
53       RETURN_IF_ERROR(env->ExecuteGPUOperation(
54           src_tensor, std::make_unique<GPUOperation>(std::move(operation)),
55           BHWC(1, 3, 2, 1), &dst_tensor));
56       RETURN_IF_ERROR(
57           PointWiseNear({0.0f, 1.0f, 0.25098f, 0.498039f, 0.443137f, 0.0f},
58                         dst_tensor.data, eps));
59     }
60   }
61   return absl::OkStatus();
62 }
63 
QuantAndDequant_Dim3Bits8_NegativeRangeTest(TestExecutionEnvironment * env)64 absl::Status QuantAndDequant_Dim3Bits8_NegativeRangeTest(
65     TestExecutionEnvironment* env) {
66   TensorFloat32 src_tensor;
67   src_tensor.shape = BHWC(1, 3, 1, 2);
68   src_tensor.data = {0.0f, -0.9f, 0.25f, 0.50f, 0.4444444f, -0.00001f};
69 
70   // Unlike TFLite's FakeQuant kernel, we assume that the incoming values are
71   // pre-nudged, since this should be done during model conversion.
72   const int num_bits = 8;
73   const int quant_min = 0;
74   const int quant_max = (1 << num_bits) - 1;
75   QuantizeAndDequantizeAttributes attr;
76   NudgeQuantizationRange(/**original_min**/ -0.9, /**original_max**/ 0.9,
77                          quant_min, quant_max, &attr.min, &attr.max,
78                          &attr.scale);
79 
80   for (auto precision : env->GetSupportedPrecisions()) {
81     auto data_type = DeduceDataTypeFromPrecision(precision);
82     for (auto storage : env->GetSupportedStorages(data_type)) {
83       const float eps = precision == CalculationsPrecision::F32 ? 1e-6f : 1e-2f;
84       OperationDef op_def;
85       op_def.precision = precision;
86       op_def.src_tensors.push_back({data_type, storage, Layout::HWC});
87       op_def.dst_tensors.push_back({data_type, storage, Layout::HWC});
88       TensorFloat32 dst_tensor;
89       GPUOperation operation = CreateQuantizeAndDequantize(op_def, attr);
90       RETURN_IF_ERROR(env->ExecuteGPUOperation(
91           src_tensor, std::make_unique<GPUOperation>(std::move(operation)),
92           BHWC(1, 3, 1, 2), &dst_tensor));
93       RETURN_IF_ERROR(PointWiseNear(
94           {0.0f, -0.896471f, 0.247059f, 0.501176f, 0.444706f, 0.0f},
95           dst_tensor.data, eps));
96     }
97   }
98   return absl::OkStatus();
99 }
100 
QuantAndDequant_Dim3Bits16Test(TestExecutionEnvironment * env)101 absl::Status QuantAndDequant_Dim3Bits16Test(TestExecutionEnvironment* env) {
102   TensorFloat32 src_tensor;
103   src_tensor.shape = BHWC(1, 3, 1, 2);
104   src_tensor.data = {0.0f, 1.0f, 0.25f, 0.50f, 0.4444444f, 0.00001f};
105 
106   // Unlike TFLite's FakeQuant kernel, we assume that the incoming values are
107   // pre-nudged, since this should be done during model conversion.
108   const int num_bits = 16;
109   const int quant_min = 0;
110   const int quant_max = (1 << num_bits) - 1;
111   QuantizeAndDequantizeAttributes attr;
112   NudgeQuantizationRange(/**original_min**/ 0.0, /**original_max**/ 1.0,
113                          quant_min, quant_max, &attr.min, &attr.max,
114                          &attr.scale);
115 
116   for (auto precision : env->GetSupportedPrecisions()) {
117     auto data_type = DeduceDataTypeFromPrecision(precision);
118     for (auto storage : env->GetSupportedStorages(data_type)) {
119       const float eps = precision == CalculationsPrecision::F32 ? 1e-6f : 1e-3f;
120       OperationDef op_def;
121       op_def.precision = precision;
122       op_def.src_tensors.push_back({data_type, storage, Layout::HWC});
123       op_def.dst_tensors.push_back({data_type, storage, Layout::HWC});
124       TensorFloat32 dst_tensor;
125       GPUOperation operation = CreateQuantizeAndDequantize(op_def, attr);
126       RETURN_IF_ERROR(env->ExecuteGPUOperation(
127           src_tensor, std::make_unique<GPUOperation>(std::move(operation)),
128           BHWC(1, 3, 1, 2), &dst_tensor));
129       RETURN_IF_ERROR(PointWiseNear(
130           {0.0f, 1.0f, 0.250004f, 0.500008f, 0.44445f, 1.5259e-05f},
131           dst_tensor.data, eps));
132     }
133   }
134   return absl::OkStatus();
135 }
136 
QuantAndDequant_Dim2Bits16_NegativeRangeTest(TestExecutionEnvironment * env)137 absl::Status QuantAndDequant_Dim2Bits16_NegativeRangeTest(
138     TestExecutionEnvironment* env) {
139   TensorFloat32 src_tensor;
140   src_tensor.shape = BHWC(1, 3, 2, 1);
141   src_tensor.data = {0.0f, -0.9f, 0.25f, 0.50f, 0.4444444f, -0.00001f};
142 
143   // Unlike TFLite's FakeQuant kernel, we assume that the incoming values are
144   // pre-nudged, since this should be done during model conversion.
145   const int num_bits = 16;
146   const int quant_min = 0;
147   const int quant_max = (1 << num_bits) - 1;
148   QuantizeAndDequantizeAttributes attr;
149   NudgeQuantizationRange(/**original_min**/ -0.9, /**original_max**/ 0.9,
150                          quant_min, quant_max, &attr.min, &attr.max,
151                          &attr.scale);
152 
153   for (auto precision : env->GetSupportedPrecisions()) {
154     auto data_type = DeduceDataTypeFromPrecision(precision);
155     for (auto storage : env->GetSupportedStorages(data_type)) {
156       const float eps = precision == CalculationsPrecision::F32 ? 1e-6f : 1e-2f;
157       OperationDef op_def;
158       op_def.precision = precision;
159       op_def.src_tensors.push_back({data_type, storage, Layout::HWC});
160       op_def.dst_tensors.push_back({data_type, storage, Layout::HWC});
161       TensorFloat32 dst_tensor;
162       GPUOperation operation = CreateQuantizeAndDequantize(op_def, attr);
163       RETURN_IF_ERROR(env->ExecuteGPUOperation(
164           src_tensor, std::make_unique<GPUOperation>(std::move(operation)),
165           BHWC(1, 3, 2, 1), &dst_tensor));
166       RETURN_IF_ERROR(PointWiseNear(
167           {0.0f, -0.900014f, 0.249998f, 0.499995f, 0.444431f, 0.0f},
168           dst_tensor.data, eps));
169     }
170   }
171   return absl::OkStatus();
172 }
173 
174 }  // namespace gpu
175 }  // namespace tflite
176