blob: c66d64ed6d83ca51a6b9516e1be893ce31093224 [file] [log] [blame]
Eric Kunzee5e26762020-10-13 16:11:07 -07001
Kevin Cheng3a478572021-01-22 17:21:02 -08002// Copyright (c) 2020-2021, ARM Limited.
Eric Kunzee5e26762020-10-13 16:11:07 -07003//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16#include "data_layout.h"
17#include "quant_util.h"
18
19using namespace TosaReference;
20using namespace Eigen;
21using namespace tosa;
22
23template <int Rank, DType Dtype>
24OpConcat<Rank, Dtype>::OpConcat(TosaAttributeBase* attribute_, TosaQuantInfoBase* qinfo_, uint64_t id_)
25 : GraphNode(Op_CONCAT, id_)
26{
Kevin Chengad15dfa2021-03-04 15:15:03 -080027 setRequiredOperands(-1, 1);
Eric Kunzee5e26762020-10-13 16:11:07 -070028 setRequiredRank(1, 6);
29
30 INIT_ATTRIBUTE(Axis);
31}
32
33template <int Rank, DType Dtype>
34OpConcat<Rank, Dtype>::~OpConcat()
35{
36 if (attribute)
37 delete attribute;
38}
39
40template <int Rank, DType Dtype>
41int OpConcat<Rank, Dtype>::checkTensorAttributes()
42{
43 if (validateRequiredOperands())
44 return 1;
45
Kevin Chengad15dfa2021-03-04 15:15:03 -080046 if (inputs.empty())
Eric Kunzee5e26762020-10-13 16:11:07 -070047 {
Kevin Chengad15dfa2021-03-04 15:15:03 -080048 printNodeValidationError("Concat operator must have at least one input tensor");
Eric Kunzee5e26762020-10-13 16:11:07 -070049 return 1;
50 }
Eric Kunzee5e26762020-10-13 16:11:07 -070051 // output and input must be the same types and rank
Kevin Chengad15dfa2021-03-04 15:15:03 -080052 for (size_t i = 0; i < inputs.size(); i++)
Eric Kunzee5e26762020-10-13 16:11:07 -070053 {
Kevin Chengad15dfa2021-03-04 15:15:03 -080054 if (inputs[i]->matchRankType(*outputs[0]))
55 {
56 printNodeValidationError("Concat operator input ranks and types must match");
57 return 1;
58 }
59 ins.push_back(dynamic_cast<TosaReference::TensorTemplate<TIn>*>(inputs[i]));
Eric Kunzee5e26762020-10-13 16:11:07 -070060 }
61
Eric Kunzee5e26762020-10-13 16:11:07 -070062 out = dynamic_cast<TosaReference::TensorTemplate<TOut>*>(outputs[0]);
63
Kevin Chengad15dfa2021-03-04 15:15:03 -080064 if (attribute->axis() < 0 || (size_t)attribute->axis() >= inputs[0]->getShape().size())
Eric Kunzee5e26762020-10-13 16:11:07 -070065 {
66 printNodeValidationError("Axis is beyond input tensor rank");
67 return 1;
68 }
69
70 return 0;
71}
72
73template <int Rank, DType Dtype>
74int OpConcat<Rank, Dtype>::eval()
75{
76
77 int32_t reversed_axis = Rank - 1 - attribute->axis();
78
79 for (int32_t d = 0; d < Rank; d++)
80 {
81 reverser[d] = Rank - 1 - d;
82 }
83
Kevin Chengad15dfa2021-03-04 15:15:03 -080084 TIn result = ins[0]->getTensor().shuffle(reverser);
Eric Kunzee5e26762020-10-13 16:11:07 -070085
Kevin Chengad15dfa2021-03-04 15:15:03 -080086 for (size_t i = 1; i < ins.size(); i++)
87 {
88 TIn in_reversed = ins[i]->getTensor().shuffle(reverser);
89 TIn temp = result.concatenate(in_reversed, reversed_axis);
90 result = temp;
91 }
92 out->getTensor() = result.shuffle(reverser);
Eric Kunzee5e26762020-10-13 16:11:07 -070093
94 return GraphNode::eval();
95}
96
97template <int Rank, DType Dtype>
98OpPad<Rank, Dtype>::OpPad(TosaAttributeBase* attribute_, TosaQuantInfoBase* qinfo_, uint64_t id_)
99 : GraphNode(Op_PAD, id_)
100{
101 setRequiredOperands(2, 1);
102 setRequiredRank(0, 6);
103
104 INIT_QINFO(Pad);
105}
106
107template <int Rank, DType Dtype>
108OpPad<Rank, Dtype>::~OpPad()
109{
110 if (qinfo)
111 delete qinfo;
112}
113
114template <int Rank, DType Dtype>
115int OpPad<Rank, Dtype>::checkTensorAttributes()
116{
117 if (validateRequiredOperands())
118 return 1;
119
120 if (validateRequiredRank(inputs[0]) || validateRequiredRank(outputs[0]))
121 {
122 return 1;
123 }
124
125 // output and input must be the same types
126 if (inputs[0]->matchRankType(*outputs[0]))
127 {
128 printNodeValidationError("Failure to match input and output type and rank");
129 return 1;
130 }
131
132 in = dynamic_cast<TosaReference::TensorTemplate<TIn>*>(inputs[0]);
133 out = dynamic_cast<TosaReference::TensorTemplate<TOut>*>(outputs[0]);
134 TosaReference::TensorTemplate<ETensor2<int32_t>>* paddings =
135 dynamic_cast<TosaReference::TensorTemplate<ETensor2<int32_t>>*>(inputs[1]);
136
137 for (int i = 0; i < Rank; i++)
138 {
139 paddings_array[i] = std::make_pair(paddings->getTensor()(i, 0), paddings->getTensor()(i, 1));
140 }
141
142 return 0;
143}
144
145template <int Rank, DType Dtype>
146int OpPad<Rank, Dtype>::eval()
147{
148 InEigenType pad_value = 0;
149 if (this->qinfo)
150 {
151 pad_value = (InEigenType)this->qinfo->input_zp();
152 }
153
154 this->out->getTensor() = this->in->getTensor().pad(this->paddings_array, pad_value);
155
156 return GraphNode::eval();
157}
158
159template <int InRank, int OutRank, DType Dtype>
160OpReshape<InRank, OutRank, Dtype>::OpReshape(TosaAttributeBase* attribute_, TosaQuantInfoBase* qinfo_, uint64_t id_)
161 : GraphNode(Op_RESHAPE, id_)
162{
163 setRequiredOperands(1, 1);
164 setRequiredRank(0, 6);
165
166 INIT_ATTRIBUTE(Reshape);
167}
168
169template <int InRank, int OutRank, DType Dtype>
170OpReshape<InRank, OutRank, Dtype>::~OpReshape()
171{
172 if (attribute)
173 delete attribute;
174}
175
176template <int InRank, int OutRank, DType Dtype>
177int OpReshape<InRank, OutRank, Dtype>::checkTensorAttributes()
178{
179 uint32_t minusOneCount = 0;
180
181 if (validateRequiredOperands())
182 return 1;
183
184 if (validateRequiredRank(inputs[0]) || validateRequiredRank(outputs[0]))
185 {
186 return 1;
187 }
188
189 // output and input must be the same types
190 if (inputs[0]->matchType(*outputs[0]))
191 {
192 printNodeValidationError("OpReshape: Input and output types must match");
193 return 1;
194 }
195
196 for (uint32_t d = 0; d < OutRank; d++)
197 {
198 if (attribute->shape()[d] == -1)
199 {
200 minusOneCount++;
201 }
202 }
203
204 if (minusOneCount > 1)
205 {
206 printNodeValidationError("OpReshape: new shape has more than one -1 dimension");
207 return 1;
208 }
209
210 in = dynamic_cast<TosaReference::TensorTemplate<TIn>*>(inputs[0]);
211 out = dynamic_cast<TosaReference::TensorTemplate<TOut>*>(outputs[0]);
212
213 return 0;
214}
215
216template <int InRank, int OutRank, DType Dtype>
217int OpReshape<InRank, OutRank, Dtype>::eval()
218{
219 uint32_t remainingSize = in->getElementCount();
220
221 // If there is a -1 dimension, find the remainder in one pass over the output shape
222 for (int32_t d = 0; d < OutRank; d++)
223 {
224 if (attribute->shape()[d] != -1)
225 {
226 remainingSize = remainingSize / attribute->shape()[d];
227 }
228 }
229
230 for (int32_t d = 0; d < OutRank; d++)
231 {
232 array_shape[d] = attribute->shape()[OutRank - 1 - d];
233 out_reverser[d] = OutRank - 1 - d;
234
235 // Jam in the remainder here
236 if (array_shape[d] == -1)
237 {
238 array_shape[d] = remainingSize;
239 }
240 }
241
242 for (int32_t d = 0; d < InRank; d++)
243 {
244 in_reverser[d] = InRank - 1 - d;
245 }
246
247 // Eigen Tensor is col-major, and we're referencing row-major result
248 // need to reverse it to row-major before reshape, and perform another reverse afterward
249
250 // input tensor rank 0 can't do .shuffle(), need to be handled otherwise
251 TIn in_reversed;
252 if (InRank > 1)
253 {
254 in_reversed = in->getTensor().shuffle(in_reverser);
255 }
256 else
257 {
258 in_reversed = in->getTensor();
259 }
260
261 TOut in_reshaped = in_reversed.reshape(array_shape);
262
263 // output tensor can be rank 0, .reshape() and .shuffle() don't work, need to be handled otherwise
264 if (OutRank > 1)
265 {
266 out->getTensor() = in_reshaped.shuffle(out_reverser);
267 }
268 else
269 {
270 out->getTensor() = in_reshaped;
271 }
272
273 return GraphNode::eval();
274}
275
276template <int Rank, DType Dtype>
277OpReverse<Rank, Dtype>::OpReverse(TosaAttributeBase* attribute_, TosaQuantInfoBase* qinfo_, uint64_t id_)
278 : GraphNode(Op_REVERSE, id_)
279{
280 setRequiredOperands(1, 1);
281 setRequiredRank(1, 6);
282
283 INIT_ATTRIBUTE(Axis);
284}
285
286template <int Rank, DType Dtype>
287OpReverse<Rank, Dtype>::~OpReverse()
288{
289 if (attribute)
290 delete attribute;
291}
292
293template <int Rank, DType Dtype>
294int OpReverse<Rank, Dtype>::checkTensorAttributes()
295{
296 if (validateRequiredOperands())
297 return 1;
298
299 if (validateRequiredRank(inputs[0]) || validateRequiredRank(outputs[0]))
300 {
301 return 1;
302 }
303
304 // output and input must be the same types
305 if (inputs[0]->matchRankTypeShape(*outputs[0]))
306 {
307 printNodeValidationError("Failure to match input and output rank/type/shape");
308 return 1;
309 }
310
311 in = dynamic_cast<TosaReference::TensorTemplate<TIn>*>(inputs[0]);
312 out = dynamic_cast<TosaReference::TensorTemplate<TOut>*>(outputs[0]);
313
314 ASSERT_MEM(in && out);
315
316 if (attribute->axis() < 0 || attribute->axis() >= inputs[0]->getRank())
317 {
318 printNodeValidationError("Reverse axis must between [0, input_rank - 1]");
319 return 1;
320 }
321
322 // transform list of axis into true or false list
323 // e.g. rank=4, axis=[1,2], reverse array would be [false, true, true, false]
324 for (int i = 0; i < Rank; i++)
325 {
326 reverse_array[i] = false;
327 }
328 reverse_array[attribute->axis()] = true;
329
330 return 0;
331}
332
333template <int Rank, DType Dtype>
334int OpReverse<Rank, Dtype>::eval()
335{
336 out->getTensor() = in->getTensor().reverse(reverse_array);
337
338 return GraphNode::eval();
339}
340
341template <int Rank, DType Dtype>
342OpSlice<Rank, Dtype>::OpSlice(TosaAttributeBase* attribute_, TosaQuantInfoBase* qinfo_, uint64_t id_)
343 : GraphNode(Op_SLICE, id_)
344{
345 setRequiredOperands(1, 1);
346 setRequiredRank(0, 6);
347
348 INIT_ATTRIBUTE(Slice);
349}
350
351template <int Rank, DType Dtype>
352OpSlice<Rank, Dtype>::~OpSlice()
353{
354 if (attribute)
355 delete attribute;
356}
357
358template <int Rank, DType Dtype>
359int OpSlice<Rank, Dtype>::checkTensorAttributes()
360{
361 if (validateRequiredOperands())
362 return 1;
363
364 if (validateRequiredRank(inputs[0]) || validateRequiredRank(outputs[0]))
365 {
366 return 1;
367 }
368
369 // output and input must be the same types
370 if (inputs[0]->matchType(*outputs[0]))
371 {
372 printNodeValidationError("Failure to match input and output type");
373 return 1;
374 }
375
376 in = dynamic_cast<TosaReference::TensorTemplate<TIn>*>(inputs[0]);
377 out = dynamic_cast<TosaReference::TensorTemplate<TOut>*>(outputs[0]);
378
379 for (size_t i = 0; i < attribute->begin().size(); i++)
380 {
381 begin_array[i] = attribute->begin()[i];
382 }
383
384 for (size_t i = 0; i < attribute->size().size(); i++)
385 {
386 if (attribute->size()[i] != 0)
387 {
388 size_array[i] = attribute->size()[i];
389 }
390 else
391 {
392 // Tensorflow assigns a zero size to dimensions that are kept
393 // Eigen expects size to be the full size of the dimension
394 size_array[i] = in->getTensor().dimension(0);
395 }
396 }
397
398 return 0;
399}
400
401template <int Rank, DType Dtype>
402int OpSlice<Rank, Dtype>::eval()
403{
404 out->getTensor() = in->getTensor().slice(begin_array, size_array);
405
406 return GraphNode::eval();
407}
408
409template <int Rank, DType Dtype>
410OpTileBase<Rank, Dtype>::OpTileBase(TosaAttributeBase* attribute_, TosaQuantInfoBase* qinfo_, uint64_t id_)
411 : GraphNode(Op_TILE, id_)
412{
413 setRequiredOperands(1, 1);
414 setRequiredRank(0, 6);
415
416 INIT_ATTRIBUTE(Tile);
417}
418
419template <int Rank, DType Dtype>
420OpTileBase<Rank, Dtype>::~OpTileBase()
421{
422 if (attribute)
423 delete attribute;
424}
425
426template <int Rank, DType Dtype>
427int OpTileBase<Rank, Dtype>::checkTensorAttributes()
428{
429 if (validateRequiredOperands())
430 return 1;
431
432 if (validateRequiredRank(inputs[0]) || validateRequiredRank(outputs[0]))
433 {
434 return 1;
435 }
436
437 // output and input must be the same ranks and types
438 if (inputs[0]->matchRankType(*outputs[0]))
439 {
440 printNodeValidationError("Failure to match input and output rank or type");
441 return 1;
442 }
443
444 in = dynamic_cast<TosaReference::TensorTemplate<TIn>*>(inputs[0]);
445 out = dynamic_cast<TosaReference::TensorTemplate<TOut>*>(outputs[0]);
446
447 if (attribute->multiples().size() != Rank)
448 {
449 printNodeValidationError("1D list 'multiples' must have size equal to input rank");
450 return 1;
451 }
452
453 for (int32_t d = 0; d < Rank; d++)
454 {
455 if (in->getShape()[d] * attribute->multiples()[d] != out->getShape()[d])
456 {
457 printNodeValidationError("unexpected output shape");
458 return 1;
459 }
460 }
461
462 return 0;
463}
464
465template <int Rank, DType Dtype>
466int OpTile<Rank, Dtype>::eval()
467{
468 // primary template shouldn't be called
469 FATAL_ERROR_NODE("OpTile rank=%i, dtype=%s: not implemented yet", Rank, EnumNamesDType()[Dtype]);
470}
471
472template <DType Dtype>
473int OpTile<1, Dtype>::eval()
474{
475 for (int32_t od0 = 0; od0 < this->out->getShape()[0]; od0++)
476 {
477 int32_t id0 = od0 % this->in->getShape()[0];
478 this->out->getTensor()(od0) = this->in->getTensor()(id0);
479 }
480
481 return GraphNode::eval();
482}
483
484template <DType Dtype>
485int OpTile<2, Dtype>::eval()
486{
487 for (int32_t od0 = 0; od0 < this->out->getShape()[0]; od0++)
488 {
489 int32_t id0 = od0 % this->in->getShape()[0];
490 for (int32_t od1 = 0; od1 < this->out->getShape()[1]; od1++)
491 {
492 int32_t id1 = od1 % this->in->getShape()[1];
493 this->out->getTensor()(od0, od1) = this->in->getTensor()(id0, id1);
494 }
495 }
496
497 return GraphNode::eval();
498}
499
500template <DType Dtype>
501int OpTile<3, Dtype>::eval()
502{
503 for (int32_t od0 = 0; od0 < this->out->getShape()[0]; od0++)
504 {
505 int32_t id0 = od0 % this->in->getShape()[0];
506 for (int32_t od1 = 0; od1 < this->out->getShape()[1]; od1++)
507 {
508 int32_t id1 = od1 % this->in->getShape()[1];
509 for (int32_t od2 = 0; od2 < this->out->getShape()[2]; od2++)
510 {
511 int32_t id2 = od2 % this->in->getShape()[2];
512 this->out->getTensor()(od0, od1, od2) = this->in->getTensor()(id0, id1, id2);
513 }
514 }
515 }
516
517 return GraphNode::eval();
518}
519
520template <DType Dtype>
521int OpTile<4, Dtype>::eval()
522{
523 for (int32_t od0 = 0; od0 < this->out->getShape()[0]; od0++)
524 {
525 int32_t id0 = od0 % this->in->getShape()[0];
526 for (int32_t od1 = 0; od1 < this->out->getShape()[1]; od1++)
527 {
528 int32_t id1 = od1 % this->in->getShape()[1];
529 for (int32_t od2 = 0; od2 < this->out->getShape()[2]; od2++)
530 {
531 int32_t id2 = od2 % this->in->getShape()[2];
532 for (int32_t od3 = 0; od3 < this->out->getShape()[3]; od3++)
533 {
534 int32_t id3 = od3 % this->in->getShape()[3];
535 this->out->getTensor()(od0, od1, od2, od3) = this->in->getTensor()(id0, id1, id2, id3);
536 }
537 }
538 }
539 }
540
541 return GraphNode::eval();
542}
543
544template <int Rank, DType Dtype>
545OpTranspose<Rank, Dtype>::OpTranspose(TosaAttributeBase* attribute_, TosaQuantInfoBase* qinfo_, uint64_t id_)
546 : GraphNode(Op_TRANSPOSE, id_)
547{
548 setRequiredOperands(2, 1);
549 setRequiredRank(0, 6);
550}
551
552template <int Rank, DType Dtype>
553OpTranspose<Rank, Dtype>::~OpTranspose()
554{}
555
556template <int Rank, DType Dtype>
557int OpTranspose<Rank, Dtype>::checkTensorAttributes()
558{
559 if (validateRequiredOperands())
560 return 1;
561
562 if (validateRequiredRank(inputs[0]) || validateRequiredRank(outputs[0]))
563 {
564 return 1;
565 }
566
567 // output and input must be the same types
568 if (inputs[0]->matchRankType(*outputs[0]))
569 {
570 printNodeValidationError("Failure to match input and output rank and type");
571 return 1;
572 }
573
574 if (inputs[0]->getElementCount() != outputs[0]->getElementCount())
575 {
576 printNodeValidationError("Failure to match input and output total element count");
577 return 1;
578 }
579
580 in = dynamic_cast<TosaReference::TensorTemplate<TIn>*>(inputs[0]);
581 out = dynamic_cast<TosaReference::TensorTemplate<TOut>*>(outputs[0]);
582 perm_tensor = dynamic_cast<TosaReference::TensorTemplate<ETensor1<int32_t>>*>(inputs[1]);
583
584 return 0;
585}
586
587template <int Rank, DType Dtype>
588int OpTranspose<Rank, Dtype>::eval()
589{
590 for (int32_t d = 0; d < Rank; d++)
591 {
592 perm_array[d] = this->perm_tensor->getTensor().data()[d];
593 }
594
595 out->getTensor() = in->getTensor().shuffle(perm_array);
596
597 return GraphNode::eval();
598}
599
600// template explicit instantiation
601DEF_INSTANTIATE_RANK1_6_ONE_RANK_ONE_TYPE(OpConcat, FLOAT)
Eric Kunzee5e26762020-10-13 16:11:07 -0700602DEF_INSTANTIATE_RANK1_6_ONE_RANK_ONE_TYPE(OpConcat, INT8)
603DEF_INSTANTIATE_RANK1_6_ONE_RANK_ONE_TYPE(OpConcat, INT16)
604DEF_INSTANTIATE_RANK1_6_ONE_RANK_ONE_TYPE(OpConcat, INT32)
605DEF_INSTANTIATE_RANK1_6_ONE_RANK_ONE_TYPE(OpConcat, BOOL)
606
607DEF_INSTANTIATE_RANK1_6_ONE_RANK_ONE_TYPE(OpPad, FLOAT);
Eric Kunzee5e26762020-10-13 16:11:07 -0700608DEF_INSTANTIATE_RANK1_6_ONE_RANK_ONE_TYPE(OpPad, INT8);
609DEF_INSTANTIATE_RANK1_6_ONE_RANK_ONE_TYPE(OpPad, INT16);
610DEF_INSTANTIATE_RANK1_6_ONE_RANK_ONE_TYPE(OpPad, INT32);
611DEF_INSTANTIATE_RANK1_6_ONE_RANK_ONE_TYPE(OpPad, BOOL);
612
613DEF_INSTANTIATE_RESHAPE(OpReshape, FLOAT);
Eric Kunzee5e26762020-10-13 16:11:07 -0700614DEF_INSTANTIATE_RESHAPE(OpReshape, INT8);
615DEF_INSTANTIATE_RESHAPE(OpReshape, INT16);
616DEF_INSTANTIATE_RESHAPE(OpReshape, INT32);
617DEF_INSTANTIATE_RESHAPE(OpReshape, BOOL);
618
619DEF_INSTANTIATE_RANK1_6_ONE_RANK_ONE_TYPE(OpReverse, FLOAT);
Eric Kunzee5e26762020-10-13 16:11:07 -0700620DEF_INSTANTIATE_RANK1_6_ONE_RANK_ONE_TYPE(OpReverse, INT8);
621DEF_INSTANTIATE_RANK1_6_ONE_RANK_ONE_TYPE(OpReverse, INT16);
622DEF_INSTANTIATE_RANK1_6_ONE_RANK_ONE_TYPE(OpReverse, INT32);
623DEF_INSTANTIATE_RANK1_6_ONE_RANK_ONE_TYPE(OpReverse, BOOL);
624
625DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpSlice, FLOAT);
Eric Kunzee5e26762020-10-13 16:11:07 -0700626DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpSlice, INT8);
627DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpSlice, INT16);
628DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpSlice, INT32);
629DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpSlice, BOOL);
630
631DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpTile, FLOAT);
Eric Kunzee5e26762020-10-13 16:11:07 -0700632DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpTile, INT8);
633DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpTile, INT16);
634DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpTile, INT32);
635DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpTile, BOOL);
636
637DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpTranspose, FLOAT);
Eric Kunzee5e26762020-10-13 16:11:07 -0700638DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpTranspose, INT8);
639DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpTranspose, INT16);
640DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpTranspose, INT32);
641DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpTranspose, BOOL);