From 2a72fd866fde881877050745d148df63f633afc8 Mon Sep 17 00:00:00 2001 From: zoooo0820 Date: Thu, 23 Nov 2023 03:19:46 +0000 Subject: [PATCH 1/2] remove noused indexing code --- paddle/fluid/pybind/eager_method.cc | 420 ----------------- paddle/fluid/pybind/slice_utils.h | 164 ------- .../base/dygraph/tensor_patch_methods.py | 4 - python/paddle/base/framework.py | 5 +- python/paddle/base/variable_index.py | 421 ------------------ python/paddle/static/input.py | 8 +- 6 files changed, 3 insertions(+), 1019 deletions(-) diff --git a/paddle/fluid/pybind/eager_method.cc b/paddle/fluid/pybind/eager_method.cc index 78a260f35fb841..a76d3d0ba49378 100644 --- a/paddle/fluid/pybind/eager_method.cc +++ b/paddle/fluid/pybind/eager_method.cc @@ -1313,160 +1313,6 @@ static PyObject* tensor_method__get_tensor_from_selected_rows( EAGER_CATCH_AND_THROW_RETURN_NULL } -static PyObject* tensor__getitem_index_not_tensor(TensorObject* self, - PyObject* args, - PyObject* kwargs) { - EAGER_TRY - PyObject* _index = PyTuple_GET_ITEM(args, 0); - VLOG(4) << "Call _getitem_index_not_tensor"; - std::vector slice_axes, slice_starts, slice_ends, slice_strides, - decrease_axis, none_axes, infer_flags; - std::vector list_select_idxs; - // if index is a list, list_select_flag will be true - bool list_select_flag = false; - // Note(0x45f): Using defined() instead of initialized() - // to support slice tensor which shape like [0, 0, 0]. - PADDLE_ENFORCE_EQ( - self->tensor.defined(), - true, - platform::errors::InvalidArgument( - "tensor %s has not been initialized, we can only slice initialized " - "tensor please init it first with numpy or other tensor.", - self->tensor.name())); - - ParseIndexingSlice(self->tensor.dims(), - _index, - &slice_axes, - &slice_starts, - &slice_ends, - &slice_strides, - &decrease_axis, - &none_axes, - &infer_flags, - &list_select_idxs, - &list_select_flag); - - auto out = - slice_axes.empty() && !list_select_flag - ? self->tensor - : paddle::Tensor(egr::Controller::Instance().GenerateUniqueName()); - - if (!slice_axes.empty()) { - framework::AttributeMap attrs = {{"axes", slice_axes}, - {"starts", slice_starts}, - {"ends", slice_ends}, - {"infer_flags", infer_flags}, - {"decrease_axis", decrease_axis}}; - std::string op_type = "slice"; - for (auto stride : slice_strides) { - if (stride != 1) { - op_type = "strided_slice"; - attrs.insert({"strides", slice_strides}); - attrs.erase("decrease_axis"); - break; - } - } - - if (op_type == "slice") { - eager_gil_scoped_release guard; - out = slice_ad_func(self->tensor, - slice_axes, - slice_starts, - slice_ends, - infer_flags, - decrease_axis); - } else if (op_type == "strided_slice") { - eager_gil_scoped_release guard; - std::vector slice_axes_tmp(slice_axes.begin(), slice_axes.end()); - out = strided_slice_ad_func(self->tensor, - slice_axes_tmp, - slice_starts, - slice_ends, - slice_strides); - if (!decrease_axis.empty()) { - out = squeeze_ad_func(out, decrease_axis); - } - } else { - PADDLE_THROW(platform::errors::InvalidArgument( - "Slice is only support slice and strided_slice, but we got %s which " - "is impossible, please check your code first or contact us by " - "issue. ", - op_type)); - } - } - - bool set_to_1d = FLAGS_set_to_1d; - - if (set_to_1d) { - // NOTE(zoooo0820): When all axes are decreased, the output will be 1-D - // with FLAGS_set_to_1d=True. In this case, one `None` should be pop out, - // otherwise the output shape will be not correct. - if (static_cast(decrease_axis.size()) == self->tensor.dims().size()) { - VLOG(1) - << "Warning: In Tensor '__getitem__', if the number of scalar " - "elements " - "in the index is equal to the rank of the Tensor, the output " - "should " - "be 0-D. In order to be consistent with the behavior of previous " - "versions, it will be processed to 1-D. But it is not correct and " - "will be " - "removed in release 2.6. " - "If 1-D is still wanted, please modify the index element from " - "scalar to slice " - "(e.g. 'x[i]' => 'x[i:i+1]'). "; - if (!none_axes.empty()) { - none_axes.pop_back(); - } - } - } - if (!none_axes.empty()) { - paddle::Tensor new_out; - { - eager_gil_scoped_release guard; - // Deal with cases that decrease_axes is not empty - // For example: - // # x.shape: (2,3,4) - // out = x[0, 0:2, None] # out.shape : (2, 1, 4) - for (auto& axis : none_axes) { - int len = 0; - for (int da : decrease_axis) { - if (da < axis) { - len++; - } - } - axis -= len; - } - new_out = unsqueeze_ad_func(out, none_axes); - } - return ToPyObject(new_out); - } - - // the index is a list - if (list_select_flag) { - eager_gil_scoped_release guard; - if (FLAGS_use_stride_kernel && list_select_idxs.size() == 1) { - out = index_select_strided_ad_func(self->tensor, list_select_idxs[0], 0); - } else { - auto select_index = - paddle::Tensor(egr::Controller::Instance().GenerateUniqueName()); - auto idx_tensor = std::make_shared(); - select_index.set_impl(idx_tensor); - auto* dev_ctx = platform::DeviceContextPool::Instance().Get( - egr::Controller::Instance().GetExpectedPlace()); - paddle::framework::TensorFromVector( - list_select_idxs, *dev_ctx, idx_tensor.get()); - const phi::distributed::ProcessMesh* mesh = nullptr; - if (InputsContainDistTensor(&mesh, self->tensor, select_index)) { - ConvertAllInputsToDistTensor(mesh, self->tensor, select_index); - } - out = index_select_ad_func(self->tensor, select_index, 0); - } - } - - return ToPyObject(out); - EAGER_CATCH_AND_THROW_RETURN_NULL -} - static PyObject* tensor__getitem_dygraph(TensorObject* self, PyObject* args, PyObject* kwargs) { @@ -1907,264 +1753,6 @@ static PyObject* tensor__setitem_dygraph(TensorObject* self, EAGER_CATCH_AND_THROW_RETURN_NULL } -static PyObject* tensor_method__setitem_eager_tensor(TensorObject* self, - PyObject* args, - PyObject* kwargs) { - EAGER_TRY - VLOG(4) << "Call __setitem_eager_tensor"; - - PyObject* _index = PyTuple_GET_ITEM(args, 0); - PyObject* value_obj = PyTuple_GET_ITEM(args, 1); - // NOTE(zhiqiu): PyTuple_Pack increases refcount while PyTuple_New - // https://github.com/python/cpython/blob/24b63c695ae0a95b06379eaadace66735abac1e2/Objects/tupleobject.c#L251 - PyObject* index_ptr = - !PyTuple_Check(_index) ? PyTuple_Pack(1, _index) : _index; - DEFINE_PADDLE_SCOPE_GUARD([index_ptr, &_index]() { - if (!PyTuple_Check(_index)) { - Py_DECREF(index_ptr); - VLOG(4) << "Call Py_DECREF"; - } - }); - - // 1. Check argumnets - bool parse_index = true; - - // Check whether _index can be parsed. - const int size = PyTuple_GET_SIZE(index_ptr); - for (int dim = 0; dim < size; ++dim) { - PyObject* slice_item = PyTuple_GetItem(index_ptr, dim); - if (!(PyCheckInteger(slice_item) || PySlice_Check(slice_item) || - slice_item == Py_Ellipsis || slice_item == Py_None)) { - parse_index = false; - break; - } - } - - // 2. Call op set_value to speed up if the condition is met, - // otherwise call TensorToPyArray. - // TODO(liym27): Try not to call TensorToPyArray because it always - // copys data to cpu place, which reduces performance. - if (parse_index) { - std::vector axes, starts, ends, steps, decrease_axes, none_axes, - infer_flags; - std::vector list_select_idxs; - // if index is a list, list_select_flag will be true - bool list_select_flag = false; - ParseIndexingSlice(self->tensor.dims(), - index_ptr, - &axes, - &starts, - &ends, - &steps, - &decrease_axes, - &none_axes, - &infer_flags, - &list_select_idxs, - &list_select_flag); - - if (egr::Controller::Instance().HasGrad()) { - PADDLE_ENFORCE_EQ( - egr::EagerUtils::IsLeafTensor(self->tensor) && - !egr::EagerUtils::autograd_meta(&self->tensor)->StopGradient(), - false, - platform::errors::InvalidArgument( - "Leaf Tensor (%s) that doesn't stop gradient can't use " - "inplace strategy.", - self->tensor.name())); - } - - paddle::Tensor value_tensor; - std::vector values; - std::vector shape = std::vector{1}; - - if (PyCheckTensor(value_obj)) { - value_tensor = reinterpret_cast(value_obj)->tensor; - } else if (py::isinstance(value_obj)) { - paddle::Tensor value_tensor_tmp( - std::make_shared(), - egr::Controller::Instance().GenerateUniqueName()); - py::object value_obj_tmp(py::handle(value_obj), true); - py::object value = value_obj_tmp; - if (self->tensor.dtype() == phi::DataType::FLOAT32) { - if (!py::isinstance>(value_obj_tmp)) { - value = pybind11::detail::CastNumpyArray(value_obj_tmp); - } - } else if (self->tensor.dtype() == phi::DataType::FLOAT64) { - if (!py::isinstance>(value_obj_tmp)) { - value = pybind11::detail::CastNumpyArray(value_obj_tmp); - } - } else if (self->tensor.dtype() == phi::DataType::INT32) { - if (!py::isinstance>(value_obj_tmp)) { - value = pybind11::detail::CastNumpyArray(value_obj_tmp); - } - } else if (self->tensor.dtype() == phi::DataType::INT64) { - if (!py::isinstance>(value_obj_tmp)) { - value = pybind11::detail::CastNumpyArray(value_obj_tmp); - } - } else if (self->tensor.dtype() == phi::DataType::BOOL) { - if (!py::isinstance>(value_obj_tmp)) { - value = pybind11::detail::CastNumpyArray(value_obj_tmp); - } - } else if (self->tensor.dtype() == phi::DataType::COMPLEX64) { - if (!py::isinstance>>(value_obj_tmp)) { - value = pybind11::detail::CastNumpyArray>( - value_obj_tmp); - } - } else if (self->tensor.dtype() == phi::DataType::COMPLEX128) { - if (!py::isinstance>>(value_obj_tmp)) { - value = pybind11::detail::CastNumpyArray>( - value_obj_tmp); - } - } else { - PADDLE_THROW(platform::errors::InvalidArgument( - "When assign a numpy.np value to a paddle.Tensor, " - "the data type of the paddle.Tensor must be bool, " - "float32, float64, complex64, complex128, int32 or int64, " - "please check the type of tensor.")); - } - - SetTensorFromPyArray( - static_cast(value_tensor_tmp.impl().get()), - value, - self->tensor.place(), - false); - - value_tensor = value_tensor_tmp; - } else { - py::object value_obj_tmp(py::handle(value_obj), true); - // convert the value to self data type - if (py::isinstance(value_obj_tmp) || - py::isinstance(value_obj_tmp) || - py::isinstance(value_obj_tmp) || - PyComplex_Check(value_obj)) { - if (self->tensor.dtype() == phi::DataType::FLOAT32 || - self->tensor.dtype() == phi::DataType::FLOAT16) { - values = std::vector{value_obj_tmp.cast()}; - } else if (self->tensor.dtype() == phi::DataType::FLOAT64) { - values = std::vector{value_obj_tmp.cast()}; - } else if (self->tensor.dtype() == phi::DataType::INT32) { - values = std::vector{value_obj_tmp.cast()}; - } else if (self->tensor.dtype() == phi::DataType::INT64) { - values = std::vector{value_obj_tmp.cast()}; - } else if (self->tensor.dtype() == phi::DataType::BOOL) { - values = std::vector{value_obj_tmp.cast()}; - } else if (self->tensor.dtype() == phi::DataType::COMPLEX64) { - values = std::vector{ - value_obj_tmp.cast>()}; - } else if (self->tensor.dtype() == phi::DataType::COMPLEX128) { - values = std::vector{ - value_obj_tmp.cast>()}; - } else { - PADDLE_THROW(platform::errors::InvalidArgument( - "When assign a value to a paddle.Tensor, " - "the data type of the paddle.Tensor must be bool, " - "float32, float64, complex64, complex128, int32, int64 or " - "float16, " - "please check the type of tensor.")); - } - } else { - PADDLE_THROW(platform::errors::InvalidArgument( - "Value type error. The assign value allows " - "numpy.ndarray, integer, float, complex or bool, " - "but received %s.", - Py_TYPE(value_obj))); - } - } - { - // Release gil and do tracing - py::gil_scoped_release release; - // use inplace set_value_ operator - if (value_tensor.initialized()) { - if (self->tensor.dtype() != value_tensor.dtype()) { - if (egr::Controller::Instance().GetAMPLevel() != - paddle::imperative::AmpLevel::O0) { - paddle::small_vector, - egr::kSlotSmallVectorSize> - tmps = {{self->tensor}, {value_tensor}}; - auto amp_dtype = egr::GetAmpDestDtype("set_value", tmps); - self->tensor = egr::EagerAmpAutoCast( - self->tensor.name(), self->tensor, amp_dtype, "set_value"); - value_tensor = egr::EagerAmpAutoCast( - value_tensor.name(), value_tensor, amp_dtype, "set_value"); - } - if (self->tensor.dtype() != value_tensor.dtype()) { - value_tensor = cast_ad_func(value_tensor, self->tensor.dtype()); - } - } - const phi::distributed::ProcessMesh* mesh = nullptr; - if (InputsContainDistTensor(&mesh, self->tensor, value_tensor)) { - ConvertAllInputsToDistTensor(mesh, self->tensor, value_tensor); - } - self->tensor = set_value_with_tensor__ad_func(self->tensor, - value_tensor, - starts, - ends, - steps, - axes, - decrease_axes, - none_axes); - } else { - self->tensor = set_value__ad_func(self->tensor, - starts, - ends, - steps, - axes, - decrease_axes, - none_axes, - shape, - values); - } - } - if (PyCheckTensor(value_obj)) { - // pass the stop_gradient from value to tensor. - // pass stop gradient should be done after CheckInplace in - // set_value__dygraph_function. - if (!egr::EagerUtils::autograd_meta(&value_tensor)->StopGradient() && - egr::EagerUtils::autograd_meta(&self->tensor)->StopGradient()) { - egr::EagerUtils::autograd_meta(&self->tensor)->SetStopGradient(false); - } - } - } else { - PADDLE_ENFORCE_EQ(self->tensor.is_dense_tensor(), - true, - platform::errors::InvalidArgument( - "This setitem mode only support DenseTensor.")); - auto self_tensor = - static_cast(self->tensor.impl().get()); - auto self_numpy = TensorToPyArray(*self_tensor, true); - VLOG(4) << "parse_index is false"; - if (PyCheckTensor(_index)) { - VLOG(4) << "index is tensor"; - auto index_tensor = static_cast( - reinterpret_cast(_index)->tensor.impl().get()); - auto index_numpy = TensorToPyArray(*index_tensor); - self_numpy[index_numpy] = py::object(py::handle(value_obj), true); - } else { - VLOG(4) << "index is not tensor"; - self_numpy[_index] = py::object(py::handle(value_obj), true); - } - if (!self->tensor.initialized()) { -#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP) - SetTensorFromPyArray(self_tensor, - self_numpy, - platform::Place(platform::CUDAPlace(0)), - false); -#else - SetTensorFromPyArray(self_tensor, - self_numpy, - platform::Place(platform::CPUPlace()), - false); -#endif - } else { - SetTensorFromPyArray( - self_tensor, self_numpy, self->tensor.place(), false); - } - } - RETURN_PY_NONE - - EAGER_CATCH_AND_THROW_RETURN_NULL -} - static PyObject* tensor_register_grad_hook(TensorObject* self, PyObject* args, PyObject* kwargs) { @@ -3566,10 +3154,6 @@ PyMethodDef variable_methods[] = { // NOLINT (PyCFunction)(void (*)())tensor_method__get_tensor_from_selected_rows, METH_VARARGS | METH_KEYWORDS, nullptr}, - {"_getitem_index_not_tensor", - (PyCFunction)(void (*)())tensor__getitem_index_not_tensor, - METH_VARARGS | METH_KEYWORDS, - nullptr}, {"_getitem_dygraph", (PyCFunction)(void (*)())tensor__getitem_dygraph, METH_VARARGS | METH_KEYWORDS, @@ -3578,10 +3162,6 @@ PyMethodDef variable_methods[] = { // NOLINT (PyCFunction)(void (*)())tensor__getitem_from_offset, METH_VARARGS | METH_KEYWORDS, nullptr}, - {"__setitem_eager_tensor__", - (PyCFunction)(void (*)())tensor_method__setitem_eager_tensor, - METH_VARARGS | METH_KEYWORDS, - nullptr}, {"_setitem_dygraph", (PyCFunction)(void (*)())tensor__setitem_dygraph, METH_VARARGS | METH_KEYWORDS, diff --git a/paddle/fluid/pybind/slice_utils.h b/paddle/fluid/pybind/slice_utils.h index 533205ba81d94f..918d2eeae4272a 100644 --- a/paddle/fluid/pybind/slice_utils.h +++ b/paddle/fluid/pybind/slice_utils.h @@ -144,170 +144,6 @@ static int _PySlice_GetIndices(PySliceObject* r, return 0; } -static void ParseIndexingSlice(phi::DDim shape, - PyObject* _index, - std::vector* slice_axes, - std::vector* slice_starts, - std::vector* slice_ends, - std::vector* slice_strides, - std::vector* decrease_axis, - std::vector* none_axes, - std::vector* infer_flags, - std::vector* list_select_idxs, - bool* list_select_flag) { - // We allow indexing by Integers, Slices, Ellipsis, None, tuples of those - // types, and list of Bool and Integers. - // wrap to tuple - - // NOTE(zhiqiu): PyTuple_Pack increases refcount. - PyObject* index = !PyTuple_Check(_index) ? PyTuple_Pack(1, _index) : _index; - DEFINE_PADDLE_SCOPE_GUARD([index, _index]() { - if (!PyTuple_Check(_index)) { - Py_DECREF(index); - VLOG(4) << "Call Py_DECREF"; - } - }); - - const int rank = shape.size(); - const int size = PyTuple_GET_SIZE(index); - - // specified_dims is the number of dimensions which indexed by Interger, - // Slices. - int specified_dims = 0; - int ell_count = 0; - for (int dim = 0; dim < size; ++dim) { - PyObject* slice_item = PyTuple_GetItem(index, dim); - if (PyCheckInteger(slice_item) || PySlice_Check(slice_item)) { - specified_dims++; - } else if (slice_item == Py_Ellipsis) { - ell_count++; - } - } - - PADDLE_ENFORCE_LE(ell_count, - 1, - platform::errors::InvalidArgument( - "An index can only have a single ellipsis ('...')")); - int none_count = 0; - for (int i = 0, dim = 0; i < size; ++i) { - PyObject* slice_item = PyTuple_GetItem(index, i); - - infer_flags->push_back(1); - int64_t dim_len = shape[dim]; - if (PyCheckInteger(slice_item) || IsNumpyType(slice_item)) { - // integer, PyLong_AsLong supports both int and long - int64_t start = static_cast(PyLong_AsLong(slice_item)); - auto s_t = start; - start = start < 0 ? start + dim_len : start; - - PADDLE_ENFORCE( - 0 <= start && start < dim_len, - platform::errors::OutOfRange("The starting index %d of slice is out " - "of bounds in tensor %d-th axis, it " - "shound be in the range of [%d, %d).", - s_t, - dim, - -dim_len, - dim_len)); - - slice_axes->push_back(dim); - slice_starts->push_back(start); - slice_ends->push_back(start + 1); - slice_strides->push_back(1); - decrease_axis->push_back(dim); - dim++; - } else if (PySlice_Check(slice_item)) { - // slice item - Py_ssize_t start, end, step; - PySliceObject* p = reinterpret_cast(slice_item); - _PySlice_GetIndices(p, dim_len, &start, &end, &step); - - // :: or : or 0:dim_len:1 - if (start == 0 && end == dim_len && step == 1) { - dim++; - continue; - } - slice_axes->push_back(dim); - slice_starts->push_back(start); - slice_ends->push_back(end); - slice_strides->push_back(step); - dim++; - } else if (slice_item == Py_Ellipsis) { - dim += rank - specified_dims; - } else if (slice_item == Py_None) { - none_axes->push_back(dim + none_count); - none_count++; - } else if (PyList_Check(slice_item)) { - *list_select_flag = true; - PADDLE_ENFORCE_EQ( - size, - 1, - platform::errors::InvalidArgument( - "When index contains a list, its length is excepted to 1, " - "but received %d", - size)); - bool all_bool = true; - int list_size = PyList_GET_SIZE(slice_item); - for (int j = 0; j < list_size; ++j) { - PyObject* list_item = PyList_GetItem(slice_item, j); - if (PyCheckInteger(list_item)) { - all_bool = false; - } else if (!PyBool_Check(list_item)) { - PADDLE_THROW(platform::errors::InvalidArgument( - "Only support int or bool in index list.")); - } - } - if (all_bool) { - PADDLE_ENFORCE_EQ( - list_size, - shape[0], - platform::errors::InvalidArgument( - "The dimension of bool index doesn't match indexed array along " - "dimension 0, the target dimension is %d, but received %d.", - shape[0], - list_size)); - - for (int j = 0; j < list_size; ++j) { - PyObject* list_item = PyList_GetItem(slice_item, j); - if (list_item == Py_True) { - list_select_idxs->push_back(j); - } - } - } else { - for (int j = 0; j < list_size; ++j) { - PyObject* list_item = PyList_GetItem(slice_item, j); - if (PyCheckInteger(list_item)) { - list_select_idxs->push_back( - static_cast(PyLong_AsLong(list_item))); - } else if (list_item == Py_True) { - list_select_idxs->push_back(1); - } else { - list_select_idxs->push_back(0); - } - } - } - - } else { - PADDLE_THROW(platform::errors::InvalidArgument( - "Currently, Tensor.__indices__() only allows indexing " - "by Integers, Slices, Ellipsis, None, tuples of these types " - "and list of Bool and Integers, but received " - "%s in %dth slice item", - std::string(Py_TYPE(slice_item)->tp_name), - i + 1)); - } - } - - // valid_index is the number of dimensions exclude None index - const int valid_indexs = size - none_axes->size() - ell_count; - PADDLE_ENFORCE_EQ(valid_indexs <= rank, - true, - platform::errors::InvalidArgument( - "Too many indices (%d) for tensor of dimension %d.", - valid_indexs, - rank)); -} - static void ParseIndex(const paddle::Tensor& tensor, PyObject* _index, std::vector* slice_axes, diff --git a/python/paddle/base/dygraph/tensor_patch_methods.py b/python/paddle/base/dygraph/tensor_patch_methods.py index 9d77af318df587..5db6f2288de829 100644 --- a/python/paddle/base/dygraph/tensor_patch_methods.py +++ b/python/paddle/base/dygraph/tensor_patch_methods.py @@ -32,7 +32,6 @@ EagerParamBase, Parameter, Variable, - _setitem_impl_, convert_np_dtype_to_dtype_, ) from .base import switch_to_static_graph @@ -881,9 +880,6 @@ def __getitem__(self, item): return self._getitem_dygraph(item) def __setitem__(self, item, value): - if core.is_compiled_with_xpu(): - # (NOTE): Currently, there is no index_put_xpu kernel. - return _setitem_impl_(self, item, value) item, value = pre_deal_index_and_value(self, item, value) return self._setitem_dygraph(item, value) diff --git a/python/paddle/base/framework.py b/python/paddle/base/framework.py index bf97ddb08ae4cf..b1bb1622a1069f 100644 --- a/python/paddle/base/framework.py +++ b/python/paddle/base/framework.py @@ -41,7 +41,7 @@ data_feed_pb2, # noqa: F401 framework_pb2, ) -from .variable_index import _getitem_static, _setitem_impl_, _setitem_static +from .variable_index import _getitem_static, _setitem_static from .wrapped_decorator import signature_safe_contextmanager, wrap_decorator if TYPE_CHECKING: @@ -2472,9 +2472,6 @@ def __setitem__(self, item, value): from .dygraph.base import in_to_static_mode if in_to_static_mode(): - if is_compiled_with_xpu(): - # (NOTE): Currently, there is no index_put_xpu kernel. - return _setitem_impl_(self, item, value) return _setitem_static(self, item, value) else: raise RuntimeError( diff --git a/python/paddle/base/variable_index.py b/python/paddle/base/variable_index.py index 4144cb839eaf05..75b4c63922dbc4 100644 --- a/python/paddle/base/variable_index.py +++ b/python/paddle/base/variable_index.py @@ -13,7 +13,6 @@ # limitations under the License. import warnings -from functools import reduce import numpy as np @@ -24,190 +23,6 @@ MAX_INTEGER = 2**31 - 1 -def is_list_tuple(index, contain_type): - def _is_list_tuple(item): - if not (isinstance(item, (list, tuple)) or type(item) == contain_type): - return False - if isinstance(item, (tuple, list)): - for s in item: - if not _is_list_tuple(s): - return False - return True - - if not isinstance(index, (tuple, list)): - return False - for s in index: - if not _is_list_tuple(s): - return False - return True - - -def get_list_index_shape(var_dims, index_dims): - var_dims_size = len(var_dims) - index_dims_size = len(index_dims) - - out_dims_size = var_dims_size - index_dims[0] + index_dims_size - 1 - - out_dims_shape = [1] * out_dims_size - - out_dims_shape[: index_dims_size - 1] = index_dims[1:] - - out_dims_shape[index_dims_size - 1 :] = var_dims[index_dims[0] :] - return out_dims_shape - - -class SliceInfo: - def __init__(self): - self.pre_shape = None - self.indexes = [] - self.dtype = None - - def update(self, index): - if is_list_tuple(index, int) or isinstance( - index, (paddle.base.Variable, np.ndarray) - ): - # convert index to Tensor - if not isinstance(index, paddle.base.Variable): - index = paddle.assign(index) - - if self.dtype is None: - self.dtype = index.dtype - else: - if index.dtype != self.dtype: - raise IndexError( - "Data type of Tensor/List index should be same. The current data type is {}, but the previous data type is {}.".format( - index.dtype, self.dtype - ) - ) - - self.indexes.append(index) - - if self.pre_shape is None: - self.pre_shape = index.shape - else: - if self.pre_shape != index.shape: - # broadcast - cur_shape = paddle.broadcast_shape( - self.pre_shape, index.shape - ) - for i in range(len(self.indexes)): - self.indexes[i] = paddle.broadcast_to( - self.indexes[i], cur_shape - ) - self.pre_shape = self.indexes[-1].shape - else: - raise ValueError( - f"Index should be list/tuple of int or Tensor, but received {index}." - ) - - def shape_stride(self, shape): - s = [1] * len(shape) - for i in range(len(shape) - 2, -1, -1): - s[i] = shape[i + 1] * s[i + 1] - - return s - - def numel(self, shape): - return reduce(lambda x, y: x * y, shape, 1) - - def get_offset_stride(self, tensor_shape): - for index in self.indexes: - if not isinstance(index, paddle.base.Variable): - raise ValueError( - f"only support list/tensor index, but received {type(index)}." - ) - - if len(self.indexes) <= len(tensor_shape) or len(self.indexes) == 1: - shape = paddle.stack(self.indexes) - axes = list(range(1, len(self.pre_shape) + 1)) + [ - 0, - ] - - else: - raise ValueError( - "too many indices for tensor: tensor is {}-dimensional, but {} were indexed".format( - len(tensor_shape), self.pre_shape[0] - ) - ) - - shape_transpose = paddle.transpose(shape, axes) - return shape_transpose - - def get_item(self, tensor): - shape_transpose = self.get_offset_stride(tensor.shape) - index = paddle.assign(shape_transpose) - return paddle.gather_nd(tensor, index) - - def set_item(self, tensor_origin, value): - if not isinstance(value, paddle.base.Variable): - value = paddle.assign(value) - tensor_type = None - - if tensor_origin.dtype in [ - core.VarDesc.VarType.FP32, - core.VarDesc.VarType.FP64, - ]: - tensor = tensor_origin - else: - tensor_type = tensor_origin.dtype - tensor = tensor_origin.astype(core.VarDesc.VarType.FP32) - - if value.dtype != tensor.dtype: - value = value.astype(tensor.dtype) - - shape_transpose = self.get_offset_stride(tensor_origin.shape) - index = paddle.assign(shape_transpose) - - gather_tensor_shape = get_list_index_shape( - tensor.shape, - [ - len(self.indexes), - ] - + list(self.indexes[-1].shape), - ) - - value_dims_bd = [ - 1, - ] * len(gather_tensor_shape) - value_dims_bd[-len(value.shape) :] = list(value.shape) - - for i in range(len(gather_tensor_shape)): - if not ( - len(value_dims_bd) == 0 - or value_dims_bd[i] == gather_tensor_shape[i] - or value_dims_bd[i] == 1 - ): - raise ValueError( - f"{value.shape} can not broadcast into {gather_tensor_shape}" - ) - - value_broadcast = paddle.broadcast_to(value, gather_tensor_shape) - - value_1d = value_broadcast.reshape( - [-1] + gather_tensor_shape[len(index.shape) - 1 :] - ) - - index_1d = index.reshape([-1, index.shape[-1]]) - - tensor_stride = paddle.assign( - self.shape_stride(tensor.shape[: index.shape[-1]]) - ) - inds = [] - for i in range(index_1d.shape[0]): - temp = (index_1d[i] * tensor_stride).sum() - inds.append(temp) - index_1d = paddle.stack(inds).reshape([-1]) - t_reshape = tensor.reshape([-1] + list(tensor.shape[index.shape[-1] :])) - out = paddle.scatter(t_reshape, index_1d, value_1d) - if tensor_type is not None: - out = out.astype(tensor_type) - tensor_origin = _setitem_impl_( - tensor_origin, ..., out.reshape(tensor_origin.shape) - ) - - return tensor_origin - - def replace_ellipsis(var, item): from .framework import Variable @@ -376,242 +191,6 @@ def _setitem_for_tensor_array(var, item, value): ) -def _setitem_impl_(var, item, value): - from paddle.base import core - - from .framework import Variable, default_main_program - - if var.type == core.VarDesc.VarType.LOD_TENSOR_ARRAY: - return _setitem_for_tensor_array(var, item, value) - - inputs = {'Input': var} - - # 1. Parse item - if not isinstance(item, tuple): - item = (item,) - - decrease_axes = [] - axes = [] - starts = [] - ends = [] - steps = [] - - item = replace_ndarray_and_range(item) - item = replace_ellipsis(var, item) - item, none_axes = replace_none(item) - slice_info = SliceInfo() - dim = 0 - for _, slice_item in enumerate(item): - if is_integer_or_scalar_tensor(slice_item) and not is_bool_tensor( - slice_item - ): - decrease_axes.append(dim) - start = slice_item - end = slice_item + 1 if slice_item != -1 else MAX_INTEGER - step = 1 - - elif isinstance(slice_item, slice): - start = slice_item.start - end = slice_item.stop - step = slice_item.step - - if start is None and end is None and step is None: - dim += 1 - continue - - step = 1 if step is None else step - - if not isinstance(step, Variable) and step == 0: - raise ValueError( - "When assign a value to a paddle.Tensor, step can not be 0, " - f"but received step is {step}." - ) - - if isinstance(step, Variable) and (start is None or end is None): - raise ValueError( - "When assign a value to a paddle.Tensor, it's not supported that " - "the start or end is None when the type of step is paddle.Tensor." - ) - - if start is None: - start = 0 if step > 0 else MAX_INTEGER - - if end is None: - end = MAX_INTEGER if step > 0 else (0 - MAX_INTEGER) - elif isinstance(slice_item, list): - if is_list_tuple(slice_item, int): - slice_info.update(slice_item) - continue - - for i in slice_item: - if not isinstance(i, bool): - raise TypeError(f"Doesn't support {type(i)} in index list.") - - if len(item) != 1: - raise IndexError( - "When index contains a bool list, its length must be 1, but received {}.".format( - len(item) - ) - ) - - idx_tensor = paddle.assign(slice_item) - return set_value_for_bool_tensor(var, idx_tensor, value) - - elif isinstance(slice_item, Variable): - if slice_item.dtype == core.VarDesc.VarType.BOOL: - if len(item) != 1: - raise IndexError( - "When index contains a bool tensor, its length must be 1, but received {}.".format( - len(item) - ) - ) - return set_value_for_bool_tensor(var, slice_item, value) - else: - slice_info.update(slice_item) - continue - else: - raise IndexError( - "Valid index accept int, slice, ellipsis, None, list of bool, Variable, " - f"but received {slice_item}." - ) - - axes.append(dim) - starts.append(start) - ends.append(end) - steps.append(step) - - dim += 1 - if slice_info.indexes: - if len(slice_info.indexes) != len(item): - raise IndexError( - f"Valid index accept int or slice or ellipsis or list, but received {item}." - ) - return slice_info.set_item(var, value) - attrs = { - 'axes': axes, - 'starts': starts, - 'ends': ends, - 'steps': steps, - 'decrease_axes': decrease_axes, - 'none_axes': none_axes, - } - - if paddle.utils._contain_var(starts): - inputs['StartsTensorList'] = paddle.utils._convert_to_tensor_list( - starts - ) - del attrs['starts'] - if paddle.utils._contain_var(ends): - inputs['EndsTensorList'] = paddle.utils._convert_to_tensor_list(ends) - del attrs['ends'] - if paddle.utils._contain_var(steps): - inputs['StepsTensorList'] = paddle.utils._convert_to_tensor_list(steps) - del attrs['steps'] - - # 2. Parse value - dtype = var.dtype - attrs['dtype'] = dtype - - from .data_feeder import convert_dtype - - # 2.1 value is an integer, float or complex - if isinstance(value, (bool, int, float, complex)): - value = np.array([value]).astype(convert_dtype(dtype)) - - # 2.2 value is a np.ndarray - if isinstance(value, np.ndarray): - shape = list(value.shape) - values = value.ravel().tolist() - attrs["values"] = values - attrs["shape"] = shape - - elif isinstance(value, (Variable, core.eager.Tensor)): - inputs["ValueTensor"] = value - else: - raise TypeError( - "Only support to assign an integer, float, numpy.ndarray or " - f"paddle.Tensor to a paddle.Tensor, but received {type(value)}" - ) - - if paddle.in_dynamic_mode(): - var._bump_inplace_version() - output = var - else: - helper = paddle.base.layer_helper.LayerHelper('set_value', **locals()) - if helper.main_program.current_block_idx != 0: - # not in global block, we should create a global variable. - output = helper._create_global_variable_for_type_inference( - dtype=var.dtype - ) - else: - output = helper.create_variable_for_type_inference(dtype=var.dtype) - - cur_block = default_main_program().current_block() - cur_block.append_op( - type="set_value", - inputs=inputs, - outputs={'Out': output}, - attrs=attrs, - inplace_map={"Input": "Out"}, - ) - - if not paddle.in_dynamic_mode(): - # map var to the new output - from paddle.jit.dy2static.program_translator import ProgramTranslator - - ProgramTranslator.get_instance()._inplace_map.add( - cur_block.program, var.desc.id(), output - ) - - return output - - -# the item is a tensor of bool -def set_value_for_bool_tensor(var, item, value): - if len(item.shape) > len(var.shape): - raise IndexError( - "The dims of bool index doesn't match indexed array, " - "the dims of bool index except to be equal or less " - f"than {len(var.shape)}, but received {len(item.shape)}." - ) - for i, dim_len in enumerate(item.shape): - if dim_len != -1 and var.shape[i] != -1 and dim_len != var.shape[i]: - raise IndexError( - "The dimension of bool index doesn't match indexed array along " - "dimension {}, the target dimension is {}, but received {}.".format( - i, var.shape[i], dim_len - ) - ) - - def idx_not_empty(var, item, value): - from ..tensor import gather_nd, scatter_nd_add - from .framework import Variable - - if not isinstance(value, Variable): - value = paddle.assign(value).cast(var.dtype) - - idx = paddle.nonzero(item) - gather_val = gather_nd(var, idx) - gather_val_new = value - gather_val - out = scatter_nd_add(var, idx, gather_val_new) - var = _setitem_impl_(var, ..., out) - return var - - def idx_is_empty(var): - return var - - from paddle.static.nn import cond - - # If all the bool index is False, just do nothing - var = cond( - item.any(), - lambda: idx_not_empty(var, item, value), - lambda: idx_is_empty(var), - ) - - return var - - def deal_advanced_index(ori_tensor, indices, is_for_setitem): """ Transpose origin Tensor and advanced indices to the front. diff --git a/python/paddle/static/input.py b/python/paddle/static/input.py index 5d8710535aee89..49d968d3d08dc2 100644 --- a/python/paddle/static/input.py +++ b/python/paddle/static/input.py @@ -25,7 +25,7 @@ from paddle.base.layer_helper import LayerHelper from paddle.base.libpaddle import DataType -from ..base.variable_index import _setitem_impl_, _setitem_static +from ..base.variable_index import _setitem_static __all__ = [] @@ -422,8 +422,4 @@ def setitem(x, index, value): (1) a[Tensor([10,10])]=v -> setitem(a, (Tensor([10,10]),), v) (2) a[1] = v -> setitem(a, (1,), v) """ - if core.is_compiled_with_xpu(): - # (NOTE): Currently, there is no index_put_xpu kernel. - return _setitem_impl_(x, index, value) - else: - return _setitem_static(x, index, value) + return _setitem_static(x, index, value) From f01fb01493f334ff584d53a7fbc498db1a43588e Mon Sep 17 00:00:00 2001 From: zoooo0820 Date: Fri, 24 Nov 2023 08:19:43 +0000 Subject: [PATCH 2/2] fix xpu test --- test/xpu/test_set_value_op_xpu.py | 60 ++++++++++++++----------------- 1 file changed, 26 insertions(+), 34 deletions(-) diff --git a/test/xpu/test_set_value_op_xpu.py b/test/xpu/test_set_value_op_xpu.py index ba69ff178b7380..5526fcee30e67b 100644 --- a/test/xpu/test_set_value_op_xpu.py +++ b/test/xpu/test_set_value_op_xpu.py @@ -231,7 +231,7 @@ def body(i, x): i = i + 1 return i, x - i = paddle.zeros(shape=(1,), dtype='int32') + i = paddle.zeros(shape=[], dtype='int32') i, x = paddle.static.nn.while_loop(cond, body, [i, x]) def _call_setitem_static_api(self, x): @@ -243,7 +243,7 @@ def body(i, x): i = i + 1 return i, x - i = paddle.zeros(shape=(1,), dtype='int32') + i = paddle.zeros(shape=[], dtype='int32') i, x = paddle.static.nn.while_loop(cond, body, [i, x]) return x @@ -504,11 +504,11 @@ def set_dtype(self): self.dtype = self.in_type def _call_setitem(self, x): - zero = paddle.full([1], 0, dtype="int32") + zero = paddle.full([], 0, dtype="int32") x[zero] = self.value def _call_setitem_static_api(self, x): - zero = paddle.full([1], 0, dtype="int32") + zero = paddle.full([], 0, dtype="int32") x = paddle.static.setitem(x, zero, self.value) return x @@ -517,13 +517,13 @@ def _get_answer(self): class XPUTestSetValueItemTensor2(XPUTestSetValueItemTensor): def _call_setitem(self, x): - zero = paddle.full([1], 0, dtype="int32") - two = paddle.full([1], 2, dtype="int64") + zero = paddle.full([], 0, dtype="int32") + two = paddle.full([], 2, dtype="int64") x[zero:two] = self.value def _call_setitem_static_api(self, x): - zero = paddle.full([1], 0, dtype="int32") - two = paddle.full([1], 2, dtype="int64") + zero = paddle.full([], 0, dtype="int32") + two = paddle.full([], 2, dtype="int64") x = paddle.static.setitem(x, slice(zero, two), self.value) return x @@ -532,13 +532,13 @@ def _get_answer(self): class XPUTestSetValueItemTensor3(XPUTestSetValueItemTensor): def _call_setitem(self, x): - zero = paddle.full([1], 0, dtype="int32") - two = paddle.full([1], 2, dtype="int64") + zero = paddle.full([], 0, dtype="int32") + two = paddle.full([], 2, dtype="int64") x[zero:-1, 0:two] = self.value def _call_setitem_static_api(self, x): - zero = paddle.full([1], 0, dtype="int32") - two = paddle.full([1], 2, dtype="int64") + zero = paddle.full([], 0, dtype="int32") + two = paddle.full([], 2, dtype="int64") x = paddle.static.setitem( x, (slice(zero, -1), slice(0, two)), self.value ) @@ -549,13 +549,13 @@ def _get_answer(self): class XPUTestSetValueItemTensor4(XPUTestSetValueItemTensor): def _call_setitem(self, x): - zero = paddle.full([1], 0, dtype="int32") - two = paddle.full([1], 2, dtype="int64") + zero = paddle.full([], 0, dtype="int32") + two = paddle.full([], 2, dtype="int64") x[0:-1, zero:2, 0:6:two] = self.value def _call_setitem_static_api(self, x): - zero = paddle.full([1], 0, dtype="int32") - two = paddle.full([1], 2, dtype="int64") + zero = paddle.full([], 0, dtype="int32") + two = paddle.full([], 2, dtype="int64") x = paddle.static.setitem( x, (slice(0, -1), slice(zero, 2), slice(0, 6, two)), self.value ) @@ -566,13 +566,13 @@ def _get_answer(self): class XPUTestSetValueItemTensor5(XPUTestSetValueItemTensor): def _call_setitem(self, x): - zero = paddle.full([1], 0, dtype="int32") - two = paddle.full([1], 2, dtype="int64") + zero = paddle.full([], 0, dtype="int32") + two = paddle.full([], 2, dtype="int64") x[zero:, 1:2:two, :] = self.value def _call_setitem_static_api(self, x): - zero = paddle.full([1], 0, dtype="int32") - two = paddle.full([1], 2, dtype="int64") + zero = paddle.full([], 0, dtype="int32") + two = paddle.full([], 2, dtype="int64") x = paddle.static.setitem( x, (slice(zero, None), slice(1, 2, two), slice(None, None, None)), @@ -588,13 +588,13 @@ def set_shape(self): self.shape = [3, 4, 5] def _call_setitem(self, x): - minus1 = paddle.full([1], -1, dtype="int32") - zero = paddle.full([1], 0, dtype="int32") + minus1 = paddle.full([], -1, dtype="int32") + zero = paddle.full([], 0, dtype="int32") x[2:zero:minus1, 0:2, 10:-6:minus1] = self.value def _call_setitem_static_api(self, x): - minus1 = paddle.full([1], -1, dtype="int32") - zero = paddle.full([1], 0, dtype="int32") + minus1 = paddle.full([], -1, dtype="int32") + zero = paddle.full([], 0, dtype="int32") x = paddle.static.setitem( x, (slice(2, zero, minus1), slice(0, 2), slice(10, -6, minus1)), @@ -1090,13 +1090,6 @@ def _ellipsis_error(self): x[::one] = self.value def _bool_list_error(self): - with self.assertRaises(TypeError): - x = paddle.ones(shape=self.shape, dtype=self.dtype) - if paddle.in_dynamic_mode(): - x[[True, False, 0]] = 0 - else: - x = paddle.static.setitem(x, [True, False, 0], 0) - with self.assertRaises(IndexError): x = paddle.ones(shape=self.shape, dtype=self.dtype) if paddle.in_dynamic_mode(): @@ -1129,7 +1122,6 @@ def test_error(self): paddle.enable_static() with paddle.static.program_guard(self.program): self._value_type_error() - self._step_error() self._bool_list_error() self._bool_tensor_error() self._broadcast_mismatch() @@ -1642,13 +1634,13 @@ def test_inplace(self): paddle.seed(100) a = paddle.rand(shape=[1, 4]) a.stop_gradient = False - b = a[:] + b = a[:] * 1 c = b b[paddle.zeros([], dtype='int32')] = 1.0 self.assertTrue(id(b) == id(c)) np.testing.assert_array_equal(b.numpy(), c.numpy()) - self.assertEqual(b.inplace_version, 0) + self.assertEqual(b.inplace_version, 1) paddle.enable_static()