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 "tensorflow/lite/delegates/gpu/common/tasks/mean_stddev_normalization_test_util.h"
17
18 #include <cmath>
19 #include <memory>
20 #include <vector>
21
22 #include "tensorflow/lite/delegates/gpu/common/operations.h"
23 #include "tensorflow/lite/delegates/gpu/common/status.h"
24 #include "tensorflow/lite/delegates/gpu/common/task/testing_util.h"
25 #include "tensorflow/lite/delegates/gpu/common/tasks/mean_stddev_normalization.h"
26
27 namespace tflite {
28 namespace gpu {
29
30 // Parameterized test: mean, difference, tolerance.
31 // Input is constructed as [mean-2*diff, mean-diff, mean+diff, mean+2*diff]
MeanStddevNormSeparateBatchesTest(float mean,float diff,float tolerance,TestExecutionEnvironment * env)32 absl::Status MeanStddevNormSeparateBatchesTest(float mean, float diff,
33 float tolerance,
34 TestExecutionEnvironment* env) {
35 TensorFloat32 src_tensor;
36 src_tensor.shape = BHWC(1, 1, 2, 4);
37 src_tensor.data = {mean - 2 * diff, mean - diff, mean + diff,
38 mean + 2 * diff, mean - 2 * diff, mean - diff,
39 mean + diff, mean + 2 * diff};
40 for (auto precision : env->GetSupportedPrecisions()) {
41 auto data_type = DeduceDataTypeFromPrecision(precision);
42 for (auto storage : env->GetSupportedStorages(data_type)) {
43 OperationDef op_def;
44 op_def.precision = precision;
45 op_def.src_tensors.push_back({data_type, storage, Layout::HWC});
46 op_def.dst_tensors.push_back({data_type, storage, Layout::HWC});
47 TensorFloat32 dst_tensor;
48 auto operation = CreateMeanStdDevNormalization(op_def, env->GetGpuInfo(),
49 src_tensor.shape);
50 RETURN_IF_ERROR(env->ExecuteGPUOperation(
51 {src_tensor},
52 std::make_unique<MeanStdDevNormalization>(std::move(operation)),
53 BHWC(1, 1, 2, 4), &dst_tensor));
54
55 std::vector<float> expected_output;
56 if (diff == 0.0f) {
57 expected_output.assign(
58 {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f});
59 } else {
60 const float ksqrt16 = std::sqrt(1.6f);
61 const float ksqrt04 = std::sqrt(0.4f);
62 expected_output.assign({-ksqrt16, -ksqrt04, ksqrt04, ksqrt16, -ksqrt16,
63 -ksqrt04, ksqrt04, ksqrt16});
64 }
65 RETURN_IF_ERROR(
66 PointWiseNear(expected_output, dst_tensor.data, tolerance));
67
68 TensorFloat32 dst_tensor_single_step;
69 auto operation_single_step = CreateMeanStdDevNormalization(
70 op_def, env->GetGpuInfo(), src_tensor.shape,
71 /*variance_bias*/ 1.0e-8f, /*two_step*/ false);
72 RETURN_IF_ERROR(
73 env->ExecuteGPUOperation({src_tensor},
74 std::make_unique<MeanStdDevNormalization>(
75 std::move(operation_single_step)),
76 BHWC(1, 1, 2, 4), &dst_tensor_single_step));
77 RETURN_IF_ERROR(PointWiseNear(expected_output,
78 dst_tensor_single_step.data, tolerance));
79 }
80 }
81 return absl::OkStatus();
82 }
83
MeanStddevNormalizationAllBatchesTest(TestExecutionEnvironment * env)84 absl::Status MeanStddevNormalizationAllBatchesTest(
85 TestExecutionEnvironment* env) {
86 TensorFloat32 src_tensor;
87 src_tensor.shape = BHWC(9, 1, 1, 4);
88 src_tensor.data = {
89 0.0f, 0.0f, 0.0f, 0.0f, // zero mean, zero variance
90 -0.02f, -0.01f, 0.01f, 0.02f, // zero mean, small variance
91 -200.0f, -100.0f, 100.0f, 200.0f, // zero mean, large variance
92 0.01f, 0.01f, 0.01f, 0.01f, // small mean, zero variance
93 -0.01f, 0.0f, 0.02f, 0.03f, // small mean, small variance
94 -199.0f, -99.0f, 101.0f, 201.0f, // small mean, large variance
95 100.0f, 100.0f, 100.0f, 100.0f, // large mean, zero variance
96 98.0f, 99.0f, 101.0f, 102.0f, // large mean, small variance
97 -100.0f, 0.0f, 200.0f, 300.0f, // large mean, large variance
98 };
99 for (auto precision : env->GetSupportedPrecisions()) {
100 auto data_type = DeduceDataTypeFromPrecision(precision);
101 for (auto storage : env->GetSupportedStorages(data_type)) {
102 const float eps =
103 precision == CalculationsPrecision::F32 ? 2.53e-05f : 3.57e-4f;
104 OperationDef op_def;
105 op_def.precision = precision;
106 op_def.src_tensors.push_back({data_type, storage, Layout::BHWC});
107 op_def.dst_tensors.push_back({data_type, storage, Layout::BHWC});
108 TensorFloat32 dst_tensor;
109 auto operation = CreateMeanStdDevNormalization(op_def, env->GetGpuInfo(),
110 src_tensor.shape);
111 RETURN_IF_ERROR(env->ExecuteGPUOperation(
112 {src_tensor},
113 std::make_unique<MeanStdDevNormalization>(std::move(operation)),
114 BHWC(9, 1, 1, 4), &dst_tensor));
115
116 const float ksqrt16 = std::sqrt(1.6f);
117 const float ksqrt04 = std::sqrt(0.4f);
118 const std::vector<float> expected_output = {
119 0.0f, 0.0f, 0.0f, 0.0f, // zero mean, zero variance
120 -ksqrt16, -ksqrt04, ksqrt04, ksqrt16, // zero mean, small variance
121 -ksqrt16, -ksqrt04, ksqrt04, ksqrt16, // zero mean, large variance
122 0.0f, 0.0f, 0.0f, 0.0f, // small mean, zero variance
123 -ksqrt16, -ksqrt04, ksqrt04, ksqrt16, // small mean, small variance
124 -ksqrt16, -ksqrt04, ksqrt04, ksqrt16, // small mean, large variance
125 0.0f, 0.0f, 0.0f, 0.0f, // large mean, zero variance
126 -ksqrt16, -ksqrt04, ksqrt04, ksqrt16, // large mean, small variance
127 -ksqrt16, -ksqrt04, ksqrt04, ksqrt16, // large mean, large variance
128 };
129 RETURN_IF_ERROR(PointWiseNear(expected_output, dst_tensor.data, eps))
130 << "Failed using precision " << ToString(precision);
131
132 TensorFloat32 dst_tensor_single_step;
133 auto operation_single_step = CreateMeanStdDevNormalization(
134 op_def, env->GetGpuInfo(), src_tensor.shape,
135 /*variance_bias*/ 1.0e-8f, /*two_step*/ false);
136 RETURN_IF_ERROR(
137 env->ExecuteGPUOperation({src_tensor},
138 std::make_unique<MeanStdDevNormalization>(
139 std::move(operation_single_step)),
140 BHWC(9, 1, 1, 4), &dst_tensor_single_step));
141 RETURN_IF_ERROR(
142 PointWiseNear(expected_output, dst_tensor_single_step.data, eps))
143 << "Failed using precision " << ToString(precision);
144 }
145 }
146 return absl::OkStatus();
147 }
148
MeanStddevNormalizationLargeVectorTest(TestExecutionEnvironment * env)149 absl::Status MeanStddevNormalizationLargeVectorTest(
150 TestExecutionEnvironment* env) {
151 const float mean = 100.0f;
152 const float diff = 1.0f;
153 // Some large vector that is not a round multiple of any SIMD vector sizes.
154 constexpr int kVectorSize = 16 * 16 + 16 + 1;
155
156 TensorFloat32 src_tensor;
157 src_tensor.shape = BHWC(1, 1, 2, kVectorSize);
158 src_tensor.data.resize(kVectorSize * 2);
159 // First input is mean.
160 src_tensor.data[0] = mean;
161 src_tensor.data[kVectorSize] = mean;
162 // Rest is alternating between mean + diff and mean - diff.
163 for (int i = 1; i < kVectorSize - 1; i += 2) {
164 src_tensor.data[i + 0] = mean + diff;
165 src_tensor.data[i + 1] = mean - diff;
166 src_tensor.data[kVectorSize + i + 0] = mean + diff;
167 src_tensor.data[kVectorSize + i + 1] = mean - diff;
168 }
169
170 for (auto precision : env->GetSupportedPrecisions()) {
171 auto data_type = DeduceDataTypeFromPrecision(precision);
172 for (auto storage : env->GetSupportedStorages(data_type)) {
173 const float eps =
174 precision == CalculationsPrecision::F32 ? 5.0e-7f : 8.60e-4f;
175 OperationDef op_def;
176 op_def.precision = precision;
177 op_def.src_tensors.push_back({data_type, storage, Layout::HWC});
178 op_def.dst_tensors.push_back({data_type, storage, Layout::HWC});
179 TensorFloat32 dst_tensor;
180 auto operation = CreateMeanStdDevNormalization(op_def, env->GetGpuInfo(),
181 src_tensor.shape);
182 RETURN_IF_ERROR(env->ExecuteGPUOperation(
183 {src_tensor},
184 std::make_unique<MeanStdDevNormalization>(std::move(operation)),
185 BHWC(1, 1, 2, kVectorSize), &dst_tensor));
186
187 std::vector<float> expected_output(kVectorSize * 2);
188 // First output should be 0.
189 expected_output[0] = 0.0;
190 expected_output[kVectorSize] = 0.0;
191 // Rest should be alternating between ±√(N/(N-1)).
192 const float expected_elem =
193 std::sqrt(static_cast<double>(kVectorSize) /
194 static_cast<double>(kVectorSize - 1));
195 for (int i = 1; i < kVectorSize - 1; i += 2) {
196 expected_output[i + 0] = +expected_elem;
197 expected_output[i + 1] = -expected_elem;
198 expected_output[kVectorSize + i + 0] = +expected_elem;
199 expected_output[kVectorSize + i + 1] = -expected_elem;
200 }
201 RETURN_IF_ERROR(PointWiseNear(expected_output, dst_tensor.data, eps))
202 << "Failed using precision " << ToString(precision);
203
204 if (precision != CalculationsPrecision::F32) {
205 TensorFloat32 dst_tensor_single_step;
206 auto operation_single_step = CreateMeanStdDevNormalization(
207 op_def, env->GetGpuInfo(), src_tensor.shape,
208 /*variance_bias*/ 1.0e-8f, /*two_step*/ false);
209 RETURN_IF_ERROR(env->ExecuteGPUOperation(
210 {src_tensor},
211 std::make_unique<MeanStdDevNormalization>(
212 std::move(operation_single_step)),
213 BHWC(1, 1, 2, kVectorSize), &dst_tensor_single_step));
214 RETURN_IF_ERROR(
215 PointWiseNear(expected_output, dst_tensor_single_step.data, eps))
216 << "Failed using precision " << ToString(precision);
217 }
218 }
219 }
220 return absl::OkStatus();
221 }
222
223 } // namespace gpu
224 } // namespace tflite
225