mxnet
ndarray.h
Go to the documentation of this file.
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 
25 #ifndef MXNET_NDARRAY_H_
26 #define MXNET_NDARRAY_H_
27 
28 #include <dmlc/base.h>
29 #include <dmlc/logging.h>
30 #include <dmlc/io.h>
31 #include <dmlc/type_traits.h>
32 #include <dmlc/registry.h>
33 #include <nnvm/node.h>
34 #include <vector>
35 #include <map>
36 #include <string>
37 #include <algorithm>
38 #include <memory>
39 #include <algorithm>
40 #if MXNET_USE_MKLDNN == 1
41 #include <mkldnn.hpp>
42 #endif
43 #include "./base.h"
44 #include "./storage.h"
45 #include "./engine.h"
46 // check c++11
47 #if DMLC_USE_CXX11 == 0
48 #error "cxx11 was required for ndarray module"
49 #endif
50 
51 namespace mxnet {
52 // enum for storage types
53 namespace csr {
55 }
56 
57 namespace rowsparse {
59 }
60 
62  kUndefinedStorage = -1, // undefined storage
63  kDefaultStorage, // dense
64  kRowSparseStorage, // row sparse
65  kCSRStorage, // csr
66 };
67 
69  kNormalErr, // normal
70  kCSRShapeErr, // shape mismatch for csr
71  kCSRIndPtrErr, // indptr error for csr
72  kCSRIdxErr, // idx error for csr
73  kRSPShapeErr, // shape mismatch for row sparse
74  kRSPIdxErr, // indices error for row sparse
75 };
76 
77 class MKLDNNMemory;
78 
82 class NDArray {
83  public:
85  NDArray() {
86  }
94  NDArray(const TShape &shape, Context ctx,
95  bool delay_alloc = false, int dtype = mshadow::default_type_flag)
96  : ptr_(std::make_shared<Chunk>(shape, ctx, delay_alloc, dtype)),
97  shape_(shape), dtype_(dtype), storage_type_(kDefaultStorage),
98  entry_({nullptr, 0, 0}) {
99  }
102  NDArray(const NDArrayStorageType stype, const TShape &shape, Context ctx,
103  bool delay_alloc = true, int dtype = mshadow::default_type_flag,
104  std::vector<int> aux_types = {}, std::vector<TShape> aux_shapes = {},
105  TShape storage_shape = TShape(mshadow::Shape1(0)));
112  explicit NDArray(Context ctx, int dtype = mshadow::default_type_flag) {
113  ptr_ = std::make_shared<Chunk>(TShape(mshadow::Shape1(0)), ctx, true, dtype);
114  dtype_ = dtype;
115  storage_type_ = kDefaultStorage;
116  entry_ = {nullptr, 0, 0};
117  }
125  NDArray(const TBlob &data, int dev_id)
126  : ptr_(std::make_shared<Chunk>(data, dev_id)), shape_(data.shape_),
127  dtype_(data.type_flag_), storage_type_(kDefaultStorage),
128  entry_({nullptr, 0, 0}) {
129  }
130 
139  NDArray(const TBlob &data, int dev_id, const std::function<void()>& deleter)
140  : ptr_(new Chunk(data, dev_id),
141  [deleter](Chunk *p) {
142  deleter(); // call custom deleter
143  delete p; // delete Chunk object
144  }),
145  shape_(data.shape_),
146  dtype_(data.type_flag_), storage_type_(kDefaultStorage),
147  entry_({nullptr, 0, 0}) {
148  }
149 
151  NDArray(int shared_pid, int shared_id, const TShape& shape, int dtype)
152  : ptr_(std::make_shared<Chunk>(shared_pid, shared_id, shape, dtype)), shape_(shape),
153  dtype_(dtype), storage_type_(kDefaultStorage), entry_({nullptr, 0, 0}) {
154  }
155 
166  NDArray(const NDArrayStorageType stype, const TShape &shape,
167  const TBlob &data, const std::vector<TBlob> &aux_data, int dev_id)
168  : ptr_(std::make_shared<Chunk>(stype, data, aux_data, dev_id)), shape_(shape),
169  dtype_(data.type_flag_), storage_type_(stype), entry_({nullptr, 0, 0}) {
170  }
175  void Init(const TShape &shape) {
176  ptr_->Init(shape, this->dtype_);
177  this->shape_ = shape;
178  }
183  shape_ = ptr_->storage_shape;
184  }
185  /*
186  * This indicates whether an array is a view of another array (created by
187  * reshape or slice). If an array is a view and the the data is stored in
188  * MKLDNN format, we need to convert the data to the default format when
189  * data in the view is accessed.
190  */
191  inline bool IsView() const {
192  // View only works on the default storage
193  if (storage_type() != kDefaultStorage)
194  return false;
195  // If the array reuses memory, its shape may be different from the storage
196  // shape. However, we shouldn't consider it as a view.
197  if (reuse_)
198  return false;
199  return byte_offset_ > 0 || shape() != ptr_->storage_shape;
200  }
201 
202  /* \brief Check whether the two arrays are the same array */
203  inline bool IsSame(const NDArray& other) const {
204  return ptr_ == other.ptr_ &&
205  shape_ == other.shape_ &&
206  byte_offset_ == other.byte_offset_ &&
207  dtype_ == other.dtype_;
208  }
209 
213  inline const TShape& shape() const {
214  return shape_;
215  }
221  inline const TShape &storage_shape() const {
222  CHECK(ptr_ != nullptr);
223  CHECK_NE(storage_type(), kDefaultStorage)
224  << "storage_shape() is not intended for kDefaultStorage.";
225  return ptr_->storage_shape;
226  }
227 
233  inline const TShape& aux_shape(size_t index) const {
234  CHECK_NE(storage_type(), kDefaultStorage)
235  << "aux_shape() is not intended for kDefaultStorage.";
236  return ptr_->aux_shapes[index];
237  }
238 
239  /* \return the shapes of all aux data */
240  const std::vector<TShape>& aux_shapes() const {
241  CHECK_NE(storage_type(), kDefaultStorage)
242  << "aux_shapes() is not intended for kDefaultStorage.";
243  return ptr_->aux_shapes;
244  }
245 
247  const std::vector<int>& aux_types() const {
248  CHECK_NE(storage_type(), kDefaultStorage)
249  << "aux_types() is not intended for kDefaultStorage.";
250  return ptr_->aux_types;
251  }
252 
260  inline void set_aux_shape(size_t index, const TShape& shape) const {
261  CHECK_NE(storage_type(), kDefaultStorage)
262  << "set_aux_shape() is not intended for kDefaultStorage.";
263  ptr_->set_aux_shape(index, shape);
264  }
265 
269  inline const TBlob& data() const {
270  if (storage_type() == kDefaultStorage) CheckAndAlloc();
271  SetTBlob();
272  return tblob_;
273  }
277  NDArray grad() const;
278 
282  inline TBlob aux_data(size_t i) const {
283  auto stype = storage_type();
284  TBlob res;
285  auto shape = aux_shape(i);
286  auto type = aux_type(i);
287  MSHADOW_TYPE_SWITCH(type, DType, {
288  auto dptr = static_cast<DType*>(ptr_->aux_handles[i].dptr);
289  CHECK(stype == kRowSparseStorage || stype == kCSRStorage)
290  << "Unexpected storage type: " << stype;
291  res = TBlob(dptr, shape, ptr_->aux_handles[i].ctx.dev_mask(), type);
292  });
293  return res;
294  }
298  inline Context ctx() const {
299  CHECK(!is_none());
300  return ptr_->shandle.ctx;
301  }
305  inline int dtype() const {
306  return dtype_;
307  }
308  inline int aux_type(size_t i) const {
309  CHECK(!is_none());
310  return ptr_->aux_types[i];
311  }
312 
314  return storage_type_;
315  }
317  inline bool is_none() const {
318  return ptr_.get() == nullptr;
319  }
321  bool fresh_out_grad() const;
323  void set_fresh_out_grad(bool state) const;
328  inline bool storage_initialized() const {
329  if (is_none()) return false;
330  auto stype = storage_type();
331  CHECK_NE(stype, kDefaultStorage)
332  << "storage_initialized() is not intended for kDefaultStorage.";
333  if (stype == kRowSparseStorage) {
334  CHECK_EQ(aux_shape(rowsparse::kIdx)[0], storage_shape()[0])
335  << "inconsistent storage shape " << storage_shape()
336  << " vs. aux shape " << aux_shape(rowsparse::kIdx);
337  return aux_shape(rowsparse::kIdx).Size() != 0;
338  } else if (stype == kCSRStorage) {
339  CHECK_EQ(aux_shape(csr::kIdx)[0], storage_shape()[0])
340  << "inconsistent storage shape " << storage_shape()
341  << " vs. aux shape " << aux_shape(csr::kIdx);
342  return aux_shape(csr::kIdx).Size() != 0;
343  } else {
344  LOG(FATAL) << "Unknown storage type";
345  }
346  return true;
347  }
350  CHECK(!is_none());
351  CHECK_EQ(storage_type(), kDefaultStorage);
352  CheckAndAlloc();
353  return ptr_->shandle;
354  }
359  inline void WaitToRead() const {
360  if (is_none()) return;
361  Engine::Get()->WaitForVar(ptr_->var);
362  }
367  inline void WaitToWrite() const {
368  if (is_none()) return;
374  [](RunContext, Engine::CallbackOnComplete on_complete) {
375  on_complete();
376  }, Context{}, {}, {ptr_->var});
377  Engine::Get()->WaitForVar(ptr_->var);
378  }
380  inline Engine::VarHandle var() const {
381  return ptr_->var;
382  }
384  inline size_t byte_offset() const {
385  return byte_offset_;
386  }
388  inline size_t version() const {
389  return var()->version();
390  }
395  void Save(dmlc::Stream *strm) const;
401  bool LegacyLoad(dmlc::Stream *strm, const uint32_t magic);
407  bool Load(dmlc::Stream *strm);
413  NDArray &operator=(real_t scalar);
420  NDArray &operator+=(const NDArray &src);
427  NDArray &operator+=(const real_t &src);
434  NDArray &operator-=(const NDArray &src);
441  NDArray &operator-=(const real_t &src);
448  NDArray &operator*=(const NDArray &src);
455  NDArray &operator*=(const real_t &src);
462  NDArray &operator/=(const NDArray &src);
469  NDArray &operator/=(const real_t &src);
475  NDArray Copy(Context ctx) const;
486  void SyncCopyFromCPU(const void *data, size_t size) const;
487 
491  void SyncCopyFromNDArray(const NDArray &src, int i = -1, int j = -1);
492 
503  void SyncCopyToCPU(void *data, size_t size) const;
509  void SyncCheckFormat(const bool full_check) const;
516  NDArray Slice(index_t begin, index_t end) const;
523  NDArray SliceWithRecord(index_t begin, index_t end);
529  NDArray At(index_t idx) const;
535  NDArray AtWithRecord(index_t idx);
540  NDArray aux_ndarray(size_t i) const;
541 
546  NDArray data_ndarray() const;
547 
555  inline NDArray AsArray(const TShape &shape, int dtype) const {
556  CHECK_EQ(storage_type(), kDefaultStorage)
557  << "AsArray is intended only for kDefaultStorage.";
558  CHECK_GE(ptr_->shandle.size,
559  shape.Size() * mshadow::mshadow_sizeof(dtype))
560  << "NDArray.AsArray: target memory size is bigger";
561  // We can't reuse memory in a view.
562  CHECK(!IsView());
563  NDArray ret = *this;
564  ret.shape_ = shape;
565  ret.dtype_ = dtype;
566  ret.reuse_ = true;
567  return ret;
568  }
569 
575  DLManagedTensor* ToDLPack() const;
576 
588  static NDArray FromDLPack(const DLManagedTensor* tensor);
589 
597  inline void SparseUpdateChunk(const NDArray &arr) const {
598  CHECK(shape_ == arr.shape_) << "ndarray shape is different from the target";
599  CHECK(dtype_ == arr.dtype_) << "ndarray dtype is different from the target";
600  auto stype = arr.storage_type();
601  CHECK(stype == kCSRStorage || stype == kRowSparseStorage)
602  << "Only to be used with CSR and RSP storage types";
603  // swap shandles between src and dst
604  Storage::Handle shandle_dst = arr.ptr_->shandle;
605  arr.ptr_->shandle = ptr_->shandle;
606  ptr_->shandle = shandle_dst;
607 
608  ptr_->storage_shape = arr.ptr_->storage_shape;
609  ptr_->storage_type = arr.ptr_->storage_type;
610  ptr_->ctx = arr.ptr_->ctx;
611 
612  // swap aux_handles between src and dst
613  size_t aux_idx = 0;
614  CHECK(ptr_->aux_handles.size() == arr.ptr_->aux_handles.size())
615  << "ndarray number of aux_handles is different from target";
616  for (auto &aux_handle : arr.ptr_->aux_handles) {
617  Storage::Handle aux_dst = ptr_->aux_handles[aux_idx];
618  ptr_->aux_handles[aux_idx] = aux_handle;
619  aux_handle = aux_dst;
620  aux_idx++;
621  }
622  ptr_->aux_types = arr.ptr_->aux_types;
623  ptr_->aux_shapes = arr.ptr_->aux_shapes;
624  }
625 
631  NDArray Reshape(const TShape &shape) const;
637  NDArray ReshapeWithRecord(const TShape &shape);
641  NDArray Detach() const {
642  NDArray ret(*this);
643  ret.entry_ = nnvm::NodeEntry{nullptr, 0, 0};
644  return ret;
645  }
646 
647  nnvm::Symbol get_autograd_symbol() const;
652  inline void CheckAndAlloc() const {
653  CHECK_EQ(storage_type(), kDefaultStorage);
654  ptr_->CheckAndAlloc();
655  }
656 
666  void ReshapeAndAlloc(const TShape& shape) {
667  CHECK_EQ(storage_type(), kDefaultStorage);
668  CHECK(!is_none());
669  shape_ = shape;
670  ptr_->CheckAndAlloc(shape.Size() * mshadow::mshadow_sizeof(dtype_));
671  }
672 
673  /* !
674  * \brief Alloc memory for non-default storage
675  * aux_shape is only known at run time
676  */
677  inline void CheckAndAlloc(const std::vector<TShape> &aux_shapes) const {
678  CHECK_NE(storage_type(), kDefaultStorage)
679  << "CheckAndAlloc(aux_shapes) is not intended for kDefaultStorage";
680  ptr_->CheckAndAlloc(shape_, aux_shapes, dtype_);
681  }
682  inline void CheckAndAllocData(const TShape &storage_shape) const {
683  CHECK_NE(storage_type(), kDefaultStorage)
684  << "CheckAndAllocData is not intended for kDefaultStorage";
685  ptr_->CheckAndAllocData(storage_shape, dtype_);
686  }
687  inline void CheckAndAllocAuxData(size_t i, const TShape &aux_shape) const {
688  CHECK_NE(storage_type(), kDefaultStorage)
689  << "CheckAndAllocAuxData is not intended for kDefaultStorage";
690  ptr_->CheckAndAllocAuxData(i, aux_shape);
691  }
692 
693 #if MXNET_USE_MKLDNN == 1
694  /*
695  * Create NDArray from mkldnn memory.
696  * mkldnn_mem The mkldnn memory to be managed.
697  */
698  explicit NDArray(const std::shared_ptr<mkldnn::memory> &mkldnn_mem);
699  /*
700  * Create NDArray from mkldnn memory descriptor.
701  * mem_pd The mkldnn memory descriptor to be created.
702  */
703  explicit NDArray(mkldnn::memory::primitive_desc mem_pd);
704  /*
705  * Test if the data is stored in one of special MKLDNN format.
706  */
707  bool IsMKLDNNData() const {
708  return ptr_->IsMKLDNN();
709  }
710  /*
711  * Test if the data is stored in one of default MXNet formats.
712  */
713  bool IsDefaultData() const {
714  return ptr_->IsDefault();
715  }
716  /*
717  * All functions below return a raw pointer to mkldnn memory. Actually there
718  * is a shared pointer that hold the memory either in NDArray or in MKLDNN
719  * stream. As long as we call these functions inside an operator, the return
720  * memory is always valid.
721  */
722 
723  /*
724  * This function returns mkldnn::memory with the default primitive_desc.
725  */
726  const mkldnn::memory *GetMKLDNNData() const;
727  /*
728  * This function returns mkldnn::memory with the given primitive_desc
729  * as long as the array size meets the required size in the given primitive_desc.
730  */
731  const mkldnn::memory *GetMKLDNNData(
732  const mkldnn::memory::primitive_desc &desc) const;
733  /*
734  * This function returns mkldnn::memory with the given primitive_desc.
735  * The returned mkldnn::memory will have the same physical layout as
736  * the given primitive_desc.
737  */
738  const mkldnn::memory *GetMKLDNNDataReorder(
739  const mkldnn::memory::primitive_desc &desc) const;
740 
741  /*
742  * This function copies data from mkldnn memory.
743  */
744  void CopyFrom(const mkldnn::memory &mem);
745  /*
746  * This function allocates memory for array and creates mkldnn memory
747  * with the specified format.
748  */
749  mkldnn::memory *CreateMKLDNNData(
750  const mkldnn::memory::primitive_desc &desc);
751 
752  /*
753  * These are the async version of the methods above.
754  * It changes the layout of this NDArray, but it happens after all accesses to
755  * the array are complete.
756  */
757  void Reorder2DefaultAsync();
758  void MKLDNNDataReorderAsync(const mkldnn::memory::primitive_desc &desc);
759 
760  /*
761  * This creates a new NDArray with the reordered data.
762  * It doesn't affect the data of the original NDArray.
763  */
764  NDArray Reorder2Default() const;
765 
766  void InvalidateMKLDNNData();
767 
768  /*
769  * This function is used inside operators to reshape an array.
770  * It doesn't change the layout of the original array and allocate memory from
771  * the temporary buffer. The returned array is only valid inside the current
772  * invocation of this operator.
773  * This is different from Reshape. Reshape will cause data in the array to be
774  * converted to the default layout and allocate memory from malloc directly,
775  * which can be expensive.
776  * It's used by FullyConnected right now.
777  */
778  NDArray MKLDNNDataReshape(const TShape &shape) const;
779 
783  void UpdateMKLDNNMemDesc(mkldnn::memory::format format);
784 #endif
785 
792  static void Save(dmlc::Stream* fo,
793  const std::vector<NDArray>& data,
794  const std::vector<std::string>& names);
801  static void Load(dmlc::Stream* fi,
802  std::vector<NDArray>* data,
803  std::vector<std::string>* keys);
804 
805  private:
806  friend class Imperative;
808  // shandle is used to store the actual values in the NDArray
809  // aux_handles store the aux data(such as indices) if it's needed by non-default storage.
810  struct Chunk {
814  Storage::Handle shandle;
819  std::vector<Storage::Handle> aux_handles;
820 
821 #if MXNET_USE_MKLDNN == 1
822 
824  std::shared_ptr<MKLDNNMemory> mkl_mem_;
825 #endif
826 
827  Engine::VarHandle var;
833  bool static_data;
836  bool delay_alloc;
837  // the type of the storage. The storage_type is never kUndefinedStorage once the chunk
838  // is constructed.
839  NDArrayStorageType storage_type = kDefaultStorage;
841  std::vector<int> aux_types;
842  // context of data
843  Context ctx;
844  // The shape of the chunk data.
845  // This might not be the same shape as the NDArray, since the storage may be sparse.
846  // The default value for storage_shape is {0} when an empty non-default NDArray is created.
847  TShape storage_shape;
848  // The shape of aux data. The default value for the shape depends on the type of storage.
849  // If aux_shapes[i].Size() is zero, aux data i is empty.
850  std::vector<TShape> aux_shapes;
851 
853  Chunk() : static_data(true), delay_alloc(false) {}
854 
856  Chunk(TShape shape, Context ctx_, bool delay_alloc_, int dtype)
857  : static_data(false), delay_alloc(true), ctx(ctx_) {
858  auto size = shape.Size();
859  storage_shape = shape;
860  var = Engine::Get()->NewVariable();
861  shandle.size = size * mshadow::mshadow_sizeof(dtype);
862  shandle.ctx = ctx_;
863  if (!delay_alloc_) this->CheckAndAlloc();
864  }
865 
866  Chunk(const TBlob &data, int dev_id)
867  : static_data(true), delay_alloc(false) {
868  CHECK(storage_type == kDefaultStorage);
869  var = Engine::Get()->NewVariable();
870  if (data.dev_mask() == cpu::kDevMask) {
871  ctx = Context::CPU();
872  } else {
873  CHECK_EQ(data.dev_mask(), gpu::kDevMask);
874  ctx = Context::GPU(dev_id);
875  }
876  // init shandle
877  shandle.ctx = ctx;
878  shandle.dptr = data.dptr_;
879  shandle.size = data.shape_.Size() * mshadow::mshadow_sizeof(data.type_flag_);
880  storage_shape = data.shape_;
881  }
882 
883  Chunk(int shared_pid, int shared_id, const TShape& shape, int dtype)
884  : static_data(false), delay_alloc(false) {
885  var = Engine::Get()->NewVariable();
886  ctx = Context::CPUShared(0);
887  shandle.size = shape.Size() * mshadow::mshadow_sizeof(dtype);
888  shandle.ctx = ctx;
889  shandle.shared_pid = shared_pid;
890  shandle.shared_id = shared_id;
891  Storage::Get()->Alloc(&shandle);
892  storage_shape = shape;
893  }
894  // Constructor for a non-default storage chunk
895  Chunk(NDArrayStorageType storage_type_, const TShape &storage_shape_, Context ctx_,
896  bool delay_alloc_, int dtype, const std::vector<int> &aux_types_,
897  const std::vector<TShape> &aux_shapes_)
898  : static_data(false), delay_alloc(delay_alloc_), storage_type(storage_type_),
899  aux_types(aux_types_), ctx(ctx_), storage_shape(storage_shape_),
900  aux_shapes(aux_shapes_) {
901  shandle.ctx = ctx;
902  var = Engine::Get()->NewVariable();
903  // aux_handles always reflect the correct number of aux data
904  for (size_t i = 0; i < aux_shapes.size(); i++) {
905  CheckAndAllocAuxData(i, aux_shapes[i]);
906  // this line is needed in case when aux_shapes[i].Size() = 0
907  // aux_handles[i] will not be updated and take only default value.
908  aux_handles[i].ctx = ctx;
909  }
910  if (!delay_alloc) {
911  CheckAndAllocData(storage_shape, dtype);
912  }
913  }
914 
915  Chunk(const NDArrayStorageType storage_type_, const TBlob &data,
916  const std::vector<TBlob> &aux_data, int dev_id)
917  : static_data(true), delay_alloc(false), storage_type(storage_type_) {
918  using namespace mshadow;
919  CHECK_NE(storage_type, kDefaultStorage);
920  // init var
921  var = Engine::Get()->NewVariable();
922  // init ctx
923  if (data.dev_mask() == cpu::kDevMask) {
924  ctx = Context::CPU();
925  } else {
926  CHECK_EQ(data.dev_mask(), gpu::kDevMask);
927  ctx = Context::GPU(dev_id);
928  }
929  // init shandle
930  shandle.ctx = ctx;
931  shandle.dptr = data.dptr_;
932  shandle.size = data.shape_.Size() * mshadow_sizeof(data.type_flag_);
933  storage_shape = data.shape_;
934  // init aux handles
935  for (const auto &aux : aux_data) {
936  Storage::Handle aux_handle;
937  aux_handle.ctx = ctx;
938  aux_handle.dptr = aux.dptr_;
939  aux_handle.size = aux.shape_.Size() * mshadow_sizeof(aux.type_flag_);
940  aux_handles.push_back(aux_handle);
941  aux_types.emplace_back(aux.type_flag_);
942  aux_shapes.emplace_back(aux.shape_);
943  }
944  }
945 
947  inline void set_aux_shape(const size_t i, const TShape& shape) {
948  aux_shapes[i] = shape;
949  if (storage_shape.ndim() > 0) {
950  if (storage_type == kRowSparseStorage && i == rowsparse::kIdx) {
951  storage_shape[0] = shape[0];
952  } else if (storage_type == kCSRStorage && i == csr::kIdx) {
953  storage_shape[0] = shape[0];
954  }
955  }
956  }
957 
959  inline void CheckAndAlloc(void) {
960  if (delay_alloc) {
961  shandle = Storage::Get()->Alloc(shandle.size, shandle.ctx);
962 #if MXNET_USE_MKLDNN == 1
963  mkl_mem_ = nullptr;
964 #endif
965  delay_alloc = false;
966  }
967  }
968 
970  // size is the number of bytes
971  void CheckAndAlloc(uint64_t dbytes) {
972  CHECK_EQ(kDefaultStorage, storage_type)
973  << "CheckAndAlloc(dbytes) is only intended for kDefaultStorage";
974  dbytes = std::max(dbytes, static_cast<uint64_t>(shandle.size));
975  if (delay_alloc) {
976  shandle = Storage::Get()->Alloc(dbytes, shandle.ctx);
977 #if MXNET_USE_MKLDNN == 1
978  mkl_mem_ = nullptr;
979 #endif
980  delay_alloc = false;
981  } else if (shandle.size < dbytes) {
982  // free storage
983  Storage::Get()->Free(shandle);
984  // init storage
985  shandle = Storage::Get()->Alloc(dbytes, shandle.ctx);
986 #if MXNET_USE_MKLDNN == 1
987  mkl_mem_ = nullptr;
988 #endif
989  }
990  }
992  void Init(const TShape &shape, int dtype) {
993  auto size = shape.Size();
994  storage_shape = shape;
995  shandle.size = size * mshadow::mshadow_sizeof(dtype);
996  this->CheckAndAlloc();
997  }
998  inline void CheckAndAlloc(const TShape &shape, const std::vector<TShape> &aux_shapes,
999  int dtype) {
1000  // calculate size, perform allocation
1001  if (kRowSparseStorage == storage_type) {
1002  // For row sparse, aux_shape indicates the number of rows to allocate
1003  auto aux_shape = aux_shapes[rowsparse::kIdx];
1004  CheckAndAllocAuxData(rowsparse::kIdx, aux_shape);
1005  TShape storage_shape(shape);
1006  storage_shape[0] = aux_shape[0];
1007  CheckAndAllocData(storage_shape, dtype);
1008  } else if (kCSRStorage == storage_type) {
1009  CheckAndAllocAuxData(csr::kIndPtr, aux_shapes[csr::kIndPtr]);
1010  CheckAndAllocAuxData(csr::kIdx, aux_shapes[csr::kIdx]);
1011  CheckAndAllocData(aux_shapes[csr::kIdx], dtype);
1012  } else {
1013  LOG(FATAL) << "Storage type " << storage_type << " not implemented for CheckAndAlloc";
1014  }
1015  }
1016  // create storage handle for data based on shape and dtype, assuming ctx is set
1017  // storage shape is also updated
1018  // if data is already allocated, try reuse the storage. Otherwise, free the current one
1019  // and allocate new storage
1020  void CheckAndAllocData(const TShape &shape, int dtype);
1021 
1022 #if MXNET_USE_MKLDNN == 1
1023  // Have MKL memory reference to the data in the default storage
1024  // or create memory for MKLDNN.
1025  void SetMKLMem(const TShape &shape, int dtype);
1026  // If the data is stored in MKLDNN layout, we reorder data in mkl_mem_ and
1027  // save the result in shandle.
1028  void Reorder2Default();
1029  // Reroder data to a specified layout.
1030  void MKLDNNDataReorder(const mkldnn::memory::primitive_desc &desc);
1031  bool IsMKLDNN() const;
1032  bool IsDefault() const;
1033 #endif
1034 
1035  // create storage handle for aux data based on shape
1036  // this function assumes ctx, aux shapes and aux types are set
1037  // aux shape is also updated
1038  // if aux data is already allocated, try reuse the storage. Otherwise, free the current one
1039  // and allocate new storage
1040  inline void CheckAndAllocAuxData(size_t i, const TShape &shape) {
1041  CHECK_EQ(shape.ndim(), 1) << "shape must be 1D in CheckAndAllocAuxData";
1042  CHECK_NE(storage_type, kUndefinedStorage)
1043  << "storage type cannot be kUndefinedStorage in CheckAndAllocAuxData";
1044  CHECK_NE(storage_type, kDefaultStorage)
1045  << "storage type cannot be kDefaultStorage in CheckAndAllocAuxData";
1046  if (aux_handles.size() <= i) {
1047  aux_handles.resize(i + 1);
1048  }
1049  size_t aux_bytes = shape.Size() * mshadow::mshadow_sizeof(aux_types[i]);
1050  if (aux_handles[i].size < aux_bytes) {
1051  // free storage
1052  Storage::Get()->Free(aux_handles[i]);
1053  // init aux storage
1054  aux_handles[i] = Storage::Get()->Alloc(aux_bytes, ctx);
1055  }
1056  // init shape
1057  set_aux_shape(i, shape);
1058  }
1060  ~Chunk();
1061  }; // struct Chunk
1062 
1063  void SetTBlob() const;
1064 
1066  std::shared_ptr<Chunk> ptr_{nullptr};
1068  TShape shape_;
1070  size_t byte_offset_ = 0;
1072  int dtype_ = -1;
1074  bool reuse_ = false;
1076  NDArrayStorageType storage_type_ = kUndefinedStorage;
1078  nnvm::NodeEntry entry_;
1086  mutable TBlob tblob_;
1087 }; // class NDArray
1088 
1092 size_t num_aux_data(NDArrayStorageType stype);
1093 
1105 void CopyFromTo(const NDArray &from, const NDArray *to, int priority = 0);
1106 
1120 void CopyFromTo(const NDArray &from, const NDArray& to, int priority = 0, bool is_opr = false);
1121 
1128 void ElementwiseSum(const std::vector<NDArray> &source, NDArray *out, int priority = 0);
1129 
1136 NDArray operator+(const NDArray &lhs, const NDArray &rhs);
1143 NDArray operator+(const NDArray &lhs, const real_t &rhs);
1150 NDArray operator-(const NDArray &lhs, const NDArray &rhs);
1157 NDArray operator-(const NDArray &lhs, const real_t &rhs);
1164 NDArray operator*(const NDArray &lhs, const NDArray &rhs); \
1171 NDArray operator*(const NDArray &lhs, const real_t &rhs);
1178 NDArray operator/(const NDArray &lhs, const NDArray &rhs);
1185 NDArray operator/(const NDArray &lhs, const real_t &rhs);
1186 
1191 void RandomSeed(uint32_t seed);
1196 void RandomSeed(Context ctx, uint32_t seed);
1203 void SampleUniform(real_t begin, real_t end, NDArray *out);
1210 void SampleGaussian(real_t mu, real_t sigma, NDArray *out);
1217 void SampleGamma(real_t alpha, real_t beta, NDArray *out);
1223 void SampleExponential(real_t lambda, NDArray *out);
1229 void SamplePoisson(real_t lambda, NDArray *out);
1236 void SampleNegBinomial(int32_t k, real_t p, NDArray *out);
1243 void SampleGenNegBinomial(real_t mu, real_t alpha, NDArray *out);
1244 
1245 
1246 //--------------------------------------------------------------
1247 // The following part are API Registration of NDArray functions.
1248 //--------------------------------------------------------------
1249 
1251 typedef std::function<void (NDArray **used_vars,
1252  real_t *scalars,
1253  NDArray **mutate_vars,
1254  int num_params,
1255  char **param_keys,
1256  char **param_vals)> NDArrayAPIFunction;
1272 };
1275  : public dmlc::FunctionRegEntryBase<NDArrayFunctionReg,
1276  NDArrayAPIFunction> {
1278  unsigned num_use_vars;
1282  unsigned num_scalars;
1289  : num_use_vars(0),
1290  num_mutate_vars(0),
1291  num_scalars(0),
1292  type_mask(0) {}
1299  inline NDArrayFunctionReg &set_function(void (*fsetvalue)(const real_t &rhs,
1300  NDArray *out)) {
1301  body = [fsetvalue] (NDArray **used_vars, real_t *s, NDArray **mutate_vars,
1302  int num_params, char **param_keys, char **param_vals) {
1303  (*fsetvalue)(s[0], mutate_vars[0]);
1304  };
1305  num_mutate_vars = 1; num_scalars = 1;
1306  this->add_argument("src", "real_t", "Source input to the function.");
1307  return *this;
1308  }
1315  inline NDArrayFunctionReg &set_function(void(*fternary)(const NDArray &lhs,
1316  const NDArray &mhs,
1317  const NDArray &rhs,
1318  NDArray *out)) {
1319  body = [fternary](NDArray **used_vars,
1320  real_t *s, NDArray **mutate_vars,
1321  int num_params, char **param_keys, char **param_vals) {
1322  (*fternary)(*used_vars[0], *used_vars[1], *used_vars[2], mutate_vars[0]);
1323  };
1324  num_use_vars = 3; num_mutate_vars = 1;
1326  this->add_argument("lhs", "NDArray", "Left operand to the function.");
1327  this->add_argument("mhs", "NDArray", "Middle operand to the function.");
1328  this->add_argument("rhs", "NDArray", "Right operand to the function.");
1329  return *this;
1330  }
1337  inline NDArrayFunctionReg &set_function(void (*fbinary)(const NDArray &lhs,
1338  const NDArray &rhs,
1339  NDArray *out)) {
1340  body = [fbinary] (NDArray **used_vars, real_t *s, NDArray **mutate_vars,
1341  int num_params, char **param_keys, char **param_vals) {
1342  (*fbinary)(*used_vars[0], *used_vars[1], mutate_vars[0]);
1343  };
1344  num_use_vars = 2; num_mutate_vars = 1;
1346  this->add_argument("lhs", "NDArray", "Left operand to the function.");
1347  this->add_argument("rhs", "NDArray", "Right operand to the function.");
1348  return *this;
1349  }
1356  inline NDArrayFunctionReg &set_function(void (*fscalar)(const NDArray &lhs,
1357  const real_t &rhs,
1358  NDArray *out)) {
1359  body = [fscalar] (NDArray **used_vars, real_t *s, NDArray **mutate_vars,
1360  int num_params, char **param_keys, char **param_vals) {
1361  (*fscalar)(*used_vars[0], s[0], mutate_vars[0]);
1362  };
1363  num_use_vars = 1; num_mutate_vars = 1; num_scalars = 1;
1365  this->add_argument("lhs", "NDArray", "Left operand to the function.");
1366  this->add_argument("rhs", "real_t", "Right operand to the function.");
1367  return *this;
1368  }
1375  inline NDArrayFunctionReg &set_function(void (*funary)(const NDArray &src,
1376  NDArray *out)) {
1377  body = [funary] (NDArray **used_vars, real_t *s, NDArray **mutate_vars,
1378  int num_params, char **param_keys, char **param_vals) {
1379  (*funary)(*used_vars[0], mutate_vars[0]);
1380  };
1381  num_use_vars = 1; num_mutate_vars = 1;
1383  this->add_argument("src", "NDArray", "Source input to the function.");
1384  return *this;
1385  }
1393  void (*fgeneric)(NDArray **used_vars,
1394  real_t *s,
1395  NDArray **mutate_vars,
1396  const std::map<std::string, std::string>& param)) {
1397  body = [fgeneric] (NDArray **used_vars, real_t *s, NDArray **mutate_vars,
1398  int num_params, char **param_keys, char **param_vals) {
1399  std::map<std::string, std::string> param;
1400  for (int i = 0; i < num_params; ++i) {
1401  param[param_keys[i]] = param_vals[i];
1402  }
1403  fgeneric(used_vars, s, mutate_vars, param);
1404  };
1405  return *this;
1406  }
1412  inline NDArrayFunctionReg &set_num_use_vars(unsigned n) {
1413  num_use_vars = n; return *this;
1414  }
1421  num_mutate_vars = n; return *this;
1422  }
1428  inline NDArrayFunctionReg &set_num_scalars(unsigned n) {
1429  num_scalars = n; return *this;
1430  }
1436  inline NDArrayFunctionReg &set_type_mask(int tmask) {
1437  type_mask = tmask; return *this;
1438  }
1439 }; // NDArrayFunctionReg
1440 
1452 #define MXNET_REGISTER_NDARRAY_FUN(name) \
1453  DMLC_REGISTRY_REGISTER(::mxnet::NDArrayFunctionReg, NDArrayFunctionReg, name)
1454 
1455 } // namespace mxnet
1456 
1457 namespace dmlc {
1459 DMLC_DECLARE_TRAITS(has_saveload, mxnet::NDArray, true);
1460 } // namespace dmlc
1461 #endif // MXNET_NDARRAY_H_
Definition: ndarray.h:74
Definition: ndarray.h:63
NDArrayStorageType
Definition: ndarray.h:61
Definition: ndarray.h:54
NDArrayFunctionReg & set_num_mutate_vars(unsigned n)
set the number of mutate variables
Definition: ndarray.h:1420
NDArrayFormatErr
Definition: ndarray.h:68
Engine::VarHandle var() const
Definition: ndarray.h:380
void RandomSeed(uint32_t seed)
Seed all random number generator in mxnet.
NDArrayStorageType storage_type() const
Definition: ndarray.h:313
Engine that schedules all the operations according to dependency.
TShape shape_
shape of the tensor
Definition: tensor_blob.h:72
const TShape & storage_shape() const
Definition: ndarray.h:221
NDArrayFunctionReg()
constructor
Definition: ndarray.h:1288
namespace of mxnet
Definition: base.h:118
void ReshapeAndAlloc(const TShape &shape)
Allocate the space if the allocation has been delayed or the requested size is bigger than the availa...
Definition: ndarray.h:666
NDArray operator*(const NDArray &lhs, const NDArray &rhs)
elementwise multiplication
virtual void Free(Handle handle)=0
Free storage.
NDArrayFunctionReg & set_num_use_vars(unsigned n)
set the number of mutate variables
Definition: ndarray.h:1412
DMLC_DECLARE_TRAITS(has_saveload, mxnet::NDArray, true)
traits
mshadow::default_real_t real_t
data type that will be used to store ndarray
Definition: base.h:126
static Context GPU(int32_t dev_id=-1)
int type_mask
information on how function should be called from API
Definition: ndarray.h:1284
NDArrayFunctionReg & set_function(void(*funary)(const NDArray &src, NDArray *out))
set the function body to a unary NDArray function this will also auto set the parameters correctly ...
Definition: ndarray.h:1375
NDArray Detach() const
Return a copy of this NDArray without autograd history.
Definition: ndarray.h:641
int type_flag_
type flag of the tensor blob
Definition: tensor_blob.h:74
NDArrayFunctionReg & set_num_scalars(unsigned n)
set the number of scalar arguments
Definition: ndarray.h:1428
nnvm::TShape TShape
Shape data structure used to record shape information.
Definition: base.h:128
Definition: ndarray.h:72
unsigned num_mutate_vars
number of variable mutated by this function
Definition: ndarray.h:1280
execution time context. The information needed in runtime for actual execution.
Definition: base.h:257
void * dptr
Pointer to the data.
Definition: storage.h:45
NDArrayFunctionReg & set_function(void(*fscalar)(const NDArray &lhs, const real_t &rhs, NDArray *out))
set the function body to a binary NDArray function this will also auto set the parameters correctly ...
Definition: ndarray.h:1356
base class of engine variables.
Definition: engine.h:44
Definition: ndarray.h:65
Context ctx
Context information about device and ID.
Definition: storage.h:53
Storage::Handle storage_handle() const
get storage handle
Definition: ndarray.h:349
NDArray()
default constructor
Definition: ndarray.h:85
unsigned num_use_vars
number of variable used by this function
Definition: ndarray.h:1278
int shared_id
Definition: storage.h:58
NDArrayFunctionReg & set_function(void(*fternary)(const NDArray &lhs, const NDArray &mhs, const NDArray &rhs, NDArray *out))
set the function body to a ternary NDArray function this will also auto set the parameters correctly ...
Definition: ndarray.h:1315
Definition: ndarray.h:62
Symbol max(const std::string &symbol_name, Symbol data, dmlc::optional< Shape > axis=dmlc::optional< Shape >(), bool keepdims=false, bool exclude=false)
Definition: op.h:2756
RowSparseAuxType
Definition: ndarray.h:58
Definition: ndarray.h:70
bool is_none() const
Definition: ndarray.h:317
all the scalar should go before use_vars
Definition: ndarray.h:1262
void SampleExponential(real_t lambda, NDArray *out)
Sample exponential distribution for each elements of out.
void SparseUpdateChunk(const NDArray &arr) const
Update ndarray chunk storage handles using existing ndarray storage handles Also update the aux_handl...
Definition: ndarray.h:597
void * dptr_
pointer to the data
Definition: tensor_blob.h:70
virtual VarHandle NewVariable()=0
Allocate a new variable, the variable can then be used to schedule the operation concurrently via dep...
Definition: ndarray.h:58
whether this function allows the handles in the target to be empty NDArray that are not yet initializ...
Definition: ndarray.h:1271
Definition: ndarray.h:73
static Storage * Get()
const TShape & shape() const
Definition: ndarray.h:213
Definition: ndarray.h:1457
virtual void WaitForVar(VarHandle var)=0
Wait for a variable.
const std::vector< TShape > & aux_shapes() const
Definition: ndarray.h:240
bool IsView() const
Definition: ndarray.h:191
Context ctx() const
Definition: ndarray.h:298
void CopyFromTo(const NDArray &from, const NDArray *to, int priority=0)
issue an copy operation from one NDArray to another the two ndarray can sit on different devices this...
CSRAuxType
Definition: ndarray.h:54
void SampleGaussian(real_t mu, real_t sigma, NDArray *out)
Sample gaussian distribution for each elements of out.
Definition: ndarray.h:54
Storage manager across multiple devices.
void WaitToRead() const
Block until all the pending write operations with respect to current NDArray are finished, and read can be performed.
Definition: ndarray.h:359
virtual void PushAsync(AsyncFn exec_fun, Context exec_ctx, std::vector< VarHandle > const &const_vars, std::vector< VarHandle > const &mutable_vars, FnProperty prop=FnProperty::kNormal, int priority=0, const char *opr_name=nullptr, bool wait=false)=0
Push an asynchronous operation to the engine.
int dtype() const
Definition: ndarray.h:305
bool storage_initialized() const
Returns true if a sparse ndarray&#39;s aux_data and storage are initialized Throws an exception if the in...
Definition: ndarray.h:328
Storage handle.
Definition: storage.h:41
static Context CPUShared(int32_t dev_id=0)
Definition: ndarray.h:64
void set_aux_shape(size_t index, const TShape &shape) const
For a sparse operation on a csr matrix for example, the size of the column index array is an estimate...
Definition: ndarray.h:260
void CheckAndAllocData(const TShape &storage_shape) const
Definition: ndarray.h:682
size_t num_aux_data(NDArrayStorageType stype)
NDArrayFunctionReg & set_type_mask(int tmask)
set type mask
Definition: ndarray.h:1436
void WaitToWrite() const
Block until all the pending read/write operations with respect to current NDArray are finished...
Definition: ndarray.h:367
NDArray(const TBlob &data, int dev_id, const std::function< void()> &deleter)
constructing a static NDArray that shares data with TBlob which is with deleter Use with caution: all...
Definition: ndarray.h:139
Handle Alloc(size_t size, Context ctx)
Allocate a new contiguous memory for a given size.
Definition: storage.h:66
NDArray operator-(const NDArray &lhs, const NDArray &rhs)
elementwise subtraction
Definition: ndarray.h:71
NDArrayFunctionReg & set_function(void(*fsetvalue)(const real_t &rhs, NDArray *out))
set the function body to a NDArray setvalue function this will also auto set the parameters correctly...
Definition: ndarray.h:1299
void Init(const TShape &shape)
initialize the NDArray, assuming it is not assigned a meaningful shape before
Definition: ndarray.h:175
NDArray(int shared_pid, int shared_id, const TShape &shape, int dtype)
create ndarray from shared memory
Definition: ndarray.h:151
NDArray operator+(const NDArray &lhs, const NDArray &rhs)
elementwise add
size_t byte_offset() const
Definition: ndarray.h:384
void SampleUniform(real_t begin, real_t end, NDArray *out)
Sample uniform distribution for each elements of out.
Registry entry for NDArrayFunction.
Definition: ndarray.h:1274
NDArrayFunctionReg & set_function(void(*fbinary)(const NDArray &lhs, const NDArray &rhs, NDArray *out))
set the function body to a binary NDArray function this will also auto set the parameters correctly ...
Definition: ndarray.h:1337
static Context CPU(int32_t dev_id=0)
runtime functions for NDArray
Definition: imperative.h:39
int aux_type(size_t i) const
Definition: ndarray.h:308
OnComplete Callback to the engine, called by AsyncFn when action completes.
Definition: engine.h:73
all the use_vars should go before scalar
Definition: ndarray.h:1260
NDArray AsArray(const TShape &shape, int dtype) const
Create a NDArray that shares memory with current one The new array must have smaller memory size than...
Definition: ndarray.h:555
size_t version() const
return var version of the NDArray
Definition: ndarray.h:388
void CheckAndAlloc(const std::vector< TShape > &aux_shapes) const
Definition: ndarray.h:677
unsigned num_scalars
number of scalars used by this function
Definition: ndarray.h:1282
static Engine * Get()
const TBlob & data() const
Definition: ndarray.h:269
void CheckAndAllocAuxData(size_t i, const TShape &aux_shape) const
Definition: ndarray.h:687
NDArray(const NDArrayStorageType stype, const TShape &shape, const TBlob &data, const std::vector< TBlob > &aux_data, int dev_id)
constructing a static NDArray of non-default storage that shares data with TBlob Use with caution: al...
Definition: ndarray.h:166
Definition: ndarray.h:69
void CheckAndAlloc() const
Allocate the space if it is delayed allocated. This is an internal function used by system that norma...
Definition: ndarray.h:652
mshadow::index_t index_t
index type usually use unsigned
Definition: base.h:124
size_t size
Size of the storage.
Definition: storage.h:49
void SetShapeFromChunk()
set the correct shape of NDArray directly from the storage_shape of its own chunk.
Definition: ndarray.h:182
TBlob aux_data(size_t i) const
Definition: ndarray.h:282
void SampleGenNegBinomial(real_t mu, real_t alpha, NDArray *out)
Sample generalized negative binomial distribution for each elements of out.
Context information about the execution environment.
Definition: base.h:133
void SamplePoisson(real_t lambda, NDArray *out)
Sample Poisson distribution for each elements of out.
const TShape & aux_shape(size_t index) const
get the shape of aux_data(index)
Definition: ndarray.h:233
ndarray interface
Definition: ndarray.h:82
NDArray(Context ctx, int dtype=mshadow::default_type_flag)
constructs a new dynamic NDArray whose shape is unknown, hence the NDArray is inherently lazily creat...
Definition: ndarray.h:112
NDArray(const TBlob &data, int dev_id)
constructing a static NDArray that shares data with TBlob Use with caution: allocate ONLY ONE NDArray...
Definition: ndarray.h:125
int dev_mask() const
device mask of the corresponding device
Definition: tensor_blob.h:242
Symbol Reshape(const std::string &symbol_name, Symbol data, Shape shape=Shape(), bool reverse=false, Shape target_shape=Shape(), bool keep_highest=false)
Definition: op.h:302
void ElementwiseSum(const std::vector< NDArray > &source, NDArray *out, int priority=0)
Perform elementwise sum over each data from source, store result into out.
std::function< void(NDArray **used_vars, real_t *scalars, NDArray **mutate_vars, int num_params, char **param_keys, char **param_vals)> NDArrayAPIFunction
definition of NDArray function
Definition: ndarray.h:1256
void SampleNegBinomial(int32_t k, real_t p, NDArray *out)
Sample negative binomial distribution for each elements of out.
NDArrayFunctionReg & set_function(void(*fgeneric)(NDArray **used_vars, real_t *s, NDArray **mutate_vars, const std::map< std::string, std::string > &param))
set the function body to a unary NDArray function this will also auto set the parameters correctly ...
Definition: ndarray.h:1392
bool IsSame(const NDArray &other) const
Definition: ndarray.h:203
int shared_pid
Id for IPC shared memory.
Definition: storage.h:57
tensor blob class that can be used to hold tensor of any dimension, any device and any data type...
Definition: tensor_blob.h:66
const std::vector< int > & aux_types() const
Definition: ndarray.h:247
void SampleGamma(real_t alpha, real_t beta, NDArray *out)
Sample gamma distribution for each elements of out.
NDArray(const TShape &shape, Context ctx, bool delay_alloc=false, int dtype=mshadow::default_type_flag)
constructs a new dynamic NDArray
Definition: ndarray.h:94
NDArray operator/(const NDArray &lhs, const NDArray &rhs)
elementwise division
NDArrayFunctionTypeMask
mask information on how functions can be exposed
Definition: ndarray.h:1258