1/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20/*!
21 * \file unary.cc
22 * \brief Unary operators.
23 */
24#include <tvm/relay/attrs/transform.h>
25#include <tvm/relay/expr.h>
26#include <tvm/relay/op.h>
27#include <tvm/topi/elemwise.h>
28#include <tvm/topi/transform.h>
29
30#include "../make_op.h"
31#include "../op_common.h"
32#include "../type_relations.h"
33
34namespace tvm {
35namespace relay {
36
37#define RELAY_UNARY_COMPUTE(FTOPI) \
38 [](const Attrs& attrs, const Array<te::Tensor>& inputs, \
39 const Type& out_type) -> Array<te::Tensor> { return {FTOPI(inputs[0])}; }
40
41RELAY_REGISTER_UNARY_OP("log")
42 .describe(R"code(Returns the log input array, computed element-wise.
43
44.. math::
45 log(x)
46
47)code" TVM_ADD_FILELINE)
48 .set_support_level(1)
49 .set_attr<FTVMCompute>("FTVMCompute", RELAY_UNARY_COMPUTE(topi::log));
50
51RELAY_REGISTER_UNARY_OP("log2")
52 .describe(R"code(Returns the log to base 2 of input array, computed element-wise.
53
54.. math::
55 log2(x)
56
57)code" TVM_ADD_FILELINE)
58 .set_support_level(1)
59 .set_attr<FTVMCompute>("FTVMCompute", RELAY_UNARY_COMPUTE(topi::log2));
60
61RELAY_REGISTER_UNARY_OP("log10")
62 .describe(R"code(Returns the log to base 10 of input array, computed element-wise.
63
64.. math::
65 log10(x)
66
67)code" TVM_ADD_FILELINE)
68 .set_support_level(1)
69 .set_attr<FTVMCompute>("FTVMCompute", RELAY_UNARY_COMPUTE(topi::log10));
70
71RELAY_REGISTER_UNARY_OP("tan")
72 .describe(R"code(Returns the tan of input array, computed element-wise.
73
74.. math::
75 Y = tan(X)
76
77)code" TVM_ADD_FILELINE)
78 .set_support_level(1)
79 .set_attr<FTVMCompute>("FTVMCompute", RELAY_UNARY_COMPUTE(topi::tan));
80
81RELAY_REGISTER_UNARY_OP("cos")
82 .describe(R"code(Returns the cos of input array, computed element-wise.
83
84.. math::
85 Y = cos(X)
86
87)code" TVM_ADD_FILELINE)
88 .set_support_level(1)
89 .set_attr<FTVMCompute>("FTVMCompute", RELAY_UNARY_COMPUTE(topi::cos));
90
91RELAY_REGISTER_UNARY_OP("cosh")
92 .describe(R"code(Returns the cosh of input array, computed element-wise.
93
94.. math::
95 Y = cosh(X)
96
97)code" TVM_ADD_FILELINE)
98 .set_support_level(1)
99 .set_attr<FTVMCompute>("FTVMCompute", RELAY_UNARY_COMPUTE(topi::cosh));
100
101RELAY_REGISTER_UNARY_OP("sin")
102 .describe(R"code(Returns the sin of input array, computed element-wise.
103
104.. math::
105 Y = sin(X)
106
107)code" TVM_ADD_FILELINE)
108 .set_support_level(1)
109 .set_attr<FTVMCompute>("FTVMCompute", RELAY_UNARY_COMPUTE(topi::sin));
110
111RELAY_REGISTER_UNARY_OP("sinh")
112 .describe(R"code(Returns the sinh of input array, computed element-wise.
113
114.. math::
115 Y = sinh(X)
116
117)code" TVM_ADD_FILELINE)
118 .set_support_level(1)
119 .set_attr<FTVMCompute>("FTVMCompute", RELAY_UNARY_COMPUTE(topi::sinh));
120
121RELAY_REGISTER_UNARY_OP("acos")
122 .describe(R"code(Returns the acos of input array, computed element-wise.
123
124.. math::
125 Y = acos(X)
126
127)code" TVM_ADD_FILELINE)
128 .set_support_level(1)
129 .set_attr<FTVMCompute>("FTVMCompute", RELAY_UNARY_COMPUTE(topi::acos));
130
131RELAY_REGISTER_UNARY_OP("acosh")
132 .describe(R"code(Returns the acosh of input array, computed element-wise.
133
134.. math::
135 Y = acosh(X)
136
137)code" TVM_ADD_FILELINE)
138 .set_support_level(1)
139 .set_attr<FTVMCompute>("FTVMCompute", RELAY_UNARY_COMPUTE(topi::acosh));
140
141RELAY_REGISTER_UNARY_OP("asin")
142 .describe(R"code(Returns the asin of input array, computed element-wise.
143
144.. math::
145 Y = asin(X)
146
147)code" TVM_ADD_FILELINE)
148 .set_support_level(1)
149 .set_attr<FTVMCompute>("FTVMCompute", RELAY_UNARY_COMPUTE(topi::asin));
150
151RELAY_REGISTER_UNARY_OP("asinh")
152 .describe(R"code(Returns the asinh of input array, computed element-wise.
153
154.. math::
155 Y = asinh(X)
156
157)code" TVM_ADD_FILELINE)
158 .set_support_level(1)
159 .set_attr<FTVMCompute>("FTVMCompute", RELAY_UNARY_COMPUTE(topi::asinh));
160
161RELAY_REGISTER_UNARY_OP("atan")
162 .describe(R"code(Returns the atan of input array, computed element-wise.
163
164.. math::
165 Y = atan(X)
166
167)code" TVM_ADD_FILELINE)
168 .set_support_level(1)
169 .set_attr<FTVMCompute>("FTVMCompute", RELAY_UNARY_COMPUTE(topi::atan));
170
171RELAY_REGISTER_UNARY_OP("atanh")
172 .describe(R"code(Returns the atanh of input array, computed element-wise.
173
174.. math::
175 Y = atanh(X)
176
177)code" TVM_ADD_FILELINE)
178 .set_support_level(1)
179 .set_attr<FTVMCompute>("FTVMCompute", RELAY_UNARY_COMPUTE(topi::atanh));
180
181RELAY_REGISTER_UNARY_OP("exp")
182 .describe(R"code(Returns the exp input array, computed element-wise.
183
184.. math::
185 \exp(x)
186
187)code" TVM_ADD_FILELINE)
188 .set_support_level(1)
189 .set_attr<FTVMCompute>("FTVMCompute", RELAY_UNARY_COMPUTE(topi::exp));
190
191RELAY_REGISTER_UNARY_OP("fast_exp")
192 .describe(R"code(Returns the fast_exp input array, computed element-wise.
193
194.. math::
195 \fast_exp(x)
196
197)code" TVM_ADD_FILELINE)
198 .set_support_level(1)
199 .set_attr<FTVMCompute>("FTVMCompute", RELAY_UNARY_COMPUTE(topi::fast_exp));
200
201RELAY_REGISTER_UNARY_OP("erf")
202 .describe(R"code(Returns the error function value for input array, computed element-wise.
203
204.. math::
205 \erf(x)
206
207)code" TVM_ADD_FILELINE)
208 .set_support_level(1)
209 .set_attr<FTVMCompute>("FTVMCompute", RELAY_UNARY_COMPUTE(topi::erf));
210
211RELAY_REGISTER_UNARY_OP("fast_erf")
212 .describe(R"code(Returns the error function value for input array, computed element-wise.
213
214.. math::
215 \fast_erf(x)
216
217)code" TVM_ADD_FILELINE)
218 .set_support_level(1)
219 .set_attr<FTVMCompute>("FTVMCompute", RELAY_UNARY_COMPUTE(topi::fast_erf));
220
221RELAY_REGISTER_UNARY_OP("sqrt")
222 .describe(R"code(Returns the sqrt input array, computed element-wise.
223
224.. math::
225 sqrt(x)
226
227)code" TVM_ADD_FILELINE)
228 .set_support_level(1)
229 .set_attr<FTVMCompute>("FTVMCompute", RELAY_UNARY_COMPUTE(topi::sqrt));
230
231RELAY_REGISTER_UNARY_OP("rsqrt")
232 .describe(R"code(Returns the rsqrt input array, computed element-wise.
233
234.. math::
235 1/sqrt(x)
236
237)code" TVM_ADD_FILELINE)
238 .set_support_level(1)
239 .set_attr<FTVMCompute>("FTVMCompute", RELAY_UNARY_COMPUTE(topi::rsqrt));
240
241RELAY_REGISTER_UNARY_OP("zeros_like")
242 .describe(R"code(Returns an array of zeros, with same type and shape as the input.
243)code" TVM_ADD_FILELINE)
244 .set_support_level(4);
245
246RELAY_REGISTER_UNARY_OP("ones_like")
247 .describe(R"code(Returns an array of ones, with same type and shape as the input.
248)code" TVM_ADD_FILELINE)
249 .set_support_level(4);
250
251RELAY_REGISTER_UNARY_OP("sigmoid")
252 .describe(R"code(Returns the sigmoid input array, computed element-wise.
253
254.. math::
255 sigmoid(x)
256
257)code" TVM_ADD_FILELINE)
258 .set_support_level(1)
259 .set_attr<FTVMCompute>("FTVMCompute", RELAY_UNARY_COMPUTE(topi::sigmoid));
260
261RELAY_REGISTER_UNARY_OP("copy")
262 .describe(R"code(Copy a tensor.
263)code" TVM_ADD_FILELINE)
264 .set_support_level(3)
265 .set_attr<FTVMCompute>("FTVMCompute", RELAY_UNARY_COMPUTE(topi::identity));
266
267// relay.clip
268TVM_REGISTER_NODE_TYPE(ClipAttrs);
269
270Expr MakeClip(Expr a, double a_min, double a_max) {
271 auto attrs = make_object<ClipAttrs>();
272 attrs->a_min = a_min;
273 attrs->a_max = a_max;
274 static const Op& op = Op::Get("clip");
275 return Call(op, {a}, Attrs(attrs), {});
276}
277
278TVM_REGISTER_GLOBAL("relay.op._make.clip").set_body_typed(MakeClip);
279
280RELAY_REGISTER_OP("clip")
281 .describe(R"code(Clip tensor values.
282This function takes a tensor, a minimum value `a_min`, and a maximum value `a_max`, and returns a clipped tensor where all values below `a_min` are set to `a_min` and all values above `a_max` are set to `a_max`. `a_min` and `a_max` are cast to the tensor's dtype.
283)code" TVM_ADD_FILELINE)
284 .set_num_inputs(1)
285 .add_argument("data", "Tensor", "The input tensor.")
286 .add_type_rel("Identity", IdentityRel)
287 .set_attr<TOpPattern>("TOpPattern", kElemWise)
288 .set_attr<TOpIsStateful>("TOpIsStateful", false)
289 .set_attr<FInferCorrectLayout>("FInferCorrectLayout", ElemwiseArbitraryLayout)
290 .set_attrs_type<ClipAttrs>()
291 .set_support_level(3);
292
293// relay.fixed_point_multiply
294TVM_REGISTER_NODE_TYPE(FixedPointMultiplyAttrs);
295
296TVM_REGISTER_GLOBAL("relay.op._make.fixed_point_multiply")
297 .set_body_typed([](Expr a, int32_t multiplier, int32_t shift) {
298 auto attrs = make_object<FixedPointMultiplyAttrs>();
299 attrs->multiplier = multiplier;
300 attrs->shift = shift;
301 static const Op& op = Op::Get("fixed_point_multiply");
302 return Call(op, {a}, Attrs(attrs), {});
303 });
304
305RELAY_REGISTER_OP("fixed_point_multiply")
306 .describe(R"code(fixed point multiplication)code" TVM_ADD_FILELINE)
307 .set_num_inputs(1)
308 .add_argument("data", "Tensor", "The input tensor.")
309 .add_type_rel("Identity", IdentityRel)
310 .set_attr<TOpPattern>("TOpPattern", kElemWise)
311 .set_attr<TOpIsStateful>("TOpIsStateful", false)
312 .set_attr<FInferCorrectLayout>("FInferCorrectLayout", ElemwiseArbitraryLayout)
313 .set_attrs_type<FixedPointMultiplyAttrs>()
314 .set_support_level(10);
315
316RELAY_REGISTER_UNARY_OP("floor")
317 .describe(R"code(Returns the floor of input array, computed element-wise.
318)code" TVM_ADD_FILELINE)
319 .set_support_level(3)
320 .set_attr<FTVMCompute>("FTVMCompute", RELAY_UNARY_COMPUTE(topi::floor));
321
322RELAY_REGISTER_UNARY_OP("ceil")
323 .describe(R"code(Returns the ceil of input array, computed element-wise.
324
325.. math::
326 ceil(x)
327
328)code" TVM_ADD_FILELINE)
329 .set_support_level(3)
330 .set_attr<FTVMCompute>("FTVMCompute", RELAY_UNARY_COMPUTE(topi::ceil));
331
332RELAY_REGISTER_UNARY_OP("trunc")
333 .describe(R"code(Returns the trunc of input array, computed element-wise.
334
335.. math::
336 trunc(x)
337
338)code" TVM_ADD_FILELINE)
339 .set_support_level(3)
340 .set_attr<FTVMCompute>("FTVMCompute", RELAY_UNARY_COMPUTE(topi::trunc));
341
342RELAY_REGISTER_UNARY_OP("round")
343 .describe(R"code(Returns the round of input array, computed element-wise.
344
345.. math::
346 round(x)
347
348)code" TVM_ADD_FILELINE)
349 .set_support_level(3)
350 .set_attr<FTVMCompute>("FTVMCompute", RELAY_UNARY_COMPUTE(topi::round));
351
352RELAY_REGISTER_UNARY_OP("sign")
353 .describe(R"code(Returns the sign of input array, computed element-wise.
354
355.. numpy::
356 sign(x)
357
358)code" TVM_ADD_FILELINE)
359 .set_support_level(3)
360 .set_attr<FTVMCompute>("FTVMCompute", RELAY_UNARY_COMPUTE(topi::sign));
361
362RELAY_REGISTER_UNARY_OP("abs")
363 .describe(R"code(Returns the abs of input array, computed element-wise.
364
365.. math::
366 abs(x)
367
368)code" TVM_ADD_FILELINE)
369 .set_support_level(3)
370 .set_attr<FTVMCompute>("FTVMCompute", RELAY_UNARY_COMPUTE(topi::abs));
371
372RELAY_REGISTER_UNARY_OP("tanh")
373 .describe(R"code(Returns the tanh of input array, computed element-wise.
374
375.. math::
376 Y = sinh(X) / cosh(X)
377
378)code" TVM_ADD_FILELINE)
379 .set_support_level(1)
380 .set_attr<FTVMCompute>("FTVMCompute", RELAY_UNARY_COMPUTE(topi::tanh));
381
382RELAY_REGISTER_UNARY_OP("fast_tanh")
383 .describe(R"code(Returns the fast_tanh of input array, computed element-wise.
384
385.. math::
386 Y = sinh(X) / cosh(X)
387
388)code" TVM_ADD_FILELINE)
389 .set_support_level(1)
390 .set_attr<FTVMCompute>("FTVMCompute", RELAY_UNARY_COMPUTE(topi::fast_tanh));
391
392RELAY_REGISTER_UNARY_OP("negative")
393 .describe(R"code(Returns the numeric negative of input array, computed element-wise.
394
395.. math::
396 -(x)
397
398)code" TVM_ADD_FILELINE)
399 .set_support_level(3)
400 .set_attr<FTVMCompute>("FTVMCompute", RELAY_UNARY_COMPUTE(topi::negative));
401
402RELAY_REGISTER_UNARY_OP("logical_not")
403 .describe(R"code(Returns the logical inverse of input array, computed element-wise.
404
405.. math::
406 !(x)
407
408)code" TVM_ADD_FILELINE)
409 .set_support_level(4)
410 .set_attr<FTVMCompute>("FTVMCompute", RELAY_UNARY_COMPUTE(topi::logical_not));
411
412RELAY_REGISTER_UNARY_OP("bitwise_not")
413 .describe(R"code(Returns the bitwise inverse of input array, computed element-wise.
414
415.. math::
416 ~(x)
417
418)code" TVM_ADD_FILELINE)
419 .set_support_level(4)
420 .set_attr<FTVMCompute>("FTVMCompute", RELAY_UNARY_COMPUTE(topi::bitwise_not));
421
422Array<te::Tensor> ShapeOfCompute(const Attrs& attrs, const Array<te::Tensor>& inputs,
423 const Type& out_type) {
424 ICHECK_EQ(inputs.size(), 1);
425 const auto* param = attrs.as<ShapeOfAttrs>();
426 ICHECK(param != nullptr);
427 return {topi::shape(inputs[0], param->dtype)};
428}
429
430Expr MakeShapeOf(Expr data, DataType dtype) {
431 auto attrs = make_object<ShapeOfAttrs>();
432 attrs->dtype = dtype;
433 static const Op& op = Op::Get("shape_of");
434 return Call(op, {data}, Attrs(attrs), {});
435}
436
437TVM_REGISTER_GLOBAL("relay.op._make.shape_of").set_body_typed(MakeShapeOf);
438
439RELAY_REGISTER_OP("shape_of")
440 .describe(R"code(Returns a tensor representing the shape of a tensor.
441
442)code" TVM_ADD_FILELINE)
443 .set_num_inputs(1)
444 .set_attrs_type<ShapeOfAttrs>()
445 .add_argument("data", "Tensor", "The input tensor.")
446 .add_type_rel("ShapeOf", ShapeOfRel)
447 .set_attr<TOpIsStateful>("TOpIsStateful", false)
448 // Use kOpaque for shape_of op for now since it won't be performance critic,
449 // and it makes things easier for dynamic shape func
450 .set_attr<TOpPattern>("TOpPattern", kOpaque)
451 .set_support_level(10)
452 .set_attr<FTVMCompute>("FTVMCompute", ShapeOfCompute);
453
454TVM_REGISTER_NODE_TYPE(NdarraySizeAttrs);
455
456bool NdarraySizeRel(const Array<Type>& types, int num_inputs, const Attrs& attrs,
457 const TypeReporter& reporter) {
458 ICHECK_EQ(num_inputs, 1);
459 auto tt = types[0].as<TensorTypeNode>();
460
461 if (tt == nullptr) {
462 return false;
463 }
464
465 const auto* param = attrs.as<NdarraySizeAttrs>();
466 ICHECK(param != nullptr);
467 reporter->Assign(types[1], TensorType({}, param->dtype));
468 return true;
469}
470
471Array<te::Tensor> NdarraySizeCompute(const Attrs& attrs, const Array<te::Tensor>& inputs,
472 const Type& out_type) {
473 ICHECK_EQ(inputs.size(), 1);
474 const auto* param = attrs.as<NdarraySizeAttrs>();
475 ICHECK(param != nullptr);
476 return Array<te::Tensor>{topi::ndarray_size(inputs[0], param->dtype)};
477}
478
479TVM_REGISTER_GLOBAL("relay.op._make.ndarray_size").set_body_typed([](Expr data, DataType dtype) {
480 auto attrs = make_object<NdarraySizeAttrs>();
481 attrs->dtype = dtype;
482 static const Op& op = Op::Get("ndarray_size");
483 return Call(op, {data}, Attrs(attrs), {});
484});
485
486RELAY_REGISTER_OP("ndarray_size")
487 .describe(R"code(Returns a tensor representing the number of elements of input tensor.
488
489)code" TVM_ADD_FILELINE)
490 .set_num_inputs(1)
491 .set_attrs_type<NdarraySizeAttrs>()
492 .add_argument("data", "Tensor", "The input tensor.")
493 .add_type_rel("NdarraySize", NdarraySizeRel)
494 .set_attr<TOpIsStateful>("TOpIsStateful", false)
495 .set_attr<TOpPattern>("TOpPattern", kInjective)
496 .set_attr<FInferCorrectLayout>("FInferCorrectLayout", ElemwiseArbitraryLayout)
497 .set_support_level(10)
498 .set_attr<FTVMCompute>("FTVMCompute", NdarraySizeCompute);
499
500RELAY_REGISTER_UNARY_OP("isnan")
501 .describe(R"code(Returns whether the input contains any NaN, computed element-wise.
502.. math::
503 isnan(x)
504)code" TVM_ADD_FILELINE)
505 .set_support_level(3)
506 .add_type_rel("IdentityCompRel", IdentityCompRel)
507 .set_attr<FTVMCompute>("FTVMCompute", RELAY_UNARY_COMPUTE(topi::isnan));
508
509RELAY_REGISTER_UNARY_OP("isfinite")
510 .describe(R"code(Returns the finiteness of input, computed element-wise.
511.. math::
512 isfinite(x)
513)code" TVM_ADD_FILELINE)
514 .set_support_level(3)
515 .add_type_rel("IdentityCompRel", IdentityCompRel)
516 .set_attr<FTVMCompute>("FTVMCompute", RELAY_UNARY_COMPUTE(topi::isfinite));
517
518RELAY_REGISTER_UNARY_OP("isinf")
519 .describe(R"code(Returns the infiniteness of input, computed element-wise.
520.. math::
521 isinf(x)
522)code" TVM_ADD_FILELINE)
523 .set_support_level(3)
524 .add_type_rel("IdentityCompRel", IdentityCompRel)
525 .set_attr<FTVMCompute>("FTVMCompute", RELAY_UNARY_COMPUTE(topi::isinf));
526
527} // namespace relay
528} // namespace tvm
529