tvm
Loading...
Searching...
No Matches
nn.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_NN_H_
25#define TVM_TOPI_NN_H_
26
27#include <tvm/ir/prim/expr.h>
28#include <tvm/ir/prim/op.h>
29#include <tvm/sym/analyzer.h>
30#include <tvm/te/operation.h>
32#include <tvm/topi/reduction.h>
33#include <tvm/topi/tags.h>
34#include <tvm/topi/transform.h>
35
36#include <algorithm>
37#include <string>
38
39namespace tvm {
40namespace topi {
41using namespace tvm::te;
42
53template <typename T>
54inline tvm::te::Tensor relu(const tvm::te::Tensor& t, T threshold = static_cast<T>(0),
55 std::string name = "T_relu", std::string tag = kElementWise) {
56 return tvm::te::compute(
57 t->shape,
58 [&](const tvm::ffi::Array<tvm::PrimVar>& i) {
59 auto threshold_const = tvm::prim::MakeConst(tvm::PrimType(t->dtype), threshold);
60 return tvm::max(t(i), threshold_const);
61 },
62 name, tag);
63}
64
75inline tvm::te::Tensor leaky_relu(const tvm::te::Tensor& t, double alpha = 0.1,
76 std::string name = "T_leaky_relu",
77 std::string tag = kElementWise) {
78 return tvm::te::compute(
79 t->shape,
80 [&](const tvm::ffi::Array<tvm::PrimVar>& i) {
81 auto value = t(i);
82 auto calpha = tvm::prim::MakeConst(value.ty(), alpha);
83 return tvm::prim::Select(value > 0, value, value * calpha);
84 },
85 name, tag);
86}
87
100 const int axis = 1, std::string name = "T_prelu",
101 std::string tag = kBroadcast) {
102 TVM_FFI_ICHECK((size_t)axis < x->shape.size()) << "Wrong axis (" << axis << ")value. ";
103 TVM_FFI_ICHECK(topi::detail::GetConstInt(slope->shape[0]) ==
104 topi::detail::GetConstInt(x->shape[axis]))
105 << "Wrong slope shape received.";
106
107 return tvm::te::compute(
108 x->shape,
109 [&](const tvm::ffi::Array<tvm::PrimVar>& indices) {
110 auto xval = x(indices);
111 return tvm::prim::Select(xval > 0, xval, xval * slope(indices[axis]));
112 },
113 name, tag);
114}
115
156 const tvm::te::Tensor& t, const tvm::ffi::Array<tvm::PrimExpr>& pad_before,
157 tvm::ffi::Array<tvm::PrimExpr> pad_after = tvm::ffi::Array<tvm::PrimExpr>(),
158 ffi::Optional<PrimExpr> pad_value = std::nullopt, std::string name = "T_pad",
159 std::string tag = kElementWise, std::string pad_mode = "constant",
160 const ffi::Array<PrimExpr>* dyn_output_shape = nullptr) {
161 using namespace tvm::prim;
162 if (pad_after.size() < pad_before.size()) {
163 for (size_t i = pad_after.size(); i < pad_before.size(); ++i) {
164 pad_after.push_back(pad_before[i]);
165 }
166 }
167
168 sym::Analyzer analyzer;
169 TVM_FFI_ICHECK_GE(pad_before.size(), 1);
170 TVM_FFI_ICHECK_EQ(pad_before.size(), pad_after.size());
171 tvm::ffi::Array<tvm::PrimExpr> pad_before_int32;
172 tvm::ffi::Array<tvm::PrimExpr> pad_after_int32;
173
174 for (const auto& ele : pad_before) {
175 pad_before_int32.push_back(tvm::prim::cast(tvm::PrimType::Int(32), ele));
176 }
177 for (const auto& ele : pad_after) {
178 pad_after_int32.push_back(tvm::prim::cast(tvm::PrimType::Int(32), ele));
179 }
180
181 tvm::ffi::Array<tvm::PrimExpr> output_shape;
182 if (dyn_output_shape == nullptr) {
183 for (size_t i = 0; i < t->shape.size(); ++i) {
184 if (i >= pad_before.size()) {
185 output_shape.push_back(t->shape[i]);
186 } else {
187 output_shape.push_back(
188 analyzer->Simplify(t->shape[i] + pad_before_int32[i] + pad_after_int32[i]));
189 }
190 }
191 } else {
192 for (size_t i = 0; i < dyn_output_shape->size(); i++) {
193 output_shape.push_back((*dyn_output_shape)[i]);
194 }
195 }
196
197 if (!pad_value.has_value()) {
198 pad_value = tvm::prim::MakeConst(tvm::PrimType(t->dtype), 0);
199 }
200
201 auto l = [&](tvm::ffi::Array<tvm::PrimVar> ovars) {
202 tvm::ffi::Array<tvm::PrimExpr> indices;
203 tvm::ffi::Array<tvm::PrimExpr> sel;
204 tvm::ffi::Array<tvm::PrimExpr> pad_idx;
205 for (size_t i = 0; i < t->shape.size(); ++i) {
206 if (i >= pad_before_int32.size()) {
207 indices.push_back(ovars[i]);
208 continue;
209 }
210 if (!topi::detail::EqualCheck(pad_before_int32[i], 0)) {
211 sel.push_back(ovars[i] >= pad_before_int32[i]);
212 indices.push_back(ovars[i] - pad_before_int32[i]);
213 } else {
214 indices.push_back(ovars[i]);
215 }
216 if (!topi::detail::EqualCheck(pad_after_int32[i], 0)) {
217 sel.push_back(analyzer->Simplify(ovars[i].as_or_throw<PrimExpr>() <
218 pad_before_int32[i] + t->shape[i]));
219 }
220 if (pad_mode == "edge") {
221 pad_idx.push_back(
222 tvm::if_then_else(ovars[i].as_or_throw<PrimExpr>() < pad_before[i], 0,
223 tvm::if_then_else(ovars[i] >= pad_before[i] + t->shape[i],
224 t->shape[i] - 1, ovars[i] - pad_before[i])));
225 } else if (pad_mode == "reflect") {
226 pad_idx.push_back(tvm::if_then_else(
227 ovars[i].as_or_throw<PrimExpr>() < pad_before[i], pad_before[i] - ovars[i],
228 tvm::if_then_else(ovars[i] >= pad_before[i] + t->shape[i],
229 t->shape[i] * 2 - ovars[i] + pad_before[i] - 2,
230 ovars[i] - pad_before[i])));
231 }
232 }
233 if (sel.size() != 0) {
234 if (pad_mode == "constant") {
235 return tvm::if_then_else(
236 foldl([](PrimExpr a, PrimExpr b, Location loc) { return tvm::logical_and(a, b, loc); },
237 IntImm::Bool(true), sel),
238 t(indices), pad_value.value());
239 } else if (pad_mode == "edge" || pad_mode == "reflect") {
240 return tvm::if_then_else(
241 foldl([](PrimExpr a, PrimExpr b, Location loc) { return tvm::logical_and(a, b, loc); },
242 IntImm::Bool(true), sel),
243 t(indices), t(pad_idx));
244 }
245 }
246 return t(indices);
247 };
248 return tvm::te::compute(output_shape, l, name, tag);
249}
250
272 int pad_h = 0, int pad_w = 0, int stride_h = 1, int stride_w = 1,
273 std::string name = "T_conv2d_nchw",
274 std::string tag = kConv2dNCHW) {
275 TVM_FFI_ICHECK_EQ(4, I->shape.size());
276 TVM_FFI_ICHECK_EQ(4, W->shape.size());
277 auto pH = I->shape[2];
278 auto pW = I->shape[3];
279 tvm::ffi::Array<tvm::PrimExpr> output_shape{
280 I->shape[0], // B
281 W->shape[0], // O
282 indexdiv(I->shape[2] - W->shape[2] + 2 * pad_h, stride_h) + 1, // H
283 indexdiv(I->shape[3] - W->shape[3] + 2 * pad_w, stride_w) + 1 // W
284 };
285 auto i = tvm::te::reduce_axis(tvm::Range{0, I->shape[1]}, "i");
286 auto kh = tvm::te::reduce_axis(tvm::Range{0, W->shape[2]}, "kh");
287 auto kw = tvm::te::reduce_axis(tvm::Range{0, W->shape[3]}, "kw");
288 auto T =
289 (pad_h == 0 && pad_w == 0) ? I : pad(I, {tvm::PrimExpr(0), tvm::PrimExpr(0), pad_h, pad_w});
290 auto l = [&](tvm::PrimVar b, tvm::PrimVar o, tvm::PrimVar h, tvm::PrimVar w) {
291 return tvm::prim::sum(T(b, i, stride_h * h + kh, stride_w * w + kw) * W(o, i, kh, kw),
292 {i, kh, kw});
293 };
294 return tvm::te::compute(output_shape, l, name, tag);
295}
296
317 int pad_h = 0, int pad_w = 0, int stride_h = 1, int stride_w = 1,
318 std::string name = "T_conv2d_hwcn",
319 std::string tag = kConv2dHWCN) {
320 TVM_FFI_ICHECK_EQ(4, I->shape.size());
321 TVM_FFI_ICHECK_EQ(4, W->shape.size());
322 auto pH = I->shape[2];
323 auto pW = I->shape[3];
324 tvm::ffi::Array<tvm::PrimExpr> output_shape{
325 indexdiv(I->shape[2] - W->shape[2] + 2 * pad_h, stride_h) + 1, // H
326 indexdiv(I->shape[3] - W->shape[3] + 2 * pad_w, stride_w) + 1, // W
327 I->shape[2], // B
328 W->shape[3] // O
329 };
330 auto i = tvm::te::reduce_axis(tvm::Range{0, I->shape[3]}, "i");
331 auto kh = tvm::te::reduce_axis(tvm::Range{0, W->shape[0]}, "kh");
332 auto kw = tvm::te::reduce_axis(tvm::Range{0, W->shape[1]}, "kw");
333 auto T = (pad_h == 0 && pad_w == 0) ? I : pad(I, {pad_h, pad_w});
334 auto l = [&](tvm::PrimVar b, tvm::PrimVar o, tvm::PrimVar h, tvm::PrimVar w) {
335 return tvm::prim::sum(T(stride_h * h + kh, stride_w * w + kw, i, b) * W(kh, kw, i, o),
336 {i, kh, kw});
337 };
338 return tvm::te::compute(output_shape, l, name, tag);
339}
340
362 int pad_h = 0, int pad_w = 0, int stride_h = 1,
363 int stride_w = 1,
364 std::string name = "T_depthwise_conv2d_nchw",
365 std::string tag = kDepthwiseConv2dNCHW) {
366 TVM_FFI_ICHECK_EQ(4, I->shape.size());
367 TVM_FFI_ICHECK_EQ(4, W->shape.size());
368 auto pH = I->shape[2];
369 auto pW = I->shape[3];
370 auto pCM = W->shape[1]; // channel_multiplier
371 tvm::ffi::Array<tvm::PrimExpr> output_shape{
372 I->shape[0], // B
373 W->shape[1], // O
374 indexdiv(I->shape[2] - W->shape[2] + 2 * pad_h, stride_h) + 1, // H
375 indexdiv(I->shape[3] - W->shape[3] + 2 * pad_w, stride_w) + 1 // W
376 };
377 auto i = tvm::te::reduce_axis(tvm::Range{0, I->shape[1]}, "i");
378 auto kh = tvm::te::reduce_axis(tvm::Range{0, W->shape[2]}, "kh");
379 auto kw = tvm::te::reduce_axis(tvm::Range{0, W->shape[3]}, "kw");
380 auto T =
381 (pad_h == 0 && pad_w == 0) ? I : pad(I, {tvm::PrimExpr(0), tvm::PrimExpr(0), pad_h, pad_w});
382 auto l = [&](tvm::PrimVar b, tvm::PrimVar o, tvm::PrimVar h, tvm::PrimVar w) {
383 return tvm::prim::sum(T(b, indexdiv(i, pCM), stride_h * h + kh, stride_w * w + kw) *
384 W(indexdiv(i, pCM), indexmod(o, pCM), kh, kw),
385 {i, kh, kw});
386 };
387 return tvm::te::compute(output_shape, l, name, tag);
388}
389
391 int pad_h = 0, int pad_w = 0, int stride_h = 1,
392 int stride_w = 1,
393 std::string name = "T_depthwise_conv2d_nhwc",
394 std::string tag = kDepthwiseConv2dNHWC) {
395 TVM_FFI_ICHECK_EQ(4, I->shape.size());
396 TVM_FFI_ICHECK_EQ(4, W->shape.size());
397 auto pH = I->shape[1];
398 auto pW = I->shape[2];
399 auto pCM = W->shape[1]; // channel_multiplier
400 tvm::ffi::Array<tvm::PrimExpr> output_shape{
401 I->shape[0], // B
402 indexdiv(I->shape[1] - W->shape[1] + 2 * pad_h, stride_h) + 1, // H
403 indexdiv(I->shape[2] - W->shape[2] + 2 * pad_w, stride_w) + 1, // W
404 W->shape[3], // O
405 };
406 auto i = tvm::te::reduce_axis(tvm::Range{0, I->shape[3]}, "i");
407 auto kh = tvm::te::reduce_axis(tvm::Range{0, W->shape[0]}, "kh");
408 auto kw = tvm::te::reduce_axis(tvm::Range{0, W->shape[1]}, "kw");
409 auto T =
410 (pad_h == 0 && pad_w == 0) ? I : pad(I, {tvm::PrimExpr(0), pad_h, pad_w, tvm::PrimExpr(0)});
411 auto l = [&](tvm::PrimVar b, tvm::PrimVar h, tvm::PrimVar w, tvm::PrimVar o) {
412 return tvm::prim::sum(T(b, stride_h * h + kh, stride_w * w + kw, indexdiv(i, pCM)) *
413 W(kh, kw, indexdiv(i, pCM), indexmod(o, pCM)),
414 {kh, kw, i});
415 };
416 return tvm::te::compute(output_shape, l, name, tag);
417}
418
440 int pad_h = 0, int pad_w = 0, int stride_h = 1,
441 int stride_w = 1,
442 std::string name = "T_group_conv2d_ngchw",
443 std::string tag = kGroupConv2d) {
444 TVM_FFI_ICHECK_EQ(5, I->shape.size());
445 TVM_FFI_ICHECK_EQ(5, W->shape.size());
446 auto pH = I->shape[2];
447 auto pW = I->shape[3];
448 tvm::ffi::Array<tvm::PrimExpr> output_shape{
449 I->shape[0], // B
450 I->shape[1], // G
451 W->shape[2], // O
452 indexdiv(I->shape[3] - W->shape[3] + 2 * pad_h, stride_h) + 1, // H
453 indexdiv(I->shape[4] - W->shape[4] + 2 * pad_w, stride_w) + 1 // W
454 };
455 auto i = tvm::te::reduce_axis(tvm::Range{0, I->shape[2]}, "i");
456 auto kh = tvm::te::reduce_axis(tvm::Range{0, W->shape[3]}, "kh");
457 auto kw = tvm::te::reduce_axis(tvm::Range{0, W->shape[4]}, "kw");
458
459 auto T = (pad_h == 0 && pad_w == 0)
460 ? I
461 : pad(I, {tvm::PrimExpr(0), tvm::PrimExpr(0), tvm::PrimExpr(0), pad_h, pad_w});
462 auto l = [&](tvm::ffi::Array<tvm::PrimVar> args) {
463 tvm::PrimVar b = args[0];
464 tvm::PrimVar g = args[1];
465 tvm::PrimVar o = args[2];
466 tvm::PrimVar h = args[3];
467 tvm::PrimVar w = args[4];
468 return tvm::prim::sum(I(b, g, i, stride_h * h + kh, stride_w * w + kw) * W(g, i, o, kh, kw),
469 {i, kh, kw});
470 };
471 return tvm::te::compute(output_shape, l, name, tag);
472}
473
488 const tvm::ffi::Array<int64_t>& block_shape,
489 const tvm::ffi::Array<tvm::PrimExpr>& pad_before,
490 const tvm::ffi::Array<tvm::PrimExpr>& pad_after,
491 ffi::Optional<PrimExpr> pad_value = std::nullopt,
492 std::string name = "space_to_batch_nd",
493 std::string tag = kInjective) {
494 TVM_FFI_ICHECK_EQ(pad_before.size(), pad_after.size());
495 TVM_FFI_ICHECK_EQ(block_shape.size(), pad_before.size())
496 << "Paddings must be provided for each spatial dimension";
497 tvm::ffi::Array<tvm::PrimExpr> pad_before_int32;
498 tvm::ffi::Array<tvm::PrimExpr> pad_after_int32;
499
500 // pad size for batch dimension is 0
501 pad_before_int32.push_back(tvm::prim::cast(tvm::PrimType::Int(32), 0));
502 pad_after_int32.push_back(tvm::prim::cast(tvm::PrimType::Int(32), 0));
503 // insert pad sizes given for spatial dimensions
504 for (const auto& ele : pad_before) {
505 pad_before_int32.push_back(tvm::prim::cast(tvm::PrimType::Int(32), ele));
506 }
507 for (const auto& ele : pad_after) {
508 pad_after_int32.push_back(tvm::prim::cast(tvm::PrimType::Int(32), ele));
509 }
510
511 // pad the input with paddings provided
512 if (!pad_value.has_value()) {
513 pad_value = tvm::prim::MakeConst(tvm::PrimType(data->dtype), 0);
514 }
515 tvm::te::Tensor padded_t = pad(data, pad_before_int32, pad_after_int32, pad_value);
516
517 auto input_shape = data->shape;
518 auto padded_shape = padded_t->shape;
519
520 // infer shapes
521 tvm::ffi::Array<PrimExpr> r_shape;
522 tvm::ffi::Array<int64_t> axis;
523 tvm::ffi::Array<PrimExpr> o_shape;
524
525 size_t num_block_dims = block_shape.size();
526 int batch = static_cast<int>(GetConstInt(input_shape[0]));
527 tvm::PrimExpr block_shape_prod(1);
528 r_shape.push_back(batch);
529
530 for (size_t i = 1; i <= num_block_dims; i++) {
531 int padded_input = static_cast<int>(GetConstInt(padded_shape[i]));
532 int block_size = static_cast<int>(block_shape[i - 1]);
533 TVM_FFI_ICHECK_EQ((padded_input % block_size), 0)
534 << "(" << i
535 << ")th "
536 "Input dimension after padding ("
537 << padded_input << ")"
538 << " must be divisible by its block size (" << block_size << ")";
539
540 PrimExpr bs = IntImm::Int64(block_shape[i - 1]);
541 r_shape.push_back(div(padded_shape[i], bs));
542 r_shape.push_back(bs);
543 block_shape_prod *= bs;
544 axis.push_back(static_cast<int64_t>(r_shape.size() - 1)); // index of block_shape[i - 1]
545 }
546
547 size_t n = axis.size();
548 axis.push_back(0); // batch is at index 0
549 // index of (padded_shape[i] / block_shape[i - 1]) in r_shape
550 for (size_t i = 0; i < n; i++) {
551 axis.push_back(axis[i] - 1);
552 }
553 o_shape.push_back(tvm::PrimExpr(batch) * block_shape_prod);
554 for (size_t i = 1; i <= num_block_dims; i++) {
555 PrimExpr bs = IntImm::Int64(block_shape[i - 1]);
556 o_shape.push_back(div(padded_shape[i], bs));
557 }
558 // append remaining shape
559 for (size_t i = num_block_dims + 1; i < input_shape.size(); i++) {
560 r_shape.push_back(input_shape[i]);
561 axis.push_back(
562 static_cast<int64_t>(r_shape.size() - 1)); // index of remaining shape in r_shape
563 o_shape.push_back(input_shape[i]);
564 }
565
566 tvm::te::Tensor output = reshape(padded_t, r_shape);
567 output = transpose(output, axis);
568 output = reshape(output, o_shape);
569
570 return output;
571}
572
586 const tvm::ffi::Array<int64_t>& block_shape,
587 const tvm::ffi::Array<tvm::PrimExpr>& crop_begin_list,
588 const tvm::ffi::Array<tvm::PrimExpr>& crop_end_list,
589 std::string name = "batch_to_space_nd",
590 std::string tag = kInjective) {
591 // Construct shapes for reshape and transpose operation
592 ffi::Array<PrimExpr> in_shape = data->shape;
593 ffi::Array<PrimExpr> r_shape;
594 ffi::Array<int64_t> axis;
595 size_t num_block_dims = block_shape.size();
596 size_t num_input_dims = in_shape.size();
597 tvm::PrimExpr block_shape_prod(1);
598 int batch = static_cast<int>(GetConstInt(in_shape[0]));
599
600 for (size_t i = 0; i < num_block_dims; i++) {
601 PrimExpr bs = IntImm::Int64(block_shape[i]);
602 r_shape.push_back(bs);
603 block_shape_prod *= bs;
604 }
605 axis.push_back(static_cast<int64_t>(r_shape.size())); // axis of (batch / block_shape_prod)
606 r_shape.push_back(batch / block_shape_prod);
607
608 for (size_t i = 1; i < num_input_dims; i++) {
609 axis.push_back(static_cast<int64_t>(r_shape.size())); // axis of in_shape[i]
610 if (axis.size() < (num_block_dims + num_input_dims)) {
611 axis.push_back(
612 static_cast<int64_t>(r_shape.size() - (num_block_dims + 1))); // axis of block_shape[i]
613 }
614 r_shape.push_back(in_shape[i]);
615 }
616
617 ffi::Array<PrimExpr> r_p_shape;
618 r_p_shape.push_back(batch / block_shape_prod);
619 for (size_t i = 1; i <= num_block_dims; i++) {
620 PrimExpr bs = IntImm::Int64(block_shape[i - 1]);
621 r_p_shape.push_back(in_shape[i] * bs);
622 }
623 for (size_t i = num_block_dims + 1; i < num_input_dims; i++) {
624 r_p_shape.push_back(in_shape[i]);
625 }
626
627 tvm::te::Tensor out = reshape(data, r_shape);
628 out = transpose(out, axis);
629 out = reshape(out, r_p_shape);
630
631 // Crop the start and end of dimensions of out
632 ffi::Array<ffi::Optional<IntImm>> begin_idx, end_idx;
633 ffi::Array<IntImm> strides;
634 PrimType index_ty = PrimType::Int(64);
635 for (size_t i = 0; i < r_p_shape.size(); ++i) {
636 strides.push_back(IntImm(index_ty, 1));
637 if (i > 0 && i <= num_block_dims) {
638 // prepare begin and end index for spatial dimensions
639 const auto* begin_i_imm = crop_begin_list[i - 1].as<IntImmNode>();
640 ffi::BigInt begin_i = begin_i_imm ? begin_i_imm->value : GetConstInt(crop_begin_list[i - 1]);
641 const auto* end_i_imm = crop_end_list[i - 1].as<IntImmNode>();
642 ffi::BigInt end_i = end_i_imm ? end_i_imm->value : GetConstInt(crop_end_list[i - 1]);
643 const auto* out_i_imm = r_p_shape[i].as<IntImmNode>();
644 ffi::BigInt out_i = out_i_imm ? out_i_imm->value : GetConstInt(r_p_shape[i]);
645 TVM_FFI_ICHECK_GT(out_i, (begin_i + end_i))
646 << "Incorrect crop sizes for (" << i << ")th dim, can not crop more than"
647 << " output size" << out_i << " vs " << (begin_i + end_i);
648 begin_idx.push_back(IntImm(index_ty, begin_i));
649 end_idx.push_back(IntImm(index_ty, out_i - end_i));
650 } else {
651 // ignore the batch and remaining dimension
652 begin_idx.push_back(IntImm(index_ty, 0));
653 const auto* extent = r_p_shape[i].as<IntImmNode>();
654 end_idx.push_back(IntImm(index_ty, extent ? extent->value : GetConstInt(r_p_shape[i])));
655 }
656 }
657
658 out = strided_slice(out, begin_idx, end_idx, strides);
659 return out;
660}
661
675inline Tensor nll_loss(const Tensor& predictions, const Tensor& targets, const Tensor& weights,
676 std::string reduction = "mean", int ignore_index = -100,
677 const std::string name = "nll_loss", const std::string tag = kBroadcast) {
678 if (predictions.ndim() == 1) {
679 // corner case: no batch in shape
680 // prediction->shape = (C,), targets->shape = (), weights->shape = (C,)
681 auto T = tvm::te::compute(
682 {},
683 [&](const tvm::ffi::Array<tvm::PrimVar>& target_indices) {
684 auto c = targets();
685 return tvm::prim::Select(c != ignore_index, -predictions(c) * weights(c),
686 tvm::prim::MakeConst(tvm::PrimType(predictions->dtype), 0));
687 },
688 name, tag);
689 if (reduction == "mean") {
690 auto W = tvm::te::compute(
691 {},
692 [&](const tvm::ffi::Array<tvm::PrimVar>& target_indices) {
693 auto c = targets();
694 return tvm::prim::Select(c != ignore_index, weights(c),
695 tvm::prim::MakeConst(tvm::PrimType(predictions->dtype), 0));
696 },
697 name, tag);
698 return topi::divide(T, W);
699 } else {
700 return T;
701 }
702 }
703 auto T = tvm::te::compute(
704 targets->shape,
705 [&](const tvm::ffi::Array<tvm::PrimVar>& target_indices) {
706 auto c = targets(target_indices);
707 tvm::ffi::Array<tvm::PrimExpr> pred_indices;
708 pred_indices.push_back(target_indices[0]); // batch index
709 pred_indices.push_back(c); // class index
710 for (size_t i = 1; i < target_indices.size(); i++) {
711 pred_indices.push_back(target_indices[i]); // indices for multidimensional loss
712 }
713 return tvm::prim::Select(c != ignore_index, -predictions(pred_indices) * weights(c),
714 tvm::prim::MakeConst(tvm::PrimType(predictions->dtype), 0));
715 },
716 name, tag);
717 TVM_FFI_ICHECK(T->shape.size() != 0);
718 if (reduction == "mean") {
719 auto W = tvm::te::compute(
720 targets->shape,
721 [&](const tvm::ffi::Array<tvm::PrimVar>& target_indices) {
722 auto c = targets(target_indices);
723 return tvm::prim::Select(c != ignore_index, weights(c),
724 tvm::prim::MakeConst(tvm::PrimType(predictions->dtype), 0));
725 },
726 name, tag);
727 return topi::divide(topi::sum(T, std::nullopt), topi::sum(W, std::nullopt));
728 } else if (reduction == "sum") {
729 return topi::sum(T, std::nullopt);
730 } else { // reduction == "none"
731 return T;
732 }
733}
734
735} // namespace topi
736} // namespace tvm
737#endif // TVM_TOPI_NN_H_
Algebra expression simplifications.
Constant integer literals in the program.
Definition expr.h:135
ffi::BigInt value
the Internal value.
Definition expr.h:138
Managed reference class to IntImmNode.
Definition expr.h:152
static IntImm Int64(ffi::BigInt value, Location loc=UnknownLoc())
Construct a scalar int64 constant.
Definition expr.h:195
static IntImm Bool(bool value, Location loc=UnknownLoc())
Construct a scalar boolean constant.
Definition expr.h:172
Non-nullable source-location metadata.
Definition location.h:91
Typed reference/view over any Expr whose ExprNode::ty is PrimType.
Definition base_expr.h:447
Definition base_expr.h:161
static TVM_TIRX_DLL PrimType Int(int bits, int lanes=1)
Construct a signed integer type with fixed lanes.
Checked scalar view over a VarNode.
Definition expr.h:742
Range container
Definition expr.h:1025
Managed reference to SelectNode.
Definition expr.h:712
Managed reference to AnalyzerObj.
Definition analyzer.h:916
Tensor structure representing a possible input, or intermediate computation result.
Definition tensor.h:111
size_t ndim() const
Definition tensor.h:236
Utility functions for handling constants in TVM expressions.
TIR expressions.
Shared primitive construction and constant helpers.
Definition expr.h:47
PrimExpr sum(PrimExpr source, ffi::Array< s_tir::IterVar > axis, ffi::Array< PrimExpr > init={}, Location loc=UnknownLoc())
sum of source expression over axis
PrimExpr MakeConst(PrimType dtype, ValueType value, Location loc=UnknownLoc())
Make a const value with certain data type.
Definition op.h:553
TVM_TIRX_DLL PrimExpr cast(PrimType t, PrimExpr value, Location loc=UnknownLoc())
cast value to type.
Tensor expression language DSL.
Definition extracted_task.h:33
IterVar reduce_axis(Range dom, std::string name="rv")
Create a new IterVar for reduction operations.
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...
constexpr auto kElementWise
Definition tags.h:32
tvm::te::Tensor pad(const tvm::te::Tensor &t, const tvm::ffi::Array< tvm::PrimExpr > &pad_before, tvm::ffi::Array< tvm::PrimExpr > pad_after=tvm::ffi::Array< tvm::PrimExpr >(), ffi::Optional< PrimExpr > pad_value=std::nullopt, std::string name="T_pad", std::string tag=kElementWise, std::string pad_mode="constant", const ffi::Array< PrimExpr > *dyn_output_shape=nullptr)
Creates an operation that performs padding.
Definition nn.h:155
Tensor reshape(const Tensor &x, ffi::Array< PrimExpr > newshape, std::string name="T_reshape", std::string tag=kInjective)
Reshape a tensor.
Definition transform.h:329
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:2016
tvm::te::Tensor batch_to_space_nd(const tvm::te::Tensor &data, const tvm::ffi::Array< int64_t > &block_shape, const tvm::ffi::Array< tvm::PrimExpr > &crop_begin_list, const tvm::ffi::Array< tvm::PrimExpr > &crop_end_list, std::string name="batch_to_space_nd", std::string tag=kInjective)
Reshape the batch dimension into spatial dimensions.
Definition nn.h:585
constexpr auto kBroadcast
Definition tags.h:36
constexpr auto kInjective
Definition tags.h:33
Tensor sum(const Tensor &data, const ffi::Optional< ffi::Array< int64_t > > &axis, bool keepdims=false, bool atleast1d=false)
Creates an operation that sums array elements over a given axis.
Definition reduction.h:336
constexpr auto kConv2dNCHW
Definition tags.h:38
tvm::te::Tensor prelu(const tvm::te::Tensor &x, const tvm::te::Tensor &slope, const int axis=1, std::string name="T_prelu", std::string tag=kBroadcast)
Creates an operation that performs a parametric rectified linear unit.
Definition nn.h:99
Tensor strided_slice(const Tensor &x, const ffi::Array< ffi::Optional< IntImm > > &begin, const ffi::Array< ffi::Optional< IntImm > > &end, const ffi::Array< IntImm > &strides, std::string slice_mode="end", std::string name="T_strided_slice", std::string tag=kInjective)
strided_slice of a tensor
Definition transform.h:965
tvm::te::Tensor group_conv2d_ngchw(const tvm::te::Tensor &I, const tvm::te::Tensor &W, int pad_h=0, int pad_w=0, int stride_h=1, int stride_w=1, std::string name="T_group_conv2d_ngchw", std::string tag=kGroupConv2d)
Creates an operation that performs a 2-D group convolution with an NGCHW-layout.
Definition nn.h:439
tvm::te::Tensor leaky_relu(const tvm::te::Tensor &t, double alpha=0.1, std::string name="T_leaky_relu", std::string tag=kElementWise)
Creates an operation that performs a leaky rectified linear unit.
Definition nn.h:75
tvm::PrimExpr divide(const tvm::PrimExpr &a, const tvm::PrimExpr &b)
Definition broadcast.h:241
constexpr auto kDepthwiseConv2dNCHW
Definition tags.h:40
tvm::te::Tensor depthwise_conv2d_nchw(const tvm::te::Tensor &I, const tvm::te::Tensor &W, int pad_h=0, int pad_w=0, int stride_h=1, int stride_w=1, std::string name="T_depthwise_conv2d_nchw", std::string tag=kDepthwiseConv2dNCHW)
Creates an operation that performs a 2-D depthwise convolution with an NCHW-layout.
Definition nn.h:361
constexpr auto kGroupConv2d
Definition tags.h:45
constexpr auto kConv2dHWCN
Definition tags.h:39
constexpr auto kDepthwiseConv2dNHWC
Definition tags.h:41
tvm::te::Tensor conv2d_nchw(const tvm::te::Tensor &I, const tvm::te::Tensor &W, int pad_h=0, int pad_w=0, int stride_h=1, int stride_w=1, std::string name="T_conv2d_nchw", std::string tag=kConv2dNCHW)
Creates an operation that performs a 2-D convolution with an NCHW-layout.
Definition nn.h:271
Tensor transpose(const Tensor &x, ffi::Optional< ffi::Array< int64_t > > opt_axes, std::string name="T_transpose", std::string tag=kInjective)
Permute the dimensions of an array.
Definition transform.h:204
tvm::te::Tensor conv2d_hwcn(const tvm::te::Tensor &I, const tvm::te::Tensor &W, int pad_h=0, int pad_w=0, int stride_h=1, int stride_w=1, std::string name="T_conv2d_hwcn", std::string tag=kConv2dHWCN)
Creates an operation for 2-D convolution layer with an HWCN-layout.
Definition nn.h:316
tvm::te::Tensor space_to_batch_nd(const tvm::te::Tensor &data, const tvm::ffi::Array< int64_t > &block_shape, const tvm::ffi::Array< tvm::PrimExpr > &pad_before, const tvm::ffi::Array< tvm::PrimExpr > &pad_after, ffi::Optional< PrimExpr > pad_value=std::nullopt, std::string name="space_to_batch_nd", std::string tag=kInjective)
Divide spatial dimensions of the input into a grid of blocks.
Definition nn.h:487
tvm::te::Tensor relu(const tvm::te::Tensor &t, T threshold=static_cast< T >(0), std::string name="T_relu", std::string tag=kElementWise)
Creates an operation that performs a rectified linear unit.
Definition nn.h:54
Tensor nll_loss(const Tensor &predictions, const Tensor &targets, const Tensor &weights, std::string reduction="mean", int ignore_index=-100, const std::string name="nll_loss", const std::string tag=kBroadcast)
Negative log likelihood loss.
Definition nn.h:675
tvm::te::Tensor depthwise_conv2d_nhwc(const tvm::te::Tensor &I, const tvm::te::Tensor &W, int pad_h=0, int pad_w=0, int stride_h=1, int stride_w=1, std::string name="T_depthwise_conv2d_nhwc", std::string tag=kDepthwiseConv2dNHWC)
Definition nn.h:390
An object that builds and maintains block scope and StmtSref mapping for Dependence analysis.
Definition attr.h:23
TVM_TIRX_DLL PrimExpr logical_and(PrimExpr a, PrimExpr b, Location loc=UnknownLoc())
and
TVM_TIRX_DLL PrimExpr if_then_else(PrimExpr cond, PrimExpr true_value, PrimExpr false_value, Location loc=UnknownLoc())
Conditional expression.
TVM_TIRX_DLL PrimExpr indexdiv(PrimExpr a, PrimExpr b, Location loc=UnknownLoc())
compute floor(a / b) where a and b are non-negative.
TVM_TIRX_DLL PrimExpr div(PrimExpr a, PrimExpr b, Location loc=UnknownLoc())
compute division in C semantics.
TVM_TIRX_DLL PrimExpr indexmod(PrimExpr a, PrimExpr b, Location loc=UnknownLoc())
compute the remainder floor(a / b) where a and b are non-negative.
Operation node can generate one or multiple Tensors.
Tag definitions.
Reduction op constructors.
Transform op constructors.