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)));
106 
114  NDArray(const TBlob &data, int dev_id)
115  : ptr_(std::make_shared<Chunk>(data, dev_id)), shape_(data.shape_),
116  dtype_(data.type_flag_), storage_type_(kDefaultStorage),
117  entry_({nullptr, 0, 0}) {
118  }
120  NDArray(int shared_pid, int shared_id, const TShape& shape, int dtype)
121  : ptr_(std::make_shared<Chunk>(shared_pid, shared_id, shape, dtype)), shape_(shape),
122  dtype_(dtype), storage_type_(kDefaultStorage), entry_({nullptr, 0, 0}) {
123  }
124 
135  NDArray(const NDArrayStorageType stype, const TShape &shape,
136  const TBlob &data, const std::vector<TBlob> &aux_data, int dev_id)
137  : ptr_(std::make_shared<Chunk>(stype, data, aux_data, dev_id)), shape_(shape),
138  dtype_(data.type_flag_), storage_type_(stype), entry_({nullptr, 0, 0}) {
139  }
140 
141  /*
142  * This indicates whether an array is a view of another array (created by
143  * reshape or slice). If an array is a view and the the data is stored in
144  * MKLDNN format, we need to convert the data to the default format when
145  * data in the view is accessed.
146  */
147  inline bool IsView() const {
148  // View only works on the default storage
149  if (storage_type() != kDefaultStorage)
150  return false;
151  // If the array reuses memory, its shape may be different from the storage
152  // shape. However, we shouldn't consider it as a view.
153  if (reuse_)
154  return false;
155  return byte_offset_ > 0 || shape() != ptr_->storage_shape;
156  }
157 
161  inline const TShape& shape() const {
162  return shape_;
163  }
169  inline const TShape &storage_shape() const {
170  CHECK(ptr_ != nullptr);
171  CHECK_NE(storage_type(), kDefaultStorage)
172  << "storage_shape() is not intended for kDefaultStorage.";
173  return ptr_->storage_shape;
174  }
175 
181  inline const TShape& aux_shape(size_t index) const {
182  CHECK_NE(storage_type(), kDefaultStorage)
183  << "aux_shape() is not intended for kDefaultStorage.";
184  return ptr_->aux_shapes[index];
185  }
186 
187  /* \return the shapes of all aux data */
188  const std::vector<TShape>& aux_shapes() const {
189  CHECK_NE(storage_type(), kDefaultStorage)
190  << "aux_shapes() is not intended for kDefaultStorage.";
191  return ptr_->aux_shapes;
192  }
193 
195  const std::vector<int>& aux_types() const {
196  CHECK_NE(storage_type(), kDefaultStorage)
197  << "aux_types() is not intended for kDefaultStorage.";
198  return ptr_->aux_types;
199  }
200 
208  inline void set_aux_shape(size_t index, const TShape& shape) const {
209  ptr_->set_aux_shape(index, shape);
210  }
211 
215  inline const TBlob& data() const {
216  if (storage_type() == kDefaultStorage) CheckAndAlloc();
217  SetTBlob();
218  return tblob_;
219  }
223  NDArray grad() const;
224 
228  inline TBlob aux_data(size_t i) const {
229  auto stype = storage_type();
230  TBlob res;
231  auto shape = aux_shape(i);
232  auto type = aux_type(i);
233  MSHADOW_TYPE_SWITCH(type, DType, {
234  auto dptr = static_cast<DType*>(ptr_->aux_handles[i].dptr);
235  CHECK(stype == kRowSparseStorage || stype == kCSRStorage)
236  << "Unexpected storage type: " << stype;
237  res = TBlob(dptr, shape, ptr_->aux_handles[i].ctx.dev_mask(), type);
238  });
239  return res;
240  }
244  inline Context ctx() const {
245  CHECK(!is_none());
246  return ptr_->shandle.ctx;
247  }
251  inline int dtype() const {
252  return dtype_;
253  }
254  inline int aux_type(size_t i) const {
255  CHECK(!is_none());
256  return ptr_->aux_types[i];
257  }
258 
260  return storage_type_;
261  }
263  inline bool is_none() const {
264  return ptr_.get() == nullptr;
265  }
267  bool fresh_out_grad() const;
269  void set_fresh_out_grad(bool state) const;
274  inline bool storage_initialized() const {
275  if (is_none()) return false;
276  auto stype = storage_type();
277  CHECK_NE(stype, kDefaultStorage)
278  << "storage_initialized() is not intended for kDefaultStorage.";
279  if (stype == kRowSparseStorage) {
280  CHECK_EQ(aux_shape(rowsparse::kIdx)[0], storage_shape()[0])
281  << "inconsistent storage shape " << storage_shape()
282  << " vs. aux shape " << aux_shape(rowsparse::kIdx);
283  return aux_shape(rowsparse::kIdx).Size() != 0;
284  } else if (stype == kCSRStorage) {
285  CHECK_EQ(aux_shape(csr::kIdx)[0], storage_shape()[0])
286  << "inconsistent storage shape " << storage_shape()
287  << " vs. aux shape " << aux_shape(csr::kIdx);
288  return aux_shape(csr::kIdx).Size() != 0;
289  } else {
290  LOG(FATAL) << "Unknown storage type";
291  }
292  return true;
293  }
296  CHECK(!is_none());
297  CHECK_EQ(storage_type(), kDefaultStorage);
298  CheckAndAlloc();
299  return ptr_->shandle;
300  }
305  inline void WaitToRead() const {
306  if (is_none()) return;
307  Engine::Get()->WaitForVar(ptr_->var);
308  }
313  inline void WaitToWrite() const {
314  if (is_none()) return;
320  [](RunContext, Engine::CallbackOnComplete on_complete) {
321  on_complete();
322  }, Context{}, {}, {ptr_->var});
323  Engine::Get()->WaitForVar(ptr_->var);
324  }
326  inline Engine::VarHandle var() const {
327  return ptr_->var;
328  }
330  inline size_t byte_offset() const {
331  return byte_offset_;
332  }
337  void Save(dmlc::Stream *strm) const;
343  bool LegacyLoad(dmlc::Stream *strm, const uint32_t magic);
349  bool Load(dmlc::Stream *strm);
355  NDArray &operator=(real_t scalar);
362  NDArray &operator+=(const NDArray &src);
369  NDArray &operator+=(const real_t &src);
376  NDArray &operator-=(const NDArray &src);
383  NDArray &operator-=(const real_t &src);
390  NDArray &operator*=(const NDArray &src);
397  NDArray &operator*=(const real_t &src);
404  NDArray &operator/=(const NDArray &src);
411  NDArray &operator/=(const real_t &src);
417  NDArray Copy(Context ctx) const;
428  void SyncCopyFromCPU(const void *data, size_t size) const;
429 
433  void SyncCopyFromNDArray(const NDArray &src, int i = -1, int j = -1);
434 
445  void SyncCopyToCPU(void *data, size_t size) const;
451  void SyncCheckFormat(const bool full_check) const;
458  NDArray Slice(index_t begin, index_t end) const;
465  NDArray SliceWithRecord(index_t begin, index_t end);
471  NDArray At(index_t idx) const;
477  NDArray AtWithRecord(index_t idx);
482  NDArray aux_ndarray(size_t i) const;
483 
488  NDArray data_ndarray() const;
489 
497  inline NDArray AsArray(const TShape &shape, int dtype) const {
498  CHECK_EQ(storage_type(), kDefaultStorage)
499  << "AsArray is intended only for kDefaultStorage.";
500  CHECK_GE(ptr_->shandle.size,
501  shape.Size() * mshadow::mshadow_sizeof(dtype))
502  << "NDArray.AsArray: target memory size is bigger";
503  // We can't reuse memory in a view.
504  CHECK(!IsView());
505  NDArray ret = *this;
506  ret.shape_ = shape;
507  ret.dtype_ = dtype;
508  ret.reuse_ = true;
509  return ret;
510  }
511 
519  inline void SparseUpdateChunk(const NDArray &arr) const {
520  CHECK(shape_ == arr.shape_) << "ndarray shape is different from the target";
521  CHECK(dtype_ == arr.dtype_) << "ndarray dtype is different from the target";
522  auto stype = arr.storage_type();
523  CHECK(stype == kCSRStorage || stype == kRowSparseStorage)
524  << "Only to be used with CSR and RSP storage types";
525  // swap shandles between src and dst
526  Storage::Handle shandle_dst = arr.ptr_->shandle;
527  arr.ptr_->shandle = ptr_->shandle;
528  ptr_->shandle = shandle_dst;
529 
530  ptr_->storage_shape = arr.ptr_->storage_shape;
531  ptr_->storage_type = arr.ptr_->storage_type;
532  ptr_->ctx = arr.ptr_->ctx;
533 
534  // swap aux_handles between src and dst
535  size_t aux_idx = 0;
536  CHECK(ptr_->aux_handles.size() == arr.ptr_->aux_handles.size())
537  << "ndarray number of aux_handles is different from target";
538  for (auto &aux_handle : arr.ptr_->aux_handles) {
539  Storage::Handle aux_dst = ptr_->aux_handles[aux_idx];
540  ptr_->aux_handles[aux_idx] = aux_handle;
541  aux_handle = aux_dst;
542  aux_idx++;
543  }
544  ptr_->aux_types = arr.ptr_->aux_types;
545  ptr_->aux_shapes = arr.ptr_->aux_shapes;
546  }
547 
553  NDArray Reshape(const TShape &shape) const;
559  NDArray ReshapeWithRecord(const TShape &shape);
563  NDArray Detach() const {
564  NDArray ret(*this);
565  ret.entry_ = nnvm::NodeEntry{nullptr, 0, 0};
566  return ret;
567  }
568 
569  nnvm::Symbol get_autograd_symbol() const;
574  inline void CheckAndAlloc() const {
575  CHECK_EQ(storage_type(), kDefaultStorage);
576  ptr_->CheckAndAlloc();
577  }
578 
588  void ReshapeAndAlloc(const TShape& shape) {
589  CHECK_EQ(storage_type(), kDefaultStorage);
590  CHECK(!is_none());
591  shape_ = shape;
592  ptr_->CheckAndAlloc(shape.Size() * mshadow::mshadow_sizeof(dtype_));
593  }
594 
595  /* !
596  * \brief Alloc memory for non-default storage
597  * aux_shape is only known at run time
598  */
599  inline void CheckAndAlloc(const std::vector<TShape> &aux_shapes) const {
600  CHECK_NE(storage_type(), kDefaultStorage)
601  << "CheckAndAlloc(aux_shapes) is not intended for kDefaultStorage";
602  ptr_->CheckAndAlloc(shape_, aux_shapes, dtype_);
603  }
604  inline void CheckAndAllocData(const TShape &storage_shape) const {
605  CHECK_NE(storage_type(), kDefaultStorage)
606  << "CheckAndAllocData is not intended for kDefaultStorage";
607  ptr_->CheckAndAllocData(storage_shape, dtype_);
608  }
609  inline void CheckAndAllocAuxData(size_t i, const TShape &aux_shape) const {
610  CHECK_NE(storage_type(), kDefaultStorage)
611  << "CheckAndAllocAuxData is not intended for kDefaultStorage";
612  ptr_->CheckAndAllocAuxData(i, aux_shape);
613  }
614 
615 #if MXNET_USE_MKLDNN == 1
616  /*
617  * Test if the data is stored in one of special MKLDNN format.
618  */
619  bool IsMKLDNNData() const {
620  return ptr_->IsMKLDNN();
621  }
622  /*
623  * Test if the data is stored in one of default MXNet formats.
624  */
625  bool IsDefaultData() const {
626  return ptr_->IsDefault();
627  }
628  /*
629  * All functions below return a raw pointer to mkldnn memory. Actually there
630  * is a shared pointer that hold the memory either in NDArray or in MKLDNN
631  * stream. As long as we call these functions inside an operator, the return
632  * memory is always valid.
633  */
634 
635  /*
636  * This function returns mkldnn::memory with the default primitive_desc.
637  */
638  const mkldnn::memory *GetMKLDNNData() const;
639  /*
640  * This function returns mkldnn::memory with the given primitive_desc
641  * as long as the array size meets the required size in the given primitive_desc.
642  */
643  const mkldnn::memory *GetMKLDNNData(
644  const mkldnn::memory::primitive_desc &desc) const;
645  /*
646  * This function returns mkldnn::memory with the given primitive_desc.
647  * The returned mkldnn::memory will have the same physical layout as
648  * the given primitive_desc.
649  */
650  const mkldnn::memory *GetMKLDNNDataReorder(
651  const mkldnn::memory::primitive_desc &desc) const;
652 
653  /*
654  * This function copies data from mkldnn memory.
655  */
656  void CopyFrom(const mkldnn::memory &mem);
657  /*
658  * This function allocates memory for array and creates mkldnn memory
659  * with the specified format.
660  */
661  mkldnn::memory *CreateMKLDNNData(
662  const mkldnn::memory::primitive_desc &desc);
663 
664  /*
665  * These are the async version of the methods above.
666  * It changes the layout of this NDArray, but it happens after all accesses to
667  * the array are complete.
668  */
669  void Reorder2DefaultAsync();
670  void MKLDNNDataReorderAsync(const mkldnn::memory::primitive_desc &desc);
671 
672  /*
673  * This creates a new NDArray with the reordered data.
674  * It doesn't affect the data of the original NDArray.
675  */
676  NDArray Reorder2Default() const;
677 
678  void InvalidateMKLDNNData() {
679  // Removing mkl_mem_ means the NDArray will store data in the default format.
680  ptr_->mkl_mem_ = nullptr;
681  }
682 
683  /*
684  * This function is used inside operators to reshape an array.
685  * It doesn't change the layout of the original array and allocate memory from
686  * the temporary buffer. The returned array is only valid inside the current
687  * invocation of this operator.
688  * This is different from Reshape. Reshape will cause data in the array to be
689  * converted to the default layout and allocate memory from malloc directly,
690  * which can be expensive.
691  * It's used by FullyConnected right now.
692  */
693  NDArray MKLDNNDataReshape(const TShape &shape) const;
694 #endif
695 
702  static void Save(dmlc::Stream* fo,
703  const std::vector<NDArray>& data,
704  const std::vector<std::string>& names);
711  static void Load(dmlc::Stream* fi,
712  std::vector<NDArray>* data,
713  std::vector<std::string>* keys);
714 
715  private:
716  friend class Imperative;
718  // shandle is used to store the actual values in the NDArray
719  // aux_handles store the aux data(such as indices) if it's needed by non-default storage.
720  struct Chunk {
724  Storage::Handle shandle;
729  std::vector<Storage::Handle> aux_handles;
730 
731 #if MXNET_USE_MKLDNN == 1
732 
734  std::shared_ptr<MKLDNNMemory> mkl_mem_;
735 #endif
736 
737  Engine::VarHandle var;
743  bool static_data;
746  bool delay_alloc;
747  // the type of the storage. The storage_type is never kUndefinedStorage once the chunk
748  // is constructed.
749  NDArrayStorageType storage_type = kDefaultStorage;
751  std::vector<int> aux_types;
752  // context of data
753  Context ctx;
754  // The shape of the chunk data.
755  // This might not be the same shape as the NDArray, since the storage may be sparse.
756  // The default value for storage_shape is {0} when an empty non-default NDArray is created.
757  TShape storage_shape;
758  // The shape of aux data. The default value for the shape depends on the type of storage.
759  // If aux_shapes[i].Size() is zero, aux data i is empty.
760  std::vector<TShape> aux_shapes;
761 
763  Chunk() : static_data(true), delay_alloc(false) {}
764 
766  Chunk(TShape shape, Context ctx_, bool delay_alloc_, int dtype)
767  : static_data(false), delay_alloc(true), ctx(ctx_) {
768  auto size = shape.Size();
769  storage_shape = shape;
770  var = Engine::Get()->NewVariable();
771  shandle.size = size * mshadow::mshadow_sizeof(dtype);
772  shandle.ctx = ctx_;
773  if (!delay_alloc_) this->CheckAndAlloc();
774  }
775 
776  Chunk(const TBlob &data, int dev_id)
777  : static_data(true), delay_alloc(false) {
778  CHECK(storage_type == kDefaultStorage);
779  var = Engine::Get()->NewVariable();
780  if (data.dev_mask() == cpu::kDevMask) {
781  ctx = Context::CPU();
782  } else {
783  CHECK_EQ(data.dev_mask(), gpu::kDevMask);
784  ctx = Context::GPU(dev_id);
785  }
786  // init shandle
787  shandle.ctx = ctx;
788  shandle.dptr = data.dptr_;
789  shandle.size = data.shape_.Size() * mshadow::mshadow_sizeof(data.type_flag_);
790  storage_shape = data.shape_;
791  }
792 
793  Chunk(int shared_pid, int shared_id, const TShape& shape, int dtype)
794  : static_data(false), delay_alloc(false) {
795  var = Engine::Get()->NewVariable();
796  ctx = Context::CPUShared(0);
797  shandle.size = shape.Size() * mshadow::mshadow_sizeof(dtype);
798  shandle.ctx = ctx;
799  shandle.shared_pid = shared_pid;
800  shandle.shared_id = shared_id;
801  Storage::Get()->Alloc(&shandle);
802  storage_shape = shape;
803  }
804  // Constructor for a non-default storage chunk
805  Chunk(NDArrayStorageType storage_type_, const TShape &storage_shape_, Context ctx_,
806  bool delay_alloc_, int dtype, const std::vector<int> &aux_types_,
807  const std::vector<TShape> &aux_shapes_)
808  : static_data(false), delay_alloc(delay_alloc_), storage_type(storage_type_),
809  aux_types(aux_types_), ctx(ctx_), storage_shape(storage_shape_),
810  aux_shapes(aux_shapes_) {
811  shandle.ctx = ctx;
812  var = Engine::Get()->NewVariable();
813  // aux_handles always reflect the correct number of aux data
814  for (size_t i = 0; i < aux_shapes.size(); i++) {
815  CheckAndAllocAuxData(i, aux_shapes[i]);
816  // this line is needed in case when aux_shapes[i].Size() = 0
817  // aux_handles[i] will not be updated and take only default value.
818  aux_handles[i].ctx = ctx;
819  }
820  if (!delay_alloc) {
821  CheckAndAllocData(storage_shape, dtype);
822  }
823  }
824 
825  Chunk(const NDArrayStorageType storage_type_, const TBlob &data,
826  const std::vector<TBlob> &aux_data, int dev_id)
827  : static_data(true), delay_alloc(false), storage_type(storage_type_) {
828  using namespace mshadow;
829  CHECK_NE(storage_type, kDefaultStorage);
830  // init var
831  var = Engine::Get()->NewVariable();
832  // init ctx
833  if (data.dev_mask() == cpu::kDevMask) {
834  ctx = Context::CPU();
835  } else {
836  CHECK_EQ(data.dev_mask(), gpu::kDevMask);
837  ctx = Context::GPU(dev_id);
838  }
839  // init shandle
840  shandle.ctx = ctx;
841  shandle.dptr = data.dptr_;
842  shandle.size = data.shape_.Size() * mshadow_sizeof(data.type_flag_);
843  storage_shape = data.shape_;
844  // init aux handles
845  for (const auto &aux : aux_data) {
846  Storage::Handle aux_handle;
847  aux_handle.ctx = ctx;
848  aux_handle.dptr = aux.dptr_;
849  aux_handle.size = aux.shape_.Size() * mshadow_sizeof(aux.type_flag_);
850  aux_handles.push_back(aux_handle);
851  aux_types.emplace_back(aux.type_flag_);
852  aux_shapes.emplace_back(aux.shape_);
853  }
854  }
855 
857  inline void set_aux_shape(const size_t i, const TShape& shape) {
858  aux_shapes[i] = shape;
859  if (storage_shape.ndim() > 0) {
860  if (storage_type == kRowSparseStorage && i == rowsparse::kIdx) {
861  storage_shape[0] = shape[0];
862  } else if (storage_type == kCSRStorage && i == csr::kIdx) {
863  storage_shape[0] = shape[0];
864  }
865  }
866  }
867 
869  inline void CheckAndAlloc(void) {
870  if (delay_alloc) {
871  shandle = Storage::Get()->Alloc(shandle.size, shandle.ctx);
872 #if MXNET_USE_MKLDNN == 1
873  mkl_mem_ = nullptr;
874 #endif
875  delay_alloc = false;
876  }
877  }
878 
880  // size is the number of bytes
881  void CheckAndAlloc(uint64_t dbytes) {
882  CHECK_EQ(kDefaultStorage, storage_type)
883  << "CheckAndAlloc(dbytes) is only intended for kDefaultStorage";
884  dbytes = std::max(dbytes, static_cast<uint64_t>(shandle.size));
885  if (delay_alloc) {
886  shandle = Storage::Get()->Alloc(dbytes, shandle.ctx);
887 #if MXNET_USE_MKLDNN == 1
888  mkl_mem_ = nullptr;
889 #endif
890  delay_alloc = false;
891  } else if (shandle.size < dbytes) {
892  // free storage if necessary and alloc again
893  if (shandle.size > 0) Storage::Get()->Free(shandle);
894  // init storage
895  shandle = Storage::Get()->Alloc(dbytes, shandle.ctx);
896 #if MXNET_USE_MKLDNN == 1
897  mkl_mem_ = nullptr;
898 #endif
899  }
900  }
901 
902  inline void CheckAndAlloc(const TShape &shape, const std::vector<TShape> &aux_shapes,
903  int dtype) {
904  // calculate size, perform allocation
905  if (kRowSparseStorage == storage_type) {
906  // For row sparse, aux_shape indicates the number of rows to allocate
907  auto aux_shape = aux_shapes[rowsparse::kIdx];
908  CheckAndAllocAuxData(rowsparse::kIdx, aux_shape);
909  TShape storage_shape(shape);
910  storage_shape[0] = aux_shape[0];
911  CheckAndAllocData(storage_shape, dtype);
912  } else if (kCSRStorage == storage_type) {
913  CheckAndAllocAuxData(csr::kIndPtr, aux_shapes[csr::kIndPtr]);
914  CheckAndAllocAuxData(csr::kIdx, aux_shapes[csr::kIdx]);
915  CheckAndAllocData(aux_shapes[csr::kIdx], dtype);
916  } else {
917  LOG(FATAL) << "Storage type " << storage_type << " not implemented for CheckAndAlloc";
918  }
919  }
920  // create storage handle for data based on shape and dtype, assuming ctx is set
921  // storage shape is also updated
922  // if data is already allocated, try reuse the storage. Otherwise, free the current one
923  // and allocate new storage
924  void CheckAndAllocData(const TShape &shape, int dtype);
925 
926 #if MXNET_USE_MKLDNN == 1
927  // Have MKL memory reference to the data in the default storage
928  // or create memory for MKLDNN.
929  void SetMKLMem(const TShape &shape, int dtype);
930  // If the data is stored in MKLDNN layout, we reorder data in mkl_mem_ and
931  // save the result in shandle.
932  void Reorder2Default();
933  // Reroder data to a specified layout.
934  void MKLDNNDataReorder(const mkldnn::memory::primitive_desc &desc);
935  bool IsMKLDNN() const;
936  bool IsDefault() const;
937 #endif
938 
939  // create storage handle for aux data based on shape
940  // this function assumes ctx, aux shapes and aux types are set
941  // aux shape is also updated
942  // if aux data is already allocated, try reuse the storage. Otherwise, free the current one
943  // and allocate new storage
944  inline void CheckAndAllocAuxData(size_t i, const TShape &shape) {
945  CHECK_EQ(shape.ndim(), 1) << "shape must be 1D in CheckAndAllocAuxData";
946  CHECK_NE(storage_type, kUndefinedStorage)
947  << "storage type cannot be kUndefinedStorage in CheckAndAllocAuxData";
948  CHECK_NE(storage_type, kDefaultStorage)
949  << "storage type cannot be kDefaultStorage in CheckAndAllocAuxData";
950  if (aux_handles.size() <= i) {
951  aux_handles.resize(i + 1);
952  }
953  size_t aux_bytes = shape.Size() * mshadow::mshadow_sizeof(aux_types[i]);
954  if (aux_handles[i].size < aux_bytes) {
955  // free storage if necessary and alloc again
956  if (aux_handles[i].size > 0) Storage::Get()->Free(aux_handles[i]);
957  // init aux storage
958  aux_handles[i] = Storage::Get()->Alloc(aux_bytes, ctx);
959  }
960  // init shape
961  set_aux_shape(i, shape);
962  }
964  ~Chunk();
965  }; // struct Chunk
966 
967  void SetTBlob() const;
968 
970  std::shared_ptr<Chunk> ptr_{nullptr};
972  TShape shape_;
974  size_t byte_offset_ = 0;
976  int dtype_ = -1;
978  bool reuse_ = false;
980  NDArrayStorageType storage_type_ = kUndefinedStorage;
982  nnvm::NodeEntry entry_;
990  mutable TBlob tblob_;
991 }; // class NDArray
992 
996 size_t num_aux_data(NDArrayStorageType stype);
997 
1009 void CopyFromTo(const NDArray &from, const NDArray *to, int priority = 0);
1010 
1022 void CopyFromTo(const NDArray &from, const NDArray& to, int priority = 0);
1023 
1030 void ElementwiseSum(const std::vector<NDArray> &source, NDArray *out, int priority = 0);
1031 
1038 NDArray operator+(const NDArray &lhs, const NDArray &rhs);
1045 NDArray operator+(const NDArray &lhs, const real_t &rhs);
1052 NDArray operator-(const NDArray &lhs, const NDArray &rhs);
1059 NDArray operator-(const NDArray &lhs, const real_t &rhs);
1066 NDArray operator*(const NDArray &lhs, const NDArray &rhs); \
1073 NDArray operator*(const NDArray &lhs, const real_t &rhs);
1080 NDArray operator/(const NDArray &lhs, const NDArray &rhs);
1087 NDArray operator/(const NDArray &lhs, const real_t &rhs);
1088 
1093 void RandomSeed(uint32_t seed);
1098 void RandomSeed(Context ctx, uint32_t seed);
1105 void SampleUniform(real_t begin, real_t end, NDArray *out);
1112 void SampleGaussian(real_t mu, real_t sigma, NDArray *out);
1119 void SampleGamma(real_t alpha, real_t beta, NDArray *out);
1125 void SampleExponential(real_t lambda, NDArray *out);
1131 void SamplePoisson(real_t lambda, NDArray *out);
1138 void SampleNegBinomial(int32_t k, real_t p, NDArray *out);
1145 void SampleGenNegBinomial(real_t mu, real_t alpha, NDArray *out);
1146 
1147 
1148 //--------------------------------------------------------------
1149 // The following part are API Registration of NDArray functions.
1150 //--------------------------------------------------------------
1151 
1153 typedef std::function<void (NDArray **used_vars,
1154  real_t *scalars,
1155  NDArray **mutate_vars,
1156  int num_params,
1157  char **param_keys,
1158  char **param_vals)> NDArrayAPIFunction;
1174 };
1177  : public dmlc::FunctionRegEntryBase<NDArrayFunctionReg,
1178  NDArrayAPIFunction> {
1180  unsigned num_use_vars;
1184  unsigned num_scalars;
1191  : num_use_vars(0),
1192  num_mutate_vars(0),
1193  num_scalars(0),
1194  type_mask(0) {}
1201  inline NDArrayFunctionReg &set_function(void (*fsetvalue)(const real_t &rhs,
1202  NDArray *out)) {
1203  body = [fsetvalue] (NDArray **used_vars, real_t *s, NDArray **mutate_vars,
1204  int num_params, char **param_keys, char **param_vals) {
1205  (*fsetvalue)(s[0], mutate_vars[0]);
1206  };
1207  num_mutate_vars = 1; num_scalars = 1;
1208  this->add_argument("src", "real_t", "Source input to the function.");
1209  return *this;
1210  }
1217  inline NDArrayFunctionReg &set_function(void(*fternary)(const NDArray &lhs,
1218  const NDArray &mhs,
1219  const NDArray &rhs,
1220  NDArray *out)) {
1221  body = [fternary](NDArray **used_vars,
1222  real_t *s, NDArray **mutate_vars,
1223  int num_params, char **param_keys, char **param_vals) {
1224  (*fternary)(*used_vars[0], *used_vars[1], *used_vars[2], mutate_vars[0]);
1225  };
1226  num_use_vars = 3; num_mutate_vars = 1;
1228  this->add_argument("lhs", "NDArray", "Left operand to the function.");
1229  this->add_argument("mhs", "NDArray", "Middle operand to the function.");
1230  this->add_argument("rhs", "NDArray", "Right operand to the function.");
1231  return *this;
1232  }
1239  inline NDArrayFunctionReg &set_function(void (*fbinary)(const NDArray &lhs,
1240  const NDArray &rhs,
1241  NDArray *out)) {
1242  body = [fbinary] (NDArray **used_vars, real_t *s, NDArray **mutate_vars,
1243  int num_params, char **param_keys, char **param_vals) {
1244  (*fbinary)(*used_vars[0], *used_vars[1], mutate_vars[0]);
1245  };
1246  num_use_vars = 2; num_mutate_vars = 1;
1248  this->add_argument("lhs", "NDArray", "Left operand to the function.");
1249  this->add_argument("rhs", "NDArray", "Right operand to the function.");
1250  return *this;
1251  }
1258  inline NDArrayFunctionReg &set_function(void (*fscalar)(const NDArray &lhs,
1259  const real_t &rhs,
1260  NDArray *out)) {
1261  body = [fscalar] (NDArray **used_vars, real_t *s, NDArray **mutate_vars,
1262  int num_params, char **param_keys, char **param_vals) {
1263  (*fscalar)(*used_vars[0], s[0], mutate_vars[0]);
1264  };
1265  num_use_vars = 1; num_mutate_vars = 1; num_scalars = 1;
1267  this->add_argument("lhs", "NDArray", "Left operand to the function.");
1268  this->add_argument("rhs", "real_t", "Right operand to the function.");
1269  return *this;
1270  }
1277  inline NDArrayFunctionReg &set_function(void (*funary)(const NDArray &src,
1278  NDArray *out)) {
1279  body = [funary] (NDArray **used_vars, real_t *s, NDArray **mutate_vars,
1280  int num_params, char **param_keys, char **param_vals) {
1281  (*funary)(*used_vars[0], mutate_vars[0]);
1282  };
1283  num_use_vars = 1; num_mutate_vars = 1;
1285  this->add_argument("src", "NDArray", "Source input to the function.");
1286  return *this;
1287  }
1295  void (*fgeneric)(NDArray **used_vars,
1296  real_t *s,
1297  NDArray **mutate_vars,
1298  const std::map<std::string, std::string>& param)) {
1299  body = [fgeneric] (NDArray **used_vars, real_t *s, NDArray **mutate_vars,
1300  int num_params, char **param_keys, char **param_vals) {
1301  std::map<std::string, std::string> param;
1302  for (int i = 0; i < num_params; ++i) {
1303  param[param_keys[i]] = param_vals[i];
1304  }
1305  fgeneric(used_vars, s, mutate_vars, param);
1306  };
1307  return *this;
1308  }
1314  inline NDArrayFunctionReg &set_num_use_vars(unsigned n) {
1315  num_use_vars = n; return *this;
1316  }
1323  num_mutate_vars = n; return *this;
1324  }
1330  inline NDArrayFunctionReg &set_num_scalars(unsigned n) {
1331  num_scalars = n; return *this;
1332  }
1338  inline NDArrayFunctionReg &set_type_mask(int tmask) {
1339  type_mask = tmask; return *this;
1340  }
1341 }; // NDArrayFunctionReg
1342 
1354 #define MXNET_REGISTER_NDARRAY_FUN(name) \
1355  DMLC_REGISTRY_REGISTER(::mxnet::NDArrayFunctionReg, NDArrayFunctionReg, name)
1356 
1357 } // namespace mxnet
1358 
1359 namespace dmlc {
1361 DMLC_DECLARE_TRAITS(has_saveload, mxnet::NDArray, true);
1362 } // namespace dmlc
1363 #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:1322
NDArrayFormatErr
Definition: ndarray.h:68
Engine::VarHandle var() const
Definition: ndarray.h:326
void RandomSeed(uint32_t seed)
Seed all random number generator in mxnet.
NDArrayStorageType storage_type() const
Definition: ndarray.h:259
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:169
NDArrayFunctionReg()
constructor
Definition: ndarray.h:1190
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:588
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:1314
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:1186
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:1277
NDArray Detach() const
Return a copy of this NDArray without autograd history.
Definition: ndarray.h:563
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:1330
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:1182
execution time context. The information needed in runtime for actual execution.
Definition: base.h:244
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:1258
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:295
NDArray()
default constructor
Definition: ndarray.h:85
unsigned num_use_vars
number of variable used by this function
Definition: ndarray.h:1180
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:1217
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:2391
RowSparseAuxType
Definition: ndarray.h:58
Definition: ndarray.h:70
bool is_none() const
Definition: ndarray.h:263
all the scalar should go before use_vars
Definition: ndarray.h:1164
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:519
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:1173
Definition: ndarray.h:73
static Storage * Get()
const TShape & shape() const
Definition: ndarray.h:161
Definition: ndarray.h:1359
virtual void WaitForVar(VarHandle var)=0
Wait for a variable.
const std::vector< TShape > & aux_shapes() const
Definition: ndarray.h:188
bool IsView() const
Definition: ndarray.h:147
Context ctx() const
Definition: ndarray.h:244
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:305
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:251
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:274
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:208
void CheckAndAllocData(const TShape &storage_shape) const
Definition: ndarray.h:604
size_t num_aux_data(NDArrayStorageType stype)
NDArrayFunctionReg & set_type_mask(int tmask)
set type mask
Definition: ndarray.h:1338
engine::VarHandle VarHandle
Variable pointer.
Definition: engine.h:105
void WaitToWrite() const
Block until all the pending read/write operations with respect to current NDArray are finished...
Definition: ndarray.h:313
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:1201
NDArray(int shared_pid, int shared_id, const TShape &shape, int dtype)
create ndarray from shared memory
Definition: ndarray.h:120
NDArray operator+(const NDArray &lhs, const NDArray &rhs)
elementwise add
size_t byte_offset() const
Definition: ndarray.h:330
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:1176
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:1239
static Context CPU(int32_t dev_id=0)
runtime functions for NDArray
Definition: imperative.h:56
int aux_type(size_t i) const
Definition: ndarray.h:254
OnComplete Callback to the engine, called by AsyncFn when action completes.
Definition: engine.h:56
all the use_vars should go before scalar
Definition: ndarray.h:1162
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:497
void CheckAndAlloc(const std::vector< TShape > &aux_shapes) const
Definition: ndarray.h:599
unsigned num_scalars
number of scalars used by this function
Definition: ndarray.h:1184
static Engine * Get()
const TBlob & data() const
Definition: ndarray.h:215
void CheckAndAllocAuxData(size_t i, const TShape &aux_shape) const
Definition: ndarray.h:609
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:135
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:574
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
TBlob aux_data(size_t i) const
Definition: ndarray.h:228
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:181
ndarray interface
Definition: ndarray.h:82
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:114
int dev_mask() const
device mask of the corresponding device
Definition: tensor_blob.h:209
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:1158
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:1294
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:195
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:1160