xref: /aosp_15_r20/external/tensorflow/tensorflow/lite/delegates/gpu/common/gpu_model_test_util.cc (revision b6fb3261f9314811a0f4371741dbb8839866f948)
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