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/fully_connected_test_util.h"
17
18 #include <memory>
19 #include <vector>
20
21 #include "tensorflow/lite/delegates/gpu/common/operations.h"
22 #include "tensorflow/lite/delegates/gpu/common/status.h"
23 #include "tensorflow/lite/delegates/gpu/common/task/testing_util.h"
24 #include "tensorflow/lite/delegates/gpu/common/tasks/fully_connected.h"
25
26 namespace tflite {
27 namespace gpu {
28
FullyConnectedTest(TestExecutionEnvironment * env)29 absl::Status FullyConnectedTest(TestExecutionEnvironment* env) {
30 TensorFloat32 src_tensor;
31 src_tensor.shape = BHWC(1, 1, 1, 4);
32 src_tensor.data = {0.0f, 1.0f, 2.0f, 3.0f};
33
34 FullyConnectedAttributes attr;
35 attr.weights.shape = OHWI(2, 1, 1, 4);
36 attr.weights.data = {0.0f, 1.0f, 2.0f, 3.0f, //
37 4.0f, 5.0f, 6.0f, 7.0f};
38 attr.bias.shape = Linear(2);
39 attr.bias.data = {0.5f, -0.5f};
40
41 for (auto precision : env->GetSupportedPrecisions()) {
42 auto data_type = DeduceDataTypeFromPrecision(precision);
43 for (auto storage : env->GetSupportedStorages(data_type)) {
44 const float eps = precision == CalculationsPrecision::F32 ? 1e-6f : 1e-3f;
45 OperationDef op_def;
46 op_def.precision = precision;
47 op_def.src_tensors.push_back({data_type, storage, Layout::HWC});
48 op_def.dst_tensors.push_back({data_type, storage, Layout::HWC});
49 TensorFloat32 dst_tensor;
50 FullyConnected operation =
51 CreateFullyConnected(env->GetGpuInfo(), op_def, attr);
52 RETURN_IF_ERROR(env->ExecuteGPUOperation(
53 src_tensor, std::make_unique<FullyConnected>(std::move(operation)),
54 BHWC(1, 1, 1, 2), &dst_tensor));
55 RETURN_IF_ERROR(PointWiseNear({14.5f, 37.5f}, dst_tensor.data, eps))
56 << "Failed using precision " << ToString(precision);
57 }
58 }
59 return absl::OkStatus();
60 }
61
FullyConnectedLargeTest(TestExecutionEnvironment * env)62 absl::Status FullyConnectedLargeTest(TestExecutionEnvironment* env) {
63 TensorFloat32 src_tensor;
64 src_tensor.shape = BHWC(1, 1, 1, 8);
65 src_tensor.data = {0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f};
66
67 FullyConnectedAttributes attr;
68 attr.weights.shape = OHWI(12, 1, 1, 8);
69 attr.weights.data = {
70 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, //
71 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, //
72 16.0f, 17.0f, 18.0f, 19.0f, 20.0f, 21.0f, 22.0f, 23.0f, //
73 24.0f, 25.0f, 26.0f, 27.0f, 28.0f, 29.0f, 30.0f, 31.0f, //
74 32.0f, 33.0f, 34.0f, 35.0f, 36.0f, 37.0f, 38.0f, 39.0f, //
75 40.0f, 41.0f, 42.0f, 43.0f, 44.0f, 45.0f, 46.0f, 47.0f, //
76 48.0f, 49.0f, 50.0f, 51.0f, 52.0f, 53.0f, 54.0f, 55.0f, //
77 56.0f, 57.0f, 58.0f, 59.0f, 60.0f, 61.0f, 62.0f, 63.0f, //
78 64.0f, 65.0f, 66.0f, 67.0f, 68.0f, 69.0f, 70.0f, 71.0f, //
79 72.0f, 73.0f, 74.0f, 75.0f, 76.0f, 77.0f, 78.0f, 79.0f, //
80 80.0f, 81.0f, 82.0f, 83.0f, 84.0f, 85.0f, 86.0f, 87.0f, //
81 88.0f, 89.0f, 90.0f, 91.0f, 92.0f, 93.0f, 94.0f, 95.0f, //
82 };
83 attr.bias.shape = Linear(12);
84 attr.bias.data = {-0.6f, -0.5f, -0.4f, -0.3f, -0.2f, -0.1f,
85 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f};
86
87 for (auto precision : env->GetSupportedPrecisions()) {
88 auto data_type = DeduceDataTypeFromPrecision(precision);
89 for (auto storage : env->GetSupportedStorages(data_type)) {
90 const float eps = precision == CalculationsPrecision::F32 ? 0.0f : 1.0f;
91 OperationDef op_def;
92 op_def.precision = precision;
93 op_def.src_tensors.push_back({data_type, storage, Layout::HWC});
94 op_def.dst_tensors.push_back({data_type, storage, Layout::HWC});
95 TensorFloat32 dst_tensor;
96 FullyConnected operation =
97 CreateFullyConnected(env->GetGpuInfo(), op_def, attr);
98 RETURN_IF_ERROR(env->ExecuteGPUOperation(
99 src_tensor, std::make_unique<FullyConnected>(std::move(operation)),
100 BHWC(1, 1, 1, 12), &dst_tensor));
101 RETURN_IF_ERROR(
102 PointWiseNear({139.4f, 363.5f, 587.6f, 811.7f, 1035.8f, 1259.9f,
103 1484.1f, 1708.2f, 1932.3f, 2156.4f, 2380.5f, 2604.6f},
104 dst_tensor.data, eps))
105 << "Failed using precision " << ToString(precision);
106 }
107 }
108 return absl::OkStatus();
109 }
110
FullyConnectedExtraLargeTest(TestExecutionEnvironment * env)111 absl::Status FullyConnectedExtraLargeTest(TestExecutionEnvironment* env) {
112 static const int kInputSize = 1024;
113 static const int kOutputSize = 1024;
114 TensorFloat32 src_tensor;
115 src_tensor.shape = BHWC(1, 1, 1, kInputSize);
116 src_tensor.data.assign(kInputSize, 1.1f);
117
118 FullyConnectedAttributes attr;
119 attr.weights.shape = OHWI(1024, 1, 1, kInputSize);
120 attr.weights.data.assign(kOutputSize * kInputSize, 2.2f);
121 attr.bias.shape = Linear(kOutputSize);
122 attr.bias.data.assign(kOutputSize, 3.3f);
123
124 std::vector<float> expected(kOutputSize, 2481.38f);
125
126 for (auto precision : env->GetSupportedPrecisions()) {
127 auto data_type = DeduceDataTypeFromPrecision(precision);
128 for (auto storage : env->GetSupportedStorages(data_type)) {
129 float eps;
130 switch (precision) {
131 case CalculationsPrecision::F32:
132 eps = 2.45e-3f;
133 break;
134 case CalculationsPrecision::F32_F16:
135 eps = 1.38f;
136 break;
137 case CalculationsPrecision::F16:
138 eps = 39.0f;
139 break;
140 }
141 if (precision == CalculationsPrecision::F32_F16 &&
142 env->GetGpuInfo().IsApiMetal() && env->GetGpuInfo().IsIntel()) {
143 eps = 3.5f;
144 }
145 if (precision == CalculationsPrecision::F32_F16 &&
146 env->GetGpuInfo().IsGlsl()) {
147 eps = 3.5f;
148 }
149 if (!env->GetGpuInfo().IsRoundToNearestSupported()) {
150 eps *= 4.0f;
151 }
152 OperationDef op_def;
153 op_def.precision = precision;
154 op_def.src_tensors.push_back({data_type, storage, Layout::HWC});
155 op_def.dst_tensors.push_back({data_type, storage, Layout::HWC});
156 TensorFloat32 dst_tensor;
157 FullyConnected operation =
158 CreateFullyConnected(env->GetGpuInfo(), op_def, attr);
159 RETURN_IF_ERROR(env->ExecuteGPUOperation(
160 src_tensor, std::make_unique<FullyConnected>(std::move(operation)),
161 BHWC(1, 1, 1, kOutputSize), &dst_tensor));
162 RETURN_IF_ERROR(PointWiseNear(expected, dst_tensor.data, eps))
163 << "Failed using precision " << ToString(precision);
164 }
165 }
166 return absl::OkStatus();
167 }
168
FullyConnectedInt8Test(TestExecutionEnvironment * env)169 absl::Status FullyConnectedInt8Test(TestExecutionEnvironment* env) {
170 TensorFloat32 src_tensor;
171 src_tensor.shape = BHWC(1, 1, 1, 4);
172 src_tensor.data = {0.0f, 1.0f, 2.0f, 3.0f};
173
174 FullyConnectedInt8Attributes attr;
175 attr.weights.shape = OHWI(2, 1, 1, 4);
176 attr.weights.data = {2, 4, 6, 8, //
177 10, 12, -14, 16};
178 attr.bias.shape = Linear(2);
179 attr.bias.data = {0.5f, -0.5f};
180 attr.scale = 0.5f;
181 attr.zero_point = 0;
182
183 for (auto precision : env->GetSupportedPrecisions()) {
184 auto data_type = DeduceDataTypeFromPrecision(precision);
185 for (auto storage : env->GetSupportedStorages(data_type)) {
186 const float eps = precision == CalculationsPrecision::F32 ? 1e-6f : 1e-3f;
187 OperationDef op_def;
188 op_def.precision = precision;
189 op_def.src_tensors.push_back({data_type, storage, Layout::HWC});
190 op_def.dst_tensors.push_back({data_type, storage, Layout::HWC});
191 TensorFloat32 dst_tensor;
192 FullyConnected operation =
193 CreateFullyConnected(env->GetGpuInfo(), op_def, attr);
194 RETURN_IF_ERROR(env->ExecuteGPUOperation(
195 src_tensor, std::make_unique<FullyConnected>(std::move(operation)),
196 BHWC(1, 1, 1, 2), &dst_tensor));
197 RETURN_IF_ERROR(PointWiseNear({20.5f, 15.5f}, dst_tensor.data, eps))
198 << "Failed using precision " << ToString(precision);
199 }
200 }
201 return absl::OkStatus();
202 }
203
204 } // namespace gpu
205 } // namespace tflite
206