|
- /**
- * Copyright 2020 Huawei Technologies Co., Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- #include "ir/tensor.h"
-
- #include <functional>
- #include <numeric>
- #include <vector>
- #include <sstream>
- #include <string>
-
- #include "device/device_address.h"
- #include "pybind_api/api_register.h"
- #include "pybind_api/export_flags.h"
- #include "pipeline/static_analysis/abstract_value.h"
-
- namespace mindspore {
-
- namespace tensor {
-
- void DataBuf2Contiguous(const py::array &src, py::array *const dest) {
- if (dest == nullptr) {
- MS_LOG(EXCEPTION) << "Failed to copy data to a contiguous buffer as dest is nullptr!";
- }
-
- Py_buffer pybuf_src;
- if (PyObject_GetBuffer(src.ptr(), &pybuf_src, PyBUF_ANY_CONTIGUOUS)) {
- MS_LOG(EXCEPTION) << "Failed to get buffer info from the src!";
- }
-
- if (!PyBuffer_IsContiguous(&pybuf_src, 'C')) {
- if (PyBuffer_ToContiguous(dest->request(true).ptr, &pybuf_src, pybuf_src.len, 'C')) {
- MS_LOG(EXCEPTION) << "Can't copy numpy.ndarray to a contiguous buffer.";
- }
- } else {
- *dest = src;
- }
-
- PyBuffer_Release(&pybuf_src);
- }
-
- Tensor::Tensor(const TypePtr &type_ptr, const py::tuple &shape) {
- TypeId data_type = TypeId::kTypeUnknown;
- if (type_ptr != nullptr) {
- data_type = type_ptr->type_id();
- }
- data_type_ = data_type;
- shape_.resize(shape.size());
- for (size_t i = 0; i < shape.size(); ++i) {
- shape_[i] = py::int_(shape[i]);
- }
- init(data_type_, shape_, &data_);
- }
-
- Tensor::Tensor(TypeId data_type, const std::vector<int> &shape) { init(data_type, shape, &data_); }
-
- Tensor::Tensor(const py::array &input, const TypePtr &data_type) { init(input, data_type); }
-
- Tensor::Tensor(const py::list &input, const TypePtr &data_type) { init(py::array(input), data_type); }
-
- Tensor::Tensor(const py::tuple &input, const TypePtr &data_type) { init(py::array(input), data_type); }
-
- Tensor::Tensor(const py::float_ &input, const TypePtr &data_type) { init(py::array(input), data_type); }
-
- Tensor::Tensor(const py::int_ &input, const TypePtr &data_type) { init(py::array(input), data_type); }
-
- Tensor::Tensor(const Tensor &tensor, const TypePtr &data_type)
- : MetaTensor(tensor), device_address_(tensor.device_address_) {
- init(tensor.data_, data_type);
- dirty_ = tensor.is_dirty();
- id_ = tensor.id();
- }
-
- Tensor &Tensor::operator=(const Tensor &tensor) {
- if (this != &tensor) {
- MetaTensor::operator=(tensor);
- dirty_ = tensor.is_dirty();
- device_address_ = tensor.device_address();
- data_ = tensor.data_;
- id_ = tensor.id();
- }
- return *this;
- }
-
- bool Tensor::operator==(const Tensor &tensor) const {
- return (MetaTensor::operator==(tensor) && data_ == tensor.data_);
- }
-
- bool Tensor::ValueEqual(const Tensor &other) const {
- auto equal = [&other, this]() -> bool {
- auto np = py::module::import("numpy");
- auto equal = np.attr("equal")(data_, other.data_);
- auto all_equal = np.attr("all")(equal);
- return all_equal.cast<bool>();
- };
- return (MetaTensor::operator==(other) && (data_.is(other.data_) || equal()));
- }
-
- py::tuple Tensor::GetPyTupleShape() const {
- std::vector<int> shape = this->shape();
- py::tuple dims(shape.size());
- for (size_t i = 0; i < dims.size(); ++i) {
- dims[i] = py::int_(shape[i]);
- }
- return dims;
- }
-
- int Tensor::DataDim() const { return static_cast<int>(data_.ndim()); }
-
- int Tensor::DataSize() const { return static_cast<int>(data_.size()); }
-
- py::array Tensor::data() const { return data_; }
-
- int Tensor::data_type_c() const { return static_cast<int>(data_type_); }
-
- std::vector<int> Tensor::shape_c(void) const { return shape(); }
-
- void *Tensor::data_c(bool writable) {
- // operand of bit operation should be unsigned int.
- unsigned int flags = ((unsigned int)data_.flags()) & pybind11::detail::npy_api::NPY_ARRAY_C_CONTIGUOUS_;
- bool is_c_contiguous = (flags != 0) ? true : false;
- if (!is_c_contiguous) {
- py::array data_c;
- init(data_type_, shape_, &data_c);
- DataBuf2Contiguous(data_, &data_c);
- data_ = data_c;
- }
- return data_.request(writable).ptr;
- }
-
- TypeId Tensor::GetDataType(const py::buffer_info &buf) const {
- TypeId data_type = TypeId::kTypeUnknown;
- if (buf.format.compare("e") == 0) {
- data_type = TypeId::kNumberTypeFloat16;
- } else if (buf.format.compare("f") == 0) {
- data_type = TypeId::kNumberTypeFloat32;
- } else if (buf.format.compare("d") == 0) {
- data_type = TypeId::kNumberTypeFloat64;
- } else if (buf.format.compare("B") == 0) {
- data_type = TypeId::kNumberTypeUInt8;
- } else if (buf.format.compare("H") == 0) {
- data_type = TypeId::kNumberTypeUInt16;
- } else if (buf.format.compare("I") == 0) {
- data_type = TypeId::kNumberTypeUInt32;
- } else if (buf.format.compare("L") == 0 || buf.format.compare("Q") == 0) {
- data_type = TypeId::kNumberTypeUInt64;
- } else if (buf.format.compare("b") == 0) {
- data_type = TypeId::kNumberTypeInt8;
- } else if (buf.format.compare("h") == 0) {
- data_type = TypeId::kNumberTypeInt16;
- } else if (buf.format.compare("i") == 0) {
- data_type = TypeId::kNumberTypeInt32;
- } else if (buf.format.compare("l") == 0 || buf.format.compare("q") == 0) {
- data_type = TypeId::kNumberTypeInt64;
- } else if (buf.format.compare("?") == 0) {
- data_type = TypeId::kNumberTypeBool;
- } else {
- MS_LOG(WARNING) << "Get unsupported DataType " << buf.format << ".";
- }
- return data_type;
- }
-
- void Tensor::init(const py::array &input, const TypePtr &type_ptr) {
- TypeId data_type = TypeId::kTypeUnknown;
- if (type_ptr != nullptr) {
- data_type = type_ptr->type_id();
- }
- init(input, data_type);
- }
-
- void Tensor::init(const py::array &input, const TypeId &data_type) {
- py::buffer_info buf = input.request();
-
- data_type_ = GetDataType(buf);
- if (TypeId::kTypeUnknown == data_type && TypeId::kTypeUnknown == data_type_) {
- MS_LOG(EXCEPTION) << "Unsupported tensor type!";
- }
-
- std::vector<ssize_t> tm = buf.shape;
- size_t len = tm.size();
- std::vector<int> dims(len);
- for (size_t i = 0; i < len; ++i) {
- dims[i] = static_cast<int>(tm[i]);
- }
- (void)set_shape(dims);
-
- if (TypeId::kTypeUnknown != data_type && TypeId::kTypeUnknown != data_type_ && data_type_ != data_type) {
- // If user defined data type is not same as GetDataType from the data
- bool success = convert_data(input, data_type_, &data_, data_type);
- if (success) {
- data_type_ = data_type;
- } else {
- data_type_ = TypeId::kTypeUnknown;
- MS_LOG(EXCEPTION) << "Convert data from " << data_type_ << " to " << data_type << " failed!";
- }
- } else {
- data_ = input;
- }
- dirty_ = true;
- id_ = std::to_string((uintptr_t)(this));
- }
-
- void Tensor::init(TypeId data_type, const std::vector<int> &shape, py::array *const data) {
- data_type_ = data_type;
- shape_ = shape;
- switch (data_type) {
- case kNumberTypeBool:
- *data = py::array_t<bool, py::array::c_style>(shape);
- break;
- case kNumberTypeInt8:
- *data = py::array_t<int8_t, py::array::c_style>(shape);
- break;
- case kNumberTypeInt16:
- *data = py::array_t<int16_t, py::array::c_style>(shape);
- break;
- case kNumberTypeInt32:
- *data = py::array_t<int32_t, py::array::c_style>(shape);
- break;
- case kNumberTypeInt64:
- *data = py::array_t<int64_t, py::array::c_style>(shape);
- break;
- case kNumberTypeUInt8:
- *data = py::array_t<uint8_t, py::array::c_style>(shape);
- break;
- case kNumberTypeUInt16:
- *data = py::array_t<uint16_t, py::array::c_style>(shape);
- break;
- case kNumberTypeUInt32:
- *data = py::array_t<uint32_t, py::array::c_style>(shape);
- break;
- case kNumberTypeUInt64:
- *data = py::array_t<uint64_t, py::array::c_style>(shape);
- break;
- case kNumberTypeFloat16:
- *data = py::array_t<float16, py::array::c_style>(shape);
- break;
- case kNumberTypeFloat32:
- *data = py::array_t<float, py::array::c_style>(shape);
- break;
- case kNumberTypeFloat64:
- *data = py::array_t<double, py::array::c_style>(shape);
- break;
- default:
- MS_LOG(EXCEPTION) << "Cannot construct Tensor because of unsupported data type: " << data_type << ".";
- break;
- }
- id_ = std::to_string((uintptr_t)(this));
- }
-
- TypePtr Tensor::SetDtype(const TypePtr type_ptr) {
- MS_EXCEPTION_IF_NULL(type_ptr);
- (void)set_data_type(type_ptr->type_id());
- return type_ptr;
- }
-
- TypeId Tensor::set_data_type(const TypeId data_type) {
- if (data_.size() > 0 && data_type_ != data_type) {
- bool success = convert_data(data_, data_type_, &data_, data_type);
- if (success) {
- data_type_ = data_type;
- } else {
- MS_LOG(EXCEPTION) << "Convert data from " << data_type_ << " to " << data_type << " failed!";
- }
- } else if (data_.size() == 0) {
- data_type_ = data_type;
- }
-
- return data_type_;
- }
-
- bool Tensor::is_init() { return init_flag_; }
-
- void Tensor::set_init_flag(bool flag) { init_flag_ = flag; }
-
- bool Tensor::convert_data(const py::array &in, const TypeId in_data_type, py::array *const out,
- const TypeId out_data_type) {
- if (out == nullptr) {
- return false;
- }
-
- bool result = true;
- if (TypeId::kTypeUnknown == in_data_type || TypeId::kTypeUnknown == out_data_type) {
- result = false;
- } else if (in_data_type == out_data_type) {
- *out = in;
- } else if (TypeId::kNumberTypeFloat64 == out_data_type) {
- *out = in.attr("astype").cast<py::function>()("float64").cast<py::array>();
- } else if (TypeId::kNumberTypeFloat32 == out_data_type) {
- *out = in.attr("astype").cast<py::function>()("float32").cast<py::array>();
- } else if (TypeId::kNumberTypeFloat16 == out_data_type) {
- *out = in.attr("astype").cast<py::function>()("float16").cast<py::array>();
- } else if (TypeId::kNumberTypeInt64 == out_data_type) {
- *out = in.attr("astype").cast<py::function>()("int64").cast<py::array>();
- } else if (TypeId::kNumberTypeInt32 == out_data_type) {
- *out = in.attr("astype").cast<py::function>()("int32").cast<py::array>();
- } else if (TypeId::kNumberTypeInt16 == out_data_type) {
- *out = in.attr("astype").cast<py::function>()("int16").cast<py::array>();
- } else if (TypeId::kNumberTypeInt8 == out_data_type) {
- *out = in.attr("astype").cast<py::function>()("int8").cast<py::array>();
- } else if (TypeId::kNumberTypeUInt8 == out_data_type) {
- *out = in.attr("astype").cast<py::function>()("uint8").cast<py::array>();
- } else if (TypeId::kNumberTypeUInt16 == out_data_type) {
- *out = in.attr("astype").cast<py::function>()("uint16").cast<py::array>();
- } else if (TypeId::kNumberTypeUInt32 == out_data_type) {
- *out = in.attr("astype").cast<py::function>()("uint32").cast<py::array>();
- } else if (TypeId::kNumberTypeUInt64 == out_data_type) {
- *out = in.attr("astype").cast<py::function>()("uint64").cast<py::array>();
- } else {
- data_type_ = TypeId::kTypeUnknown;
- MS_LOG(EXCEPTION) << "Cannot convert from " << TypeIdLabel(in_data_type) << " to " << TypeIdLabel(out_data_type)
- << ".";
- }
-
- return result;
- }
-
- abstract::AbstractBasePtr Tensor::ToAbstract() {
- auto tens = shared_from_base<Tensor>();
- auto dtype = tens->Dtype();
- if (!IsSubType(dtype, kNumber)) {
- MS_LOG(EXCEPTION) << "Expect tensor type kNumber but got: " << dtype->ToString() << ".";
- }
- auto tensor_shape = tens->shape();
- auto abs_tensor = std::make_shared<abstract::AbstractTensor>(dtype, tensor_shape);
- abs_tensor->set_value(shared_from_base<Tensor>());
- return abs_tensor;
- }
-
- std::string Tensor::GetShapeAndDataTypeInfo() const {
- std::ostringstream buf;
- buf << "Tensor \nshape:[" << shape() << "]" << this->Dtype()->ToString();
- return buf.str();
- }
-
- std::string Tensor::ToString() const {
- const int small_tensor_size = 30;
- std::ostringstream buf;
- buf << "Tensor \nshape:[" << shape() << "]" << this->Dtype()->ToString();
- // only print small tensor
- if (DataSize() < small_tensor_size) {
- buf << "val:" << std::string(py::str(data()));
- }
- return buf.str();
- }
-
- std::string Tensor::ToStringRepr() const {
- std::ostringstream buf;
- auto type_ptr = this->Dtype();
- MS_EXCEPTION_IF_NULL(type_ptr);
- buf << "Tensor shape:[" << shape() << "]" << type_ptr->ToString();
- buf << "\nval:" << std::string(py::str(data()));
- return buf.str();
- }
-
- py::array Tensor::data_sync() {
- if (device_address_ != nullptr) {
- if (!device_address_->SyncDeviceToHost(this->shape(), static_cast<size_t>(this->data().nbytes()), this->data_type(),
- this->data_c(true))) {
- MS_LOG(EXCEPTION) << "SyncDeviceToHost when asnumpy.";
- }
- }
- return data_;
- }
-
- REGISTER_PYBIND_DEFINE(Tensor, ([](const py::module *m) {
- // dtype should define before Tensor, because Tensor init depend dtype
- (void)py::class_<Tensor, std::shared_ptr<Tensor>>(*m, "Tensor")
- .def(py::init<TypePtr, py::tuple>(), py::arg("dtype"), py::arg("shape"))
- .def(py::init<py::array, TypePtr>(), py::arg("input"), py::arg("dtype") = nullptr)
- .def(py::init<py::float_, TypePtr>(), py::arg("input"), py::arg("dtype") = nullptr)
- .def(py::init<py::int_, TypePtr>(), py::arg("input"), py::arg("dtype") = nullptr)
- .def(py::init<py::list, TypePtr>(), py::arg("input"), py::arg("dtype") = nullptr)
- .def(py::init<py::tuple, TypePtr>(), py::arg("input"), py::arg("dtype") = nullptr)
- .def(py::init<Tensor, TypePtr>(), py::arg("input"), py::arg("dtype") = nullptr)
- .def_readonly(PYTHON_TENSOR_FLAG, &Tensor::parse_info_)
- .def("asnumpy", &Tensor::data_sync, R"mydelimiter(
- Convert tensor to numpy.ndarray.
-
- Returns:
- numpy.ndarray.
-
- Examples:
- >>> data = mindspore.Tensor(np.ones((2, 3)))
- >>> array = data.asnumpy()
- >>> array
- array([[1., 1., 1.],
- [1., 1., 1.]])
- )mydelimiter")
- .def("size", &Tensor::DataSize, R"mydelimiter(
- Get tensor's data size.
-
- Returns:
- int, the size of tensor.
-
- Examples:
- >>> data = mindspore.Tensor(np.ones((2, 3)))
- >>> data.size()
- 6
- )mydelimiter")
- .def("is_init", &Tensor::is_init, R"mydelimiter(
- Get tensor init_flag.
-
- Returns:
- bool, whether the tensor init.
-
- Examples:
- >>> data = mindspore.Tensor(np.ones((2, 3)))
- >>> data.is_init()
- False
- )mydelimiter")
- .def("set_init_flag", &Tensor::set_init_flag, R"mydelimiter(
- Set tensor init_flag.
-
- Examples:
- >>> data = mindspore.Tensor(np.ones((2, 3)))
- >>> data.set_init_flag(True)
- )mydelimiter")
- .def("dim", &Tensor::DataDim, R"mydelimiter(
- Get tensor's data dimension.
-
- Returns:
- int, the dimension of tensor.
-
- Examples:
- >>> data = mindspore.Tensor(np.ones((2, 3)))
- >>> data.dim()
- 2
- )mydelimiter")
- .def("dtype", &Tensor::Dtype, R"mydelimiter(
- Get the tensor's data type.
-
- Returns:
- type, the data type of tensor.
-
- Examples:
- >>> data = mindspore.Tensor(np.ones((2, 1), np.int32))
- >>> data.dtype()
- Int32
- )mydelimiter")
- .def("set_dtype", &Tensor::SetDtype, R"mydelimiter(
- Set the tensor's data type.
-
- Arg:
- dtype (:class:`mindspore.dtype`): The type of output tensor.
-
- Examples:
- >>> data = mindspore.Tensor(np.ones((1, 2), np.float32))
- >>> data.set_dtype(mindspore.int32)
- mindspore.int32
- )mydelimiter")
- .def("shape", &Tensor::GetPyTupleShape, R"mydelimiter(
- Get the tensor's shape.
-
- Returns:
- tuple[int], the shape of tensor.
-
- Examples:
- >>> data = mindspore.Tensor(np.ones((3, 3)))
- >>> data.shape()
- (3, 3)
- )mydelimiter")
- .def("__str__", &Tensor::ToString)
- .def("__repr__", &Tensor::ToStringRepr)
- .def(py::pickle(
- [](const Tensor &t) { // __getstate__
- /* Return a tuple that fully encodes the state of the object */
- return py::make_tuple(t.data());
- },
- [](const py::tuple &t) { // __setstate__
- if (t.size() != 1) {
- throw std::runtime_error("Invalid state!");
- }
- /* Create a new C++ instance */
- Tensor tensor(t[0].cast<py::array>());
- return tensor;
- }));
- (void)py::class_<MetaTensor, std::shared_ptr<MetaTensor>>(*m, "MetaTensor")
- .def(py::init<TypePtr, const std::vector<int>>(), py::arg("dtype"), py::arg("shape"))
- .def_readonly(PYTHON_META_TENSOR_FLAG, &MetaTensor::parse_info_)
- .def("dtype", &MetaTensor::Dtype, "Get the MetaTensor's dtype.")
- .def("shape", &MetaTensor::shape, "Get the MetaTensor's shape.");
- }));
-
- } // namespace tensor
- } // namespace mindspore
|