1 /* Copyright 2022 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/gpu_model_test_util.h"
17
18 #include <cmath>
19
20 #include "tensorflow/lite/delegates/gpu/common/gpu_model.h"
21 #include "tensorflow/lite/delegates/gpu/common/operations.h"
22 #include "tensorflow/lite/delegates/gpu/common/tasks/conv_generic.h"
23 #include "tensorflow/lite/delegates/gpu/common/tasks/elementwise.h"
24 #include "tensorflow/lite/delegates/gpu/common/tasks/prelu.h"
25
26 namespace tflite {
27 namespace gpu {
28
TestLinkingConvolutionAndCosOp(TestExecutionEnvironment * env)29 absl::Status TestLinkingConvolutionAndCosOp(TestExecutionEnvironment* env) {
30 GraphFloat32 graph;
31 auto input = graph.NewValue();
32 input->tensor.type = DataType::FLOAT32;
33 input->tensor.shape = BHWC(1, 32, 32, 128);
34
35 auto conv_node = graph.NewNode();
36 conv_node->operation.type =
37 ToString(tflite::gpu::OperationType::CONVOLUTION_2D);
38
39 Convolution2DAttributes conv_attr;
40 conv_attr.padding.prepended = HW(0, 0);
41 conv_attr.padding.appended = HW(0, 0);
42 conv_attr.strides = HW(1, 1);
43 conv_attr.dilations = HW(1, 1);
44 conv_attr.weights.shape = OHWI(16, 1, 1, 128);
45 conv_attr.weights.data.resize(conv_attr.weights.shape.DimensionsProduct());
46 for (int i = 0; i < conv_attr.weights.data.size(); ++i) {
47 conv_attr.weights.data[i] = std::sin(i * 0.12345f);
48 }
49 conv_attr.bias.shape = Linear(16);
50 conv_attr.bias.data.resize(conv_attr.bias.shape.DimensionsProduct());
51 for (int i = 0; i < conv_attr.bias.data.size(); ++i) {
52 conv_attr.bias.data[i] = std::sin(i * 0.12345f);
53 }
54 conv_node->operation.attributes = conv_attr;
55 RETURN_IF_ERROR(graph.AddConsumer(conv_node->id, input->id));
56
57 auto cos_node = graph.NewNode();
58 cos_node->operation.type = ToString(OperationType::COS);
59 tflite::gpu::Value* conv_output = nullptr;
60 RETURN_IF_ERROR(ConnectTwoNodes(&graph, conv_node, cos_node, &conv_output));
61 conv_output->tensor.type = DataType::FLOAT32;
62 conv_output->tensor.shape = BHWC(1, 32, 32, 16);
63
64 tflite::gpu::Value* cos_output = nullptr;
65 RETURN_IF_ERROR(AddOutput(&graph, cos_node, &cos_output));
66 cos_output->tensor.type = DataType::FLOAT32;
67 cos_output->tensor.shape = BHWC(1, 32, 32, 16);
68
69 RETURN_IF_ERROR(RunGraphTransformsForGpuModel(&graph));
70
71 for (auto precision : env->GetSupportedPrecisions()) {
72 auto data_type = DeduceDataTypeFromPrecision(precision);
73 for (auto storage : env->GetSupportedStorages(data_type)) {
74 CreateGpuModelInfo create_info;
75 create_info.precision = precision;
76 create_info.storage_type = storage;
77 create_info.hints.Add(ModelHints::kAllowSpecialKernels);
78
79 GpuModel gpu_model;
80 RETURN_IF_ERROR(
81 GraphToGpuModel(graph, create_info, env->GetGpuInfo(), &gpu_model));
82
83 if (gpu_model.nodes.size() != 1) {
84 return absl::InternalError("Expected model with one node.");
85 }
86
87 TensorFloat32 src_tensor;
88 src_tensor.shape = input->tensor.shape;
89 src_tensor.data.resize(src_tensor.shape.DimensionsProduct());
90 for (int i = 0; i < src_tensor.data.size(); ++i) {
91 src_tensor.data[i] = std::sin(i * 0.12345f);
92 }
93
94 TensorFloat32 dst_tensor_v1;
95 RETURN_IF_ERROR(
96 env->ExecuteGpuModel({src_tensor}, {&dst_tensor_v1}, &gpu_model));
97
98 OperationDef op_def;
99 op_def.precision = precision;
100 op_def.src_tensors.push_back({data_type, storage, Layout::HWC});
101 op_def.dst_tensors.push_back({data_type, storage, Layout::HWC});
102
103 ConvGeneric conv_operation =
104 CreateConvGeneric(env->GetGpuInfo(), op_def, conv_attr);
105 TensorFloat32 intermediate;
106 RETURN_IF_ERROR(env->ExecuteGPUOperation(
107 src_tensor, std::make_unique<ConvGeneric>(std::move(conv_operation)),
108 conv_output->tensor.shape, &intermediate));
109
110 GPUOperation cos_operation = CreateElementwiseOneInput(
111 env->GetGpuInfo(), op_def, OperationType::COS);
112 TensorFloat32 dst_tensor_v0;
113 RETURN_IF_ERROR(env->ExecuteGPUOperation(
114 intermediate,
115 std::make_unique<GPUOperation>(std::move(cos_operation)),
116 cos_output->tensor.shape, &dst_tensor_v0));
117
118 RETURN_IF_ERROR(
119 PointWiseNear(dst_tensor_v0.data, dst_tensor_v1.data, 0.0f));
120 }
121 }
122 return absl::OkStatus();
123 }
124
TestLinkingConvolution2InputMul2InputMul(TestExecutionEnvironment * env)125 absl::Status TestLinkingConvolution2InputMul2InputMul(
126 TestExecutionEnvironment* env) {
127 GraphFloat32 graph;
128 auto input0 = graph.NewValue();
129 auto input1 = graph.NewValue();
130 auto input2 = graph.NewValue();
131 input0->tensor.type = DataType::FLOAT32;
132 input0->tensor.shape = BHWC(1, 32, 32, 128);
133 input1->tensor.type = DataType::FLOAT32;
134 input1->tensor.shape = BHWC(1, 32, 32, 16);
135 input2->tensor.type = DataType::FLOAT32;
136 input2->tensor.shape = BHWC(1, 32, 32, 16);
137
138 auto conv_node = graph.NewNode();
139 conv_node->operation.type =
140 ToString(tflite::gpu::OperationType::CONVOLUTION_2D);
141
142 Convolution2DAttributes conv_attr;
143 conv_attr.padding.prepended = HW(0, 0);
144 conv_attr.padding.appended = HW(0, 0);
145 conv_attr.strides = HW(1, 1);
146 conv_attr.dilations = HW(1, 1);
147 conv_attr.weights.shape = OHWI(16, 1, 1, 128);
148 conv_attr.weights.data.resize(conv_attr.weights.shape.DimensionsProduct());
149 for (int i = 0; i < conv_attr.weights.data.size(); ++i) {
150 conv_attr.weights.data[i] = std::sin(i * 0.12345f);
151 }
152 conv_attr.bias.shape = Linear(16);
153 conv_attr.bias.data.resize(conv_attr.bias.shape.DimensionsProduct());
154 for (int i = 0; i < conv_attr.bias.data.size(); ++i) {
155 conv_attr.bias.data[i] = std::sin(i * 0.12345f);
156 }
157 conv_node->operation.attributes = conv_attr;
158 RETURN_IF_ERROR(graph.AddConsumer(conv_node->id, input0->id));
159
160 auto mul0_node = graph.NewNode();
161 mul0_node->operation.type = ToString(OperationType::MUL);
162 tflite::gpu::Value* conv_output = nullptr;
163 RETURN_IF_ERROR(ConnectTwoNodes(&graph, conv_node, mul0_node, &conv_output));
164 RETURN_IF_ERROR(graph.AddConsumer(mul0_node->id, input1->id));
165 conv_output->tensor.type = DataType::FLOAT32;
166 conv_output->tensor.shape = BHWC(1, 32, 32, 16);
167
168 auto mul1_node = graph.NewNode();
169 mul1_node->operation.type = ToString(OperationType::MUL);
170 tflite::gpu::Value* mul0_output = nullptr;
171 RETURN_IF_ERROR(ConnectTwoNodes(&graph, mul0_node, mul1_node, &mul0_output));
172 RETURN_IF_ERROR(graph.AddConsumer(mul1_node->id, input2->id));
173 mul0_output->tensor.type = DataType::FLOAT32;
174 mul0_output->tensor.shape = BHWC(1, 32, 32, 16);
175
176 tflite::gpu::Value* mul1_output = nullptr;
177 RETURN_IF_ERROR(AddOutput(&graph, mul1_node, &mul1_output));
178 mul1_output->tensor.type = DataType::FLOAT32;
179 mul1_output->tensor.shape = BHWC(1, 32, 32, 16);
180
181 RETURN_IF_ERROR(RunGraphTransformsForGpuModel(&graph));
182
183 for (auto precision : env->GetSupportedPrecisions()) {
184 auto data_type = DeduceDataTypeFromPrecision(precision);
185 for (auto storage : env->GetSupportedStorages(data_type)) {
186 CreateGpuModelInfo create_info;
187 create_info.precision = precision;
188 create_info.storage_type = storage;
189 create_info.hints.Add(ModelHints::kAllowSpecialKernels);
190
191 GpuModel gpu_model;
192 RETURN_IF_ERROR(
193 GraphToGpuModel(graph, create_info, env->GetGpuInfo(), &gpu_model));
194
195 if (gpu_model.nodes.size() != 1) {
196 return absl::InternalError("Expected model with one node.");
197 }
198
199 TensorFloat32 src0_tensor;
200 src0_tensor.shape = input0->tensor.shape;
201 src0_tensor.data.resize(src0_tensor.shape.DimensionsProduct());
202 for (int i = 0; i < src0_tensor.data.size(); ++i) {
203 src0_tensor.data[i] = std::sin(i * 0.12345f);
204 }
205 TensorFloat32 src1_tensor;
206 src1_tensor.shape = input1->tensor.shape;
207 src1_tensor.data.resize(src1_tensor.shape.DimensionsProduct());
208 for (int i = 0; i < src1_tensor.data.size(); ++i) {
209 src1_tensor.data[i] = std::sin(i * 0.12345f);
210 }
211 TensorFloat32 src2_tensor;
212 src2_tensor.shape = input2->tensor.shape;
213 src2_tensor.data.resize(src2_tensor.shape.DimensionsProduct());
214 for (int i = 0; i < src2_tensor.data.size(); ++i) {
215 src2_tensor.data[i] = std::sin(i * 0.12345f);
216 }
217
218 TensorFloat32 dst_tensor_v1;
219 RETURN_IF_ERROR(
220 env->ExecuteGpuModel({src0_tensor, src1_tensor, src2_tensor},
221 {&dst_tensor_v1}, &gpu_model));
222
223 OperationDef op_def;
224 op_def.precision = precision;
225 op_def.src_tensors.push_back({data_type, storage, Layout::HWC});
226 op_def.dst_tensors.push_back({data_type, storage, Layout::HWC});
227
228 ConvGeneric conv_operation =
229 CreateConvGeneric(env->GetGpuInfo(), op_def, conv_attr);
230 TensorFloat32 intermediate0;
231 RETURN_IF_ERROR(env->ExecuteGPUOperation(
232 src0_tensor, std::make_unique<ConvGeneric>(std::move(conv_operation)),
233 conv_output->tensor.shape, &intermediate0));
234
235 OperationDef op_def_mul;
236 op_def_mul.precision = precision;
237 op_def_mul.src_tensors.push_back({data_type, storage, Layout::HWC});
238 op_def_mul.src_tensors.push_back({data_type, storage, Layout::HWC});
239 op_def_mul.dst_tensors.push_back({data_type, storage, Layout::HWC});
240
241 GPUOperation mul0_operation = CreateElementwiseTwoInput(
242 op_def_mul, OperationType::MUL, src1_tensor.shape);
243 TensorFloat32 intermediate1;
244 RETURN_IF_ERROR(env->ExecuteGPUOperation(
245 {intermediate0, src1_tensor},
246 std::make_unique<GPUOperation>(std::move(mul0_operation)),
247 mul0_output->tensor.shape, &intermediate1));
248
249 GPUOperation mul1_operation = CreateElementwiseTwoInput(
250 op_def_mul, OperationType::MUL, src2_tensor.shape);
251 TensorFloat32 dst_tensor_v0;
252 RETURN_IF_ERROR(env->ExecuteGPUOperation(
253 {intermediate1, src2_tensor},
254 std::make_unique<GPUOperation>(std::move(mul1_operation)),
255 mul1_output->tensor.shape, &dst_tensor_v0));
256
257 RETURN_IF_ERROR(
258 PointWiseNear(dst_tensor_v0.data, dst_tensor_v1.data, 0.0f));
259 }
260 }
261 return absl::OkStatus();
262 }
263
TestLinkingConvolution2InputBroadcastMul2InputMul(TestExecutionEnvironment * env)264 absl::Status TestLinkingConvolution2InputBroadcastMul2InputMul(
265 TestExecutionEnvironment* env) {
266 GraphFloat32 graph;
267 auto input0 = graph.NewValue();
268 auto input1 = graph.NewValue();
269 auto input2 = graph.NewValue();
270 input0->tensor.type = DataType::FLOAT32;
271 input0->tensor.shape = BHWC(1, 32, 32, 128);
272 input1->tensor.type = DataType::FLOAT32;
273 input1->tensor.shape = BHWC(1, 32, 32, 1);
274 input2->tensor.type = DataType::FLOAT32;
275 input2->tensor.shape = BHWC(1, 32, 32, 16);
276
277 auto conv_node = graph.NewNode();
278 conv_node->operation.type =
279 ToString(tflite::gpu::OperationType::CONVOLUTION_2D);
280
281 Convolution2DAttributes conv_attr;
282 conv_attr.padding.prepended = HW(0, 0);
283 conv_attr.padding.appended = HW(0, 0);
284 conv_attr.strides = HW(1, 1);
285 conv_attr.dilations = HW(1, 1);
286 conv_attr.weights.shape = OHWI(16, 1, 1, 128);
287 conv_attr.weights.data.resize(conv_attr.weights.shape.DimensionsProduct());
288 for (int i = 0; i < conv_attr.weights.data.size(); ++i) {
289 conv_attr.weights.data[i] = std::sin(i * 0.12345f);
290 }
291 conv_attr.bias.shape = Linear(16);
292 conv_attr.bias.data.resize(conv_attr.bias.shape.DimensionsProduct());
293 for (int i = 0; i < conv_attr.bias.data.size(); ++i) {
294 conv_attr.bias.data[i] = std::sin(i * 0.12345f);
295 }
296 conv_node->operation.attributes = conv_attr;
297 RETURN_IF_ERROR(graph.AddConsumer(conv_node->id, input0->id));
298
299 auto mul0_node = graph.NewNode();
300 mul0_node->operation.type = ToString(OperationType::MUL);
301 tflite::gpu::Value* conv_output = nullptr;
302 RETURN_IF_ERROR(ConnectTwoNodes(&graph, conv_node, mul0_node, &conv_output));
303 RETURN_IF_ERROR(graph.AddConsumer(mul0_node->id, input1->id));
304 conv_output->tensor.type = DataType::FLOAT32;
305 conv_output->tensor.shape = BHWC(1, 32, 32, 16);
306
307 auto mul1_node = graph.NewNode();
308 mul1_node->operation.type = ToString(OperationType::MUL);
309 tflite::gpu::Value* mul0_output = nullptr;
310 RETURN_IF_ERROR(ConnectTwoNodes(&graph, mul0_node, mul1_node, &mul0_output));
311 RETURN_IF_ERROR(graph.AddConsumer(mul1_node->id, input2->id));
312 mul0_output->tensor.type = DataType::FLOAT32;
313 mul0_output->tensor.shape = BHWC(1, 32, 32, 16);
314
315 tflite::gpu::Value* mul1_output = nullptr;
316 RETURN_IF_ERROR(AddOutput(&graph, mul1_node, &mul1_output));
317 mul1_output->tensor.type = DataType::FLOAT32;
318 mul1_output->tensor.shape = BHWC(1, 32, 32, 16);
319
320 RETURN_IF_ERROR(RunGraphTransformsForGpuModel(&graph));
321
322 for (auto precision : env->GetSupportedPrecisions()) {
323 auto data_type = DeduceDataTypeFromPrecision(precision);
324 for (auto storage : env->GetSupportedStorages(data_type)) {
325 CreateGpuModelInfo create_info;
326 create_info.precision = precision;
327 create_info.storage_type = storage;
328 create_info.hints.Add(ModelHints::kAllowSpecialKernels);
329
330 GpuModel gpu_model;
331 RETURN_IF_ERROR(
332 GraphToGpuModel(graph, create_info, env->GetGpuInfo(), &gpu_model));
333
334 if (gpu_model.nodes.size() != 1) {
335 return absl::InternalError("Expected model with one node.");
336 }
337
338 TensorFloat32 src0_tensor;
339 src0_tensor.shape = input0->tensor.shape;
340 src0_tensor.data.resize(src0_tensor.shape.DimensionsProduct());
341 for (int i = 0; i < src0_tensor.data.size(); ++i) {
342 src0_tensor.data[i] = std::sin(i * 0.12345f);
343 }
344 TensorFloat32 src1_tensor;
345 src1_tensor.shape = input1->tensor.shape;
346 src1_tensor.data.resize(src1_tensor.shape.DimensionsProduct());
347 for (int i = 0; i < src1_tensor.data.size(); ++i) {
348 src1_tensor.data[i] = std::sin(i * 0.12345f);
349 }
350 TensorFloat32 src2_tensor;
351 src2_tensor.shape = input2->tensor.shape;
352 src2_tensor.data.resize(src2_tensor.shape.DimensionsProduct());
353 for (int i = 0; i < src2_tensor.data.size(); ++i) {
354 src2_tensor.data[i] = std::sin(i * 0.12345f);
355 }
356
357 TensorFloat32 dst_tensor_v1;
358 RETURN_IF_ERROR(
359 env->ExecuteGpuModel({src0_tensor, src1_tensor, src2_tensor},
360 {&dst_tensor_v1}, &gpu_model));
361
362 OperationDef op_def;
363 op_def.precision = precision;
364 op_def.src_tensors.push_back({data_type, storage, Layout::HWC});
365 op_def.dst_tensors.push_back({data_type, storage, Layout::HWC});
366
367 ConvGeneric conv_operation =
368 CreateConvGeneric(env->GetGpuInfo(), op_def, conv_attr);
369 TensorFloat32 intermediate0;
370 RETURN_IF_ERROR(env->ExecuteGPUOperation(
371 src0_tensor, std::make_unique<ConvGeneric>(std::move(conv_operation)),
372 conv_output->tensor.shape, &intermediate0));
373
374 OperationDef op_def_mul;
375 op_def_mul.precision = precision;
376 op_def_mul.src_tensors.push_back({data_type, storage, Layout::HWC});
377 op_def_mul.src_tensors.push_back({data_type, storage, Layout::HWC});
378 op_def_mul.dst_tensors.push_back({data_type, storage, Layout::HWC});
379
380 GPUOperation mul0_operation = CreateElementwiseTwoInput(
381 op_def_mul, OperationType::MUL, src1_tensor.shape);
382 TensorFloat32 intermediate1;
383 RETURN_IF_ERROR(env->ExecuteGPUOperation(
384 {intermediate0, src1_tensor},
385 std::make_unique<GPUOperation>(std::move(mul0_operation)),
386 mul0_output->tensor.shape, &intermediate1));
387
388 GPUOperation mul1_operation = CreateElementwiseTwoInput(
389 op_def_mul, OperationType::MUL, src2_tensor.shape);
390 TensorFloat32 dst_tensor_v0;
391 RETURN_IF_ERROR(env->ExecuteGPUOperation(
392 {intermediate1, src2_tensor},
393 std::make_unique<GPUOperation>(std::move(mul1_operation)),
394 mul1_output->tensor.shape, &dst_tensor_v0));
395
396 RETURN_IF_ERROR(
397 PointWiseNear(dst_tensor_v0.data, dst_tensor_v1.data, 0.0f));
398 }
399 }
400 return absl::OkStatus();
401 }
402
TestLinkingConvolution2InputMul2InputBroadcastMul(TestExecutionEnvironment * env)403 absl::Status TestLinkingConvolution2InputMul2InputBroadcastMul(
404 TestExecutionEnvironment* env) {
405 GraphFloat32 graph;
406 auto input0 = graph.NewValue();
407 auto input1 = graph.NewValue();
408 auto input2 = graph.NewValue();
409 input0->tensor.type = DataType::FLOAT32;
410 input0->tensor.shape = BHWC(1, 32, 32, 128);
411 input1->tensor.type = DataType::FLOAT32;
412 input1->tensor.shape = BHWC(1, 32, 32, 16);
413 input2->tensor.type = DataType::FLOAT32;
414 input2->tensor.shape = BHWC(1, 1, 1, 16);
415
416 auto conv_node = graph.NewNode();
417 conv_node->operation.type =
418 ToString(tflite::gpu::OperationType::CONVOLUTION_2D);
419
420 Convolution2DAttributes conv_attr;
421 conv_attr.padding.prepended = HW(0, 0);
422 conv_attr.padding.appended = HW(0, 0);
423 conv_attr.strides = HW(1, 1);
424 conv_attr.dilations = HW(1, 1);
425 conv_attr.weights.shape = OHWI(16, 1, 1, 128);
426 conv_attr.weights.data.resize(conv_attr.weights.shape.DimensionsProduct());
427 for (int i = 0; i < conv_attr.weights.data.size(); ++i) {
428 conv_attr.weights.data[i] = std::sin(i * 0.12345f);
429 }
430 conv_attr.bias.shape = Linear(16);
431 conv_attr.bias.data.resize(conv_attr.bias.shape.DimensionsProduct());
432 for (int i = 0; i < conv_attr.bias.data.size(); ++i) {
433 conv_attr.bias.data[i] = std::sin(i * 0.12345f);
434 }
435 conv_node->operation.attributes = conv_attr;
436 RETURN_IF_ERROR(graph.AddConsumer(conv_node->id, input0->id));
437
438 auto mul0_node = graph.NewNode();
439 mul0_node->operation.type = ToString(OperationType::MUL);
440 tflite::gpu::Value* conv_output = nullptr;
441 RETURN_IF_ERROR(ConnectTwoNodes(&graph, conv_node, mul0_node, &conv_output));
442 RETURN_IF_ERROR(graph.AddConsumer(mul0_node->id, input1->id));
443 conv_output->tensor.type = DataType::FLOAT32;
444 conv_output->tensor.shape = BHWC(1, 32, 32, 16);
445
446 auto mul1_node = graph.NewNode();
447 mul1_node->operation.type = ToString(OperationType::MUL);
448 tflite::gpu::Value* mul0_output = nullptr;
449 RETURN_IF_ERROR(ConnectTwoNodes(&graph, mul0_node, mul1_node, &mul0_output));
450 RETURN_IF_ERROR(graph.AddConsumer(mul1_node->id, input2->id));
451 mul0_output->tensor.type = DataType::FLOAT32;
452 mul0_output->tensor.shape = BHWC(1, 32, 32, 16);
453
454 tflite::gpu::Value* mul1_output = nullptr;
455 RETURN_IF_ERROR(AddOutput(&graph, mul1_node, &mul1_output));
456 mul1_output->tensor.type = DataType::FLOAT32;
457 mul1_output->tensor.shape = BHWC(1, 32, 32, 16);
458
459 RETURN_IF_ERROR(RunGraphTransformsForGpuModel(&graph));
460
461 for (auto precision : env->GetSupportedPrecisions()) {
462 auto data_type = DeduceDataTypeFromPrecision(precision);
463 for (auto storage : env->GetSupportedStorages(data_type)) {
464 CreateGpuModelInfo create_info;
465 create_info.precision = precision;
466 create_info.storage_type = storage;
467 create_info.hints.Add(ModelHints::kAllowSpecialKernels);
468
469 GpuModel gpu_model;
470 RETURN_IF_ERROR(
471 GraphToGpuModel(graph, create_info, env->GetGpuInfo(), &gpu_model));
472
473 if (gpu_model.nodes.size() != 1) {
474 return absl::InternalError("Expected model with one node.");
475 }
476
477 TensorFloat32 src0_tensor;
478 src0_tensor.shape = input0->tensor.shape;
479 src0_tensor.data.resize(src0_tensor.shape.DimensionsProduct());
480 for (int i = 0; i < src0_tensor.data.size(); ++i) {
481 src0_tensor.data[i] = std::sin(i * 0.12345f);
482 }
483 TensorFloat32 src1_tensor;
484 src1_tensor.shape = input1->tensor.shape;
485 src1_tensor.data.resize(src1_tensor.shape.DimensionsProduct());
486 for (int i = 0; i < src1_tensor.data.size(); ++i) {
487 src1_tensor.data[i] = std::sin(i * 0.12345f);
488 }
489 TensorFloat32 src2_tensor;
490 src2_tensor.shape = input2->tensor.shape;
491 src2_tensor.data.resize(src2_tensor.shape.DimensionsProduct());
492 for (int i = 0; i < src2_tensor.data.size(); ++i) {
493 src2_tensor.data[i] = std::sin(i * 0.12345f);
494 }
495
496 TensorFloat32 dst_tensor_v1;
497 RETURN_IF_ERROR(
498 env->ExecuteGpuModel({src0_tensor, src1_tensor, src2_tensor},
499 {&dst_tensor_v1}, &gpu_model));
500
501 OperationDef op_def;
502 op_def.precision = precision;
503 op_def.src_tensors.push_back({data_type, storage, Layout::HWC});
504 op_def.dst_tensors.push_back({data_type, storage, Layout::HWC});
505
506 ConvGeneric conv_operation =
507 CreateConvGeneric(env->GetGpuInfo(), op_def, conv_attr);
508 TensorFloat32 intermediate0;
509 RETURN_IF_ERROR(env->ExecuteGPUOperation(
510 src0_tensor, std::make_unique<ConvGeneric>(std::move(conv_operation)),
511 conv_output->tensor.shape, &intermediate0));
512
513 OperationDef op_def_mul;
514 op_def_mul.precision = precision;
515 op_def_mul.src_tensors.push_back({data_type, storage, Layout::HWC});
516 op_def_mul.src_tensors.push_back({data_type, storage, Layout::HWC});
517 op_def_mul.dst_tensors.push_back({data_type, storage, Layout::HWC});
518
519 GPUOperation mul0_operation = CreateElementwiseTwoInput(
520 op_def_mul, OperationType::MUL, src1_tensor.shape);
521 TensorFloat32 intermediate1;
522 RETURN_IF_ERROR(env->ExecuteGPUOperation(
523 {intermediate0, src1_tensor},
524 std::make_unique<GPUOperation>(std::move(mul0_operation)),
525 mul0_output->tensor.shape, &intermediate1));
526
527 GPUOperation mul1_operation = CreateElementwiseTwoInput(
528 op_def_mul, OperationType::MUL, src2_tensor.shape);
529 TensorFloat32 dst_tensor_v0;
530 RETURN_IF_ERROR(env->ExecuteGPUOperation(
531 {intermediate1, src2_tensor},
532 std::make_unique<GPUOperation>(std::move(mul1_operation)),
533 mul1_output->tensor.shape, &dst_tensor_v0));
534
535 RETURN_IF_ERROR(
536 PointWiseNear(dst_tensor_v0.data, dst_tensor_v1.data, 0.0f));
537 }
538 }
539 return absl::OkStatus();
540 }
541
TestLinkingConvolution2InputMul2InputMulCos(TestExecutionEnvironment * env)542 absl::Status TestLinkingConvolution2InputMul2InputMulCos(
543 TestExecutionEnvironment* env) {
544 GraphFloat32 graph;
545 auto input0 = graph.NewValue();
546 auto input1 = graph.NewValue();
547 auto input2 = graph.NewValue();
548 input0->tensor.type = DataType::FLOAT32;
549 input0->tensor.shape = BHWC(1, 32, 32, 128);
550 input1->tensor.type = DataType::FLOAT32;
551 input1->tensor.shape = BHWC(1, 32, 32, 16);
552 input2->tensor.type = DataType::FLOAT32;
553 input2->tensor.shape = BHWC(1, 32, 32, 16);
554
555 auto conv_node = graph.NewNode();
556 conv_node->operation.type =
557 ToString(tflite::gpu::OperationType::CONVOLUTION_2D);
558
559 Convolution2DAttributes conv_attr;
560 conv_attr.padding.prepended = HW(0, 0);
561 conv_attr.padding.appended = HW(0, 0);
562 conv_attr.strides = HW(1, 1);
563 conv_attr.dilations = HW(1, 1);
564 conv_attr.weights.shape = OHWI(16, 1, 1, 128);
565 conv_attr.weights.data.resize(conv_attr.weights.shape.DimensionsProduct());
566 for (int i = 0; i < conv_attr.weights.data.size(); ++i) {
567 conv_attr.weights.data[i] = std::sin(i * 0.12345f);
568 }
569 conv_attr.bias.shape = Linear(16);
570 conv_attr.bias.data.resize(conv_attr.bias.shape.DimensionsProduct());
571 for (int i = 0; i < conv_attr.bias.data.size(); ++i) {
572 conv_attr.bias.data[i] = std::sin(i * 0.12345f);
573 }
574 conv_node->operation.attributes = conv_attr;
575 RETURN_IF_ERROR(graph.AddConsumer(conv_node->id, input0->id));
576
577 auto mul0_node = graph.NewNode();
578 mul0_node->operation.type = ToString(OperationType::MUL);
579 tflite::gpu::Value* conv_output = nullptr;
580 RETURN_IF_ERROR(ConnectTwoNodes(&graph, conv_node, mul0_node, &conv_output));
581 RETURN_IF_ERROR(graph.AddConsumer(mul0_node->id, input1->id));
582 conv_output->tensor.type = DataType::FLOAT32;
583 conv_output->tensor.shape = BHWC(1, 32, 32, 16);
584
585 auto mul1_node = graph.NewNode();
586 mul1_node->operation.type = ToString(OperationType::MUL);
587 tflite::gpu::Value* mul0_output = nullptr;
588 RETURN_IF_ERROR(ConnectTwoNodes(&graph, mul0_node, mul1_node, &mul0_output));
589 RETURN_IF_ERROR(graph.AddConsumer(mul1_node->id, input2->id));
590 mul0_output->tensor.type = DataType::FLOAT32;
591 mul0_output->tensor.shape = BHWC(1, 32, 32, 16);
592
593 auto cos_node = graph.NewNode();
594 cos_node->operation.type = ToString(OperationType::COS);
595 tflite::gpu::Value* mul1_output = nullptr;
596 RETURN_IF_ERROR(ConnectTwoNodes(&graph, mul1_node, cos_node, &mul1_output));
597 mul1_output->tensor.type = DataType::FLOAT32;
598 mul1_output->tensor.shape = BHWC(1, 32, 32, 16);
599
600 tflite::gpu::Value* cos_output = nullptr;
601 RETURN_IF_ERROR(AddOutput(&graph, cos_node, &cos_output));
602 cos_output->tensor.type = DataType::FLOAT32;
603 cos_output->tensor.shape = BHWC(1, 32, 32, 16);
604
605 RETURN_IF_ERROR(RunGraphTransformsForGpuModel(&graph));
606
607 for (auto precision : env->GetSupportedPrecisions()) {
608 auto data_type = DeduceDataTypeFromPrecision(precision);
609 for (auto storage : env->GetSupportedStorages(data_type)) {
610 CreateGpuModelInfo create_info;
611 create_info.precision = precision;
612 create_info.storage_type = storage;
613 create_info.hints.Add(ModelHints::kAllowSpecialKernels);
614
615 GpuModel gpu_model;
616 RETURN_IF_ERROR(
617 GraphToGpuModel(graph, create_info, env->GetGpuInfo(), &gpu_model));
618
619 if (gpu_model.nodes.size() != 1) {
620 return absl::InternalError("Expected model with one node.");
621 }
622
623 TensorFloat32 src0_tensor;
624 src0_tensor.shape = input0->tensor.shape;
625 src0_tensor.data.resize(src0_tensor.shape.DimensionsProduct());
626 for (int i = 0; i < src0_tensor.data.size(); ++i) {
627 src0_tensor.data[i] = std::sin(i * 0.12345f);
628 }
629 TensorFloat32 src1_tensor;
630 src1_tensor.shape = input1->tensor.shape;
631 src1_tensor.data.resize(src1_tensor.shape.DimensionsProduct());
632 for (int i = 0; i < src1_tensor.data.size(); ++i) {
633 src1_tensor.data[i] = std::sin(i * 0.12345f);
634 }
635 TensorFloat32 src2_tensor;
636 src2_tensor.shape = input2->tensor.shape;
637 src2_tensor.data.resize(src2_tensor.shape.DimensionsProduct());
638 for (int i = 0; i < src2_tensor.data.size(); ++i) {
639 src2_tensor.data[i] = std::sin(i * 0.12345f);
640 }
641
642 TensorFloat32 dst_tensor_v1;
643 RETURN_IF_ERROR(
644 env->ExecuteGpuModel({src0_tensor, src1_tensor, src2_tensor},
645 {&dst_tensor_v1}, &gpu_model));
646
647 OperationDef op_def;
648 op_def.precision = precision;
649 op_def.src_tensors.push_back({data_type, storage, Layout::HWC});
650 op_def.dst_tensors.push_back({data_type, storage, Layout::HWC});
651
652 ConvGeneric conv_operation =
653 CreateConvGeneric(env->GetGpuInfo(), op_def, conv_attr);
654 TensorFloat32 intermediate0;
655 RETURN_IF_ERROR(env->ExecuteGPUOperation(
656 src0_tensor, std::make_unique<ConvGeneric>(std::move(conv_operation)),
657 conv_output->tensor.shape, &intermediate0));
658
659 OperationDef op_def_mul;
660 op_def_mul.precision = precision;
661 op_def_mul.src_tensors.push_back({data_type, storage, Layout::HWC});
662 op_def_mul.src_tensors.push_back({data_type, storage, Layout::HWC});
663 op_def_mul.dst_tensors.push_back({data_type, storage, Layout::HWC});
664
665 GPUOperation mul0_operation = CreateElementwiseTwoInput(
666 op_def_mul, OperationType::MUL, src1_tensor.shape);
667 TensorFloat32 intermediate1;
668 RETURN_IF_ERROR(env->ExecuteGPUOperation(
669 {intermediate0, src1_tensor},
670 std::make_unique<GPUOperation>(std::move(mul0_operation)),
671 mul0_output->tensor.shape, &intermediate1));
672
673 GPUOperation mul1_operation = CreateElementwiseTwoInput(
674 op_def_mul, OperationType::MUL, src2_tensor.shape);
675 TensorFloat32 intermediate2;
676 RETURN_IF_ERROR(env->ExecuteGPUOperation(
677 {intermediate1, src2_tensor},
678 std::make_unique<GPUOperation>(std::move(mul1_operation)),
679 mul1_output->tensor.shape, &intermediate2));
680
681 GPUOperation cos_operation = CreateElementwiseOneInput(
682 env->GetGpuInfo(), op_def, OperationType::COS);
683 TensorFloat32 dst_tensor_v0;
684 RETURN_IF_ERROR(env->ExecuteGPUOperation(
685 intermediate2,
686 std::make_unique<GPUOperation>(std::move(cos_operation)),
687 cos_output->tensor.shape, &dst_tensor_v0));
688
689 RETURN_IF_ERROR(
690 PointWiseNear(dst_tensor_v0.data, dst_tensor_v1.data, 0.0f));
691 }
692 }
693 return absl::OkStatus();
694 }
695
TestLinkingConvolutionFirstTanh2InputDiff(TestExecutionEnvironment * env)696 absl::Status TestLinkingConvolutionFirstTanh2InputDiff(
697 TestExecutionEnvironment* env) {
698 GraphFloat32 graph;
699 auto input = graph.NewValue();
700 input->tensor.type = DataType::FLOAT32;
701 input->tensor.shape = BHWC(1, 32, 32, 128);
702
703 auto conv_node = graph.NewNode();
704 conv_node->operation.type =
705 ToString(tflite::gpu::OperationType::CONVOLUTION_2D);
706
707 Convolution2DAttributes conv_attr;
708 conv_attr.padding.prepended = HW(0, 0);
709 conv_attr.padding.appended = HW(0, 0);
710 conv_attr.strides = HW(1, 1);
711 conv_attr.dilations = HW(1, 1);
712 conv_attr.weights.shape = OHWI(16, 1, 1, 128);
713 conv_attr.weights.data.resize(conv_attr.weights.shape.DimensionsProduct());
714 for (int i = 0; i < conv_attr.weights.data.size(); ++i) {
715 conv_attr.weights.data[i] = std::sin(i * 0.12345f);
716 }
717 conv_attr.bias.shape = Linear(16);
718 conv_attr.bias.data.resize(conv_attr.bias.shape.DimensionsProduct());
719 for (int i = 0; i < conv_attr.bias.data.size(); ++i) {
720 conv_attr.bias.data[i] = std::sin(i * 0.12345f);
721 }
722 conv_node->operation.attributes = conv_attr;
723 RETURN_IF_ERROR(graph.AddConsumer(conv_node->id, input->id));
724
725 auto tanh_node = graph.NewNode();
726 tanh_node->operation.type = ToString(OperationType::TANH);
727 tflite::gpu::Value* conv_output = nullptr;
728 RETURN_IF_ERROR(ConnectTwoNodes(&graph, conv_node, tanh_node, &conv_output));
729 conv_output->tensor.type = DataType::FLOAT32;
730 conv_output->tensor.shape = BHWC(1, 32, 32, 16);
731
732 auto sub_node = graph.NewNode();
733 sub_node->operation.type = ToString(OperationType::SUB);
734 auto tanh_output = graph.NewValue();
735 tanh_output->tensor.type = DataType::FLOAT32;
736 tanh_output->tensor.shape = BHWC(1, 32, 32, 16);
737 auto sub_output = graph.NewValue();
738 sub_output->tensor.type = DataType::FLOAT32;
739 sub_output->tensor.shape = BHWC(1, 32, 32, 16);
740 RETURN_IF_ERROR(graph.SetProducer(tanh_node->id, tanh_output->id));
741 RETURN_IF_ERROR(graph.AddConsumer(sub_node->id, tanh_output->id));
742 RETURN_IF_ERROR(graph.AddConsumer(sub_node->id, conv_output->id));
743 RETURN_IF_ERROR(graph.SetProducer(sub_node->id, sub_output->id));
744
745 RETURN_IF_ERROR(RunGraphTransformsForGpuModel(&graph));
746
747 for (auto precision : env->GetSupportedPrecisions()) {
748 auto data_type = DeduceDataTypeFromPrecision(precision);
749 for (auto storage : env->GetSupportedStorages(data_type)) {
750 CreateGpuModelInfo create_info;
751 create_info.precision = precision;
752 create_info.storage_type = storage;
753 create_info.hints.Add(ModelHints::kAllowSpecialKernels);
754
755 GpuModel gpu_model;
756 RETURN_IF_ERROR(
757 GraphToGpuModel(graph, create_info, env->GetGpuInfo(), &gpu_model));
758
759 if (gpu_model.nodes.size() != 1) {
760 return absl::InternalError("Expected model with one node.");
761 }
762
763 TensorFloat32 src_tensor;
764 src_tensor.shape = input->tensor.shape;
765 src_tensor.data.resize(src_tensor.shape.DimensionsProduct());
766 for (int i = 0; i < src_tensor.data.size(); ++i) {
767 src_tensor.data[i] = std::sin(i * 0.12345f);
768 }
769
770 TensorFloat32 dst_tensor_v1;
771 RETURN_IF_ERROR(
772 env->ExecuteGpuModel({src_tensor}, {&dst_tensor_v1}, &gpu_model));
773
774 OperationDef op_def;
775 op_def.precision = precision;
776 op_def.src_tensors.push_back({data_type, storage, Layout::HWC});
777 op_def.dst_tensors.push_back({data_type, storage, Layout::HWC});
778
779 ConvGeneric conv_operation =
780 CreateConvGeneric(env->GetGpuInfo(), op_def, conv_attr);
781 TensorFloat32 intermediate0;
782 RETURN_IF_ERROR(env->ExecuteGPUOperation(
783 src_tensor, std::make_unique<ConvGeneric>(std::move(conv_operation)),
784 conv_output->tensor.shape, &intermediate0));
785
786 GPUOperation tanh_operation = CreateElementwiseOneInput(
787 env->GetGpuInfo(), op_def, OperationType::TANH);
788 TensorFloat32 intermediate1;
789 RETURN_IF_ERROR(env->ExecuteGPUOperation(
790 intermediate0,
791 std::make_unique<GPUOperation>(std::move(tanh_operation)),
792 tanh_output->tensor.shape, &intermediate1));
793
794 OperationDef op_def_sub;
795 op_def_sub.precision = precision;
796 op_def_sub.src_tensors.push_back({data_type, storage, Layout::HWC});
797 op_def_sub.src_tensors.push_back({data_type, storage, Layout::HWC});
798 op_def_sub.dst_tensors.push_back({data_type, storage, Layout::HWC});
799 GPUOperation sub_operation = CreateElementwiseTwoInput(
800 op_def_sub, OperationType::SUB, conv_output->tensor.shape);
801 TensorFloat32 dst_tensor_v0;
802 RETURN_IF_ERROR(env->ExecuteGPUOperation(
803 {intermediate1, intermediate0},
804 std::make_unique<GPUOperation>(std::move(sub_operation)),
805 sub_output->tensor.shape, &dst_tensor_v0));
806
807 RETURN_IF_ERROR(
808 PointWiseNear(dst_tensor_v0.data, dst_tensor_v1.data, 0.0f));
809 }
810 }
811 return absl::OkStatus();
812 }
813
TestLinkingConvolutionSecondTanh2InputDiff(TestExecutionEnvironment * env)814 absl::Status TestLinkingConvolutionSecondTanh2InputDiff(
815 TestExecutionEnvironment* env) {
816 GraphFloat32 graph;
817 auto input = graph.NewValue();
818 input->tensor.type = DataType::FLOAT32;
819 input->tensor.shape = BHWC(1, 32, 32, 128);
820
821 auto conv_node = graph.NewNode();
822 conv_node->operation.type =
823 ToString(tflite::gpu::OperationType::CONVOLUTION_2D);
824
825 Convolution2DAttributes conv_attr;
826 conv_attr.padding.prepended = HW(0, 0);
827 conv_attr.padding.appended = HW(0, 0);
828 conv_attr.strides = HW(1, 1);
829 conv_attr.dilations = HW(1, 1);
830 conv_attr.weights.shape = OHWI(16, 1, 1, 128);
831 conv_attr.weights.data.resize(conv_attr.weights.shape.DimensionsProduct());
832 for (int i = 0; i < conv_attr.weights.data.size(); ++i) {
833 conv_attr.weights.data[i] = std::sin(i * 0.12345f);
834 }
835 conv_attr.bias.shape = Linear(16);
836 conv_attr.bias.data.resize(conv_attr.bias.shape.DimensionsProduct());
837 for (int i = 0; i < conv_attr.bias.data.size(); ++i) {
838 conv_attr.bias.data[i] = std::sin(i * 0.12345f);
839 }
840 conv_node->operation.attributes = conv_attr;
841 RETURN_IF_ERROR(graph.AddConsumer(conv_node->id, input->id));
842
843 auto tanh_node = graph.NewNode();
844 tanh_node->operation.type = ToString(OperationType::TANH);
845 tflite::gpu::Value* conv_output = nullptr;
846 RETURN_IF_ERROR(ConnectTwoNodes(&graph, conv_node, tanh_node, &conv_output));
847 conv_output->tensor.type = DataType::FLOAT32;
848 conv_output->tensor.shape = BHWC(1, 32, 32, 16);
849
850 auto sub_node = graph.NewNode();
851 sub_node->operation.type = ToString(OperationType::SUB);
852 auto tanh_output = graph.NewValue();
853 tanh_output->tensor.type = DataType::FLOAT32;
854 tanh_output->tensor.shape = BHWC(1, 32, 32, 16);
855 auto sub_output = graph.NewValue();
856 sub_output->tensor.type = DataType::FLOAT32;
857 sub_output->tensor.shape = BHWC(1, 32, 32, 16);
858 RETURN_IF_ERROR(graph.SetProducer(tanh_node->id, tanh_output->id));
859 RETURN_IF_ERROR(graph.AddConsumer(sub_node->id, conv_output->id));
860 RETURN_IF_ERROR(graph.AddConsumer(sub_node->id, tanh_output->id));
861 RETURN_IF_ERROR(graph.SetProducer(sub_node->id, sub_output->id));
862
863 RETURN_IF_ERROR(RunGraphTransformsForGpuModel(&graph));
864
865 for (auto precision : env->GetSupportedPrecisions()) {
866 auto data_type = DeduceDataTypeFromPrecision(precision);
867 for (auto storage : env->GetSupportedStorages(data_type)) {
868 CreateGpuModelInfo create_info;
869 create_info.precision = precision;
870 create_info.storage_type = storage;
871 create_info.hints.Add(ModelHints::kAllowSpecialKernels);
872
873 GpuModel gpu_model;
874 RETURN_IF_ERROR(
875 GraphToGpuModel(graph, create_info, env->GetGpuInfo(), &gpu_model));
876
877 if (gpu_model.nodes.size() != 1) {
878 return absl::InternalError("Expected model with one node.");
879 }
880
881 TensorFloat32 src_tensor;
882 src_tensor.shape = input->tensor.shape;
883 src_tensor.data.resize(src_tensor.shape.DimensionsProduct());
884 for (int i = 0; i < src_tensor.data.size(); ++i) {
885 src_tensor.data[i] = std::sin(i * 0.12345f);
886 }
887
888 TensorFloat32 dst_tensor_v1;
889 RETURN_IF_ERROR(
890 env->ExecuteGpuModel({src_tensor}, {&dst_tensor_v1}, &gpu_model));
891
892 OperationDef op_def;
893 op_def.precision = precision;
894 op_def.src_tensors.push_back({data_type, storage, Layout::HWC});
895 op_def.dst_tensors.push_back({data_type, storage, Layout::HWC});
896
897 ConvGeneric conv_operation =
898 CreateConvGeneric(env->GetGpuInfo(), op_def, conv_attr);
899 TensorFloat32 intermediate0;
900 RETURN_IF_ERROR(env->ExecuteGPUOperation(
901 src_tensor, std::make_unique<ConvGeneric>(std::move(conv_operation)),
902 conv_output->tensor.shape, &intermediate0));
903
904 GPUOperation tanh_operation = CreateElementwiseOneInput(
905 env->GetGpuInfo(), op_def, OperationType::TANH);
906 TensorFloat32 intermediate1;
907 RETURN_IF_ERROR(env->ExecuteGPUOperation(
908 intermediate0,
909 std::make_unique<GPUOperation>(std::move(tanh_operation)),
910 tanh_output->tensor.shape, &intermediate1));
911
912 OperationDef op_def_sub;
913 op_def_sub.precision = precision;
914 op_def_sub.src_tensors.push_back({data_type, storage, Layout::HWC});
915 op_def_sub.src_tensors.push_back({data_type, storage, Layout::HWC});
916 op_def_sub.dst_tensors.push_back({data_type, storage, Layout::HWC});
917 GPUOperation sub_operation = CreateElementwiseTwoInput(
918 op_def_sub, OperationType::SUB, conv_output->tensor.shape);
919 TensorFloat32 dst_tensor_v0;
920 RETURN_IF_ERROR(env->ExecuteGPUOperation(
921 {intermediate0, intermediate1},
922 std::make_unique<GPUOperation>(std::move(sub_operation)),
923 sub_output->tensor.shape, &dst_tensor_v0));
924
925 RETURN_IF_ERROR(
926 PointWiseNear(dst_tensor_v0.data, dst_tensor_v1.data, 0.0f));
927 }
928 }
929 return absl::OkStatus();
930 }
931
932 // input
933 // |
934 // convolution
935 // / \
936 // tanh cos
937 // \ /
938 // substraction
939 // |
940 // output
TestLinkingConvolutionFirstTanhSecondCos2InputDiff(TestExecutionEnvironment * env)941 absl::Status TestLinkingConvolutionFirstTanhSecondCos2InputDiff(
942 TestExecutionEnvironment* env) {
943 GraphFloat32 graph;
944 auto input = graph.NewValue();
945 input->tensor.type = DataType::FLOAT32;
946 input->tensor.shape = BHWC(1, 32, 32, 128);
947
948 auto conv_node = graph.NewNode();
949 conv_node->operation.type =
950 ToString(tflite::gpu::OperationType::CONVOLUTION_2D);
951
952 Convolution2DAttributes conv_attr;
953 conv_attr.padding.prepended = HW(0, 0);
954 conv_attr.padding.appended = HW(0, 0);
955 conv_attr.strides = HW(1, 1);
956 conv_attr.dilations = HW(1, 1);
957 conv_attr.weights.shape = OHWI(16, 1, 1, 128);
958 conv_attr.weights.data.resize(conv_attr.weights.shape.DimensionsProduct());
959 for (int i = 0; i < conv_attr.weights.data.size(); ++i) {
960 conv_attr.weights.data[i] = std::sin(i * 0.12345f);
961 }
962 conv_attr.bias.shape = Linear(16);
963 conv_attr.bias.data.resize(conv_attr.bias.shape.DimensionsProduct());
964 for (int i = 0; i < conv_attr.bias.data.size(); ++i) {
965 conv_attr.bias.data[i] = std::sin(i * 0.12345f);
966 }
967 conv_node->operation.attributes = conv_attr;
968 RETURN_IF_ERROR(graph.AddConsumer(conv_node->id, input->id));
969
970 auto tanh_node = graph.NewNode();
971 tanh_node->operation.type = ToString(OperationType::TANH);
972 tflite::gpu::Value* conv_output = nullptr;
973 RETURN_IF_ERROR(ConnectTwoNodes(&graph, conv_node, tanh_node, &conv_output));
974 conv_output->tensor.type = DataType::FLOAT32;
975 conv_output->tensor.shape = BHWC(1, 32, 32, 16);
976
977 auto cos_node = graph.NewNode();
978 cos_node->operation.type = ToString(OperationType::COS);
979 auto cos_output = graph.NewValue();
980 cos_output->tensor.type = DataType::FLOAT32;
981 cos_output->tensor.shape = BHWC(1, 32, 32, 16);
982 RETURN_IF_ERROR(graph.AddConsumer(cos_node->id, conv_output->id));
983 RETURN_IF_ERROR(graph.SetProducer(cos_node->id, cos_output->id));
984
985 auto sub_node = graph.NewNode();
986 sub_node->operation.type = ToString(OperationType::SUB);
987 auto tanh_output = graph.NewValue();
988 tanh_output->tensor.type = DataType::FLOAT32;
989 tanh_output->tensor.shape = BHWC(1, 32, 32, 16);
990 auto sub_output = graph.NewValue();
991 sub_output->tensor.type = DataType::FLOAT32;
992 sub_output->tensor.shape = BHWC(1, 32, 32, 16);
993 RETURN_IF_ERROR(graph.SetProducer(tanh_node->id, tanh_output->id));
994 RETURN_IF_ERROR(graph.AddConsumer(sub_node->id, tanh_output->id));
995 RETURN_IF_ERROR(graph.AddConsumer(sub_node->id, cos_output->id));
996 RETURN_IF_ERROR(graph.SetProducer(sub_node->id, sub_output->id));
997
998 RETURN_IF_ERROR(RunGraphTransformsForGpuModel(&graph));
999
1000 for (auto precision : env->GetSupportedPrecisions()) {
1001 auto data_type = DeduceDataTypeFromPrecision(precision);
1002 for (auto storage : env->GetSupportedStorages(data_type)) {
1003 CreateGpuModelInfo create_info;
1004 create_info.precision = precision;
1005 create_info.storage_type = storage;
1006 create_info.hints.Add(ModelHints::kAllowSpecialKernels);
1007
1008 GpuModel gpu_model;
1009 RETURN_IF_ERROR(
1010 GraphToGpuModel(graph, create_info, env->GetGpuInfo(), &gpu_model));
1011
1012 if (gpu_model.nodes.size() != 1) {
1013 return absl::InternalError("Expected model with one node.");
1014 }
1015
1016 TensorFloat32 src_tensor;
1017 src_tensor.shape = input->tensor.shape;
1018 src_tensor.data.resize(src_tensor.shape.DimensionsProduct());
1019 for (int i = 0; i < src_tensor.data.size(); ++i) {
1020 src_tensor.data[i] = std::sin(i * 0.12345f);
1021 }
1022
1023 TensorFloat32 dst_tensor_v1;
1024 RETURN_IF_ERROR(
1025 env->ExecuteGpuModel({src_tensor}, {&dst_tensor_v1}, &gpu_model));
1026
1027 OperationDef op_def;
1028 op_def.precision = precision;
1029 op_def.src_tensors.push_back({data_type, storage, Layout::HWC});
1030 op_def.dst_tensors.push_back({data_type, storage, Layout::HWC});
1031
1032 ConvGeneric conv_operation =
1033 CreateConvGeneric(env->GetGpuInfo(), op_def, conv_attr);
1034 TensorFloat32 intermediate0;
1035 RETURN_IF_ERROR(env->ExecuteGPUOperation(
1036 src_tensor, std::make_unique<ConvGeneric>(std::move(conv_operation)),
1037 conv_output->tensor.shape, &intermediate0));
1038
1039 GPUOperation tanh_operation = CreateElementwiseOneInput(
1040 env->GetGpuInfo(), op_def, OperationType::TANH);
1041 TensorFloat32 intermediate1;
1042 RETURN_IF_ERROR(env->ExecuteGPUOperation(
1043 intermediate0,
1044 std::make_unique<GPUOperation>(std::move(tanh_operation)),
1045 tanh_output->tensor.shape, &intermediate1));
1046
1047 GPUOperation cos_operation = CreateElementwiseOneInput(
1048 env->GetGpuInfo(), op_def, OperationType::COS);
1049 TensorFloat32 intermediate2;
1050 RETURN_IF_ERROR(env->ExecuteGPUOperation(
1051 intermediate0,
1052 std::make_unique<GPUOperation>(std::move(cos_operation)),
1053 cos_output->tensor.shape, &intermediate2));
1054
1055 OperationDef op_def_sub;
1056 op_def_sub.precision = precision;
1057 op_def_sub.src_tensors.push_back({data_type, storage, Layout::HWC});
1058 op_def_sub.src_tensors.push_back({data_type, storage, Layout::HWC});
1059 op_def_sub.dst_tensors.push_back({data_type, storage, Layout::HWC});
1060 GPUOperation sub_operation = CreateElementwiseTwoInput(
1061 op_def_sub, OperationType::SUB, conv_output->tensor.shape);
1062 TensorFloat32 dst_tensor_v0;
1063 RETURN_IF_ERROR(env->ExecuteGPUOperation(
1064 {intermediate1, intermediate2},
1065 std::make_unique<GPUOperation>(std::move(sub_operation)),
1066 sub_output->tensor.shape, &dst_tensor_v0));
1067
1068 RETURN_IF_ERROR(
1069 PointWiseNear(dst_tensor_v0.data, dst_tensor_v1.data, 0.0f));
1070 }
1071 }
1072 return absl::OkStatus();
1073 }
1074
1075 // input
1076 // |
1077 // convolution
1078 // / \
1079 // tanh cos
1080 // / / \
1081 // | prelu sin
1082 // | \ /
1083 // | pow
1084 // | |
1085 // | exp
1086 // \ |
1087 // substraction
1088 // |
1089 // output
TestLinkingComplex0(TestExecutionEnvironment * env)1090 absl::Status TestLinkingComplex0(TestExecutionEnvironment* env) {
1091 GraphFloat32 graph;
1092 auto input = graph.NewValue();
1093 input->tensor.type = DataType::FLOAT32;
1094 input->tensor.shape = BHWC(1, 32, 32, 128);
1095
1096 auto conv_node = graph.NewNode();
1097 conv_node->operation.type =
1098 ToString(tflite::gpu::OperationType::CONVOLUTION_2D);
1099
1100 Convolution2DAttributes conv_attr;
1101 conv_attr.padding.prepended = HW(0, 0);
1102 conv_attr.padding.appended = HW(0, 0);
1103 conv_attr.strides = HW(1, 1);
1104 conv_attr.dilations = HW(1, 1);
1105 conv_attr.weights.shape = OHWI(16, 1, 1, 128);
1106 conv_attr.weights.data.resize(conv_attr.weights.shape.DimensionsProduct());
1107 for (int i = 0; i < conv_attr.weights.data.size(); ++i) {
1108 conv_attr.weights.data[i] = std::sin(i * 0.12345f);
1109 }
1110 conv_attr.bias.shape = Linear(16);
1111 conv_attr.bias.data.resize(conv_attr.bias.shape.DimensionsProduct());
1112 for (int i = 0; i < conv_attr.bias.data.size(); ++i) {
1113 conv_attr.bias.data[i] = std::sin(i * 0.12345f);
1114 }
1115 conv_node->operation.attributes = conv_attr;
1116 auto conv_output = graph.NewValue();
1117 conv_output->tensor.type = DataType::FLOAT32;
1118 conv_output->tensor.shape = BHWC(1, 32, 32, 16);
1119 RETURN_IF_ERROR(graph.AddConsumer(conv_node->id, input->id));
1120 RETURN_IF_ERROR(graph.SetProducer(conv_node->id, conv_output->id));
1121
1122 auto tanh_node = graph.NewNode();
1123 tanh_node->operation.type = ToString(OperationType::TANH);
1124 auto tanh_output = graph.NewValue();
1125 tanh_output->tensor.type = DataType::FLOAT32;
1126 tanh_output->tensor.shape = BHWC(1, 32, 32, 16);
1127 RETURN_IF_ERROR(graph.AddConsumer(tanh_node->id, conv_output->id));
1128 RETURN_IF_ERROR(graph.SetProducer(tanh_node->id, tanh_output->id));
1129
1130 auto cos_node = graph.NewNode();
1131 cos_node->operation.type = ToString(OperationType::COS);
1132 auto cos_output = graph.NewValue();
1133 cos_output->tensor.type = DataType::FLOAT32;
1134 cos_output->tensor.shape = BHWC(1, 32, 32, 16);
1135 RETURN_IF_ERROR(graph.AddConsumer(cos_node->id, conv_output->id));
1136 RETURN_IF_ERROR(graph.SetProducer(cos_node->id, cos_output->id));
1137
1138 auto prelu_node = graph.NewNode();
1139 prelu_node->operation.type = ToString(OperationType::PRELU);
1140 PReLUAttributes prelu_attr;
1141 tflite::gpu::Tensor<Linear, DataType::FLOAT32> parameters;
1142 parameters.shape = Linear(16);
1143 parameters.data.resize(parameters.shape.DimensionsProduct());
1144 for (int i = 0; i < parameters.data.size(); ++i) {
1145 parameters.data[i] = std::sin(i * 0.5f);
1146 }
1147 prelu_attr.alpha = parameters;
1148 prelu_node->operation.attributes = prelu_attr;
1149 auto prelu_output = graph.NewValue();
1150 prelu_output->tensor.type = DataType::FLOAT32;
1151 prelu_output->tensor.shape = BHWC(1, 32, 32, 16);
1152 RETURN_IF_ERROR(graph.AddConsumer(prelu_node->id, cos_output->id));
1153 RETURN_IF_ERROR(graph.SetProducer(prelu_node->id, prelu_output->id));
1154
1155 auto sin_node = graph.NewNode();
1156 sin_node->operation.type = ToString(OperationType::SIN);
1157 auto sin_output = graph.NewValue();
1158 sin_output->tensor.type = DataType::FLOAT32;
1159 sin_output->tensor.shape = BHWC(1, 32, 32, 16);
1160 RETURN_IF_ERROR(graph.AddConsumer(sin_node->id, cos_output->id));
1161 RETURN_IF_ERROR(graph.SetProducer(sin_node->id, sin_output->id));
1162
1163 auto pow_node = graph.NewNode();
1164 pow_node->operation.type = ToString(OperationType::POW);
1165 auto pow_output = graph.NewValue();
1166 pow_output->tensor.type = DataType::FLOAT32;
1167 pow_output->tensor.shape = BHWC(1, 32, 32, 16);
1168 RETURN_IF_ERROR(graph.AddConsumer(pow_node->id, prelu_output->id));
1169 RETURN_IF_ERROR(graph.AddConsumer(pow_node->id, sin_output->id));
1170 RETURN_IF_ERROR(graph.SetProducer(pow_node->id, pow_output->id));
1171
1172 auto exp_node = graph.NewNode();
1173 exp_node->operation.type = ToString(OperationType::EXP);
1174 auto exp_output = graph.NewValue();
1175 exp_output->tensor.type = DataType::FLOAT32;
1176 exp_output->tensor.shape = BHWC(1, 32, 32, 16);
1177 RETURN_IF_ERROR(graph.AddConsumer(exp_node->id, pow_output->id));
1178 RETURN_IF_ERROR(graph.SetProducer(exp_node->id, exp_output->id));
1179
1180 auto sub_node = graph.NewNode();
1181 sub_node->operation.type = ToString(OperationType::SUB);
1182 auto sub_output = graph.NewValue();
1183 sub_output->tensor.type = DataType::FLOAT32;
1184 sub_output->tensor.shape = BHWC(1, 32, 32, 16);
1185 RETURN_IF_ERROR(graph.AddConsumer(sub_node->id, tanh_output->id));
1186 RETURN_IF_ERROR(graph.AddConsumer(sub_node->id, exp_output->id));
1187 RETURN_IF_ERROR(graph.SetProducer(sub_node->id, sub_output->id));
1188
1189 RETURN_IF_ERROR(RunGraphTransformsForGpuModel(&graph));
1190
1191 for (auto precision : env->GetSupportedPrecisions()) {
1192 auto data_type = DeduceDataTypeFromPrecision(precision);
1193 for (auto storage : env->GetSupportedStorages(data_type)) {
1194 CreateGpuModelInfo create_info;
1195 create_info.precision = precision;
1196 create_info.storage_type = storage;
1197 create_info.hints.Add(ModelHints::kAllowSpecialKernels);
1198
1199 GpuModel gpu_model;
1200 RETURN_IF_ERROR(
1201 GraphToGpuModel(graph, create_info, env->GetGpuInfo(), &gpu_model));
1202
1203 if (gpu_model.nodes.size() != 1) {
1204 return absl::InternalError("Expected model with one node.");
1205 }
1206
1207 TensorFloat32 src_tensor;
1208 src_tensor.shape = input->tensor.shape;
1209 src_tensor.data.resize(src_tensor.shape.DimensionsProduct());
1210 for (int i = 0; i < src_tensor.data.size(); ++i) {
1211 src_tensor.data[i] = std::sin(i * 0.12345f);
1212 }
1213
1214 TensorFloat32 dst_tensor_v1;
1215 RETURN_IF_ERROR(
1216 env->ExecuteGpuModel({src_tensor}, {&dst_tensor_v1}, &gpu_model));
1217
1218 OperationDef op_def;
1219 op_def.precision = precision;
1220 op_def.src_tensors.push_back({data_type, storage, Layout::HWC});
1221 op_def.dst_tensors.push_back({data_type, storage, Layout::HWC});
1222
1223 OperationDef op_def_two_input;
1224 op_def_two_input.precision = precision;
1225 op_def_two_input.src_tensors.push_back({data_type, storage, Layout::HWC});
1226 op_def_two_input.src_tensors.push_back({data_type, storage, Layout::HWC});
1227 op_def_two_input.dst_tensors.push_back({data_type, storage, Layout::HWC});
1228
1229 ConvGeneric conv_operation =
1230 CreateConvGeneric(env->GetGpuInfo(), op_def, conv_attr);
1231 TensorFloat32 intermediate0;
1232 RETURN_IF_ERROR(env->ExecuteGPUOperation(
1233 src_tensor, std::make_unique<ConvGeneric>(std::move(conv_operation)),
1234 conv_output->tensor.shape, &intermediate0));
1235
1236 GPUOperation tanh_operation = CreateElementwiseOneInput(
1237 env->GetGpuInfo(), op_def, OperationType::TANH);
1238 TensorFloat32 intermediate1;
1239 RETURN_IF_ERROR(env->ExecuteGPUOperation(
1240 intermediate0,
1241 std::make_unique<GPUOperation>(std::move(tanh_operation)),
1242 tanh_output->tensor.shape, &intermediate1));
1243
1244 GPUOperation cos_operation = CreateElementwiseOneInput(
1245 env->GetGpuInfo(), op_def, OperationType::COS);
1246 TensorFloat32 intermediate2;
1247 RETURN_IF_ERROR(env->ExecuteGPUOperation(
1248 intermediate0,
1249 std::make_unique<GPUOperation>(std::move(cos_operation)),
1250 cos_output->tensor.shape, &intermediate2));
1251
1252 GPUOperation prelu_operation =
1253 CreatePReLU(env->GetGpuInfo(), op_def, prelu_attr);
1254 TensorFloat32 intermediate3;
1255 RETURN_IF_ERROR(env->ExecuteGPUOperation(
1256 intermediate2,
1257 std::make_unique<GPUOperation>(std::move(prelu_operation)),
1258 prelu_output->tensor.shape, &intermediate3));
1259
1260 GPUOperation sin_operation = CreateElementwiseOneInput(
1261 env->GetGpuInfo(), op_def, OperationType::SIN);
1262 TensorFloat32 intermediate4;
1263 RETURN_IF_ERROR(env->ExecuteGPUOperation(
1264 intermediate2,
1265 std::make_unique<GPUOperation>(std::move(sin_operation)),
1266 sin_output->tensor.shape, &intermediate4));
1267
1268 GPUOperation pow_operation = CreateElementwiseTwoInput(
1269 op_def_two_input, OperationType::POW, sin_output->tensor.shape);
1270 TensorFloat32 intermediate5;
1271 RETURN_IF_ERROR(env->ExecuteGPUOperation(
1272 {intermediate3, intermediate4},
1273 std::make_unique<GPUOperation>(std::move(pow_operation)),
1274 pow_output->tensor.shape, &intermediate5));
1275
1276 GPUOperation exp_operation = CreateElementwiseOneInput(
1277 env->GetGpuInfo(), op_def, OperationType::EXP);
1278 TensorFloat32 intermediate6;
1279 RETURN_IF_ERROR(env->ExecuteGPUOperation(
1280 intermediate5,
1281 std::make_unique<GPUOperation>(std::move(exp_operation)),
1282 exp_output->tensor.shape, &intermediate6));
1283
1284 GPUOperation sub_operation = CreateElementwiseTwoInput(
1285 op_def_two_input, OperationType::SUB, conv_output->tensor.shape);
1286 TensorFloat32 dst_tensor_v0;
1287 RETURN_IF_ERROR(env->ExecuteGPUOperation(
1288 {intermediate1, intermediate6},
1289 std::make_unique<GPUOperation>(std::move(sub_operation)),
1290 sub_output->tensor.shape, &dst_tensor_v0));
1291
1292 RETURN_IF_ERROR(
1293 PointWiseNear(dst_tensor_v0.data, dst_tensor_v1.data, 0.0f));
1294 }
1295 }
1296 return absl::OkStatus();
1297 }
1298
1299 } // namespace gpu
1300 } // namespace tflite
1301