| 166 | } |
| 167 | |
| 168 | Maybe<Tensor> Slice(const std::shared_ptr<Tensor>& input, const std::vector<int64_t>& starts, |
| 169 | const std::vector<int64_t>& ends, const std::vector<int64_t>& steps) { |
| 170 | const auto& shape = input->shape(); |
| 171 | const auto& strides = JUST(input->stride()); |
| 172 | const int64_t ndim = starts.size(); |
| 173 | |
| 174 | CHECK_OR_RETURN(ndim == shape->NumAxes()) |
| 175 | << Error::RuntimeError() << "view::Slice(): starts size is expected " << shape->NumAxes() |
| 176 | << ", but got " << ndim; |
| 177 | |
| 178 | CHECK_OR_RETURN(ends.size() == ndim && steps.size() == ndim) |
| 179 | << Error::RuntimeError() << "view::Slice(): " << (ends.size() != ndim ? "ends" : "steps") |
| 180 | << " size is not equal to start."; |
| 181 | |
| 182 | DimVector target_dims(ndim); |
| 183 | Stride target_strides(ndim); |
| 184 | int64_t storage_offset = JUST(JUST(input->AsLocalTensor())->storage_offset()); |
| 185 | for (int i = 0; i < ndim; ++i) { |
| 186 | int64_t step = std::min(steps[i], shape->At(i)); |
| 187 | CHECK_OR_RETURN(step >= 0) << Error::RuntimeError() << "Step must be greater than zero."; |
| 188 | int64_t start = std::min(starts[i], shape->At(i)); |
| 189 | int64_t end = std::min(ends[i], shape->At(i)); |
| 190 | if (start < 0) { start += shape->At(i); } |
| 191 | if (start < 0) start = 0; |
| 192 | if (end < 0) { end += shape->At(i); } |
| 193 | if (end < start) end = start; |
| 194 | int64_t length = start == end ? 0 : (end - start + step - 1) / step; |
| 195 | target_dims[i] = length; |
| 196 | target_strides[i] = step * strides->at(i); |
| 197 | storage_offset += start * strides->at(i); |
| 198 | } |
| 199 | |
| 200 | auto output = JUST(BasicView(input, Shape(target_dims), target_strides, storage_offset)); |
| 201 | if (autograd::GradMode::is_enabled() && input->requires_grad()) { |
| 202 | const Shape in_shape = *input->shape(); |
| 203 | auto backward_fn = std::make_shared<BackwardFunction>(); |
| 204 | backward_fn->body = [=](const TensorTuple& out_grads, TensorTuple* in_grads, |
| 205 | bool create_graph) -> Maybe<void> { |
| 206 | autograd::AutoGradMode mode(create_graph); |
| 207 | CHECK_EQ_OR_RETURN(out_grads.size(), 1); // NOLINT(maybe-need-error-msg) |
| 208 | in_grads->resize(1); |
| 209 | (*in_grads)[0] = JUST(functional::SliceGrad(out_grads[0], in_shape, starts, ends, steps)); |
| 210 | return Maybe<void>::Ok(); |
| 211 | }; |
| 212 | backward_fn->status = []() { return true; }; |
| 213 | TensorTuple outputs{output}; |
| 214 | JUST(GetThreadLocalAutogradEngine()->AddNode("view::slice_backward", backward_fn, {input}, |
| 215 | &outputs)); |
| 216 | } |
| 217 | return output; |
| 218 | } |
| 219 | |
| 220 | Maybe<Tensor> Unsqueeze(const std::shared_ptr<Tensor>& input, const int32_t expand_dim) { |
| 221 | const auto& shape = input->shape(); |
nothing calls this directly
no test coverage detected