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