| 453 | } |
| 454 | |
| 455 | Maybe<void> InplaceExpand(const std::shared_ptr<Tensor>& input, const Shape& expand_shape) { |
| 456 | const Shape& input_shape = *input->shape(); |
| 457 | const Stride& input_stride = *JUST(input->stride()); |
| 458 | size_t lpad = expand_shape.size() - input_shape.size(); |
| 459 | CHECK_GE_OR_RETURN(lpad, 0); // NOLINT(maybe-need-error-msg) |
| 460 | |
| 461 | Stride expand_stride(expand_shape.size(), 0); |
| 462 | std::vector<int32_t> reduce_dims; |
| 463 | reduce_dims.reserve(expand_shape.size()); |
| 464 | |
| 465 | for (int i = expand_shape.size() - 1; i >= 0; --i) { |
| 466 | int64_t dim = i < lpad ? 1 : input_shape[i - lpad]; |
| 467 | if (dim == expand_shape[i]) { |
| 468 | if (i >= lpad) { |
| 469 | expand_stride[i] = input_stride[i - lpad]; |
| 470 | } else if (i < expand_shape.size() - 1) { |
| 471 | expand_stride[i] = expand_stride[i + 1] * expand_shape[i + 1]; |
| 472 | } |
| 473 | } else { |
| 474 | CHECK_EQ_OR_RETURN(dim, 1); // NOLINT(maybe-need-error-msg) |
| 475 | reduce_dims.push_back(i); |
| 476 | } |
| 477 | } |
| 478 | |
| 479 | if (input_shape.size() == 0) { |
| 480 | // handle scalar expand backward reduce dims |
| 481 | reduce_dims.clear(); |
| 482 | for (int32_t axis = 0; axis < expand_shape.size(); ++axis) { reduce_dims.push_back(axis); } |
| 483 | } |
| 484 | |
| 485 | int64_t storage_offset = JUST(JUST(input->AsLocalTensor())->storage_offset()); |
| 486 | JUST(view::InplaceView(input, expand_shape, expand_stride, storage_offset)); |
| 487 | |
| 488 | if (autograd::GradMode::is_enabled() && input->requires_grad()) { |
| 489 | auto backward_fn = std::make_shared<BackwardFunction>(); |
| 490 | backward_fn->body = [=](const TensorTuple& out_grads, TensorTuple* in_grads, |
| 491 | bool create_graph) -> Maybe<void> { |
| 492 | autograd::AutoGradMode mode(create_graph); |
| 493 | CHECK_EQ_OR_RETURN(out_grads.size(), 1) |
| 494 | << "out grad size should be 1, but got " << out_grads.size(); |
| 495 | in_grads->resize(1); |
| 496 | in_grads->at(0) = out_grads[0]; |
| 497 | bool keep_dims = (input_shape.size() > 0); |
| 498 | if (reduce_dims.size() > 0) { |
| 499 | in_grads->at(0) = |
| 500 | JUST(functional::ReduceSum(in_grads->at(0), reduce_dims, keep_dims, NullOpt)); |
| 501 | } |
| 502 | if (lpad > 0 && keep_dims) { |
| 503 | in_grads->at(0) = JUST(functional::Flatten(in_grads->at(0), 0, lpad)); |
| 504 | } |
| 505 | return Maybe<void>::Ok(); |
| 506 | }; |
| 507 | backward_fn->status = []() { return true; }; |
| 508 | TensorTuple outputs{input}; |
| 509 | JUST(GetThreadLocalAutogradEngine()->AddNode("view::expand_backward", backward_fn, {input}, |
| 510 | &outputs)); |
| 511 | } |
| 512 | return Maybe<void>::Ok(); |
nothing calls this directly
no test coverage detected