tvm
elemwise.h
Go to the documentation of this file.
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 
24 #ifndef TVM_TOPI_ELEMWISE_H_
25 #define TVM_TOPI_ELEMWISE_H_
26 
27 #include <tvm/tirx/builtin.h>
28 #include <tvm/tirx/expr.h>
29 #include <tvm/tirx/op.h>
30 #include <tvm/topi/tags.h>
31 
32 #include <algorithm>
33 #include <string>
34 
35 #include "broadcast.h"
36 
37 namespace tvm {
38 namespace topi {
39 
40 using namespace tvm::te;
41 
42 // Unary intrinsic operators
43 #define TOPI_DECLARE_UNARY_OP(OpName) \
44  inline Tensor OpName(const Tensor& x, std::string name = "T_" #OpName, \
45  std::string tag = kElementWise) { \
46  return compute( \
47  x->shape, [&](const ffi::Array<PrimVar>& i) { return ::tvm::OpName(x(i)); }, name, tag); \
48  }
49 
77 
82 inline Tensor fast_tanh_float(const Tensor& in, std::string name, std::string tag) {
83  // Clamp the inputs to the range [-9, 9] since anything outside
84  // this range is +/-1.0f in single-precision.
85  PrimType input_type = in->GetDataType();
86  auto x = maximum(MakeConst(input_type, -9.0), minimum(MakeConst(input_type, 9.0), in));
87 
88  // The monomial coefficients of the numerator polynomial (odd).
89  auto alpha_1 = MakeConst(input_type, 4.89352455891786e-03);
90  auto alpha_3 = MakeConst(input_type, 6.37261928875436e-04);
91  auto alpha_5 = MakeConst(input_type, 1.48572235717979e-05);
92  auto alpha_7 = MakeConst(input_type, 5.12229709037114e-08);
93  auto alpha_9 = MakeConst(input_type, -8.60467152213735e-11);
94  auto alpha_11 = MakeConst(input_type, 2.00018790482477e-13);
95  auto alpha_13 = MakeConst(input_type, -2.76076847742355e-16);
96 
97  // The monomial coefficients of the denominator polynomial (even).
98  auto beta_0 = MakeConst(input_type, 4.89352518554385e-03);
99  auto beta_2 = MakeConst(input_type, 2.26843463243900e-03);
100  auto beta_4 = MakeConst(input_type, 1.18534705686654e-04);
101  auto beta_6 = MakeConst(input_type, 1.19825839466702e-06);
102 
103  return compute(
104  x->shape,
105  [&](const ffi::Array<PrimVar>& i) {
106  auto x2 = x(i) * x(i);
107  auto p = x2 * alpha_13 + alpha_11;
108  p = x2 * p + alpha_9;
109  p = x2 * p + alpha_7;
110  p = x2 * p + alpha_5;
111  p = x2 * p + alpha_3;
112  p = x2 * p + alpha_1;
113  p = x(i) * p;
114 
115  auto q = x2 * beta_6 + beta_4;
116  q = x2 * q + beta_2;
117  q = x2 * q + beta_0;
118  return p / q;
119  },
120  name, tag);
121 }
122 
132 inline Tensor fast_tanh(const Tensor& x, std::string name = "T_fast_tanh",
133  std::string tag = kElementWise) {
134  if (x->GetDataType().MatchesElementType(DLDataTypeCode::kDLFloat, 32)) {
135  // invoke fast_tanh_float implementation
136  return fast_tanh_float(x, name, tag);
137  } else {
138  // fallback to default implementation
139  return compute(
140  x->shape, [&](const ffi::Array<PrimVar>& i) { return ::tvm::tanh(x(i)); }, name, tag);
141  }
142 }
143 
153 inline Tensor identity(const Tensor& x, std::string name = "T_identity",
154  std::string tag = kElementWise) {
155  return compute(x->shape, [&](const ffi::Array<PrimVar>& i) { return x(i); }, name, tag);
156 }
157 
167 inline Tensor negative(const Tensor& x, std::string name = "T_negative",
168  std::string tag = kElementWise) {
169  return compute(x->shape, [&](const ffi::Array<PrimVar>& i) { return -x(i); }, name, tag);
170 }
171 
181 inline Tensor logical_not(const Tensor& x, std::string name = "T_logical_not",
182  std::string tag = kElementWise) {
183  return compute(x->shape, [&](const ffi::Array<PrimVar>& i) { return !x(i); }, name, tag);
184 }
185 
195 inline Tensor bitwise_not(const Tensor& x, std::string name = "T_bitwise_not",
196  std::string tag = kElementWise) {
197  return compute(x->shape, [&](const ffi::Array<PrimVar>& i) { return ~x(i); }, name, tag);
198 }
199 
209 inline Tensor sign(const Tensor& x, std::string name = "T_sign", std::string tag = kElementWise) {
210  return compute(
211  x->shape,
212  [&](const ffi::Array<PrimVar>& i) {
213  PrimType x_type(x->GetDataType());
214  PrimExpr zero = MakeConst(x_type, 0);
215  PrimExpr one = MakeConst(x_type, 1);
216  PrimExpr minus_one = MakeConst(x_type, -1);
217  auto s1 = tvm::tirx::Select((x(i) < zero), minus_one, zero);
218  auto s2 = tvm::tirx::Select((x(i) > zero), one, s1);
219  return s2;
220  },
221  name, tag);
222 }
223 
233 inline Tensor rsqrt(const Tensor& x, std::string name = "tensor", std::string tag = kElementWise) {
234  return compute(
235  x->shape,
236  [&](const ffi::Array<PrimVar>& i) {
237  PrimExpr one = MakeConst(x->GetDataType(), 1);
238  return one / tvm::sqrt(x(i));
239  },
240  name, tag);
241 }
242 
255 inline Tensor clip(const Tensor& x, const PrimExpr& a_min, const PrimExpr& a_max,
256  std::string name = "T_clip", std::string tag = kElementWise) {
257  return compute(
258  x->shape,
259  [&](const ffi::Array<PrimVar>& i) {
260  PrimType x_type(x->GetDataType());
261  auto min_val = tvm::cast(x_type, a_min);
262  auto max_val = tvm::cast(x_type, a_max);
263  return tvm::max(tvm::min(x(i), max_val), min_val); // NOLINT(*)
264  },
265  name, tag);
266 }
267 
280 inline Tensor cast(const Tensor& x, PrimType type, std::string name, std::string tag);
281 
282 inline Tensor cast(const Tensor& x, DLDataType type, std::string name = "T_cast",
283  std::string tag = kElementWise) {
284  return cast(x, PrimType(type), std::move(name), std::move(tag));
285 }
286 
287 inline Tensor cast(const Tensor& x, PrimType type, std::string name = "T_cast",
288  std::string tag = kElementWise) {
289  return compute(
290  x->shape,
291  [&](const ffi::Array<PrimVar>& i) -> PrimExpr {
292  auto expr = x(i);
293  PrimType expr_ty = expr.ty();
294  if (expr_ty.MatchesElementType(type.code(), type.bits())) {
295  if (expr_ty.lanes() == type.lanes()) {
296  return expr;
297  } else if (expr_ty.lanes() == 1 && type.IsFixedLengthVector()) {
298  return tvm::tirx::Broadcast(expr, type.lanes());
299  }
300  }
301 
302  return tvm::cast(type, x(i));
303  },
304  name, tag);
305 }
306 
317 inline Tensor reinterpret(const Tensor& x, PrimType type, std::string name, std::string tag);
318 
319 inline Tensor reinterpret(const Tensor& x, DLDataType type, std::string name = "tensor",
320  std::string tag = kElementWise) {
321  return reinterpret(x, PrimType(type), std::move(name), std::move(tag));
322 }
323 
324 inline Tensor reinterpret(const Tensor& x, PrimType type, std::string name = "tensor",
325  std::string tag = kElementWise) {
326  return compute(
327  x->shape, [&](const ffi::Array<PrimVar>& i) { return reinterpret(type, x(i)); }, name, tag);
328 }
329 
339 inline Tensor elemwise_sum(const ffi::Array<Tensor>& xs, std::string name = "T_elemwise_sum",
340  std::string tag = kElementWise) {
341  TVM_FFI_ICHECK_GT(xs.size(), 0) << "elemwise sum must have at least one input tensor.";
342  return compute(
343  xs[0]->shape,
344  [&](const ffi::Array<PrimVar>& i) {
345  auto sum_expr = xs[0](i);
346  for (size_t j = 1; j < xs.size(); j++) {
347  sum_expr = sum_expr + xs[j](i);
348  }
349  return sum_expr;
350  },
351  name, tag);
352 }
353 
365 inline Tensor full(const ffi::Array<PrimExpr>& shape, PrimType dtype, const PrimExpr fill_value,
366  std::string name, std::string tag);
367 
368 inline Tensor full(const ffi::Array<PrimExpr>& shape, DLDataType dtype, const PrimExpr fill_value,
369  std::string name = "T_full", std::string tag = kElementWise) {
370  return full(shape, PrimType(dtype), fill_value, std::move(name), std::move(tag));
371 }
372 
373 inline Tensor full(const ffi::Array<PrimExpr>& shape, PrimType dtype, const PrimExpr fill_value,
374  std::string name = "T_full", std::string tag = kElementWise) {
375  PrimExpr ev = cast(dtype, fill_value);
376  if (!ev.defined()) {
377  LOG(ERROR) << "Can't cast fill_value to " << dtype;
378  }
379  return compute(shape, [&](const ffi::Array<PrimVar>& i) { return ev; }, name, tag);
380 }
381 
393 inline Tensor full_like(const Tensor& x, const PrimExpr fill_value,
394  std::string name = "T_full_like", std::string tag = kElementWise) {
395  PrimExpr ev = cast(x->GetDataType(), fill_value);
396  return compute(x->shape, [&](const ffi::Array<PrimVar>& i) { return ev; }, name, tag);
397 }
398 
420 inline Tensor fast_exp_float32(const Tensor& _x, std::string name, std::string tag) {
421  PrimType f32_ty = PrimType::Float(32);
422  auto x_hi = FloatImm(f32_ty, 88.3762626647950f);
423  auto x_lo = FloatImm(f32_ty, -88.3762626647949f);
424  auto log2e = FloatImm(f32_ty, 1.44269504088896341f);
425  auto ln2 = FloatImm(f32_ty, 0.6931471805599453f);
426  PrimExpr p[6] = {FloatImm(f32_ty, 1.9875691500E-4f), FloatImm(f32_ty, 1.3981999507E-3f),
427  FloatImm(f32_ty, 8.3334519073E-3f), FloatImm(f32_ty, 4.1665795894E-2f),
428  FloatImm(f32_ty, 1.6666665459E-1f), FloatImm(f32_ty, 5.0000001201E-1f)};
429  auto one = FloatImm(f32_ty, 1.0f);
430  auto one_half = FloatImm(f32_ty, 0.5f);
431  auto b = FloatImm(f32_ty, 127.0f);
432 
433  return compute(
434  _x->shape,
435  [&](const ffi::Array<PrimVar>& i) {
436  // clamp x
437  auto x = ::tvm::max(::tvm::min(_x(i), x_hi), x_lo);
438  // integer part
439  auto n = ::tvm::floor(x * log2e + one_half);
440  // fractional part
441  auto f = x - n * ln2;
442  auto y =
443  (((((p[0] * f + p[1]) * f + p[2]) * f + p[3]) * f + p[4]) * f + p[5]) * f * f + f + one;
444  // Return 2^m * exp(r).
445  auto ef =
446  tvm::reinterpret(PrimType::Float(32), ::tvm::cast(PrimType::Int(32), n + b) << 23);
447  return ::tvm::max(ef * y, _x(i)); // NOLINT(*)
448  },
449  name, tag);
450 }
451 
462 inline Tensor fast_exp(const Tensor& x, std::string name = "T_fast_exp",
463  std::string tag = kElementWise) {
464  if (x->GetDataType().MatchesElementType(DLDataTypeCode::kDLFloat, 32)) {
465  auto ret = fast_exp_float32(x, name, tag);
466  return ret;
467  } else {
468  return compute(
469  x->shape, [&](const ffi::Array<PrimVar>& i) { return ::tvm::exp(x(i)); }, name, tag);
470  }
471 }
472 
476 inline Tensor fast_erf_float32(const Tensor& data, std::string name, std::string tag) {
477  return compute(
478  data->shape, [&](const ffi::Array<PrimVar>& i) { return fast_erf_float_expr(data(i), 32); },
479  name, tag);
480 }
481 
485 inline Tensor fast_erf_float16(const Tensor& data, std::string name, std::string tag) {
486  return compute(
487  data->shape, [&](const ffi::Array<PrimVar>& i) { return fast_erf_float_expr(data(i), 16); },
488  name, tag);
489 }
490 
500 inline Tensor fast_erf(const Tensor& x, std::string name = "T_fast_erf",
501  std::string tag = kElementWise) {
502  PrimType x_type(x->GetDataType());
503  if (x_type.MatchesElementType(DLDataTypeCode::kDLFloat, 32)) {
504  auto ret = fast_erf_float32(x, name, tag);
505  return ret;
506  } else if (x_type.MatchesElementType(DLDataTypeCode::kDLFloat, 16)) {
507  auto ret = fast_erf_float16(x, name, tag);
508  return ret;
509  } else {
510  return topi::erf(x);
511  }
512 }
513 
514 } // namespace topi
515 } // namespace tvm
516 #endif // TVM_TOPI_ELEMWISE_H_
Managed reference class to FloatImmNode.
Definition: expr.h:441
Typed reference/view over any Expr whose ExprNode::ty is PrimType.
Definition: base_expr.h:354
Definition: base_expr.h:113
static PrimType Float(int bits, int lanes=1)
Construct a floating-point type with fixed lanes.
TVM_FFI_INLINE bool MatchesElementType(DLDataTypeCode code, int bits) const
Check the scalar element code and bit width.
Definition: base_expr.h:174
Managed Tensor. The array is backed by reference counted blocks.
Definition: tensor.h:49
Tensor structure representing a possible input, or intermediate computation result.
Definition: tensor.h:100
Detail broadcast.
#define TOPI_DECLARE_UNARY_OP(OpName)
Definition: elemwise.h:43
Tensor expression language DSL.
Definition: extracted_task.h:32
Tensor compute(ffi::Array< PrimExpr > shape, FCompute fcompute, std::string name="tensor", std::string tag="", ffi::Map< ffi::String, ffi::Any > attrs={})
Construct a new tensor by computing over shape, using the computation rule: result_tensor[axis] = fco...
PrimExpr MakeConst(PrimType dtype, ValueType value, Span span=Span())
Make a const value with certain data type.
Definition: op.h:1012
constexpr auto kElementWise
Definition: tags.h:32
Tensor clip(const Tensor &x, const PrimExpr &a_min, const PrimExpr &a_max, std::string name="T_clip", std::string tag=kElementWise)
Creates an operation that clips each element of a tensor to the interval [a_min, a_max].
Definition: elemwise.h:255
Tensor ceil(const Tensor &x, std::string name="T_" "ceil", std::string tag=kElementWise)
Definition: elemwise.h:58
Tensor isinf(const Tensor &x, std::string name="T_" "isinf", std::string tag=kElementWise)
Definition: elemwise.h:76
Tensor shape(const Tensor &src, PrimType dtype, const std::string name="T_shape", const std::string tag=kInjective)
Get the shape of input tensor.
Definition: transform.h:2010
Tensor round(const Tensor &x, std::string name="T_" "round", std::string tag=kElementWise)
Definition: elemwise.h:59
Tensor tan(const Tensor &x, std::string name="T_" "tan", std::string tag=kElementWise)
Definition: elemwise.h:64
Tensor logical_not(const Tensor &x, std::string name="T_logical_not", std::string tag=kElementWise)
Creates an operation that returns the logical NOT of a given tensor.
Definition: elemwise.h:181
Tensor fast_erf_float32(const Tensor &data, std::string name, std::string tag)
Fast_erf_float expression from Eigen.
Definition: elemwise.h:476
Tensor floor(const Tensor &x, std::string name="T_" "floor", std::string tag=kElementWise)
Definition: elemwise.h:57
Tensor trunc(const Tensor &x, std::string name="T_" "trunc", std::string tag=kElementWise)
Definition: elemwise.h:60
Tensor isnan(const Tensor &x, std::string name="T_" "isnan", std::string tag=kElementWise)
Definition: elemwise.h:73
Tensor fast_erf_float16(const Tensor &data, std::string name, std::string tag)
Fast_erf_float expression from Eigen for float16.
Definition: elemwise.h:485
Tensor exp(const Tensor &x, std::string name="T_" "exp", std::string tag=kElementWise)
Definition: elemwise.h:50
Tensor acos(const Tensor &x, std::string name="T_" "acos", std::string tag=kElementWise)
Definition: elemwise.h:67
Tensor asinh(const Tensor &x, std::string name="T_" "asinh", std::string tag=kElementWise)
Definition: elemwise.h:70
Tensor log(const Tensor &x, std::string name="T_" "log", std::string tag=kElementWise)
Definition: elemwise.h:54
Tensor fast_tanh_float(const Tensor &in, std::string name, std::string tag)
Fast_tanh_float implementation from Eigen https://github.com/eigenteam/eigen-git-mirror/blob/master/E...
Definition: elemwise.h:82
Tensor fast_tanh(const Tensor &x, std::string name="T_fast_tanh", std::string tag=kElementWise)
Creates an operation that returns hyperbolic tanh of a given tensor.
Definition: elemwise.h:132
Tensor fast_erf(const Tensor &x, std::string name="T_fast_erf", std::string tag=kElementWise)
Fast erf implementation.
Definition: elemwise.h:500
Tensor cos(const Tensor &x, std::string name="T_" "cos", std::string tag=kElementWise)
Definition: elemwise.h:62
tvm::PrimExpr minimum(const tvm::PrimExpr &a, const tvm::PrimExpr &b)
Definition: broadcast.h:376
Tensor sqrt(const Tensor &x, std::string name="T_" "sqrt", std::string tag=kElementWise)
Definition: elemwise.h:53
Tensor rsqrt(const Tensor &x, std::string name="tensor", std::string tag=kElementWise)
Creates an operation that returns rsqrt of a given tensor.
Definition: elemwise.h:233
Tensor abs(const Tensor &x, std::string name="T_" "abs", std::string tag=kElementWise)
Definition: elemwise.h:61
Tensor asin(const Tensor &x, std::string name="T_" "asin", std::string tag=kElementWise)
Definition: elemwise.h:69
Tensor bitwise_not(const Tensor &x, std::string name="T_bitwise_not", std::string tag=kElementWise)
Creates an operation that returns the bitwise NOT of a given tensor.
Definition: elemwise.h:195
Tensor atan(const Tensor &x, std::string name="T_" "atan", std::string tag=kElementWise)
Definition: elemwise.h:71
Tensor atanh(const Tensor &x, std::string name="T_" "atanh", std::string tag=kElementWise)
Definition: elemwise.h:72
Tensor log10(const Tensor &x, std::string name="T_" "log10", std::string tag=kElementWise)
Definition: elemwise.h:56
Tensor sigmoid(const Tensor &x, std::string name="T_" "sigmoid", std::string tag=kElementWise)
Definition: elemwise.h:52
Tensor identity(const Tensor &x, std::string name="T_identity", std::string tag=kElementWise)
Creates an operation that returns identity of a given tensor.
Definition: elemwise.h:153
Tensor isfinite(const Tensor &x, std::string name="T_" "isfinite", std::string tag=kElementWise)
Definition: elemwise.h:75
Tensor log2(const Tensor &x, std::string name="T_" "log2", std::string tag=kElementWise)
Definition: elemwise.h:55
Tensor elemwise_sum(const ffi::Array< Tensor > &xs, std::string name="T_elemwise_sum", std::string tag=kElementWise)
Creates an operation that sum each element of a tensor.
Definition: elemwise.h:339
Tensor cosh(const Tensor &x, std::string name="T_" "cosh", std::string tag=kElementWise)
Definition: elemwise.h:63
Tensor acosh(const Tensor &x, std::string name="T_" "acosh", std::string tag=kElementWise)
Definition: elemwise.h:68
Tensor full(const ffi::Array< PrimExpr > &shape, PrimType dtype, const PrimExpr fill_value, std::string name, std::string tag)
Creates an operation that fill a tensor with fill_value.
Definition: elemwise.h:373
Tensor sin(const Tensor &x, std::string name="T_" "sin", std::string tag=kElementWise)
Definition: elemwise.h:65
Tensor tanh(const Tensor &x, std::string name="T_" "tanh", std::string tag=kElementWise)
Definition: elemwise.h:74
Tensor full_like(const Tensor &x, const PrimExpr fill_value, std::string name="T_full_like", std::string tag=kElementWise)
Creates an operation that construct a tensor with same shape as input tensor, then fill a tensor with...
Definition: elemwise.h:393
Tensor erf(const Tensor &x, std::string name="T_" "erf", std::string tag=kElementWise)
Definition: elemwise.h:51
Tensor reinterpret(const Tensor &x, PrimType type, std::string name, std::string tag)
Reinterpret each element of x to the given type.
Definition: elemwise.h:324
Tensor fast_exp(const Tensor &x, std::string name="T_fast_exp", std::string tag=kElementWise)
Fast exponential function implementation.
Definition: elemwise.h:462
Tensor cast(const Tensor &x, PrimType type, std::string name, std::string tag)
Cast each element of x to the given type. If expr is scalar and type is a corresponding vector type,...
Definition: elemwise.h:287
Tensor sign(const Tensor &x, std::string name="T_sign", std::string tag=kElementWise)
Returns the sign of the tensor.
Definition: elemwise.h:209
Tensor negative(const Tensor &x, std::string name="T_negative", std::string tag=kElementWise)
Creates an operation that returns the negation of a given tensor.
Definition: elemwise.h:167
Tensor sinh(const Tensor &x, std::string name="T_" "sinh", std::string tag=kElementWise)
Definition: elemwise.h:66
tvm::PrimExpr maximum(const tvm::PrimExpr &a, const tvm::PrimExpr &b)
Definition: broadcast.h:363
Tensor fast_exp_float32(const Tensor &_x, std::string name, std::string tag)
Fast exponential function implementation.
Definition: elemwise.h:420
An object that builds and maintains block scope and StmtSref mapping for Dependence analysis.
Definition: analyzer.h:40
PrimExpr ret(PrimExpr value, Span span=Span())
Return the value.
PrimExpr cast(PrimType t, PrimExpr value, Span span=Span())
cast value to type.
Tag definitions.
TIR builtin intrinsics.
TIR expressions.
Common operators defined for Expr.