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