| 776 | } |
| 777 | |
| 778 | Maybe<Tensor> UnfoldTensor(const std::shared_ptr<Tensor>& input, const int32_t dimension, |
| 779 | const int32_t size, const int32_t step) { |
| 780 | const auto& shape = input->shape(); |
| 781 | const auto& stride = JUST(input->stride()); |
| 782 | const int64_t ndim = shape->NumAxes(); |
| 783 | int64_t storage_offset = JUST(JUST(input->AsLocalTensor())->storage_offset()); |
| 784 | |
| 785 | CHECK_GE_OR_RETURN(dimension, 0) << "attibute dimension should be >= 0, but got " << dimension; |
| 786 | CHECK_LE_OR_RETURN(dimension, ndim) |
| 787 | << "attibute dimension should be <= input tensor's ndim, but got " << dimension; |
| 788 | |
| 789 | const int32_t max_size = ndim == 0 ? 1 : shape->At(dimension); |
| 790 | CHECK_GT_OR_RETURN(size, 0) << "attibute size should be > 0, but got " << size; |
| 791 | CHECK_LE_OR_RETURN(size, max_size) |
| 792 | << "attibute size should be <= max_size(" << max_size << ") but got " << size; |
| 793 | CHECK_GT_OR_RETURN(step, 0) << "attibute step should be > 0, but got " << size; |
| 794 | |
| 795 | DimVector out_shape(ndim + 1); |
| 796 | Stride out_stride(ndim + 1); |
| 797 | out_shape[ndim] = size; |
| 798 | out_stride[ndim] = ndim == 0 ? 1 : stride->at(dimension); |
| 799 | for (int64_t d = 0; d < ndim; ++d) { |
| 800 | const int64_t in_size_at_d = shape->At(d); |
| 801 | if (d == dimension) { |
| 802 | out_shape.at(d) = (in_size_at_d - size) / step + 1; |
| 803 | out_stride.at(d) = step * stride->at(d); |
| 804 | } else { |
| 805 | out_shape.at(d) = in_size_at_d; |
| 806 | out_stride.at(d) = stride->at(d); |
| 807 | } |
| 808 | } |
| 809 | auto output = JUST(BasicView(input, Shape(out_shape), out_stride, storage_offset)); |
| 810 | |
| 811 | if (autograd::GradMode::is_enabled() && input->requires_grad()) { |
| 812 | auto backward_fn = std::make_shared<BackwardFunction>(); |
| 813 | backward_fn->body = [=](const TensorTuple& out_grads, TensorTuple* in_grads, |
| 814 | bool create_graph) -> Maybe<void> { |
| 815 | autograd::AutoGradMode mode(create_graph); |
| 816 | CHECK_EQ_OR_RETURN(out_grads.size(), 1) |
| 817 | << "out grad size should be 1, but got " << out_grads.size(); |
| 818 | in_grads->resize(1); |
| 819 | (*in_grads)[0] = |
| 820 | JUST(functional::UnfoldTensorGrad(out_grads[0], input, dimension, size, step)); |
| 821 | return Maybe<void>::Ok(); |
| 822 | }; |
| 823 | backward_fn->status = []() { return true; }; |
| 824 | TensorTuple outputs{output}; |
| 825 | JUST(GetThreadLocalAutogradEngine()->AddNode("view::unfold_tensor_backward", backward_fn, |
| 826 | {input}, &outputs)); |
| 827 | } |
| 828 | |
| 829 | return output; |
| 830 | } |
| 831 | |
| 832 | Maybe<Tensor> Diagonal(const std::shared_ptr<Tensor>& input, const int32_t offset, |
| 833 | const int32_t dim1, const int32_t dim2) { |
no test coverage detected