diff --git a/mindspore/ccsrc/ir/tensor.cc b/mindspore/ccsrc/ir/tensor.cc index dccdbb65b8cc87c328d97b5001f74c0bdcd017fe..5ea761794524a2e428898c6ac76bc946ea0f20c7 100644 --- a/mindspore/ccsrc/ir/tensor.cc +++ b/mindspore/ccsrc/ir/tensor.cc @@ -23,12 +23,18 @@ #include #include #include +#include +#include +#include +#include #include "device/device_address.h" #include "pipeline/static_analysis/abstract_value.h" namespace mindspore { namespace tensor { +constexpr auto kEllipsis = "..."; +constexpr auto kThreshold = 6; using Bool = unsigned char; @@ -127,21 +133,22 @@ std::vector CopyData(const std::vector &shape, void *data, size_t data_l template class TensorDataImpl : public TensorData { public: - explicit TensorDataImpl(const std::vector &shape) : ndim_(shape.size()), data_size_(SizeOf(shape)) {} + explicit TensorDataImpl(const std::vector &shape) + : ndim_(shape.size()), data_size_(SizeOf(shape)), shape_(shape) {} TensorDataImpl(const std::vector &shape, void *data, size_t data_len) - : ndim_(shape.size()), data_size_(SizeOf(shape)), data_(CopyData(shape, data, data_len)) {} + : ndim_(shape.size()), data_size_(SizeOf(shape)), data_(CopyData(shape, data, data_len)), shape_(shape) {} TensorDataImpl(const std::vector &shape, void *data, TypeId data_type) - : ndim_(shape.size()), data_size_(SizeOf(shape)), data_(CopyData(shape, data, data_type)) {} + : ndim_(shape.size()), data_size_(SizeOf(shape)), data_(CopyData(shape, data, data_type)), shape_(shape) {} template TensorDataImpl(const std::vector &shape, InputIt first, InputIt last) - : ndim_(shape.size()), data_size_(SizeOf(shape)), data_(first, last) {} + : ndim_(shape.size()), data_size_(SizeOf(shape)), data_(first, last), shape_(shape) {} template TensorDataImpl(const std::vector &shape, Scalar scalar) - : ndim_(shape.size()), data_size_(SizeOf(shape)), data_({static_cast(scalar)}) {} + : ndim_(shape.size()), data_size_(SizeOf(shape)), data_({static_cast(scalar)}), shape_(shape) {} ssize_t size() const override { return static_cast(data_size_); } @@ -157,13 +164,12 @@ class TensorDataImpl : public TensorData { // Prevent null pointer for empty shape. return empty_data.data(); } - if (data_.empty()) { - // Lazy allocation. - data_.resize(data_size_); - } + CheckDataSafe(); return data_.data(); } + std::vector shape() const { return shape_; } + bool equals(const TensorData &other) const override { auto ptr = dynamic_cast *>(&other); if (ptr) { @@ -172,20 +178,121 @@ class TensorDataImpl : public TensorData { return false; } + // Prepare for lazy allocation. + void CheckDataSafe() { + // Lazy allocation. + if (data_.empty()) { + data_.resize(data_size_); + } + } + + // ToString() for lazy allocation. + std::string ToStringSafe() { + CheckDataSafe(); + return ToString(); + } + std::string ToString() const override { + constexpr auto valid = + std::is_same::value || std::is_same::value || std::is_same::value || + std::is_same::value || std::is_same::value || std::is_same::value || + std::is_same::value || std::is_same::value || std::is_same::value || + std::is_same::value || std::is_same::value || std::is_same::value; + if (!valid) { + MS_LOG(EXCEPTION) << "Type is invalid, T: " << typeid(T).name(); + } + if (data_size_ == 0) { + return ""; + } + if (data_.empty()) { + MS_LOG(ERROR) << "data_ is empty, data_size_: " << data_size_; + return ""; + } + std::ostringstream ss; + ssize_t cursor = 0; + SummaryStringRecursive(ss, &cursor, 0); + return ss.str(); + } + + private: + void OutputDataString(std::ostringstream &ss, ssize_t cursor, ssize_t start, ssize_t end) const { + constexpr auto isFloat = + std::is_same::value || std::is_same::value || std::is_same::value; + constexpr auto isSigned = std::is_same::value || std::is_same::value || + std::is_same::value || std::is_same::value; + for (ssize_t i = start; i < end && (cursor + i) < static_cast(data_size_); i++) { + if (isFloat) { + ss << std::setw(15) << std::setprecision(8) << std::setiosflags(std::ios::scientific | std::ios::right) + << data_[cursor + i]; + } else { + if (isSigned && static_cast(data_[cursor + i]) >= 0) { + ss << ' '; + } + ss << data_[cursor + i]; + } + if (i != end - 1) { + ss << ' '; + } + } + } + + void SummaryStringRecursive(std::ostringstream &ss, ssize_t *cursor, ssize_t depth) const { + if (depth >= static_cast(ndim_)) { + return; + } ss << '['; - for (auto value : data_) { - ss << value << ','; + if (depth == static_cast(ndim_) - 1) { // Bottom dimension + ssize_t num = shape_[depth]; + if (num > kThreshold) { + OutputDataString(ss, *cursor, 0, kThreshold / 2); + ss << ' ' << kEllipsis << ' '; + OutputDataString(ss, *cursor, num - kThreshold / 2, num); + } else { + OutputDataString(ss, *cursor, 0, num); + } + *cursor += num; + } else { // Middle dimension + ssize_t num = shape_[depth]; + // Handle the first half. + for (ssize_t i = 0; i < std::min(static_cast(kThreshold / 2), num); i++) { + if (i > 0) { + ss << '\n'; + ss << std::setw(depth + 1) << ' '; // Add the indent. + } + SummaryStringRecursive(ss, cursor, depth + 1); + } + // Handle the ignored part. + if (num > kThreshold) { + ss << '\n'; + ss << std::setw(depth + 1) << ' '; // Add the indent. + ss << kEllipsis << '\n'; + // Ignored at this layer. + ssize_t ignored = shape_[depth + 1]; + for (ssize_t i = depth + 2; i < static_cast(ndim_); i++) { + ignored *= shape_[i]; + } + // Multiple with ignored layers number. + ignored *= num - kThreshold; + + *cursor += ignored; + } + // Handle the second half. + if (num > kThreshold / 2) { + for (ssize_t i = num - kThreshold / 2; i < num; i++) { + ss << '\n'; + ss << std::setw(depth + 1) << ' '; // Add the indent. + SummaryStringRecursive(ss, cursor, depth + 1); + } + } } ss << ']'; - return ss.str(); } - private: size_t ndim_{0}; size_t data_size_{0}; std::vector data_; + std::vector shape_; }; template @@ -314,7 +421,7 @@ std::string Tensor::ToString() const { buf << "Tensor shape:[" << shape() << "]" << this->Dtype()->ToString(); // only print small tensor if (DataSize() < small_tensor_size) { - buf << "val:" << data().ToString(); + buf << ", value:" << data().ToString(); } return buf.str(); } @@ -324,10 +431,20 @@ std::string Tensor::ToStringRepr() const { auto type_ptr = this->Dtype(); MS_EXCEPTION_IF_NULL(type_ptr); buf << "Tensor shape:[" << shape() << "]" << type_ptr->ToString(); - buf << "\nval:" << data().ToString(); + buf << "\nvalue:" << data().ToString(); return buf.str(); } +std::string Tensor::ToStringSafe() { + data().CheckDataSafe(); + return ToString(); +} + +std::string Tensor::ToStringReprSafe() { + data().CheckDataSafe(); + return ToStringRepr(); +} + void Tensor::data_sync() const { if (device_address_ != nullptr) { if (!device_address_->SyncDeviceToHost(shape(), static_cast(data().nbytes()), data_type(), data_c())) { diff --git a/mindspore/ccsrc/ir/tensor.h b/mindspore/ccsrc/ir/tensor.h index 5be8a063c1119ed0e80f899a222b9e58f877e95e..d6951b389f5e34e65fd10fb28f38c8546b50a5c9 100644 --- a/mindspore/ccsrc/ir/tensor.h +++ b/mindspore/ccsrc/ir/tensor.h @@ -54,8 +54,14 @@ class TensorData { virtual ssize_t ndim() const = 0; /// Data pointer. virtual void *data() = 0; + /// Shape of data. + virtual std::vector shape() const = 0; /// Is data equals. virtual bool equals(const TensorData &other) const = 0; + /// Check for lazy allocation. + virtual void CheckDataSafe() = 0; + /// To string for lazy allocation. + virtual std::string ToStringSafe() = 0; /// To string. virtual std::string ToString() const = 0; }; @@ -180,7 +186,6 @@ class Tensor : public MetaTensor { // brief Get Tensor data pointer for c++ type // - // param writable true if writable, false if read only // return The pointer to the object void *data_c() { return data().data(); } @@ -217,6 +222,12 @@ class Tensor : public MetaTensor { std::string ToStringRepr() const; + /// To string for lazy allocation. + std::string ToStringSafe(); + + /// To string for lazy allocation. + std::string ToStringReprSafe(); + bool is_init() { return init_flag_; } void set_init_flag(bool flag) { init_flag_ = flag; } diff --git a/mindspore/ccsrc/ir/tensor_py.cc b/mindspore/ccsrc/ir/tensor_py.cc index 11a000cef7d3c83096da051f5663f08001233167..43b57cf616caac6ead3c24a4fbc136b950247694 100644 --- a/mindspore/ccsrc/ir/tensor_py.cc +++ b/mindspore/ccsrc/ir/tensor_py.cc @@ -351,8 +351,8 @@ REGISTER_PYBIND_DEFINE(Tensor, ([](const py::module *m) { >>> data.set_dtype(mindspore.int32) mindspore.int32 )mydelimiter") - .def("__str__", &Tensor::ToString) - .def("__repr__", &Tensor::ToStringRepr) + .def("__str__", &Tensor::ToStringSafe) + .def("__repr__", &Tensor::ToStringReprSafe) .def(py::pickle( [](const Tensor &t) { // __getstate__ /* Return a tuple that fully encodes the state of the object */